Guest User

Untitled

a guest
Apr 9th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 49.36 KB | None | 0 0
  1. #pragma once
  2. #include <boost/format.hpp>
  3. #include <boost/preprocessor.hpp>
  4. #include <climits>
  5. #include <cstdlib>
  6. #include <iostream>
  7. #include <optional>
  8. #include <stdexcept>
  9. #include <tuple>
  10. #include <type_traits>
  11. #include <utility>
  12. #include <vector>
  13.  
  14. static_assert(CHAR_BIT == 8);
  15.  
  16. #ifdef ADSDATACURSOR_DEBUG
  17. #    define ADSDATACURSOR_VERIFY_MSG(x) ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER(x)
  18. #else
  19. #    define ADSDATACURSOR_VERIFY_MSG(x) ADSDATACURSOR_VERIFY_MSG_HANDLER(x)
  20. #endif
  21.  
  22. #ifndef ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER
  23. #    define ADSDATACURSOR_VERIFY_DEBUG_MSG_HANDLER(msg) \
  24.         {                                               \
  25.             ::std::cerr << msg << ::std::endl;          \
  26.             abort();                                    \
  27.         }
  28. #endif
  29.  
  30. #ifndef ADSDATACURSOR_VERIFY_MSG_HANDLER
  31. #    define ADSDATACURSOR_VERIFY_MSG_HANDLER(msg)                           \
  32.         {                                                                   \
  33.             throw ::adsDataCursor::AdsDataCursorError(std::move(full_msg)); \
  34.         }
  35. #endif
  36.  
  37. #define ADSDATACURSOR_VERIFY(...)                                                                              \
  38.     {                                                                                                          \
  39.         if (!(BOOST_PP_VARIADIC_ELEM(1, __VA_ARGS__)))                                                         \
  40.         {                                                                                                      \
  41.             auto error_msg =                                                                                   \
  42.                 [](const char* fmt, auto&&... args) {                                                          \
  43.                     return ((boost::format(fmt) % ... % std::forward<decltype(args)>(args))).str();            \
  44.                 }(BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__),                                                      \
  45.                   BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_PUSH_FRONT(                                                   \
  46.                       BOOST_PP_SEQ_POP_FRONT(BOOST_PP_SEQ_POP_FRONT(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))),   \
  47.                       BOOST_PP_STRINGIZE(BOOST_PP_VARIADIC_ELEM(1, __VA_ARGS__)))));                           \
  48.             auto full_msg = (::boost::format("%1%\n%2% %3%:\nassertion failed:\n%4%") % BOOST_CURRENT_FUNCTION \
  49.                              % __FILE__ % __LINE__ % error_msg)                                                \
  50.                                 .str();                                                                        \
  51.             ADSDATACURSOR_VERIFY_MSG(full_msg);                                                                \
  52.         }                                                                                                      \
  53.     }
  54.  
  55. namespace adsDataCursor
  56. {
  57.     template <typename T, typename U>
  58.     constexpr T implicit_cast(U&& v)
  59.     {
  60.         using V = std::remove_cv_t<std::remove_reference_t<U>>;
  61.         // silence warning on sign conversion without loss of precision
  62.         if constexpr (
  63.             std::is_integral_v<
  64.                 T> && std::is_integral_v<V> && std::is_signed_v<T> != std::is_signed_v<V> && sizeof(T) >= sizeof(V))
  65.             return static_cast<T>(v);
  66.         else
  67.             return std::forward<U>(v);
  68.     }
  69.  
  70.     struct GUID
  71.     {
  72.         std::uint32_t Data1;
  73.         std::uint16_t Data2;
  74.         std::uint16_t Data3;
  75.         std::uint8_t  Data4[8];
  76.  
  77.         friend bool operator==(const GUID& lhs, const GUID& rhs) noexcept
  78.         {
  79.             return lhs.Data1 == rhs.Data1 && lhs.Data2 == rhs.Data2 && lhs.Data3 == rhs.Data3
  80.                    && std::equal(std::begin(lhs.Data4), std::end(lhs.Data4), std::begin(rhs.Data4));
  81.         }
  82.         friend bool operator!=(const GUID& lhs, const GUID& rhs) noexcept { return !(lhs == rhs); }
  83.     };
  84.  
  85.     class AdsDataCursorError : public std::runtime_error
  86.     {
  87.     public:
  88.         AdsDataCursorError(std::string msg) : std::runtime_error(std::move(msg)) {}
  89.     };
  90.  
  91.     enum class DatatypeId : std::uint32_t
  92.     {
  93.         void_     = 0,  // VT_EMPTY,
  94.         int16_    = 2,  // VT_I2,
  95.         int32_    = 3,  // VT_I4,
  96.         float_    = 4,  // VT_R4,
  97.         double_   = 5,  // VT_R8,
  98.         int8_     = 16, // VT_I1,
  99.         uint8_    = 17, // VT_UI1,
  100.         uint16_   = 18, // VT_UI2,
  101.         uint32_   = 19, // VT_UI4,
  102.         int64_    = 20, // VT_I8,
  103.         uint64_   = 21, // VT_UI8,
  104.         string_   = 30, // VT_LPSTR,
  105.         wstring_  = 31, // VT_LPWSTR,
  106.         ldouble_  = 32, // VT_LPWSTR + 1,
  107.         bool_     = 33, // VT_LPWSTR + 2
  108.         blob_     = 65, // VT_BLOB,
  109.         maxtypes_ = 70  // VT_MAXTYPES
  110.     };
  111.     inline constexpr bool operator==(std::uint32_t lhs, DatatypeId rhs) noexcept
  112.     {
  113.         return lhs == static_cast<std::uint32_t>(rhs);
  114.     }
  115.     inline constexpr bool operator==(DatatypeId lhs, std::uint32_t rhs) noexcept
  116.     {
  117.         return rhs == static_cast<std::uint32_t>(lhs);
  118.     }
  119.     inline constexpr bool operator!=(std::uint32_t lhs, DatatypeId rhs) noexcept { return !(lhs == rhs); }
  120.     inline constexpr bool operator!=(DatatypeId lhs, std::uint32_t rhs) noexcept { return !(lhs == rhs); }
  121.  
  122.     template <typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
  123.     T readRaw(const char* p) noexcept
  124.     {
  125.         using U  = std::make_unsigned_t<T>;
  126.         U result = 0;
  127.         for (auto i = sizeof(T); i--;)
  128.             result = static_cast<U>((result << 8u) | static_cast<unsigned char>(p[i]));
  129.         return implicit_cast<T>(result);
  130.     }
  131.  
  132.     template <typename T, std::enable_if_t<std::is_same_v<T, GUID>, int> = 0>
  133.     T readRaw(const char* p) noexcept
  134.     {
  135.         return GUID{readRaw<decltype(GUID::Data1)>(p + offsetof(GUID, Data1)),
  136.                     readRaw<decltype(GUID::Data2)>(p + offsetof(GUID, Data2)),
  137.                     readRaw<decltype(GUID::Data3)>(p + offsetof(GUID, Data3)),
  138.                     {readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 0),
  139.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 1),
  140.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 2),
  141.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 3),
  142.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 4),
  143.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 5),
  144.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 6),
  145.                      readRaw<std::remove_extent_t<decltype(GUID::Data4)>>(p + offsetof(GUID, Data4) + 7)}};
  146.     }
  147.  
  148.     enum class LimitMode
  149.     {
  150.         byCount,
  151.         bySize
  152.     };
  153.  
  154.     enum class AdsTypeTag
  155.     {
  156.         copyMaskByte,
  157.         datatypeArrayInfo,
  158.         symbolEntry,
  159.         attributeEntry,
  160.         datatypeEntry,
  161.         methodParaEntry,
  162.         methodEntry,
  163.         enumInfoEntry
  164.     };
  165.  
  166.     template <AdsTypeTag tag>
  167.     struct IdList;
  168.     template <AdsTypeTag tag>
  169.     struct PropertyList;
  170.  
  171.     using IdType               = int;
  172.     constexpr IdType entryLen_ = -1;
  173.     constexpr IdType noElement = -2;
  174.  
  175.     template <IdType id_, typename Accessor_>
  176.     struct Property
  177.     {
  178.         static constexpr IdType id = id_;
  179.         using Accessor             = Accessor_;
  180.     };
  181.  
  182.     template <typename Accessor>
  183.     struct HasConstantEntryLen : std::false_type
  184.     {};
  185.     template <typename Accessor>
  186.     constexpr bool hasConstantEntryLen = HasConstantEntryLen<Accessor>::value;
  187.  
  188.     template <typename Accessor>
  189.     struct NeedsParentProperty : std::false_type
  190.     {};
  191.     template <typename Accessor>
  192.     constexpr bool needsParentProperty = NeedsParentProperty<Accessor>::value;
  193.  
  194.     struct UnmatchedAccessor
  195.     {};
  196.  
  197.     UnmatchedAccessor operator^(UnmatchedAccessor,
  198.                                 UnmatchedAccessor); // not defined
  199.  
  200.     template <typename T>
  201.     T operator^(UnmatchedAccessor, T)
  202.     {
  203.         return T{};
  204.     }
  205.  
  206.     template <typename T>
  207.     T operator^(T, UnmatchedAccessor)
  208.     {
  209.         return T{};
  210.     }
  211.  
  212.     template <AdsTypeTag Tag, LimitMode limitMode, bool checked>
  213.     class AdsDataCursor;
  214.  
  215.     template <typename T>
  216.     struct ReplaceCursor
  217.     {
  218.         using type = T;
  219.     };
  220.     template <AdsTypeTag tag, LimitMode limitMode, bool checked>
  221.     struct ReplaceCursor<AdsDataCursor<tag, limitMode, checked>>
  222.     {
  223.         using type = std::vector<AdsDataCursor<tag, limitMode, checked>>;
  224.     };
  225.  
  226.     template <typename... Properties>
  227.     struct PropertyMap
  228.     {
  229.         template <IdType id>
  230.         static auto get_accessor() noexcept
  231.         {
  232.             static_assert((0 + ... + (Properties::id == id)) <= 1, "id cannot appear more than once in Properties");
  233.             static_assert((0 + ... + (Properties::id == id)) == 1, "id must appear exactly once in Properties");
  234.             return (... ^ std::conditional_t<Properties::id == id, typename Properties::Accessor, UnmatchedAccessor>{});
  235.         }
  236.  
  237.         template <IdType id>
  238.         using accessor = decltype(get_accessor<id>());
  239.  
  240.         template <IdType id>
  241.         static constexpr decltype(auto) get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  242.         {
  243.             return accessor<id>::get(p, q);
  244.         }
  245.  
  246.         template <IdType id>
  247.         static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  248.         {
  249.             return accessor<id>::offset(p, q);
  250.         }
  251.  
  252.         template <IdType id>
  253.         static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  254.         {
  255.             return accessor<id>::size(p, q);
  256.         }
  257.  
  258.         template <IdType id>
  259.         static constexpr std::size_t next_offset([[maybe_unused]] const char* p,
  260.                                                  [[maybe_unused]] const char* q) noexcept
  261.         {
  262.             return offset<id>(p, q) + size<id>(p, q);
  263.         }
  264.  
  265.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  266.         {
  267.             (..., Properties::Accessor::check(p, q, entryLimit)); // check all properties in order
  268.         }
  269.  
  270.         static constexpr bool needsParent_() noexcept { return (... || needsParentProperty<accessor<Properties::id>>); }
  271.         static constexpr bool needsParent = needsParent_(); // Visual C++ doesn't like fold expressions here
  272.  
  273.         using DebugInfo =
  274.             std::tuple<std::pair<const char*, typename ReplaceCursor<typename Properties::Accessor::type>::type>...>;
  275.         template <AdsTypeTag tag>
  276.         static constexpr DebugInfo getDebugInfo(const char* p, const char* q, std::size_t limit)
  277.         {
  278.             if (limit == 0)
  279.                 return {};
  280.             else
  281.                 return {{IdList<tag>::at(Properties::id), Properties::Accessor::get(p, q)}...};
  282.         }
  283.     };
  284.  
  285.     // most serialized data structures are self contained, but some may depend on data stored in a surrounding structure
  286.     template <bool withParent>
  287.     struct AdsDataCursorData
  288.     {
  289.         constexpr AdsDataCursorData(const char* data, [[maybe_unused]] const char* parent) noexcept : data_(data) {}
  290.         constexpr const char* parent() const noexcept { return nullptr; }
  291.         const char*           data_;
  292.     };
  293.     template <>
  294.     struct AdsDataCursorData<true>
  295.     {
  296.         constexpr AdsDataCursorData(const char* data, [[maybe_unused]] const char* parent) noexcept
  297.             : data_(data), parent_(parent)
  298.         {}
  299.         const char* parent() const noexcept { return parent_; }
  300.         const char* data_;
  301.         const char* parent_;
  302.     };
  303.  
  304.     // AdsDataCursor is a Cursor into a serialized structure corresponding to its tag
  305.     // since these structures generally exist as part of a sequence, we provide an iterator- as well as a
  306.     // range-Interface to that sequence
  307.     template <AdsTypeTag Tag, LimitMode limitMode, bool checked>
  308.     class AdsDataCursor
  309.     {
  310.     public:
  311.         static constexpr auto tag = Tag;
  312.  
  313.         static constexpr bool hasRandomAccess =
  314.             hasConstantEntryLen<typename PropertyList<tag>::map::template accessor<entryLen_>>;
  315.         using value_type       = AdsDataCursor;
  316.         using const_value_type = value_type;
  317.         using reference        = const AdsDataCursor&;
  318.         using const_reference  = reference;
  319.         using pointer          = const AdsDataCursor*;
  320.         using const_pointer    = pointer;
  321.         using size_type        = std::size_t;
  322.         using difference_type  = std::ptrdiff_t;
  323.         using iterator_category =
  324.             std::conditional_t<hasRandomAccess, std::random_access_iterator_tag, std::forward_iterator_tag>;
  325.  
  326.         using iterator       = AdsDataCursor;
  327.         using const_iterator = iterator;
  328.  
  329.         using reverse_iterator       = std::conditional_t<hasRandomAccess, std::reverse_iterator<iterator>, void>;
  330.         using const_reverse_iterator = reverse_iterator;
  331.  
  332.         constexpr AdsDataCursor() noexcept : data_(nullptr, nullptr), limit_(0) {}
  333.  
  334.         constexpr AdsDataCursor(const char* data, std::size_t limit,
  335.                                 const char* parent = nullptr) noexcept(noexcept(!checked))
  336.             : data_(data, parent), limit_(limit)
  337.         {
  338.             updateDebugInfo();
  339.         }
  340.  
  341.         template <IdType prop>
  342.         constexpr auto get() const noexcept
  343.         {
  344.             return PropertyList<tag>::map::template get<prop>(data_.data_, data_.parent());
  345.         }
  346.  
  347.         constexpr const char* data() const noexcept { return data_.data_; }
  348.  
  349.         // iterator interface
  350.         // forward iterator
  351.         constexpr reference operator*() const noexcept { return *this; }
  352.         constexpr pointer   operator->() const noexcept { return &*this; }
  353.  
  354.         friend constexpr bool operator==(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  355.         {
  356.             return lhs.limit_ == rhs.limit_;
  357.         }
  358.         friend constexpr bool operator!=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  359.         {
  360.             return !(lhs == rhs);
  361.         }
  362.  
  363.         AdsDataCursor& operator++() noexcept(noexcept(!checked))
  364.         {
  365.             assert(*this);
  366.             if constexpr (limitMode == LimitMode::byCount)
  367.                 --limit_;
  368.             else
  369.                 limit_ -= get<entryLen_>();
  370.             data_.data_ += get<entryLen_>();
  371.             updateDebugInfo();
  372.             return *this;
  373.         }
  374.  
  375.         AdsDataCursor operator++(int) noexcept(noexcept(!checked))
  376.         {
  377.             auto tmp = *this;
  378.             ++*this;
  379.             return tmp;
  380.         }
  381.  
  382.         // random access iterator (requires constant EntryLen)
  383.         AdsDataCursor& operator+=(difference_type n) noexcept(noexcept(!checked)) { return *this = *this + n; }
  384.         AdsDataCursor& operator-=(difference_type n) noexcept(noexcept(!checked)) { return *this = *this - n; }
  385.  
  386.         AdsDataCursor& operator--() noexcept(noexcept(!checked)) { return *this -= 1; }
  387.         AdsDataCursor  operator--(int) noexcept(noexcept(!checked))
  388.         {
  389.             auto tmp = *this;
  390.             --*this;
  391.             return tmp;
  392.         }
  393.  
  394.         friend constexpr difference_type operator-(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  395.         {
  396.             static_assert(hasRandomAccess);
  397.             if constexpr (limitMode == LimitMode::byCount)
  398.                 return implicit_cast<difference_type>(rhs.limit_ - lhs.limit_);
  399.             else
  400.                 return implicit_cast<difference_type>((rhs.limit_ - lhs.limit_) / lhs.get<entryLen_>());
  401.         }
  402.  
  403.         AdsDataCursor operator[](difference_type n) const noexcept(noexcept(!checked)) { return *this + n; }
  404.  
  405.         friend constexpr AdsDataCursor operator+(const AdsDataCursor& lhs,
  406.                                                  difference_type      rhs) noexcept(noexcept(!checked))
  407.         {
  408.             static_assert(hasRandomAccess);
  409.             auto disp = rhs * implicit_cast<difference_type>(lhs.get<entryLen_>());
  410.             if constexpr (limitMode == LimitMode::byCount)
  411.                 return AdsDataCursor(lhs.data_.data_ + disp, lhs.limit_ - implicit_cast<size_type>(rhs),
  412.                                      lhs.data_.parent());
  413.             else
  414.                 return AdsDataCursor(lhs.data_.data_ + disp, lhs.limit_ - implicit_cast<size_type>(disp),
  415.                                      lhs.data_.parent());
  416.         }
  417.         friend constexpr AdsDataCursor operator+(difference_type      lhs,
  418.                                                  const AdsDataCursor& rhs) noexcept(noexcept(!checked))
  419.         {
  420.             return rhs + lhs;
  421.         }
  422.         friend constexpr AdsDataCursor operator-(const AdsDataCursor& lhs,
  423.                                                  difference_type      rhs) noexcept(noexcept(!checked))
  424.         {
  425.             return lhs + -rhs;
  426.         }
  427.  
  428.         friend constexpr bool operator<(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  429.         {
  430.             return lhs.limit_ > rhs.limit_;
  431.         }
  432.         friend constexpr bool operator>(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  433.         {
  434.             return rhs < lhs;
  435.         }
  436.         friend constexpr bool operator<=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  437.         {
  438.             return !(rhs < lhs);
  439.         }
  440.         friend constexpr bool operator>=(const AdsDataCursor& lhs, const AdsDataCursor& rhs) noexcept
  441.         {
  442.             return !(lhs < rhs);
  443.         }
  444.  
  445.         // range interface
  446.         constexpr reference front() const { return *this; }
  447.  
  448.         constexpr iterator begin() const noexcept { return *this; }
  449.         constexpr iterator cbegin() const noexcept { return *this; }
  450.  
  451.         constexpr iterator end() const noexcept
  452.         {
  453.             if constexpr (hasRandomAccess && limitMode == LimitMode::byCount)
  454.                 return *this + implicit_cast<difference_type>(limit_);
  455.             else if constexpr (hasRandomAccess)
  456.                 return *this + implicit_cast<difference_type>(limit_) / get<entryLen_>();
  457.             else
  458.                 return AdsDataCursor{};
  459.         }
  460.         constexpr iterator cend() const noexcept { return end(); }
  461.  
  462.         constexpr reverse_iterator rbegin() const noexcept
  463.         {
  464.             static_assert(hasRandomAccess);
  465.             return reverse_iterator{end()};
  466.         }
  467.         constexpr reverse_iterator rend() const noexcept
  468.         {
  469.             static_assert(hasRandomAccess);
  470.             return reverse_iterator{begin()};
  471.         }
  472.  
  473.         constexpr reverse_iterator crbegin() const { return rbegin(); }
  474.         constexpr reverse_iterator crend() const { return rend(); }
  475.  
  476.         constexpr bool empty() const noexcept { return limit_ == 0; }
  477.  
  478.         constexpr explicit operator bool() const noexcept { return !empty(); }
  479.  
  480.         constexpr std::size_t count() const noexcept
  481.         {
  482.             static_assert(limitMode == LimitMode::byCount);
  483.             return limit_;
  484.         }
  485.  
  486.         constexpr std::size_t size() const noexcept(noexcept(!checked))
  487.         {
  488.             if constexpr (limitMode == LimitMode::byCount)
  489.                 return count();
  490.             else
  491.                 return implicit_cast<std::size_t>(std::distance(begin(), end()));
  492.         }
  493.  
  494.     private:
  495.         // verify integrity of data
  496.         void doCheck() const
  497.         {
  498.             if (*this)
  499.             {
  500.                 if constexpr (limitMode == LimitMode::byCount)
  501.                     PropertyList<tag>::map::check(data_.data_, data_.parent(), get<entryLen_>());
  502.                 else
  503.                     PropertyList<tag>::map::check(data_.data_, data_.parent(), limit_);
  504.             }
  505.         }
  506.  
  507.         void updateDebugInfo() noexcept(noexcept(!checked))
  508.         {
  509.             if constexpr (checked)
  510.                 doCheck();
  511. #ifdef ADSDATACURSOR_DEBUG
  512.             debugInfo_ = PropertyList<tag>::map::template getDebugInfo<tag>(data_.data_, data_.parent(), limit_);
  513. #endif
  514.         }
  515. #ifdef ADSDATACURSOR_DEBUG
  516.     public:
  517.         operator std::vector<AdsDataCursor>() const { return std::vector<AdsDataCursor>(begin(), end()); }
  518.  
  519.     private:
  520.         typename PropertyList<tag>::map::DebugInfo debugInfo_{};
  521. #endif
  522.  
  523.         AdsDataCursorData<PropertyList<tag>::map::needsParent> data_;
  524.         size_type                                              limit_;
  525.     };
  526.  
  527.     // Accessor models:
  528.     // with p = pointer to data of structed_type
  529.     // with q = pointer to data of containing PropertyMap
  530.     // entryLimit = maximum available memory starting at p
  531.     // all models:              member function   check(p, q, entryLimit)
  532.     // model value_accessor:    member function   get(p, q): see accessor description
  533.     //                          checks: nothing unless specified otherwise
  534.     // model memory_accessor:   member functions  offset(p, q):      offset rel. to p of memory location
  535.     //                                            size(p, q):        size of memory location
  536.     //                          checks: memory location within bounds of entryLimit
  537.     // model predicate: model of value_accessor of bool type
  538.  
  539.     struct Unchecked
  540.     {
  541.         static constexpr void check(const char*, const char*, std::size_t) noexcept {}
  542.     };
  543.  
  544.     template <typename Accessor>
  545.     struct MemoryCheck
  546.     {
  547.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  548.         {
  549.             ADSDATACURSOR_VERIFY(
  550.                 "%1%\nwith\nAccessor::offset(p, q) == %2%\nentryLimit == %3%\nAccessor::size(p, q) == %4%",
  551.                 (Accessor::offset(p, q) <= entryLimit && entryLimit - Accessor::offset(p, q) >= Accessor::size(p, q)),
  552.                 Accessor::offset(p, q), entryLimit, Accessor::size(p, q));
  553.         }
  554.     };
  555.  
  556.     // common template parameters:
  557.     // T - type indexing current structected_type
  558.     // before - id of preceding Property which must model memory_accessor
  559.     // align - alignment of memory location
  560.  
  561.     // NextData
  562.     // model of: value_accessor
  563.     // returns: aligned offset following preceding Property
  564.     // checks: value equals or is less than value of referenced Property which
  565.     // must model value_accessor
  566.     template <AdsTypeTag tag, IdType before = noElement, IdType expected = noElement, bool constant_expected = false>
  567.     struct NextData : Unchecked
  568.     {
  569.         using type = std::size_t;
  570.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  571.         {
  572.             if constexpr (before == noElement)
  573.                 return 0;
  574.             else if constexpr (constant_expected)
  575.             {
  576.                 constexpr auto result = PropertyList<tag>::map::template next_offset<before>(nullptr, nullptr);
  577.                 return result;
  578.             }
  579.             else
  580.                 return PropertyList<tag>::map::template next_offset<before>(p, q);
  581.         }
  582.  
  583.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t)
  584.         {
  585.             if constexpr (expected != noElement)
  586.                 ADSDATACURSOR_VERIFY(
  587.                     "%1%\nwith\nget(p, q) == %2%\nPropertyList<tag>::map::template get<expected>(p, q) == %3%",
  588.                     (get(p, q) <= PropertyList<tag>::map::template get<expected>(p, q)), (get(p, q)),
  589.                     (PropertyList<tag>::map::template get<expected>(p, q)));
  590.         }
  591.     };
  592.  
  593.     template <AdsTypeTag tag, IdType before, IdType expected>
  594.     struct HasConstantEntryLen<NextData<tag, before, expected, true>> : std::true_type
  595.     {};
  596.  
  597.     // NextElement
  598.     // model of: value_accessor, memory_accessor
  599.     // object of type U following preceding Property
  600.     // returns: stored value
  601.     // checks: stored value equals one of the expected values (if any)
  602.     template <AdsTypeTag tag, typename U, IdType before = noElement, typename V = U, V... expected>
  603.     struct NextElement : MemoryCheck<NextElement<tag, U, before, V, expected...>>
  604.     {
  605.         using type = V;
  606.  
  607.         static type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  608.         {
  609.             return static_cast<V>(readRaw<U>(p + offset(p, q)));
  610.         }
  611.  
  612.         static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  613.         {
  614.             if constexpr (before == noElement)
  615.                 return 0;
  616.             else
  617.                 return PropertyList<tag>::map::template next_offset<before>(p, q);
  618.         }
  619.  
  620.         static constexpr std::size_t size(const char*, const char*) noexcept { return sizeof(U); }
  621.  
  622.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  623.         {
  624.             MemoryCheck<NextElement<tag, U, before, V, expected...>>::check(p, q, entryLimit);
  625.             if constexpr (sizeof...(expected) != 0)
  626.                 ADSDATACURSOR_VERIFY("%1%\nwith\nget(p, q) == %2%", (... || (get(p, q) == expected)), (get(p, q)));
  627.         }
  628.     };
  629.  
  630.     // VarData
  631.     // model of: value_accessor, memory_accessor
  632.     // String of Element with offset of data's value and size of length
  633.     // returns: string_view
  634.     template <AdsTypeTag tag, IdType before, IdType length, typename Element, std::size_t add = 0>
  635.     struct VarData : MemoryCheck<VarData<tag, before, length, Element, add>>
  636.     {
  637.         using type = std::basic_string_view<Element>;
  638.  
  639.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  640.         {
  641.             return type{reinterpret_cast<const Element*>(p + offset(p, q)), size(p, q) - add};
  642.         }
  643.  
  644.         static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  645.         {
  646.             return PropertyList<tag>::map::template next_offset<before>(p, q);
  647.         }
  648.  
  649.         static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  650.         {
  651.             return PropertyList<tag>::map::template get<length>(p, q) + add;
  652.         }
  653.     };
  654.  
  655.     // String
  656.     // derived from: VarData
  657.     // checks: no embedded '\0' in character String
  658.     //         terminator at the end
  659.     template <AdsTypeTag tag, IdType before, IdType length>
  660.     struct String : VarData<tag, before, length, char, 1>
  661.     {
  662.         using base = VarData<tag, before, length, char, 1>;
  663.  
  664.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  665.         {
  666.             VarData<tag, before, length, char, 1>::check(p, q, entryLimit);
  667.             ADSDATACURSOR_VERIFY("%1%\nembedded \\0 in\n%2%", (base::get(p, q).find('\0') == std::string_view::npos),
  668.                                  (base::get(p, q)));
  669.             ADSDATACURSOR_VERIFY("%1%\nmissing terminator for\n%2%",
  670.                                  (base::get(p, q).data()[base::size(p, q) - 1] == '\0'), (base::get(p, q)));
  671.         }
  672.     };
  673.  
  674.     // Flag
  675.     // model of: predicate
  676.     // returns: bool: (apply mask to value of referenced Property) == compare
  677.     template <AdsTypeTag tag, IdType ref, std::uint64_t mask, std::uint64_t compare = mask>
  678.     struct Flag : Unchecked
  679.     {
  680.         using type = bool;
  681.  
  682.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  683.         {
  684.             auto                      value    = PropertyList<tag>::map::template get<ref>(p, q);
  685.             constexpr decltype(value) mask_    = mask;
  686.             constexpr decltype(value) compare_ = compare;
  687.             return (value & mask_) == compare_;
  688.         }
  689.     };
  690.  
  691.     // And
  692.     // model of: predicate
  693.     // returns: all reference predicates are true
  694.     template <AdsTypeTag tag, IdType... refs>
  695.     struct And : Unchecked
  696.     {
  697.         using type = bool;
  698.  
  699.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  700.         {
  701.             return (... && PropertyList<tag>::map::template get<refs>(p, q));
  702.         }
  703.     };
  704.  
  705.     // Optional
  706.     // model of: value_accessor, memory_accessor
  707.     // Property accessed by Accessor (of model memory_accessor) which existence
  708.     // is predicated by Flag returns: std::optional<...> with value of Accessor
  709.     template <AdsTypeTag tag, IdType Flag, typename Access>
  710.     struct Optional : MemoryCheck<Optional<tag, Flag, Access>>
  711.     {
  712.         using type = std::optional<typename Access::type>;
  713.  
  714.         static constexpr
  715.             typename Access::type value([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  716.         {
  717.             return Access::get(p, q);
  718.         }
  719.  
  720.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  721.         {
  722.             return exists(p, q) ? type{value(p, q)} : type{};
  723.         }
  724.  
  725.         static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  726.         {
  727.             return Access::offset(p, q);
  728.         }
  729.  
  730.         static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  731.         {
  732.             return exists(p, q) ? Access::size(p, q) : 0;
  733.         }
  734.  
  735.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  736.         {
  737.             MemoryCheck<Optional>::check(p, q, entryLimit);
  738.             if (exists(p, q))
  739.                 Access::check(p, q, entryLimit);
  740.         }
  741.  
  742.         static constexpr bool exists([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  743.         {
  744.             return PropertyList<tag>::map::template get<Flag>(p, q);
  745.         }
  746.     };
  747.  
  748.     // OptionalDef
  749.     // derived from: Optional
  750.     // returns: predicated on Flag value of Accessor or default_value
  751.     template <AdsTypeTag tag, IdType Flag, typename Access, decltype(Access::get(nullptr, nullptr)) default_value>
  752.     struct OptionalDef : Optional<tag, Flag, Access>
  753.     {
  754.         using type = typename Access::type;
  755.  
  756.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  757.         {
  758.             return Optional<tag, Flag, Access>::exists(p, q) ? Optional<tag, Flag, Access>::value(p, q) : default_value;
  759.         }
  760.     };
  761.  
  762.     // Array
  763.     // model of: value_accessor, memory_accessor
  764.     // sequence of #num structured types indexed by Element following preceding
  765.     // Property returns: AdsDataCursor to first element check: all contained
  766.     // elements
  767.     template <AdsTypeTag tag, IdType before, IdType num, AdsTypeTag elementTag>
  768.     struct Array
  769.     {
  770.         using type = AdsDataCursor<elementTag, LimitMode::byCount, false>;
  771.  
  772.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  773.         {
  774.             return type(p + offset(p, q), elements(p, q), p);
  775.         }
  776.  
  777.         static constexpr std::size_t offset([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  778.         {
  779.             return PropertyList<tag>::map::template next_offset<before>(p, q);
  780.         }
  781.  
  782.         static constexpr std::size_t size([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  783.         {
  784.             if constexpr (hasConstantEntryLen<typename PropertyList<elementTag>::map::template accessor<entryLen_>>)
  785.             {
  786.                 return elements(p, q) * PropertyList<elementTag>::map::template get<entryLen_>(nullptr, nullptr);
  787.             }
  788.             else
  789.             {
  790.                 auto elem = get(p, q);
  791.                 while (elem)
  792.                     ++elem;
  793.                 return implicit_cast<std::size_t>(elem.data() - (p + offset(p, q)));
  794.             }
  795.         }
  796.  
  797.         static void check([[maybe_unused]] const char* p, [[maybe_unused]] const char* q, std::size_t entryLimit)
  798.         {
  799.             ADSDATACURSOR_VERIFY("%1%\nwith\noffset(p, q) = %2%\nentryLimit = %3%", (offset(p, q) <= entryLimit),
  800.                                  (offset(p, q)), entryLimit);
  801.             if (auto n = elements(p, q))
  802.             {
  803.                 AdsDataCursor<elementTag, LimitMode::bySize, true> elem(p + offset(p, q), entryLimit - offset(p, q), p);
  804.                 while (--n)
  805.                 {
  806.                     ADSDATACURSOR_VERIFY("%1%\ntoo many elements", elem);
  807.                     ++elem;
  808.                 }
  809.                 ADSDATACURSOR_VERIFY("%1%\ntoo many elements", elem);
  810.             }
  811.         }
  812.  
  813.         static constexpr std::size_t elements([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  814.         {
  815.             return PropertyList<tag>::map::template get<num>(p, q);
  816.         }
  817.     };
  818.  
  819.     // ParentProperty
  820.     // model of: value_accessor
  821.     // returns: value of referenced Property of containing structured type
  822.     // indexed by P
  823.     template <AdsTypeTag parentTag, IdType prop>
  824.     struct ParentProperty : Unchecked
  825.     {
  826.         using type = typename PropertyList<parentTag>::map::template accessor<prop>::type;
  827.         static constexpr type get([[maybe_unused]] const char* p, [[maybe_unused]] const char* q) noexcept
  828.         {
  829.             return PropertyList<parentTag>::map::template get<prop>(q, nullptr);
  830.         }
  831.     };
  832.  
  833.     template <AdsTypeTag parentTag, IdType prop>
  834.     struct NeedsParentProperty<ParentProperty<parentTag, prop>> : std::true_type
  835.     {};
  836.  
  837.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  838.     // note: in the absence of support for auto non-type template parameters
  839.     // where we could different enum class types, we make sure different *_prop
  840.     // constants do not oberlap, so that trying to access a Property of the
  841.     // wrong type will result in an error at comptile time entryLen is special
  842.     // and needs to be the same in all cases, since it is used in the definition
  843.     // of accessors
  844.  
  845. #define ADSDATACURSOR_ID_LIST(typeTag, baseValue, ...)                                                         \
  846.     template <>                                                                                                \
  847.     struct IdList<typeTag>                                                                                     \
  848.     {                                                                                                          \
  849.         static constexpr AdsTypeTag tag = typeTag;                                                             \
  850.         enum                                                                                                   \
  851.         {                                                                                                      \
  852.             entryLen                               = entryLen_,                                                \
  853.             BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__) = baseValue,                                                \
  854.             BOOST_PP_LIST_ENUM(BOOST_PP_LIST_REST(BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)))                     \
  855.         };                                                                                                     \
  856.         static constexpr const char* const idString[] = {BOOST_PP_SEQ_ENUM(                                    \
  857.             BOOST_PP_SEQ_TRANSFORM(ADSDATACURSOR_STRINGIZE_ID, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))}; \
  858.         static constexpr const char*       at(IdType id) noexcept                                              \
  859.         {                                                                                                      \
  860.             return id == entryLen_ ? "entryLen" : idString[id - baseValue];                                    \
  861.         }                                                                                                      \
  862.     };
  863.  
  864. #define ADSDATACURSOR_STRINGIZE_ID(s, data, elem) BOOST_PP_STRINGIZE(elem)
  865.  
  866.     ADSDATACURSOR_ID_LIST(AdsTypeTag::copyMaskByte, 0, value)
  867.     template <>
  868.     struct PropertyList<AdsTypeTag::copyMaskByte> : IdList<AdsTypeTag::copyMaskByte>
  869.     {
  870.         using map = PropertyMap<Property<value, NextElement<tag, std::uint8_t, noElement, std::uint8_t, 0, 0xff>>,
  871.                                 Property<entryLen, NextData<tag, value, noElement, true>>>;
  872.     };
  873.  
  874.     ADSDATACURSOR_ID_LIST(AdsTypeTag::datatypeArrayInfo, 1000, lBound, elements)
  875.     template <>
  876.     struct PropertyList<AdsTypeTag::datatypeArrayInfo> : IdList<AdsTypeTag::datatypeArrayInfo>
  877.     {
  878.         using map = PropertyMap<Property<lBound, NextElement<tag, std::uint32_t, noElement>>,
  879.                                 Property<elements, NextElement<tag, std::uint32_t, lBound>>,
  880.                                 Property<entryLen, NextData<tag, elements, noElement, true>>>;
  881.     };
  882.  
  883.     ADSDATACURSOR_ID_LIST(AdsTypeTag::symbolEntry, 2000, group, offset, size, typeId, flags, isPersistent, isBitValue,
  884.                           isReference, hasTypeGuid, isTcComIFacePtr, isReadOnly, ITFMethodAccess, isMethodRef,
  885.                           hasAttributes, isStatic, reserved, nameLen, typeLen, commentLen, name, type, comment, guid,
  886.                           numAttributes, attributeData, expEntryLen)
  887.     template <>
  888.     struct PropertyList<AdsTypeTag::symbolEntry> : IdList<AdsTypeTag::symbolEntry>
  889.     {
  890.         using map = PropertyMap<
  891.             Property<entryLen, NextElement<tag, std::uint32_t>>,
  892.             Property<group, NextElement<tag, std::uint32_t, entryLen>>,
  893.             Property<offset, NextElement<tag, std::uint32_t, group>>,
  894.             Property<size, NextElement<tag, std::uint32_t, offset>>,
  895.             Property<typeId, NextElement<tag, std::uint32_t, size, DatatypeId>>,
  896.             Property<flags, NextElement<tag, std::uint16_t, typeId>>, Property<isPersistent, Flag<tag, flags, 0x0001>>,
  897.             Property<isBitValue, Flag<tag, flags, 0x0002>>, Property<isReference, Flag<tag, flags, 0x0004>>,
  898.             Property<hasTypeGuid, Flag<tag, flags, 0x0008>>, Property<isTcComIFacePtr, Flag<tag, flags, 0x0010>>,
  899.             Property<isReadOnly, Flag<tag, flags, 0x0020>>, Property<ITFMethodAccess, Flag<tag, flags, 0x0040>>,
  900.             Property<isMethodRef, Flag<tag, flags, 0x0080>>, Property<hasAttributes, Flag<tag, flags, 0x1000>>,
  901.             Property<isStatic, Flag<tag, flags, 0x2000>>,
  902.             Property<reserved, NextElement<tag, std::uint16_t, flags, std::uint16_t, 0>>,
  903.             Property<nameLen, NextElement<tag, std::uint16_t, reserved>>,
  904.             Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
  905.             Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
  906.             Property<name, String<tag, commentLen, nameLen>>, Property<type, String<tag, name, typeLen>>,
  907.             Property<comment, String<tag, type, commentLen>>,
  908.             Property<guid, Optional<tag, hasTypeGuid, NextElement<tag, GUID, comment>>>,
  909.             Property<numAttributes, OptionalDef<tag, hasAttributes, NextElement<tag, std::uint16_t, guid>, 0>>,
  910.             Property<attributeData, Array<tag, numAttributes, numAttributes, AdsTypeTag::attributeEntry>>,
  911.             Property<expEntryLen, NextData<tag, attributeData, entryLen>>>;
  912.     };
  913.  
  914.     ADSDATACURSOR_ID_LIST(AdsTypeTag::attributeEntry, 3000, nameLen, valueLen, name, value)
  915.     template <>
  916.     struct PropertyList<AdsTypeTag::attributeEntry> : IdList<AdsTypeTag::attributeEntry>
  917.     {
  918.         using map = PropertyMap<Property<nameLen, NextElement<tag, std::uint8_t>>,
  919.                                 Property<valueLen, NextElement<tag, std::uint8_t, nameLen>>,
  920.                                 Property<name, String<tag, valueLen, nameLen>>,
  921.                                 Property<value, String<tag, name, valueLen>>, Property<entryLen, NextData<tag, value>>>;
  922.     };
  923.  
  924.     ADSDATACURSOR_ID_LIST(AdsTypeTag::datatypeEntry, 4000, version, reserved1, reserved2, size, offset, typeId, flags,
  925.                           isDatatype, isDataitem, isReference, isMethodRef, isOversample, isBitValue, isPropItem,
  926.                           hasTypeGuid, flagPersistent, containsPersistent, isPersistent, hasCopyMask,
  927.                           flagTcComInterfacePtr, containsTcComInterfacePtr, isTcComInterfacePtr, hasMethodInfos,
  928.                           hasAttributes, hasEnumInfos, isAligned, isStatic, nameLen, typeLen, commentLen, numArrayDims,
  929.                           numSubItems, name, type, comment, arrayInfoData, subItemData, guid, copyMaskLen, copyMaskData,
  930.                           copyMaskBegin, copyMask, numMethods, methodData, numAttributes, attributeData, numEnumInfos,
  931.                           enumInfoData, expEntryLen)
  932.     template <>
  933.     struct PropertyList<AdsTypeTag::datatypeEntry> : IdList<AdsTypeTag::datatypeEntry>
  934.     {
  935.         using map = PropertyMap<
  936.             Property<entryLen, NextElement<tag, std::uint32_t>>,
  937.             Property<version, NextElement<tag, std::uint32_t, entryLen, std::uint32_t, 1>>,
  938.             Property<reserved1, NextElement<tag, std::uint32_t, version>>,
  939.             Property<reserved2, NextElement<tag, std::uint32_t, reserved1>>,
  940.             Property<size, NextElement<tag, std::uint32_t, reserved2>>,
  941.             Property<offset, NextElement<tag, std::uint32_t, size>>,
  942.             Property<typeId, NextElement<tag, std::uint32_t, offset, DatatypeId>>,
  943.             Property<flags, NextElement<tag, std::uint32_t, typeId>>,
  944.             Property<isDatatype, Flag<tag, flags, 0x00000001>>, Property<isDataitem, Flag<tag, flags, 0x00000002>>,
  945.             Property<isReference, Flag<tag, flags, 0x00000004>>, Property<isMethodRef, Flag<tag, flags, 0x00000008>>,
  946.             Property<isOversample, Flag<tag, flags, 0x00000010>>, Property<isBitValue, Flag<tag, flags, 0x00000020>>,
  947.             Property<isPropItem, Flag<tag, flags, 0x00000040>>, Property<hasTypeGuid, Flag<tag, flags, 0x00000080>>,
  948.             Property<flagPersistent, Flag<tag, flags, 0x00000100>>,
  949.             Property<containsPersistent, And<tag, flagPersistent, isDatatype>>,
  950.             Property<isPersistent, And<tag, flagPersistent, isDataitem>>,
  951.             Property<hasCopyMask, Flag<tag, flags, 0x00000200>>,
  952.             Property<flagTcComInterfacePtr, Flag<tag, flags, 0x00000400>>,
  953.             Property<containsTcComInterfacePtr, And<tag, flagTcComInterfacePtr, isDatatype>>,
  954.             Property<isTcComInterfacePtr, And<tag, flagTcComInterfacePtr, isDataitem>>,
  955.             Property<hasMethodInfos, Flag<tag, flags, 0x00000800>>,
  956.             Property<hasAttributes, Flag<tag, flags, 0x00001000>>, Property<hasEnumInfos, Flag<tag, flags, 0x00002000>>,
  957.             Property<isAligned, Flag<tag, flags, 0x00010000>>, Property<isStatic, Flag<tag, flags, 0x00020000>>,
  958.             Property<nameLen, NextElement<tag, std::uint16_t, flags>>,
  959.             Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
  960.             Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
  961.             Property<numArrayDims, NextElement<tag, std::uint16_t, commentLen>>,
  962.             Property<numSubItems, NextElement<tag, std::uint16_t, numArrayDims>>,
  963.             Property<name, String<tag, numSubItems, nameLen>>, Property<type, String<tag, name, typeLen>>,
  964.             Property<comment, String<tag, type, commentLen>>,
  965.             Property<arrayInfoData, Array<tag, comment, numArrayDims, AdsTypeTag::datatypeArrayInfo>>,
  966.             Property<subItemData, Array<tag, arrayInfoData, numSubItems, tag>>,
  967.             Property<guid, Optional<tag, hasTypeGuid, NextElement<tag, GUID, subItemData>>>,
  968.             Property<copyMaskLen, OptionalDef<tag, hasCopyMask, NextElement<tag, std::uint32_t, reserved2>, 0>>,
  969.             Property<copyMaskData, Array<tag, guid, copyMaskLen, AdsTypeTag::copyMaskByte>>,
  970.             Property<copyMask, VarData<tag, guid, copyMaskLen, std::uint8_t>>,
  971.             Property<numMethods, OptionalDef<tag, hasMethodInfos, NextElement<tag, std::uint16_t, copyMask>, 0>>,
  972.             Property<methodData, Array<tag, numMethods, numMethods, AdsTypeTag::methodEntry>>,
  973.             Property<numAttributes, OptionalDef<tag, hasAttributes, NextElement<tag, std::uint16_t, methodData>, 0>>,
  974.             Property<attributeData, Array<tag, numAttributes, numAttributes, AdsTypeTag::attributeEntry>>,
  975.             Property<numEnumInfos, OptionalDef<tag, hasEnumInfos, NextElement<tag, std::uint16_t, attributeData>, 0>>,
  976.             Property<enumInfoData, Array<tag, numEnumInfos, numEnumInfos, AdsTypeTag::enumInfoEntry>>,
  977.             Property<expEntryLen, NextData<tag, enumInfoData, entryLen>>>;
  978.     };
  979.  
  980.     ADSDATACURSOR_ID_LIST(AdsTypeTag::methodParaEntry, 5000, size, alignSize, typeId, flags, isIn, isOut, isInOut,
  981.                           isReference, reserved, guid, lengthIsPara, nameLen, typeLen, commentLen, name, type, comment,
  982.                           expEntryLen)
  983.     template <>
  984.     struct PropertyList<AdsTypeTag::methodParaEntry> : IdList<AdsTypeTag::methodParaEntry>
  985.     {
  986.         using map =
  987.             PropertyMap<Property<entryLen, NextElement<tag, std::uint32_t>>,
  988.                         Property<size, NextElement<tag, std::uint32_t, entryLen>>,
  989.                         Property<alignSize, NextElement<tag, std::uint32_t, size>>,
  990.                         Property<typeId, NextElement<tag, std::uint32_t, alignSize, DatatypeId>>,
  991.                         Property<flags, NextElement<tag, std::uint32_t, typeId>>,
  992.                         Property<isIn, Flag<tag, flags, 0x00000007, 0x00000001>>,
  993.                         Property<isOut, Flag<tag, flags, 0x00000007, 0x00000002>>,
  994.                         Property<isInOut, Flag<tag, flags, 0x00000007, 0x00000003>>,
  995.                         Property<isReference, Flag<tag, flags, 0x00000007, 0x00000004>>,
  996.                         Property<reserved, NextElement<tag, std::uint32_t, flags, std::uint32_t, 0>>,
  997.                         Property<guid, NextElement<tag, GUID, reserved>>,
  998.                         Property<lengthIsPara, NextElement<tag, std::uint16_t, guid>>,
  999.                         Property<nameLen, NextElement<tag, std::uint16_t, lengthIsPara>>,
  1000.                         Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
  1001.                         Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
  1002.                         Property<name, String<tag, typeLen, nameLen>>, Property<type, String<tag, name, typeLen>>,
  1003.                         Property<comment, String<tag, type, commentLen>>,
  1004.                         Property<expEntryLen, NextData<tag, comment, entryLen>>>;
  1005.     };
  1006.  
  1007.     ADSDATACURSOR_ID_LIST(AdsTypeTag::methodEntry, 6000, version, vTableIndex, returnSize, returnAlignSize, reserved,
  1008.                           returnTypeGuid, returnTypeId, flags, isPlcCallingConvention, isCallUnlocked, nameLen, typeLen,
  1009.                           commentLen, numParas, name, type, comment, paraData, expEntryLen)
  1010.     template <>
  1011.     struct PropertyList<AdsTypeTag::methodEntry> : IdList<AdsTypeTag::methodEntry>
  1012.     {
  1013.         using map =
  1014.             PropertyMap<Property<entryLen, NextElement<tag, std::uint32_t>>,
  1015.                         Property<version, NextElement<tag, std::uint32_t, entryLen, std::uint32_t, 1>>,
  1016.                         Property<vTableIndex, NextElement<tag, std::uint32_t, version>>,
  1017.                         Property<returnSize, NextElement<tag, std::uint32_t, vTableIndex>>,
  1018.                         Property<returnAlignSize, NextElement<tag, std::uint32_t, returnSize>>,
  1019.                         Property<reserved, NextElement<tag, std::uint32_t, returnAlignSize, std::uint32_t, 0>>,
  1020.                         Property<returnTypeGuid, NextElement<tag, GUID, reserved>>,
  1021.                         Property<returnTypeId, NextElement<tag, std::uint32_t, returnTypeGuid, DatatypeId>>,
  1022.                         Property<flags, NextElement<tag, std::uint32_t, returnTypeId>>,
  1023.                         Property<nameLen, NextElement<tag, std::uint16_t, flags>>,
  1024.                         Property<typeLen, NextElement<tag, std::uint16_t, nameLen>>,
  1025.                         Property<commentLen, NextElement<tag, std::uint16_t, typeLen>>,
  1026.                         Property<numParas, NextElement<tag, std::uint16_t, commentLen>>,
  1027.                         Property<name, String<tag, numParas, nameLen>>, Property<type, String<tag, name, typeLen>>,
  1028.                         Property<comment, String<tag, type, commentLen>>,
  1029.                         Property<paraData, Array<tag, comment, numParas, AdsTypeTag::methodParaEntry>>,
  1030.                         Property<expEntryLen, NextData<tag, paraData, entryLen>>>;
  1031.     };
  1032.  
  1033.     ADSDATACURSOR_ID_LIST(AdsTypeTag::enumInfoEntry, 7000, nameLen, valueLen, name, value)
  1034.     template <>
  1035.     struct PropertyList<AdsTypeTag::enumInfoEntry> : IdList<AdsTypeTag::enumInfoEntry>
  1036.     {
  1037.         using map = PropertyMap<
  1038.             Property<valueLen, ParentProperty<AdsTypeTag::datatypeEntry, IdList<AdsTypeTag::datatypeEntry>::size>>,
  1039.             Property<nameLen, NextElement<tag, std::uint8_t>>, Property<name, String<tag, nameLen, nameLen>>,
  1040.             Property<value, VarData<tag, name, valueLen, char>>, Property<entryLen, NextData<tag, value>>>;
  1041.     };
  1042.  
  1043. } // namespace adsDataCursor
Add Comment
Please, Sign In to add comment