Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <boost/format.hpp>
- #include <boost/preprocessor.hpp>
- #include <climits>
- #include <cstdlib>
- #include <iostream>
- #include <optional>
- #include <stdexcept>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- #include <vector>
- static_assert(CHAR_BIT == 8);
- #ifdef ADSDATACURSOR_DEBUG
- # define ADSDATACURSOR_VERIFY_MSG(x) ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER(x)
- #else
- # define ADSDATACURSOR_VERIFY_MSG(x) ADSDATACURSOR_VERIFY_MSG_HANDLER(x)
- #endif
- #ifndef ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER
- # define ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER(msg) \
- { \
- ::std::cerr << msg << ::std::endl; \
- abort(); \
- }
- #endif
- #ifndef ADSDATACURSOR_VERIFY_MSG_HANDLER
- # define ADSDATACURSOR_VERIFY_MSG_HANDLER(msg) \
- { \
- throw ::adsDataCursor::AdsDataCursorError(std::move(full_msg)); \
- }
- #endif
- #define ADSDATACURSOR_VERIFY(...) \
- { \
- if (!(BOOST_PP_VARIADIC_ELEM(1, __VA_ARGS__))) \
- { \
- auto error_msg = \
- [](const char* fmt, auto&&... args) { \
- return ((boost::format(fmt) % ... % std::forward<decltype(args)>(args))).str(); \
- }(BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__), \
- BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_PUSH_FRONT( \
- BOOST_PP_SEQ_POP_FRONT(BOOST_PP_SEQ_POP_FRONT(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))), \
- BOOST_PP_STRINGIZE(BOOST_PP_VARIADIC_ELEM(1, __VA_ARGS__))))); \
- auto full_msg = (::boost::format("%1%\n%2% %3%:\nassertion failed:\n%4%") % BOOST_CURRENT_FUNCTION \
- % __FILE__ % __LINE__ % error_msg) \
- .str(); \
- ADSDATACURSOR_VERIFY_MSG(full_msg); \
- } \
- }
- namespace adsDataCursor
- {
- template <typename T, typename U>
- constexpr T implicit_cast(U&& v)
- {
- using V = std::remove_cv_t<std::remove_reference_t<U>>;
- // silence warning on sign conversion without loss of precision
- if constexpr (
- std::is_integral_v<
- T> && std::is_integral_v<V> && std::is_signed_v<T> != std::is_signed_v<V> && sizeof(T) >= sizeof(V))
- return static_cast<T>(v);
- else
- return std::forward<U>(v);
- }
- struct GUID
- {
- std::uint32_t Data1;
- std::uint16_t Data2;
- std::uint16_t Data3;
- std::uint8_t Data4[8];
- friend bool operator==(const GUID& lhs, const GUID& rhs) noexcept
- {
- return lhs.Data1 == rhs.Data1 && lhs.Data2 == rhs.Data2 && lhs.Data3 == rhs.Data3
- && std::equal(std::begin(lhs.Data4), std::end(lhs.Data4), std::begin(rhs.Data4));
- }
- friend bool operator!=(const GUID& lhs, const GUID& rhs) noexcept { return !(lhs == rhs); }
- };
- class AdsDataCursorError : public std::runtime_error
- {
- public:
- AdsDataCursorError(std::string msg) : std::runtime_error(std::move(msg)) {}
- };
- enum class DatatypeId : std::uint32_t
- {
- void_ = 0, // VT_EMPTY,
- int16_ = 2, // VT_I2,
- int32_ = 3, // VT_I4,
- float_ = 4, // VT_R4,
- double_ = 5, // VT_R8,
- int8_ = 16, // VT_I1,
- uint8_ = 17, // VT_UI1,
- uint16_ = 18, // VT_UI2,
- uint32_ = 19, // VT_UI4,
- int64_ = 20, // VT_I8,
- uint64_ = 21, // VT_UI8,
- string_ = 30, // VT_LPSTR,
- wstring_ = 31, // VT_LPWSTR,
- ldouble_ = 32, // VT_LPWSTR + 1,
- bool_ = 33, // VT_LPWSTR + 2
- blob_ = 65, // VT_BLOB,
- maxtypes_ = 70 // VT_MAXTYPES
- };
- inline constexpr bool operator==(std::uint32_t lhs, DatatypeId rhs) noexcept
- {
- return lhs == static_cast<std::uint32_t>(rhs);
- }
- inline constexpr bool operator==(DatatypeId lhs, std::uint32_t rhs) noexcept
- {
- return rhs == static_cast<std::uint32_t>(lhs);
- }
- inline constexpr bool operator!=(std::uint32_t lhs, DatatypeId rhs) noexcept { return !(lhs == rhs); }
- inline constexpr bool operator!=(DatatypeId lhs, std::uint32_t rhs) noexcept { return !(lhs == rhs); }
- template <typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
- T readRaw(const char* p) noexcept
- {
- using U = std::make_unsigned_t<T>;
- U result = 0;
- for (auto i = sizeof(T); i--;)
- result = static_cast<U>((result << 8u) | static_cast<unsigned char>(p[i]));
- return implicit_cast<T>(result);
- }
- template <typename T, std::enable_if_t<std::is_same_v<T, GUID>, int> = 0>
- T readRaw(const char* p) noexcept
- {
- return GUID{readRaw<decltype(GUID::Data1)>(p + offsetof(GUID, Data1)),
- readRaw<decltype(GUID::Data2)>(p + offsetof(GUID, Data2)),
- readRaw<decltype(GUID::Data3)>(p + offsetof(GUID, Data3)),
- {readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 0),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 1),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 2),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 3),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 4),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 5),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 6),
- readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 7)}};
- }
- enum class LimitMode
- {
- byCount,
- bySize
- };
- enum class AdsTypeTag
- {
- copyMaskByte,
- datatypeArrayInfo,
- symbolEntry,
- attributeEntry,
- datatypeEntry,
- methodParaEntry,
- methodEntry,
- enumInfoEntry
- };
- template <AdsTypeTag tag>
- struct IdList;
- template <AdsTypeTag tag>
- struct PropertyList;
- using IdType = int;
- constexpr IdType entryLen_ = -1;
- constexpr IdType noElement = -2;
- template <IdType id_, typename Accessor_>
- struct Property
- {
- static constexpr IdType id = id_;
- using Accessor = Accessor_;
- };
- template <typename Accessor>
- struct HasConstantEntryLen : std::false_type
- {};
- template <typename Accessor>
- constexpr bool hasConstantEntryLen = HasConstantEntryLen<Accessor>::value;
- template <typename Accessor>
- struct NeedsParentProperty : std::false_type
- {};
- template <typename Accessor>
- constexpr bool needsParentProperty = NeedsParentProperty<Accessor>::value;
- struct UnmatchedAccessor
- {};
- UnmatchedAccessor operator^(UnmatchedAccessor,
- UnmatchedAccessor); // not defined
- template <typename T>
- T operator^(UnmatchedAccessor, T)
- {
- return T{};
- }
- template <typename T>
- T operator^(T, UnmatchedAccessor)
- {
- return T{};
- }
- template <AdsTypeTag Tag, LimitMode limitMode, bool checked>
- class AdsDataCursor;
- template <typename T>
- struct ReplaceCursor
- {
- using type = T;
- };
- template <AdsTypeTag tag, LimitMode limitMode, bool checked>
- struct ReplaceCursor<AdsDataCursor<tag, limitMode, checked>>
- {
- using type = std::vector<AdsDataCursor<tag, limitMode, checked>>;
- };
- template <typename... Properties>
- struct PropertyMap
- {
- template <IdType id>
- static auto get_accessor() noexcept
- {
- static_assert((0 + ... + (Properties::id == id)) <= 1, "id cannot appear more than once in Properties");
- static_assert((0 + ... + (Properties::id == id)) == 1, "id must appear exactly once in Properties");
- return (... ^ std::conditional_t<Properties::id == id, typename Properties::Accessor, UnmatchedAccessor>{});
- }
- template <IdType id>
- using accessor = decltype(get_accessor<id>());
- template <IdType id>
- static constexpr decltype(auto) get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return accessor<id>::get(p, q);
- }
- template <IdType id>
- static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return accessor<id>::offset(p, q);
- }
- template <IdType id>
- static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return accessor<id>::size(p, q);
- }
- template <IdType id>
- static constexpr std::size_t next_offset([[maybe_unused]] const char* p,
- [[maybe_unused]] const char* q) noexcept
- {
- return offset<id>(p, q) + size<id>(p, q);
- }
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- (..., Properties::Accessor::check(p, q, entryLimit)); // check all properties in order
- }
- static constexpr bool needsParent_() noexcept { return (... || needsParentProperty<accessor<Properties::id>>); }
- static constexpr bool needsParent = needsParent_(); // Visual C++ doesn't like fold expressions here
- using DebugInfo =
- std::tuple<std::pair<const char*, typename ReplaceCursor<typename Properties::Accessor::type>::type>...>;
- template <AdsTypeTag tag>
- static constexpr DebugInfo getDebugInfo(const char* p, const char* q, std::size_t limit)
- {
- if (limit == 0)
- return {};
- else
- return {{IdList<tag>::at(Properties::id), Properties::Accessor::get(p, q)}...};
- }
- };
- // most serialized data structures are self contained, but some may depend on data stored in a surrounding structure
- template <bool withParent>
- struct AdsDataCursorData
- {
- constexpr AdsDataCursorData(const char* data, [[maybe_unused]] const char* parent) noexcept : data_(data) {}
- constexpr const char* parent() const noexcept { return nullptr; }
- const char* data_;
- };
- template <>
- struct AdsDataCursorData<true>
- {
- constexpr AdsDataCursorData(const char* data, [[maybe_unused]] const char* parent) noexcept
- : data_(data), parent_(parent)
- {}
- const char* parent() const noexcept { return parent_; }
- const char* data_;
- const char* parent_;
- };
- // AdsDataCursor is a Cursor into a serialized structure corresponding to its tag
- // since these structures generally exist as part of a sequence, we provide an iterator- as well as a
- // range-Interface to that sequence
- template <AdsTypeTag Tag, LimitMode limitMode, bool checked>
- class AdsDataCursor
- {
- public:
- static constexpr auto tag = Tag;
- static constexpr bool hasRandomAccess =
- hasConstantEntryLen<typename PropertyList<tag>::map::template accessor<entryLen_>>;
- using value_type = AdsDataCursor;
- using const_value_type = value_type;
- using reference = const AdsDataCursor&;
- using const_reference = reference;
- using pointer = const AdsDataCursor*;
- using const_pointer = pointer;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::conditional_t<hasRandomAccess, std::random_access_iterator_tag, std::forward_iterator_tag>;
- using iterator = AdsDataCursor;
- using const_iterator = iterator;
- using reverse_iterator = std::conditional_t<hasRandomAccess, std::reverse_iterator<iterator>, void>;
- using const_reverse_iterator = reverse_iterator;
- constexpr AdsDataCursor() noexcept : data_(nullptr, nullptr), limit_(0) {}
- constexpr AdsDataCursor(const char* data, std::size_t limit,
- const char* parent = nullptr) noexcept(noexcept(!checked))
- : data_(data, parent), limit_(limit)
- {
- updateDebugInfo();
- }
- template <IdType prop>
- constexpr auto get() const noexcept
- {
- return PropertyList<tag>::map::template get<prop>(data_.data_, data_.parent());
- }
- constexpr const char* data() const noexcept { return data_.data_; }
- // iterator interface
- // forward iterator
- constexpr reference operator*() const noexcept { return *this; }
- constexpr pointer operator->() const noexcept { return &*this; }
- friend constexpr bool operator==(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return lhs.limit_ == rhs.limit_;
- }
- friend constexpr bool operator!=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return !(lhs == rhs);
- }
- AdsDataCursor& operator++() noexcept(noexcept(!checked))
- {
- assert(*this);
- if constexpr (limitMode == LimitMode::byCount)
- --limit_;
- else
- limit_ -= get<entryLen_>();
- data_.data_ += get<entryLen_>();
- updateDebugInfo();
- return *this;
- }
- AdsDataCursor operator++(int) noexcept(noexcept(!checked))
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- // random access iterator (requires constant EntryLen)
- AdsDataCursor& operator+=(difference_type n) noexcept(noexcept(!checked)) { return *this = *this + n; }
- AdsDataCursor& operator-=(difference_type n) noexcept(noexcept(!checked)) { return *this = *this - n; }
- AdsDataCursor& operator--() noexcept(noexcept(!checked)) { return *this -= 1; }
- AdsDataCursor operator--(int) noexcept(noexcept(!checked))
- {
- auto tmp = *this;
- --*this;
- return tmp;
- }
- friend constexpr difference_type operator-(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- static_assert(hasRandomAccess);
- if constexpr (limitMode == LimitMode::byCount)
- return implicit_cast<difference_type>(rhs.limit_ - lhs.limit_);
- else
- return implicit_cast<difference_type>((rhs.limit_ - lhs.limit_) / lhs.get<entryLen_>());
- }
- AdsDataCursor operator[](difference_type n) const noexcept(noexcept(!checked)) { return *this + n; }
- friend constexpr AdsDataCursor operator+(const AdsDataCursor& lhs,
- difference_type rhs) noexcept(noexcept(!checked))
- {
- static_assert(hasRandomAccess);
- auto disp = rhs * implicit_cast<difference_type>(lhs.get<entryLen_>());
- if constexpr (limitMode == LimitMode::byCount)
- return AdsDataCursor(lhs.data_.data_ + disp, lhs.limit_ - implicit_cast<size_type>(rhs),
- lhs.data_.parent());
- else
- return AdsDataCursor(lhs.data_.data_ + disp, lhs.limit_ - implicit_cast<size_type>(disp),
- lhs.data_.parent());
- }
- friend constexpr AdsDataCursor operator+(difference_type lhs,
- const AdsDataCursor& rhs) noexcept(noexcept(!checked))
- {
- return rhs + lhs;
- }
- friend constexpr AdsDataCursor operator-(const AdsDataCursor& lhs,
- difference_type rhs) noexcept(noexcept(!checked))
- {
- return lhs + -rhs;
- }
- friend constexpr bool operator<(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return lhs.limit_ > rhs.limit_;
- }
- friend constexpr bool operator>(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return rhs < lhs;
- }
- friend constexpr bool operator<=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return !(rhs < lhs);
- }
- friend constexpr bool operator>=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
- {
- return !(lhs < rhs);
- }
- // range interface
- constexpr reference front() const { return *this; }
- constexpr iterator begin() const noexcept { return *this; }
- constexpr iterator cbegin() const noexcept { return *this; }
- constexpr iterator end() const noexcept
- {
- if constexpr (hasRandomAccess && limitMode == LimitMode::byCount)
- return *this + implicit_cast<difference_type>(limit_);
- else if constexpr (hasRandomAccess)
- return *this + implicit_cast<difference_type>(limit_) / get<entryLen_>();
- else
- return AdsDataCursor{};
- }
- constexpr iterator cend() const noexcept { return end(); }
- constexpr reverse_iterator rbegin() const noexcept
- {
- static_assert(hasRandomAccess);
- return reverse_iterator{end()};
- }
- constexpr reverse_iterator rend() const noexcept
- {
- static_assert(hasRandomAccess);
- return reverse_iterator{begin()};
- }
- constexpr reverse_iterator crbegin() const { return rbegin(); }
- constexpr reverse_iterator crend() const { return rend(); }
- constexpr bool empty() const noexcept { return limit_ == 0; }
- constexpr explicit operator bool() const noexcept { return !empty(); }
- constexpr std::size_t count() const noexcept
- {
- static_assert(limitMode == LimitMode::byCount);
- return limit_;
- }
- constexpr std::size_t size() const noexcept(noexcept(!checked))
- {
- if constexpr (limitMode == LimitMode::byCount)
- return count();
- else
- return implicit_cast<std::size_t>(std::distance(begin(), end()));
- }
- private:
- // verify integrity of data
- void doCheck() const
- {
- if (*this)
- {
- if constexpr (limitMode == LimitMode::byCount)
- PropertyList<tag>::map::check(data_.data_, data_.parent(), get<entryLen_>());
- else
- PropertyList<tag>::map::check(data_.data_, data_.parent(), limit_);
- }
- }
- void updateDebugInfo() noexcept(noexcept(!checked))
- {
- if constexpr (checked)
- doCheck();
- #ifdef ADSDATACURSOR_DEBUG
- debugInfo_ = PropertyList<tag>::map::template getDebugInfo<tag>(data_.data_, data_.parent(), limit_);
- #endif
- }
- #ifdef ADSDATACURSOR_DEBUG
- public:
- operator std::vector<AdsDataCursor>() const { return std::vector<AdsDataCursor>(begin(), end()); }
- private:
- typename PropertyList<tag>::map::DebugInfo debugInfo_{};
- #endif
- AdsDataCursorData<PropertyList<tag>::map::needsParent> data_;
- size_type limit_;
- };
- // Accessor models:
- // with p = pointer to data of structed_type
- // with q = pointer to data of containing PropertyMap
- // entryLimit = maximum available memory starting at p
- // all models: member function check(p, q, entryLimit)
- // model value_accessor: member function get(p, q): see accessor description
- // checks: nothing unless specified otherwise
- // model memory_accessor: member functions offset(p, q): offset rel. to p of memory location
- // size(p, q): size of memory location
- // checks: memory location within bounds of entryLimit
- // model predicate: model of value_accessor of bool type
- struct Unchecked
- {
- static constexpr void check(const char*, const char*, std::size_t) noexcept {}
- };
- template <typename Accessor>
- struct MemoryCheck
- {
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- ADSDATACURSOR_VERIFY(
- "%1%\nwith\nAccessor::offset(p, q) == %2%\nentryLimit == %3%\nAccessor::size(p, q) == %4%",
- (Accessor::offset(p, q) <= entryLimit && entryLimit - Accessor::offset(p, q) >= Accessor::size(p, q)),
- Accessor::offset(p, q), entryLimit, Accessor::size(p, q));
- }
- };
- // common template parameters:
- // T - type indexing current structected_type
- // before - id of preceding Property which must model memory_accessor
- // align - alignment of memory location
- // NextData
- // model of: value_accessor
- // returns: aligned offset following preceding Property
- // checks: value equals or is less than value of referenced Property which
- // must model value_accessor
- template <AdsTypeTag tag, IdType before = noElement, IdType expected = noElement, bool constant_expected = false>
- struct NextData : Unchecked
- {
- using type = std::size_t;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- if constexpr (before == noElement)
- return 0;
- else if constexpr (constant_expected)
- {
- constexpr auto result = PropertyList<tag>::map::template next_offset<before>(nullptr, nullptr);
- return result;
- }
- else
- return PropertyList<tag>::map::template next_offset<before>(p, q);
- }
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t)
- {
- if constexpr (expected != noElement)
- ADSDATACURSOR_VERIFY(
- "%1%\nwith\nget(p, q) == %2%\nPropertyList<tag>::map::template get<expected>(p, q) == %3%",
- (get(p, q) <= PropertyList<tag>::map::template get<expected>(p, q)), (get(p, q)),
- (PropertyList<tag>::map::template get<expected>(p, q)));
- }
- };
- template <AdsTypeTag tag, IdType before, IdType expected>
- struct HasConstantEntryLen<NextData<tag, before, expected, true>> : std::true_type
- {};
- // NextElement
- // model of: value_accessor, memory_accessor
- // object of type U following preceding Property
- // returns: stored value
- // checks: stored value equals one of the expected values (if any)
- template <AdsTypeTag tag, typename U, IdType before = noElement, typename V = U, V... expected>
- struct NextElement : MemoryCheck<NextElement<tag, U, before, V, expected...>>
- {
- using type = V;
- static type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return static_cast<V>(readRaw<U>(p + offset(p, q)));
- }
- static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- if constexpr (before == noElement)
- return 0;
- else
- return PropertyList<tag>::map::template next_offset<before>(p, q);
- }
- static constexpr std::size_t size(const char*, const char*) noexcept { return sizeof(U); }
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- MemoryCheck<NextElement<tag, U, before, V, expected...>>::check(p, q, entryLimit);
- if constexpr (sizeof...(expected) != 0)
- ADSDATACURSOR_VERIFY("%1%\nwith\nget(p, q) == %2%", (... || (get(p, q) == expected)), (get(p, q)));
- }
- };
- // VarData
- // model of: value_accessor, memory_accessor
- // String of Element with offset of data's value and size of length
- // returns: string_view
- template <AdsTypeTag tag, IdType before, IdType length, typename Element, std::size_t add = 0>
- struct VarData : MemoryCheck<VarData<tag, before, length, Element, add>>
- {
- using type = std::basic_string_view<Element>;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return type{reinterpret_cast<const Element*>(p + offset(p, q)), size(p, q) - add};
- }
- static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<tag>::map::template next_offset<before>(p, q);
- }
- static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<tag>::map::template get<length>(p, q) + add;
- }
- };
- // String
- // derived from: VarData
- // checks: no embedded '\0' in character String
- // terminator at the end
- template <AdsTypeTag tag, IdType before, IdType length>
- struct String : VarData<tag, before, length, char, 1>
- {
- using base = VarData<tag, before, length, char, 1>;
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- VarData<tag, before, length, char, 1>::check(p, q, entryLimit);
- ADSDATACURSOR_VERIFY("%1%\nembedded \\0 in\n%2%", (base::get(p, q).find('\0') == std::string_view::npos),
- (base::get(p, q)));
- ADSDATACURSOR_VERIFY("%1%\nmissing terminator for\n%2%",
- (base::get(p, q).data()[base::size(p, q) - 1] == '\0'), (base::get(p, q)));
- }
- };
- // Flag
- // model of: predicate
- // returns: bool: (apply mask to value of referenced Property) == compare
- template <AdsTypeTag tag, IdType ref, std::uint64_t mask, std::uint64_t compare = mask>
- struct Flag : Unchecked
- {
- using type = bool;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- auto value = PropertyList<tag>::map::template get<ref>(p, q);
- constexpr decltype(value) mask_ = mask;
- constexpr decltype(value) compare_ = compare;
- return (value & mask_) == compare_;
- }
- };
- // And
- // model of: predicate
- // returns: all reference predicates are true
- template <AdsTypeTag tag, IdType... refs>
- struct And : Unchecked
- {
- using type = bool;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return (... && PropertyList<tag>::map::template get<refs>(p, q));
- }
- };
- // Optional
- // model of: value_accessor, memory_accessor
- // Property accessed by Accessor (of model memory_accessor) which existence
- // is predicated by Flag returns: std::optional<...> with value of Accessor
- template <AdsTypeTag tag, IdType Flag, typename Access>
- struct Optional : MemoryCheck<Optional<tag, Flag, Access>>
- {
- using type = std::optional<typename Access::type>;
- static constexpr
- typename Access::type value([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return Access::get(p, q);
- }
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return exists(p, q) ? type{value(p, q)} : type{};
- }
- static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return Access::offset(p, q);
- }
- static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return exists(p, q) ? Access::size(p, q) : 0;
- }
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- MemoryCheck<Optional>::check(p, q, entryLimit);
- if (exists(p, q))
- Access::check(p, q, entryLimit);
- }
- static constexpr bool exists([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<tag>::map::template get<Flag>(p, q);
- }
- };
- // OptionalDef
- // derived from: Optional
- // returns: predicated on Flag value of Accessor or default_value
- template <AdsTypeTag tag, IdType Flag, typename Access, decltype(Access::get(nullptr, nullptr)) default_value>
- struct OptionalDef : Optional<tag, Flag, Access>
- {
- using type = typename Access::type;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return Optional<tag, Flag, Access>::exists(p, q) ? Optional<tag, Flag, Access>::value(p, q) : default_value;
- }
- };
- // Array
- // model of: value_accessor, memory_accessor
- // sequence of #num structured types indexed by Element following preceding
- // Property returns: AdsDataCursor to first element check: all contained
- // elements
- template <AdsTypeTag tag, IdType before, IdType num, AdsTypeTag elementTag>
- struct Array
- {
- using type = AdsDataCursor<elementTag, LimitMode::byCount, false>;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return type(p + offset(p, q), elements(p, q), p);
- }
- static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<tag>::map::template next_offset<before>(p, q);
- }
- static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- if constexpr (hasConstantEntryLen<typename PropertyList<elementTag>::map::template accessor<entryLen_>>)
- {
- return elements(p, q) * PropertyList<elementTag>::map::template get<entryLen_>(nullptr, nullptr);
- }
- else
- {
- auto elem = get(p, q);
- while (elem)
- ++elem;
- return implicit_cast<std::size_t>(elem.data() - (p + offset(p, q)));
- }
- }
- static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
- {
- ADSDATACURSOR_VERIFY("%1%\nwith\noffset(p, q) = %2%\nentryLimit = %3%", (offset(p, q) <= entryLimit),
- (offset(p, q)), entryLimit);
- if (auto n = elements(p, q))
- {
- AdsDataCursor<elementTag, LimitMode::bySize, true> elem(p + offset(p, q), entryLimit - offset(p, q), p);
- while (--n)
- {
- ADSDATACURSOR_VERIFY("%1%\ntoo many elements", elem);
- ++elem;
- }
- ADSDATACURSOR_VERIFY("%1%\ntoo many elements", elem);
- }
- }
- static constexpr std::size_t elements([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<tag>::map::template get<num>(p, q);
- }
- };
- // ParentProperty
- // model of: value_accessor
- // returns: value of referenced Property of containing structured type
- // indexed by P
- template <AdsTypeTag parentTag, IdType prop>
- struct ParentProperty : Unchecked
- {
- using type = typename PropertyList<parentTag>::map::template accessor<prop>::type;
- static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
- {
- return PropertyList<parentTag>::map::template get<prop>(q, nullptr);
- }
- };
- template <AdsTypeTag parentTag, IdType prop>
- struct NeedsParentProperty<ParentProperty<parentTag, prop>> : std::true_type
- {};
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // note: in the absence of support for auto non-type template parameters
- // where we could different enum class types, we make sure different *_prop
- // constants do not oberlap, so that trying to access a Property of the
- // wrong type will result in an error at comptile time entryLen is special
- // and needs to be the same in all cases, since it is used in the definition
- // of accessors
- #define ADSDATACURSOR_ID_LIST(typeTag, baseValue, ...) \
- template <> \
- struct IdList<typeTag> \
- { \
- static constexpr AdsTypeTag tag = typeTag; \
- enum \
- { \
- entryLen = entryLen_, \
- BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__) = baseValue, \
- BOOST_PP_LIST_ENUM(BOOST_PP_LIST_REST(BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__))) \
- }; \
- static constexpr const char* const idString[] = {BOOST_PP_SEQ_ENUM( \
- BOOST_PP_SEQ_TRANSFORM(ADSDATACURSOR_STRINGIZE_ID, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))}; \
- static constexpr const char* at(IdType id) noexcept \
- { \
- return id == entryLen_ ? "entryLen" : idString[id - baseValue]; \
- } \
- };
- #define ADSDATACURSOR_STRINGIZE_ID(s, data, elem) BOOST_PP_STRINGIZE(elem)
- ADSDATACURSOR_ID_LIST(AdsTypeTag::copyMaskByte, 0, value)
- template <>
- struct PropertyList<AdsTypeTag::copyMaskByte> : IdList<AdsTypeTag::copyMaskByte>
- {
- using map = PropertyMap<Property<value, NextElement<tag, std::uint8_t, noElement, std::uint8_t, 0, 0xff>>,
- Property<entryLen, NextData<tag, value, noElement, true>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::datatypeArrayInfo, 1000, lBound, elements)
- template <>
- struct PropertyList<AdsTypeTag::datatypeArrayInfo> : IdList<AdsTypeTag::datatypeArrayInfo>
- {
- using map = PropertyMap<Property<lBound, NextElement<tag, std::uint32_t, noElement>>,
- Property<elements, NextElement<tag, std::uint32_t, lBound>>,
- Property<entryLen, NextData<tag, elements, noElement, true>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::symbolEntry, 2000, group, offset, size, typeId, flags, isPersistent, isBitValue,
- isReference, hasTypeGuid, isTcComIFacePtr, isReadOnly, ITFMethodAccess, isMethodRef,
- hasAttributes, isStatic, reserved, nameLen, typeLen, commentLen, name, type, comment, guid,
- numAttributes, attributeData, expEntryLen)
- template <>
- struct PropertyList<AdsTypeTag::symbolEntry> : IdList<AdsTypeTag::symbolEntry>
- {
- using map = PropertyMap<
- Property<entryLen, NextElement<tag, std::uint32_t>>,
- Property<group, NextElement<tag, std::uint32_t, entryLen>>,
- Property<offset, NextElement<tag, std::uint32_t, group>>,
- Property<size, NextElement<tag, std::uint32_t, offset>>,
- Property<typeId, NextElement<tag, std::uint32_t, size, DatatypeId>>,
- Property<flags, NextElement<tag, std::uint16_t, typeId>>, Property<isPersistent, Flag<tag, flags, 0x0001>>,
- Property<isBitValue, Flag<tag, flags, 0x0002>>, Property<isReference, Flag<tag, flags, 0x0004>>,
- Property<hasTypeGuid, Flag<tag, flags, 0x0008>>, Property<isTcComIFacePtr, Flag<tag, flags, 0x0010>>,
- Property<isReadOnly, Flag<tag, flags, 0x0020>>, Property<ITFMethodAccess, Flag<tag, flags, 0x0040>>,
- Property<isMethodRef, Flag<tag, flags, 0x0080>>, Property<hasAttributes, Flag<tag, flags, 0x1000>>,
- Property<isStatic, Flag<tag, flags, 0x2000>>,
- Property<reserved, NextElement<tag, std::uint16_t, flags, std::uint16_t, 0>>,
- Property<nameLen, NextElement<tag, std::uint16_t, reserved>>,
- Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
- Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
- Property<name, String<tag, commentLen, nameLen>>, Property<type, String<tag, name, typeLen>>,
- Property<comment, String<tag, type, commentLen>>,
- Property<guid, Optional<tag, hasTypeGuid, NextElement<tag, GUID, comment>>>,
- Property<numAttributes, OptionalDef<tag, hasAttributes, NextElement<tag, std::uint16_t, guid>, 0>>,
- Property<attributeData, Array<tag, numAttributes, numAttributes, AdsTypeTag::attributeEntry>>,
- Property<expEntryLen, NextData<tag, attributeData, entryLen>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::attributeEntry, 3000, nameLen, valueLen, name, value)
- template <>
- struct PropertyList<AdsTypeTag::attributeEntry> : IdList<AdsTypeTag::attributeEntry>
- {
- using map = PropertyMap<Property<nameLen, NextElement<tag, std::uint8_t>>,
- Property<valueLen, NextElement<tag, std::uint8_t, nameLen>>,
- Property<name, String<tag, valueLen, nameLen>>,
- Property<value, String<tag, name, valueLen>>, Property<entryLen, NextData<tag, value>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::datatypeEntry, 4000, version, reserved1, reserved2, size, offset, typeId, flags,
- isDatatype, isDataitem, isReference, isMethodRef, isOversample, isBitValue, isPropItem,
- hasTypeGuid, flagPersistent, containsPersistent, isPersistent, hasCopyMask,
- flagTcComInterfacePtr, containsTcComInterfacePtr, isTcComInterfacePtr, hasMethodInfos,
- hasAttributes, hasEnumInfos, isAligned, isStatic, nameLen, typeLen, commentLen, numArrayDims,
- numSubItems, name, type, comment, arrayInfoData, subItemData, guid, copyMaskLen, copyMaskData,
- copyMaskBegin, copyMask, numMethods, methodData, numAttributes, attributeData, numEnumInfos,
- enumInfoData, expEntryLen)
- template <>
- struct PropertyList<AdsTypeTag::datatypeEntry> : IdList<AdsTypeTag::datatypeEntry>
- {
- using map = PropertyMap<
- Property<entryLen, NextElement<tag, std::uint32_t>>,
- Property<version, NextElement<tag, std::uint32_t, entryLen, std::uint32_t, 1>>,
- Property<reserved1, NextElement<tag, std::uint32_t, version>>,
- Property<reserved2, NextElement<tag, std::uint32_t, reserved1>>,
- Property<size, NextElement<tag, std::uint32_t, reserved2>>,
- Property<offset, NextElement<tag, std::uint32_t, size>>,
- Property<typeId, NextElement<tag, std::uint32_t, offset, DatatypeId>>,
- Property<flags, NextElement<tag, std::uint32_t, typeId>>,
- Property<isDatatype, Flag<tag, flags, 0x00000001>>, Property<isDataitem, Flag<tag, flags, 0x00000002>>,
- Property<isReference, Flag<tag, flags, 0x00000004>>, Property<isMethodRef, Flag<tag, flags, 0x00000008>>,
- Property<isOversample, Flag<tag, flags, 0x00000010>>, Property<isBitValue, Flag<tag, flags, 0x00000020>>,
- Property<isPropItem, Flag<tag, flags, 0x00000040>>, Property<hasTypeGuid, Flag<tag, flags, 0x00000080>>,
- Property<flagPersistent, Flag<tag, flags, 0x00000100>>,
- Property<containsPersistent, And<tag, flagPersistent, isDatatype>>,
- Property<isPersistent, And<tag, flagPersistent, isDataitem>>,
- Property<hasCopyMask, Flag<tag, flags, 0x00000200>>,
- Property<flagTcComInterfacePtr, Flag<tag, flags, 0x00000400>>,
- Property<containsTcComInterfacePtr, And<tag, flagTcComInterfacePtr, isDatatype>>,
- Property<isTcComInterfacePtr, And<tag, flagTcComInterfacePtr, isDataitem>>,
- Property<hasMethodInfos, Flag<tag, flags, 0x00000800>>,
- Property<hasAttributes, Flag<tag, flags, 0x00001000>>, Property<hasEnumInfos, Flag<tag, flags, 0x00002000>>,
- Property<isAligned, Flag<tag, flags, 0x00010000>>, Property<isStatic, Flag<tag, flags, 0x00020000>>,
- Property<nameLen, NextElement<tag, std::uint16_t, flags>>,
- Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
- Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
- Property<numArrayDims, NextElement<tag, std::uint16_t, commentLen>>,
- Property<numSubItems, NextElement<tag, std::uint16_t, numArrayDims>>,
- Property<name, String<tag, numSubItems, nameLen>>, Property<type, String<tag, name, typeLen>>,
- Property<comment, String<tag, type, commentLen>>,
- Property<arrayInfoData, Array<tag, comment, numArrayDims, AdsTypeTag::datatypeArrayInfo>>,
- Property<subItemData, Array<tag, arrayInfoData, numSubItems, tag>>,
- Property<guid, Optional<tag, hasTypeGuid, NextElement<tag, GUID, subItemData>>>,
- Property<copyMaskLen, OptionalDef<tag, hasCopyMask, NextElement<tag, std::uint32_t, reserved2>, 0>>,
- Property<copyMaskData, Array<tag, guid, copyMaskLen, AdsTypeTag::copyMaskByte>>,
- Property<copyMask, VarData<tag, guid, copyMaskLen, std::uint8_t>>,
- Property<numMethods, OptionalDef<tag, hasMethodInfos, NextElement<tag, std::uint16_t, copyMask>, 0>>,
- Property<methodData, Array<tag, numMethods, numMethods, AdsTypeTag::methodEntry>>,
- Property<numAttributes, OptionalDef<tag, hasAttributes, NextElement<tag, std::uint16_t, methodData>, 0>>,
- Property<attributeData, Array<tag, numAttributes, numAttributes, AdsTypeTag::attributeEntry>>,
- Property<numEnumInfos, OptionalDef<tag, hasEnumInfos, NextElement<tag, std::uint16_t, attributeData>, 0>>,
- Property<enumInfoData, Array<tag, numEnumInfos, numEnumInfos, AdsTypeTag::enumInfoEntry>>,
- Property<expEntryLen, NextData<tag, enumInfoData, entryLen>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::methodParaEntry, 5000, size, alignSize, typeId, flags, isIn, isOut, isInOut,
- isReference, reserved, guid, lengthIsPara, nameLen, typeLen, commentLen, name, type, comment,
- expEntryLen)
- template <>
- struct PropertyList<AdsTypeTag::methodParaEntry> : IdList<AdsTypeTag::methodParaEntry>
- {
- using map =
- PropertyMap<Property<entryLen, NextElement<tag, std::uint32_t>>,
- Property<size, NextElement<tag, std::uint32_t, entryLen>>,
- Property<alignSize, NextElement<tag, std::uint32_t, size>>,
- Property<typeId, NextElement<tag, std::uint32_t, alignSize, DatatypeId>>,
- Property<flags, NextElement<tag, std::uint32_t, typeId>>,
- Property<isIn, Flag<tag, flags, 0x00000007, 0x00000001>>,
- Property<isOut, Flag<tag, flags, 0x00000007, 0x00000002>>,
- Property<isInOut, Flag<tag, flags, 0x00000007, 0x00000003>>,
- Property<isReference, Flag<tag, flags, 0x00000007, 0x00000004>>,
- Property<reserved, NextElement<tag, std::uint32_t, flags, std::uint32_t, 0>>,
- Property<guid, NextElement<tag, GUID, reserved>>,
- Property<lengthIsPara, NextElement<tag, std::uint16_t, guid>>,
- Property<nameLen, NextElement<tag, std::uint16_t, lengthIsPara>>,
- Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
- Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
- Property<name, String<tag, typeLen, nameLen>>, Property<type, String<tag, name, typeLen>>,
- Property<comment, String<tag, type, commentLen>>,
- Property<expEntryLen, NextData<tag, comment, entryLen>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::methodEntry, 6000, version, vTableIndex, returnSize, returnAlignSize, reserved,
- returnTypeGuid, returnTypeId, flags, isPlcCallingConvention, isCallUnlocked, nameLen, typeLen,
- commentLen, numParas, name, type, comment, paraData, expEntryLen)
- template <>
- struct PropertyList<AdsTypeTag::methodEntry> : IdList<AdsTypeTag::methodEntry>
- {
- using map =
- PropertyMap<Property<entryLen, NextElement<tag, std::uint32_t>>,
- Property<version, NextElement<tag, std::uint32_t, entryLen, std::uint32_t, 1>>,
- Property<vTableIndex, NextElement<tag, std::uint32_t, version>>,
- Property<returnSize, NextElement<tag, std::uint32_t, vTableIndex>>,
- Property<returnAlignSize, NextElement<tag, std::uint32_t, returnSize>>,
- Property<reserved, NextElement<tag, std::uint32_t, returnAlignSize, std::uint32_t, 0>>,
- Property<returnTypeGuid, NextElement<tag, GUID, reserved>>,
- Property<returnTypeId, NextElement<tag, std::uint32_t, returnTypeGuid, DatatypeId>>,
- Property<flags, NextElement<tag, std::uint32_t, returnTypeId>>,
- Property<nameLen, NextElement<tag, std::uint16_t, flags>>,
- Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
- Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
- Property<numParas, NextElement<tag, std::uint16_t, commentLen>>,
- Property<name, String<tag, numParas, nameLen>>, Property<type, String<tag, name, typeLen>>,
- Property<comment, String<tag, type, commentLen>>,
- Property<paraData, Array<tag, comment, numParas, AdsTypeTag::methodParaEntry>>,
- Property<expEntryLen, NextData<tag, paraData, entryLen>>>;
- };
- ADSDATACURSOR_ID_LIST(AdsTypeTag::enumInfoEntry, 7000, nameLen, valueLen, name, value)
- template <>
- struct PropertyList<AdsTypeTag::enumInfoEntry> : IdList<AdsTypeTag::enumInfoEntry>
- {
- using map = PropertyMap<
- Property<valueLen, ParentProperty<AdsTypeTag::datatypeEntry, IdList<AdsTypeTag::datatypeEntry>::size>>,
- Property<nameLen, NextElement<tag, std::uint8_t>>, Property<name, String<tag, nameLen, nameLen>>,
- Property<value, VarData<tag, name, valueLen, char>>, Property<entryLen, NextData<tag, value>>>;
- };
- } // namespace adsDataCursor
Add Comment
Please, Sign In to add comment