From: Adrian Szyndela Date: Mon, 26 Oct 2020 07:59:21 +0000 (+0100) Subject: serialization: add direct backend X-Git-Tag: accepted/tizen/unified/20201105.124409~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F65%2F246365%2F4;p=platform%2Fcore%2Fsystem%2Flibdbuspolicy.git serialization: add direct backend Change-Id: I5c9345310f58fa62c7fec3d8a1ccc56978e4c53a --- diff --git a/Makefile.am b/Makefile.am index f17af0b..da4f145 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,8 +64,10 @@ COMMON_SRC =\ src/internal/tslog.cpp \ src/internal/serializer.cpp \ src/internal/serializer_flatbuffers.cpp \ + src/internal/serializer_direct.cpp \ src/internal/policy_containers.cpp \ src/internal/print_content.cpp \ + src/internal/storage_backend_direct.cpp \ src/internal/storage_backend_flatbuffers.cpp \ src/internal/storage_backend_serialized.cpp \ src/internal/storage_backend_xml.cpp diff --git a/src/internal/serialization_backend.hpp b/src/internal/serialization_backend.hpp index 2b3395a..159ae0d 100644 --- a/src/internal/serialization_backend.hpp +++ b/src/internal/serialization_backend.hpp @@ -22,6 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "serializer_direct.hpp" +#include "storage_backend_direct.hpp" + #include "serializer_flatbuffers.hpp" #include "storage_backend_flatbuffers.hpp" @@ -32,6 +35,11 @@ struct SerializationBackendFlatbuffers { typedef ldp_serializer::SerializerFlatbuffers Serializer; }; -typedef SerializationBackendFlatbuffers SerializationBackend; +struct SerializationBackendDirect { + typedef ldp_serialized::StorageBackendDirect Storage; + typedef ldp_serializer::SerializerDirect Serializer; +}; + +typedef SerializationBackendDirect SerializationBackend; } diff --git a/src/internal/serialized.hpp b/src/internal/serialized.hpp new file mode 100644 index 0000000..70589af --- /dev/null +++ b/src/internal/serialized.hpp @@ -0,0 +1,259 @@ +#pragma once + +/* MIT License + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ + +#include +#include +#include +#include + +namespace ldp_serializer { + +/* The Serialized class represents serialized data created from some structures. + * It serializes values of the following types: + * - uint32_t; + * - enum types (serialized as uint32_t); + * - bool type (serialized as uint32_t) + * - container types (maps, sets, vectors, serialized as a kind of array, needs special preparation, see below); + * - string types, as a special case of container types. + * + * Usage: prepare your data, and pass them to the constructor. + * Example: if your data is: + * - single integer: 123; + * - single enum value: MyEnumValue; + * - single string: "MyString"; + * - a single, already serialized object Already; + * - a map v: int->string; + * you may serialize the data by writing: + * auto serialized = Serialized{123, MyEnumValue, "MyString", Already, + * serialize_container(v, [](const auto &elem) { + * return Serialized{elem.first, elem.second}; + * })}; + * const uint8_t *data = serialized.releaseData(); // or better const auto *data = ... + * + * when you're done serializing, get your data with releaseData() method. You're now responsible for + * freeing the data. The Serialized object can be now disposed. + * + * NOTE: Never try to serialize just a single already serialized object, as this probably won't work. + * It may destroy your object. + * ... and it makes little sense. It would just wrap it in another, unnecessary layer. + * Unfortunately, I didn't come up with a way to prevent it yet. + * + * The map above is serialized with helper function serialize_container, which takes 2 arguments: + * - a container; + * - a function object used to prepare a serialized element of the container. + * This is all for the special preparation. It creates a Serialized vector of Serialized elements, + * which you can pass as an argument for further serialization. + * + * Internal layout: + * Each Serialized object data contains a data buffer. + * A data buffer contains a number of fields and additional data. + * The number of fields is equal to the number of the parameters of the constructor. + * Each field is the same size as uint32_t. + * Any integer, enum, or bool is serialized as a field. + * Every other type is serialized like this: + * - the data is appended directly after the fields. + * - the corresponding field contains offset (from the start of the buffer) of the start of the data. + * The appended data may be a string. String data is serialized as: + * - a single uint32_t value, the string's length; + * - the characters; + * - nul byte; + * - padding. + * The appended data may be a vector. Vector data is serialized as fields: + * - field at index 0 contains number of elements in the vector; + * - first input element is serialized as a field at index 1, taking into account the rules + * above, that is integer = in-place field, other type = offset + data. + * - the indexes are relative to the first field at which vector is appended. The idea is + * that a vector should serialized to its own Serialized object, and then to another Serialized object as a field, + * but it should also work with serializing it "inline", as a series of fields. + */ + +class Serialized { + typedef uint32_t HeaderFieldType; + constexpr size_t alignment() { return sizeof(HeaderFieldType); } + + std::unique_ptr _data; + size_t _size{0}; // keeps the total allocated _data size + size_t _done{0}; // indicates how many fields were already written + size_t _done_bytes{0}; // indicates an offset where another field's data can be written + + HeaderFieldType *fields() { return reinterpret_cast(_data.get()); } + uint8_t *buf() { return &_data[_done_bytes]; } + + void startNextDataField() { + fields()[_done++] = _done_bytes; + } + + void written(size_t len) { + _done_bytes += len; + } + + template + void writeContainerData(T iterator, T end_iterator) { + std::copy(iterator, end_iterator, buf()); + written((end_iterator - iterator) * sizeof(*iterator)); + } + + template + void writeString(const T &field) { + startNextDataField(); + + // write string length (without nul-byte) + *reinterpret_cast(buf()) = field.size(); + written(sizeof(uint32_t)); + + writeContainerData(field.begin(), field.end()); + + // add nul byte and padding + do { + *buf() = 0; + written(1); + } while (_done_bytes % alignment() != 0); + } + + template + size_t computeSize(const Serialized &s, const Args &...args) + { return s.size() + computeSize(args...); } + + inline size_t strSize(size_t length) { + uint32_t size = length + 1 + sizeof(uint32_t); // 1: nul byte; placeholder for string length + return size + alignment() - (size%alignment()); // padding to alignment boundary + } + + template + size_t computeSize(const std::string &s, const Args &...args) + { return strSize(s.size()) + computeSize(args...); } + + template + size_t computeSize(boost::string_ref s, const Args &...args) + { return strSize(s.size()) + computeSize(args...); } + + template + size_t computeSize(uint32_t, const Args &...args) + { return computeSize(args...); } + + template + size_t computeSize(const std::vector &v, const Args &...args) { + size_t size = sizeof(uint32_t); + for (const auto &elem: v) + size += computeSize(elem); + return size + computeSize(args...); + } + + template ::value>, + typename ...Args> + size_t computeSize(T, const Args &...args) + { return computeSize(args...); } + + size_t computeSize() { return 0; } + + template + size_t computeNumOfFields(const T &, const Args &...args) + { return 1 + computeNumOfFields(args...); } + + template + size_t computeNumOfFields(const Serialized &s, const Args &...args) + { return (s.size() ? 1 : 0) + computeNumOfFields(args...); } + + template + size_t computeNumOfFields(const std::vector &v, const Args &...args) + { return 1 + v.size() + computeNumOfFields(args...); } // 1 for list size + + size_t computeNumOfFields() { return 0; } + + template + void writeFields(const T &t, const Args &...args) { + writeField(t); + writeFields(args...); + } + + void writeFields() {} + + void writeField(const Serialized &field) { + // we ignore empty fields + if (field.size() == 0) + return; + assert(field.data()); + + startNextDataField(); + + writeContainerData(field.data(), field.data() + field.size()); + } + void writeField(const std::string &field) { + writeString(field); + } + void writeField(boost::string_ref field) { + writeString(field); + } + void writeField(uint32_t field) { + fields()[_done++] = field; + } + template + void writeField(const std::vector &v) { + writeField(v.size()); + for (const auto &elem: v) + writeField(elem); + } + template ::value>, + typename ...Args> + void writeField(T field) { + writeField(static_cast(field)); + } + const uint8_t *data() const { return _data.get(); } +public: + // NOTE: never serialize single Serialized object into Serialized object as it may just swap data + // ... and it makes little sense anyway + Serialized(Serialized &&s) : _data{s._data.release()}, _size{s._size}, _done{s._done}, _done_bytes{s._done_bytes} {} + + template + explicit Serialized(const Args &...args) + { + _done_bytes = computeNumOfFields(args...) * sizeof(uint32_t); + _size = _done_bytes + computeSize(args...); + if (_size) + _data = std::make_unique(_size); + + writeFields(args...); + } + + uint32_t size() const { return _size; } + + const uint8_t *releaseData() { + return _data.release(); + } +}; + +template +Serialized serialize_container(const T &container, const F &serialize_elem_fun) { + std::vector sx; + sx.reserve(container.size()); + + for (const auto &e: container) + sx.push_back(serialize_elem_fun(e)); + + return Serialized{sx}; +} + +} diff --git a/src/internal/serializer_direct.cpp b/src/internal/serializer_direct.cpp new file mode 100644 index 0000000..d74ce9b --- /dev/null +++ b/src/internal/serializer_direct.cpp @@ -0,0 +1,170 @@ +/* MIT License + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ + +#include "policy_containers.hpp" +#include "serialization_traits.hpp" +#include "serialized.hpp" +#include "serializer_direct.hpp" + +using namespace ldp_serializer; +using ldp_serializer::Serialized; +using ldp_serializer::serialize_container; + +class SerializerDirectImpl { + const ldp_xml::StorageBackendXML &_db; + + template + Serialized serializeItem(const ItemType &v); + + template + Serialized serializeItems(const std::vector &v) { + return serialize_container(v, + [&](const auto &item) { + return serializeItem(item); + }); + } + + template + Serialized serializePolicy(const PolicyType &policy); + + template + Serialized serializeUserGroup(const std::map &m) { + return serialize_container(m, + [&](const auto &u) { + return Serialized{ + u.first, + this->serializePolicy(u.second)}; + }); + } + + Serialized serializeDecisionItem(const ldp_xml_parser::DecisionItem &item) { + return Serialized{ + item.getDecision(), + item.getPrivilege()}; + } + + Serialized serializeTree(const std::shared_ptr &node) { + return Serialized{ + node->getToken(), + serializeDecisionItem(node->getOwnPrefixDecisionItem()), + serializeDecisionItem(node->getOwnDecisionItem()), + serialize_container(node->getChildren(), + [&](const auto &child) { + return serializeTree(child.second); + }) + }; + } + + template + Serialized serializeSet(); + +public: + SerializerDirectImpl(const ldp_xml::StorageBackendXML &db) + : _db{db} + {} + + const uint8_t *serialize(size_t &size); +}; + +template +Serialized SerializerDirectImpl::serializeItem(const ItemType &item) { + return Serialized{ + serializeDecisionItem(item.getDecision()), + item.getName(), + item.getInterface(), + item.getMember(), + item.getPath(), + item.getType(), + item.isNamePrefix()}; +} + +template <> +Serialized SerializerDirectImpl::serializeItem(const ldp_xml_parser::ItemAccess &item) { + return Serialized{ + serializeDecisionItem(item.getDecision()), + item.getUid(), + item.getGid(), + item.getType()}; +} + +template +Serialized SerializerDirectImpl::serializePolicy(const PolicyType &policy) { + return serializeItems(policy.getItems()); +} + +template <> +Serialized SerializerDirectImpl::serializePolicy(const ldp_xml_parser::PolicyOwn &policy) { + return serializeTree(policy.getTree().getRoot()); +} + +template <> +Serialized SerializerDirectImpl::serializePolicy(const ldp_xml_parser::PolicySend &policy) { + return Serialized{ + serializeItems(policy.getItems()), + serialize_container(policy.getIndex(), + [&](const auto &elem) { + return Serialized{ + elem.first, + elem.second.m_bestScore, + Serialized{elem.second.m_itemRefs} + }; + }), + Serialized{policy.getPrefixIndex()}}; +} + +template +Serialized SerializerDirectImpl::serializeSet() { + return Serialized{ + serializePolicy(_db.getPolicyContextMandatory()), + serializePolicy(_db.getPolicyContextDefault()), + serializeUserGroup(_db.getPoliciesUser()), + serializeUserGroup(_db.getPoliciesGroup()) + }; +} + +template <> +Serialized SerializerDirectImpl::serializeSet() { + return Serialized{ + serializePolicy(_db.getPolicyContextMandatory()), + serializePolicy(_db.getPolicyContextDefault()) + }; +} + +const uint8_t *SerializerDirectImpl::serialize(size_t &size) { + Serialized r{ + serializeSet(), + serializeSet(), + serializeSet(), + serializeSet()}; + + size = r.size(); + return r.releaseData(); +} + +SerializerDirect::SerializerDirect() +{} + +const uint8_t *SerializerDirect::serialize(const ldp_xml::StorageBackendXML &db, size_t &size) { + SerializerDirectImpl impl{db}; + _data.reset(impl.serialize(size)); + return _data.get(); +} diff --git a/src/internal/serializer_direct.hpp b/src/internal/serializer_direct.hpp new file mode 100644 index 0000000..8b75d19 --- /dev/null +++ b/src/internal/serializer_direct.hpp @@ -0,0 +1,37 @@ +#pragma once + +/* MIT License + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ + +#include "storage_backend_xml.hpp" +#include + +namespace ldp_serializer { + +class SerializerDirect { + std::unique_ptr _data; +public: + SerializerDirect(); + const uint8_t *serialize(const ldp_xml::StorageBackendXML &db, size_t &size); +}; + +} diff --git a/src/internal/storage_backend_direct.cpp b/src/internal/storage_backend_direct.cpp new file mode 100644 index 0000000..455f443 --- /dev/null +++ b/src/internal/storage_backend_direct.cpp @@ -0,0 +1,31 @@ +/* MIT License + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ + +#include "storage_backend_direct.hpp" + +using namespace ldp_serialized; + +bool StorageBackendDirect::initFromData(const uint8_t *mem, size_t , bool ) { + + file = reinterpret_cast(mem); + return file != nullptr; +} diff --git a/src/internal/storage_backend_direct.hpp b/src/internal/storage_backend_direct.hpp new file mode 100644 index 0000000..4b3b47b --- /dev/null +++ b/src/internal/storage_backend_direct.hpp @@ -0,0 +1,636 @@ +#pragma once + +/* MIT License + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ + +#include "serialized_convert.hpp" +#include "serialization_traits.hpp" +#include + +namespace ldp_serialized { + +/* This file contains definition of classes that help with deserializing data + * serialized with Serialized objects. + * + * It works like this: + * - the objects are not created in the traditional way (with constructors); + * - instead they are "mapped" into their serialized data - so they should not have + * any data members; + * - an existing object operates on its "this" pointer to compute offsets proper + * to the object class to find pointers to contained types, or copy integer + * values. + * + * It all starts with File object, which is mapped directly into the first byte of + * the serialized data. Then the File object knows how to find further pointers. + * This is roughly the schema for the data: + * + * File { + * OwnSet { + * context_default: PolicyOwn; + * context_mandatory: PolicyOwn; + * user: array of {id, PolicyOwn}; + * group: array of {id, PolicyOwn}; + * + * // id = integer, mapped to respectively uid_t and gid_t + * define PolicyOwn = { + * tree: PolicyOwnNode; + * + * define PolicyOwnNode = { + * token: string; + * prefix_decision_item: DecisionItem; + * decision_item: DecisionItem; + * children: array of PolicyOwnNode; + * } + * } + * } + * SendSet { + * context_default: PolicySend; + * context_mandatory: PolicySend; + * user: array of {id, PolicySend}; + * group: array of {id, PolicySend}; + * + * define PolicySend = { + * items: array of { + * define ItemSend = { + * decision: DecisionItem; + * name: string; + * interface: string; + * member: string; + * path: string; + * type: MessageType; + * is_name_prefix: bool; + * } + * } + * index: array of { + * name: string; + * best_score: uint32_t; + * item_refs: array of {uint32_t}; + * } + * prefix_index: array of {uint32_t}; + * } + * } + * ReceiveSet { + * context_default: PolicyReceive; + * context_mandatory: PolicyReceive; + * user: array of {id, PolicyReceive}; + * group: array of {id, PolicyReceive}; + * + * define PolicyReceive = { + * items: array of { + * define ItemReceive = { + * decision: DecisionItem; + * name: string; + * interface: string; + * member: string; + * path: string; + * type: MessageType; + * is_name_prefix: bool; + * } + * } + * } + * AccessSet { + * context_default: PolicyAccess; + * context_mandatory: PolicyAccess; + * + * define PolicyAccess = { + * items: array of { + * define ItemAccess = { + * uid: uint; + * gid: uint; + * decision: DecisionItem; + * type: BusAccessType; + * } + * } + * } + * } + * + * define DecisionItem = { + * decision: Decision; + * privilege: string; + * } + * } + * + */ + +/* This class is a base for all the data extractors just to provide them some handy helpers. + */ +class BufferBase { + BufferBase() = delete; +protected: + // a short-typing caster + template + const Type *T(const AnyType *t) const + { return reinterpret_cast(t); } + + // this gives pointer to the buffer with a given offset + const uint8_t *buf(size_t offset=0) const { return T(this) + offset; } + // this gives value of specified field 'num' - either the field itself + // or offset to additional data + uint32_t offset(size_t num) const { return T(this)[num]; } + + // this gives pointer to additional data of the field 'num' + template + const Type *ptr(size_t num) const + { return T(buf(offset(num))); } +}; + +// String extracting class +class Str : private BufferBase { +public: + typedef uint32_t SizeType; + + const char *c_str() const + { return T(buf(sizeof(SizeType))); } + SizeType size() const + { return offset(0); } + const boost::string_ref toStringRef() const + { return boost::string_ref(c_str(), size()); } +}; + +// Simple array extracting class - works for arrays of integers +template +class SimpleList : protected BufferBase { +public: + // first uint32_t is size (number of elements in the list) + size_t size() const { return offset(0); } + // iterators are plain pointers + const Elem *begin() const + { return T(buf(sizeof(uint32_t))); } + const Elem *end() const + { return begin() + size(); } + // at() returns by value, because SimpleList is used only for uint32_t anyway + Elem at(size_t idx) const + { return begin()[idx]; } +}; + +// Iterator for non-simple arrays +template +class Iterator { + const uint8_t *_root; + size_t _pos{0}; + uint32_t offset(size_t num) const { return reinterpret_cast(_root)[num]; } +public: + Iterator(const uint8_t *buf, size_t pos) : _root{buf}, _pos{pos} {} + + const Elem *operator*() const + { return reinterpret_cast(&_root[offset(_pos)]); } + + Iterator &operator++() { + _pos++; + return *this; + } + Iterator operator++(int) + { return Iterator(_root, _pos++); } + Iterator &operator--() { + _pos--; + return *this; + } + Iterator operator--(int) + { return Iterator(_root, _pos--); } + bool operator!=(const Iterator &rhs) + { return _pos != rhs._pos; } + + int operator-(Iterator rhs) + { return static_cast(_pos) - rhs._pos; } + void operator+=(int val) + { _pos += val; } + + // This Iterator class lacks some operators (counterparts "==" , "+", "-=" to the above) + // only because we don't need them for our goals. + // This is very internal code, so we don't push it to be nice to everyone. +}; + +// Non-simple array extracting class +template +class List : protected BufferBase { +public: + size_t size() const { return offset(0); } + auto begin() const + { return Iterator(BufferBase::buf(), 1); } + auto end() const + { return Iterator(BufferBase::buf(), size()+1); } + const auto *at(size_t idx) const + { return *Iterator(buf(), idx+1); } +}; + +class DecisionItem : private BufferBase { +public: + auto getDecision() const + { return makeDecision(offset(0)); } + const auto *getPrivilege() const + { return ptr(1); } +}; + +class PolicyOwnNode : private BufferBase { +public: + typedef DecisionItem DecisionItemType; + typedef List ChildrenType; + + const auto *getToken() const + { return ptr(0); } + const auto *getPrefixDecisionItem() const + { return ptr(1); } + const auto *getDecisionItem() const + { return ptr(2); } + const auto *getChildren() const + { return ptr(3); } +}; + +class NameScoresPair : private BufferBase { +public: + const auto *getName() const + { return ptr(0); } + uint32_t getBestScore() const + { return offset(1); } + const auto *getItemRefs() const + { return ptr>(2); } +}; + +class ItemAccess : private BufferBase { +public: + const auto *getDecisionItem() const + { return ptr(0); } + auto getUid() const + { return static_cast(offset(1)); } + auto getGid() const + { return static_cast(offset(2)); } + auto getType() const + { return makeBusAccessType(offset(3)); } +}; + +class ItemSR : private BufferBase { +public: + const auto *getDecisionItem() const + { return ptr(0); } + auto getName() const + { return ptr(1); } + auto getInterface() const + { return ptr(2); } + auto getMember() const + { return ptr(3); } + auto getPath() const + { return ptr(4); } + auto getMessageType() const + { return makeMessageType(offset(5)); } + auto getIsNamePrefix() const + { return !!offset(6); } +}; + +class ItemSend : public ItemSR {}; +class ItemReceive : public ItemSR {}; + +class PolicyOwn : private BufferBase { +public: + const auto *getTree() const + { return T(this); } +}; + +template +class Policy : protected BufferBase { +public: + typedef List ListType; + + const auto *getItems() const + { return T(this); } +}; + +using PolicyAccess = Policy; +using PolicyReceive = Policy; + +class PolicySend : protected BufferBase { +public: + typedef List ListType; + typedef NameScoresPair IndexElemType; + typedef List IndexType; + typedef SimpleList<> PrefixIndexType; + + const auto *getItems() const + { return ptr(0); } + const auto *getIndex() const + { return ptr(1); } + const auto *getPrefixIndex() const + { return ptr(2); } +}; + +template +class PolicyPair : private BufferBase { +public: + id_t getId() const + { return static_cast(offset(0)); } + + const auto *getPolicy() const + { return ptr(1); } +}; + +template +class Set : private BufferBase { +public: + typedef List> ListType; + + const auto *getContextMandatory() const + { return ptr(0); } + const auto *getContextDefault() const + { return ptr(1); } + const auto *getUser() const + { return ptr(2); } + const auto *getGroup() const + { return ptr(3); } +}; + +class File : private BufferBase { +public: + typedef Set OwnSetType; + typedef Set SendSetType; + typedef Set ReceiveSetType; + typedef Set AccessSetType; + + const auto *getOwnSet() const + { return ptr(0); } + const auto *getSendSet() const + { return ptr(1); } + const auto *getReceiveSet() const + { return ptr(2); } + const auto *getAccessSet() const + { return ptr(3); } +}; + +class StorageBackendDirect { + // this private subclass is needed for looking up elements in containers by their key with std::lower_bound + template + class Comparator { + ExtractKey _f; + public: + Comparator(const ExtractKey &fun) : _f{fun} {} + template + bool operator()(const R &r, const K &k) { + return _f(r) < k; + } + }; + + template + auto makeComparator(const T &fun) const { return Comparator{fun}; } + + template + auto containerLookupByKey(const T *container, const K &key, const E &extractKey) const { + assert(container->size()); + auto found = std::lower_bound(container->begin(), container->end(), key, makeComparator(extractKey)); + if (found != container->end() && extractKey(*found) == key) + return std::make_pair(true, *found); + return std::make_pair(false, *container->begin()); + } +public: + bool initFromData(const uint8_t *serialized_data, size_t size, bool verify = false); + void release() {} + + auto getFile() const + { return file; } + + auto fileGetOwnSet(const File *file) const + { return file->getOwnSet(); } + auto fileGetSendSet(const File *file) const + { return file->getSendSet(); } + auto fileGetReceiveSet(const File *file) const + { return file->getReceiveSet(); } + auto fileGetAccessSet(const File *file) const + { return file->getAccessSet(); } + + template + auto setGetContextDefault(const Set *set) const + { return set->getContextDefault(); } + + template + auto setGetContextMandatory(const Set *set) const + { return set->getContextMandatory(); } + + template + auto setGetUser(const Set *set) const + { return set->getUser(); } + + template + auto setGetGroup(const Set *set) const + { return set->getGroup(); } + + template + int setUserGroupGetId(const PolicyPair *set_user_group) const + { return set_user_group->getId(); } + + template + auto setUserGroupGetPolicy(const PolicyPair *set_user_group) const + { return set_user_group->getPolicy(); } + + auto policyGetTree(const PolicyOwn *policy) const + { return policy->getTree(); } + + template + auto policyGetItems(const PolicyType *policy) const + { return policy->getItems(); } + + auto policyHasIndex(const PolicySend *policy) const + { return policy->getIndex()->size() > 0; } + + auto policyGetIndex(const PolicySend *policy) const + { return policy->getIndex(); } + + auto policyGetPrefixIndex(const PolicySend *policy) const + { return policy->getPrefixIndex(); } + + auto policyIndexGetName(const NameScoresPair *p) const + { return p->getName(); } + + auto policyIndexGetBestScore(const NameScoresPair *p) const + { return p->getBestScore(); } + + auto policyIndexGetItemRefs(const NameScoresPair *p) const + { return p->getItemRefs(); } + + template + auto containerGetReverseIterator(const Container *container) const + { return makeReverseIterator(container->end()); } + + template + auto containerGetReverseIteratorEnd(const Container *container) const + { return makeReverseIterator(container->begin()); } + + template + auto containerGetIterator(const Container *container) const + { return container->begin(); } + + template + auto containerGetIteratorEnd(const Container *container) const + { return container->end(); } + + template + auto containerGetSize(const Container *container) const + { return container->size(); } + + template + auto containerLookupByIndex(const Container *container, size_t index) const + { return container->at(index); } + + template + auto containerEmpty(const Container *container) const + { return container->size() == 0; } + + auto containerLookupByKey(const List *container, const char *key) const { + return containerLookupByKey(container, key, + [](const auto *node) { return node->getToken()->toStringRef(); }); + } + + template + auto containerLookupByKey(const ContainerType *container, id_t id) const { + return containerLookupByKey(container, id, + [](const auto *elem) { return static_cast(elem->getId()); }); + } + + auto containerLookupByKey(const List *container, const char *key) const { + return containerLookupByKey(container, key, + [](const auto *elem) { return elem->getName()->toStringRef(); }); + } + + auto decisionItemGetDecision(const DecisionItem *item) const + { return item->getDecision(); } + + auto decisionItemGetPrivilege(const DecisionItem *item) const + { return item->getPrivilege(); } + + auto ownNodeGetToken(const PolicyOwnNode *node) const + { return node->getToken(); } + + auto ownNodeGetDecisionItem(const PolicyOwnNode *node) const + { return node->getDecisionItem(); } + + auto ownNodeGetPrefixDecisionItem(const PolicyOwnNode *node) const + { return node->getPrefixDecisionItem(); } + + auto ownNodeGetChildren(const PolicyOwnNode *node) const + { return node->getChildren(); } + + auto itemAccessGetType(const ItemAccess *item) const + { return item->getType(); } + + auto itemAccessGetUid(const ItemAccess *item) const + { return item->getUid(); } + + auto itemAccessGetGid(const ItemAccess *item) const + { return item->getGid(); } + + auto itemSrGetName(const ItemSR *item) const + { return item->getName(); } + + auto itemSrGetIsNamePrefix(const ItemSR *item) const + { return item->getIsNamePrefix(); } + + auto itemSrGetInterface(const ItemSR *item) const + { return item->getInterface(); } + + auto itemSrGetMember(const ItemSR *item) const + { return item->getMember(); } + + auto itemSrGetPath(const ItemSR *item) const + { return item->getPath(); } + + template + auto itemSrGetMessageType(const ItemSR *item) const + { return item->getMessageType(); } + + template + auto itemGetDecisionItem(const Item *item) const + { return item->getDecisionItem(); } + + const char *stringGetCStr(const Str *str) const + { return str->c_str(); } + + size_t stringGetSize(const Str *str) const + { return str->size(); } + +private: + const File *file{nullptr}; + template + class ReverseIterator { + T __iterator; + public: + ReverseIterator(const T &iterator) : __iterator{iterator} {} + + // note: we copy the element here, but it is ok (FOR US!) + // because it is pointer anyway + auto operator*() { + auto tmp = __iterator; + return *--tmp; + } + + auto operator++() { return __iterator--; } + auto operator++(int) { + auto tmp = __iterator; + __iterator--; + return tmp; + } + auto operator!=(const ReverseIterator &rhs) { return __iterator != rhs.__iterator; } + }; + + template + auto makeReverseIterator(const T &iterator) const + { return ReverseIterator(iterator); } +}; + +} + +namespace std { + +template +struct iterator_traits> + : public std::iterator {}; + +} // namespace std + +namespace ldp_serialization { +template <> +struct HasUserGroup +{ typedef std::true_type result; }; +template <> +struct HasUserGroup +{ typedef std::true_type result; }; +template <> +struct HasUserGroup +{ typedef std::true_type result; }; +template <> +struct HasUserGroup +{ typedef std::false_type result; }; + +template <> struct PolicyContentType +{ typedef TreeType result; }; +template <> struct PolicyContentType +{ typedef ItemsType result; }; +template <> struct PolicyContentType +{ typedef ItemsType result; }; +template <> struct PolicyContentType +{ typedef ItemsType result; }; + +template <> struct PolicyHasIndex +{ typedef std::true_type result; }; + +template <> struct ItemType +{ typedef SendType result; }; +template <> struct ItemType +{ typedef ReceiveType result; }; +template <> struct ItemType +{ typedef AccessType result; }; +}