Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cassert>
- #include <cctype>
- #include <cstring>
- #include <optional>
- #include <string>
- #include <string_view>
- #include <stdexcept>
- #include <type_traits>
- #include <vector>
- #include "adsData.h"
- using namespace std::literals::string_literals;
- using namespace std::literals::string_view_literals;
- #define ASSERT_THROW(cond) ASSERT_THROW_(cond)
- #ifdef ADS_DATA_DEBUG_THROW
- #define ASSERT_THROW_(cond) \
- { \
- assert(cond); \
- if (!(cond)) \
- throw std::runtime_error(#cond); \
- }
- #else
- #define ASSERT_THROW_(cond) \
- if (!(cond)) \
- throw std::runtime_error(#cond);
- #endif
- adsVarData::adsVarData(const adsData::subSymbolInfo* info, sizeType group, sizeType offset, sizeType index = -1)
- : info_{ info }, group_{ group }, offset_{ offset }, index_{ index }
- {}
- namespace {
- std::string operator+(std::string lhs, std::string_view rhs) {
- return std::move(lhs.append(rhs.data(), rhs.size()));
- }
- std::string operator+(std::string_view lhs, std::string_view rhs) {
- std::string result;
- result.reserve(lhs.size() + rhs.size());
- result.assign(lhs.data(), lhs.size()).append(rhs);
- return result;
- }
- using sizeType = adsData::sizeType;
- inline bool icmp_less(std::string_view lhs, std::string_view rhs) {
- return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
- [](auto x, auto y) { return
- x == '\0' ? y != '\0' : y == '\0' ? false
- : x == '.' ? y != '.' : y == '.' ? false
- : std::tolower(x) < std::tolower(y); });
- }
- inline bool icmp_equal(std::string_view lhs, std::string_view rhs) {
- return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
- [](auto x, auto y) { return std::tolower(x) == std::tolower(y); });
- }
- template <typename T, std::enable_if_t<std::is_trivial_v<T>, int> = 0>
- T readRaw(const char* p) noexcept {
- T res;
- std::memcpy(&res, p, sizeof res);
- return res;
- }
- struct by_size {};
- struct by_count {};
- namespace detail {
- template <typename T>
- struct properties_of;
- template <typename T>
- struct property_ids {
- using id_type = T;
- };
- template <typename T>
- class ref;
- using ref_prop = int;
- constexpr ref_prop entryLen_ = -1;
- template <std::size_t align>
- constexpr std::size_t do_align(std::size_t offset) {
- static_assert(align != 0 && (align & (align - 1)) == 0, "power of 2");
- return (offset + align - 1) & ~(align - 1);
- }
- template <int Id, typename Accessor>
- struct ref_property {
- static constexpr int id = Id;
- using accessor = Accessor;
- };
- // Accessor models:
- // with p = pointer to data of structed_type
- // with q = pointer to data of containing structured_type
- // 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
- // next_offset(p, q): offset(p, q) + size(p, q)
- // 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 T>
- struct memory_check {
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- auto off = T::offset(p, q); (void)off;
- auto size = T::size(p, q); (void)size;
- ASSERT_THROW(T::offset(p, q) <= entryLimit && entryLimit - T::offset(p, q) >= T::size(p, q));
- }
- };
- // simple property accessors
- // fixed_size
- // model of: value_accessor
- // returns: size of T
- template <typename T>
- struct fixed_size : unchecked {
- static constexpr std::size_t get (const char*, const char*) {
- return sizeof(T);
- }
- };
- template <typename T>
- struct is_fixed_size : std::false_type {};
- template <typename T>
- struct is_fixed_size<fixed_size<T>> : std::true_type {};
- template <typename T>
- constexpr bool is_fixed_size_v = is_fixed_size<T>::value;
- // element
- // model of: value_accessor, memory_accessor
- // object of type T at fixed displacement derived from structure member, see ELEMENT* macros
- // returns: stored value
- template <typename T, std::size_t disp, typename U = T>
- struct element : memory_check<element<T, disp, U>> {
- static U get (const char* p, const char*) noexcept {
- return static_cast<U>(readRaw<T>(p + disp));
- }
- static constexpr std::size_t offset (const char*, const char*) noexcept {
- return disp;
- }
- static constexpr std::size_t size (const char*, const char*) noexcept {
- return sizeof(T);
- }
- static constexpr std::size_t next_offset(const char* p, const char* q) noexcept {
- return offset(p, q) + size(p, q);
- }
- };
- // element_checked
- // derived from: element
- // checks: stored value equals any of expected values
- template <typename T, std::size_t disp, T... expected>
- struct element_checked : element<T, disp> {
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- element<T, disp>::check(p, q, entryLimit);
- ASSERT_THROW((... || (get(p, q) == expected)));
- }
- };
- #define ELEMENT(CLASS, MEMBER) element< std::decay_t<decltype(std::declval<CLASS&>().*&CLASS::MEMBER)>, offsetof(CLASS, MEMBER)>
- #define ELEMENT_TYPE(CLASS, MEMBER, TYPE) element< std::decay_t<decltype(std::declval<CLASS&>().*&CLASS::MEMBER)>, offsetof(CLASS, MEMBER), TYPE>
- #define ELEMENT_EXP(CLASS, MEMBER, ...) element_checked<std::decay_t<decltype(std::declval<CLASS&>().*&CLASS::MEMBER)>, offsetof(CLASS, MEMBER), __VA_ARGS__>
- // compound property accessors
- // common template parameters:
- // T - type indexing current structected_type
- // before - id of preceding property which must model memory_accessor
- // align - alignment of memory location
- // next_data
- // model of: value_accessor
- // returns: aligned offset following preceding property
- template <typename T, ref_prop before, std::size_t align = 1>
- struct next_data : unchecked {
- static constexpr std::size_t get (const char* p, const char* q) noexcept {
- return do_align<align>(properties_of<T>::template next_offset<before>(p, q));
- }
- };
- // next_data_c
- // derived from: next_data
- // checks: value equals or is less than value of referenced property which must model value_accessor
- template <typename T, ref_prop before, ref_prop expected, std::size_t align = 1>
- struct next_data_c : next_data<T, before, align> {
- static void check(const char* p, const char* q, std::size_t) {
- ASSERT_THROW((next_data<T, before, align>::get(p, q) <= properties_of<T>::template get<expected>(p, q)));
- }
- };
- // next_element
- // 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 <typename T, ref_prop before, typename U, std::size_t align = 1, U... expected>
- struct next_element : memory_check<next_element<T, before, U, align, expected...>> {
- static U get (const char* p, const char* q) noexcept {
- return readRaw<U>(p + offset(p, q));
- }
- static constexpr std::size_t offset (const char* p, const char* q) noexcept {
- return do_align<align>(properties_of<T>::template next_offset<before>(p, q));
- }
- static constexpr std::size_t size (const char*, const char*) noexcept {
- return sizeof(U);
- }
- static constexpr std::size_t next_offset(const char* p, const char* q) noexcept {
- return offset(p, q) + size(p, q);
- }
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- memory_check<next_element<T, before, U, align, expected...>>::check(p, q, entryLimit);
- if constexpr (sizeof...(expected) != 0)
- ASSERT_THROW((... || (get(p, q) == expected)));
- }
- };
- template <typename T, T... expected>
- bool val_check(T v) noexcept {
- return (... || (v == expected));
- }
- // var_data
- // model of: value_accessor, memory_accessor
- // string of Element with offset of data's value and size of length
- // returns: string_view
- template <typename T, ref_prop data, ref_prop length, typename Element = char>
- struct var_data : memory_check<var_data<T, data, length>> {
- static constexpr auto get (const char* p, const char* q) noexcept {
- return std::basic_string_view<Element>{ reinterpret_cast<const Element*>(p + offset(p, q)), size(p, q) };
- }
- static constexpr std::size_t offset (const char* p, const char* q) noexcept {
- return properties_of<T>::template get<data>(p, q);
- }
- static constexpr std::size_t size (const char* p, const char* q) noexcept {
- return properties_of<T>::template get<length>(p, q);
- }
- static constexpr std::size_t next_offset(const char* p, const char* q) noexcept {
- return offset(p, q) + size(p, q);
- }
- };
- // string
- // derived from: var_data
- // checks: no embedded '\0' in character string
- template <typename T, ref_prop data, ref_prop length>
- struct string : var_data<T, data, length> {
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- var_data<T, data, length>::check(p, q, entryLimit);
- ASSERT_THROW((var_data<T, data, length>::get(p, q).find('\0') == std::string_view::npos)); // no embedded \0
- }
- };
- // flag
- // model of: predicate
- // returns: bool: (apply mask to value of referenced property) == compare
- template <typename T, ref_prop ref, unsigned long long mask, unsigned long long compare = mask>
- struct flag : unchecked {
- static constexpr bool get (const char* p, const char* q) noexcept {
- return (properties_of<T>::template get<ref>(p, q) & mask) == compare;
- }
- };
- // and_
- // model of: predicate
- // returns: all reference predicates are true
- template <typename T, ref_prop... refs>
- struct and_ : unchecked {
- static constexpr bool get(const char* p, const char* q) noexcept {
- return (... && properties_of<T>::template get<ref>(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 <typename T, ref_prop flag, typename Access>
- struct optional : memory_check<optional<T, flag, Access>> {
- static constexpr auto get (const char* p, const char* q) noexcept {
- using return_type = std::optional<decltype(value(p, q))>;
- return exists(p, q) ? return_type{ value(p, q) } : return_type{};
- }
- static constexpr std::size_t offset (const char* p, const char* q) noexcept {
- return Access::offset(p, q);
- }
- static constexpr std::size_t size (const char* p, const char* q) noexcept {
- return exists(p, q) ? Access::size(p, q) : 0;
- }
- static constexpr std::size_t next_offset(const char* p, const char* q) noexcept {
- return offset(p, q) + size(p, q);
- }
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- memory_check<optional>::check(p, q, entryLimit);
- if (exists(p, q))
- Access::check(p, q, entryLimit);
- }
- static constexpr bool exists(const char* p, const char* q) noexcept {
- return properties_of<T>::template get<flag>(p, q);
- };
- static constexpr auto value (const char* p, const char* q) noexcept {
- return Access::get(p, q);
- }
- };
- // optional_def
- // derived from: optional
- // returns: predicated on flag value of Accessor or default_value
- template <typename T, ref_prop flag, typename Access, decltype(Access::get(nullptr, nullptr)) default_value>
- struct optional_def : optional<T, flag, Access> {
- static constexpr auto get (const char* p, const char* q) noexcept {
- return optional<T, flag, Access>::exists(p, q) ? optional<T, 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: ref to first element
- // check: all contained elements
- template <typename T, ref_prop before, ref_prop num, typename Element, std::size_t align = 1>
- struct array {
- static constexpr auto get (const char* p, const char* q) noexcept {
- return ref<Element>(p + offset(p, q), by_count{}, elements(p, q), p);
- }
- static constexpr std::size_t offset (const char* p, const char* q) noexcept {
- return do_align<align>(properties_of<T>::template next_offset<before>(p, q));
- }
- static constexpr std::size_t size (const char* p, const char* q) noexcept {
- if constexpr (is_fixed_size_v<typename properties_of<Element>::template accessor<entryLen_>>) {
- return elements(p, q) * properties_of<Element>::template get<entryLen_>(p + offset(p, q), p);
- } else {
- ref<Element> elem = get(p, q);
- while (elem)
- ++elem;
- return elem.data() - p - offset(p, q);
- }
- }
- static constexpr std::size_t next_offset(const char* p, const char* q) noexcept {
- return offset(p, q) + size(p, q);
- }
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- ASSERT_THROW(offset(p, q) <= entryLimit);
- ref<Element> elem(p + offset(p, q), by_size{}, entryLimit - offset(p, q), p);
- for (auto n = elements(p, q); n--; ++elem) {
- elem.do_check();
- }
- }
- static constexpr std::size_t elements (const char* p, const char* q) noexcept {
- return properties_of<T>::template get<num>(p, q);
- }
- };
- // parent_prop
- // model of: value_accessor
- // returns: value of referenced property of containing structured type indexed by P
- template <typename T, typename P, ref_prop prop>
- struct parent_prop : unchecked {
- constexpr static auto get(const char*, const char* q) noexcept {
- return properties_of<P>::template get<prop>(q, nullptr);
- }
- };
- // conditional
- // model of: value_accessor
- // returns: select value of referenced properties depending on predicate
- template <typename T, ref_prop flag, ref_prop yes_prop, ref_prop no_prop>
- struct conditional : unchecked {
- constexpr static auto get(const char* p, const char* q) noexcept {
- return properties_of<T>::template get<flag>(p, q) ? properties_of<T>::template get<yes_prop>(p, q) : properties_of<T>::template get<no_prop>(p, q);
- }
- };
- /////////////////////////////////////////
- struct unmatchedAccessor {
- friend constexpr auto operator^(unmatchedAccessor, unmatchedAccessor) noexcept { return unmatchedAccessor{}; }
- template <typename T>
- friend constexpr auto operator^(unmatchedAccessor, T) noexcept { return T{}; }
- template <typename T>
- friend constexpr auto operator^(T, unmatchedAccessor) noexcept { return T{}; }
- };
- template <typename... Properties>
- struct structured_type {
- using type = structured_type<Properties...>;
- template <ref_prop id>
- static auto get_accessor() noexcept {
- static_assert((... + (Properties::id == id)) <= 1, "id cannot appear more than once in Properties");
- static_assert((... + (Properties::id == id)) == 1, "id must appear exactly once in Properties");
- return (... ^ std::conditional_t<Properties::id == id, typename Properties::accessor, unmatchedAccessor>{});
- }
- template <ref_prop id>
- using accessor = decltype(get_accessor<id>());
- template <ref_prop id> static constexpr decltype(auto) get(const char* p, const char* q) noexcept {
- return accessor<id>::get(p, q);
- }
- template <ref_prop id> static constexpr decltype(auto) offset(const char* p, const char* q) noexcept {
- return accessor<id>::offset(p, q);
- }
- template <ref_prop id> static constexpr decltype(auto) size(const char* p, const char* q) noexcept {
- return accessor<id>::size(p, q);
- }
- template <ref_prop id> static constexpr decltype(auto) next_offset(const char* p, const char* q) noexcept {
- return accessor<id>::next_offset(p, q);
- }
- static void check(const char* p, const char* q, std::size_t entryLimit) {
- (..., Properties::accessor::check(p, q, entryLimit)); // check all properties in order
- }
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 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
- struct copy_mask_byte {};
- struct copy_mask_prop { enum { entryLen = entryLen_, value = 0}; };
- template <>
- struct properties_of<copy_mask_byte>
- : property_ids<copy_mask_prop>, structured_type<
- ref_property<copy_mask_prop::entryLen, fixed_size<copy_mask_byte>>,
- ref_property<copy_mask_prop::value, element_checked<ADS_UINT8, 0, 0, 0xff>>>
- {};
- struct array_info_prop { enum { entryLen = entryLen_, lBound = 1000, elements }; };
- template <>
- struct properties_of<AdsDatatypeArrayInfo>
- : property_ids<array_info_prop>, structured_type<
- ref_property<array_info_prop::entryLen, fixed_size<AdsDatatypeArrayInfo>>,
- ref_property<array_info_prop::lBound, ELEMENT(AdsDatatypeArrayInfo, lBound)>,
- ref_property<array_info_prop::elements, ELEMENT(AdsDatatypeArrayInfo, elements)>>
- {};
- struct symbol_entry_prop {
- enum {
- entryLen = entryLen_, group = 2000, offset, size, typeId, flags,
- isPersistent, isBitValue, isReference, hasTypeGuid, isTcComIFacePtr, isReadOnly, ITFMethodAccess, isMethodRef, hasAttributes, isStatic,
- reserved, nameLen, typeLen, commentLen,
- nameData, name, nameTerminator, typeData, type, typeTerminator, commentData, comment, commentTerminator, guid, numAttributes, attributeData,
- expEntryLen
- };
- };
- template <>
- struct properties_of<AdsSymbolEntry>
- : property_ids<symbol_entry_prop>, structured_type<
- ref_property<symbol_entry_prop::entryLen, ELEMENT( AdsSymbolEntry, entryLength)>,
- ref_property<symbol_entry_prop::group, ELEMENT( AdsSymbolEntry, iGroup)>,
- ref_property<symbol_entry_prop::offset, ELEMENT( AdsSymbolEntry, iOffs)>,
- ref_property<symbol_entry_prop::size, ELEMENT( AdsSymbolEntry, size)>,
- ref_property<symbol_entry_prop::typeId, ELEMENT_TYPE(AdsSymbolEntry, dataType, adsDatatypeId)>,
- ref_property<symbol_entry_prop::flags, ELEMENT( AdsSymbolEntry, flags)>,
- ref_property<symbol_entry_prop::isPersistent, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_PERSISTENT>>,
- ref_property<symbol_entry_prop::isBitValue, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_BITVALUE>>,
- ref_property<symbol_entry_prop::isReference, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_REFERENCETO>>,
- ref_property<symbol_entry_prop::hasTypeGuid, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_TYPEGUID>>,
- ref_property<symbol_entry_prop::isTcComIFacePtr, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_TCCOMIFACEPTR>>,
- ref_property<symbol_entry_prop::isReadOnly, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_READONLY>>,
- ref_property<symbol_entry_prop::ITFMethodAccess, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_ITFMETHODACCESS>>,
- ref_property<symbol_entry_prop::isMethodRef, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_METHODDEREF>>,
- ref_property<symbol_entry_prop::hasAttributes, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_ATTRIBUTES>>,
- ref_property<symbol_entry_prop::isStatic, flag< AdsSymbolEntry, symbol_entry_prop::flags, ADSSYMBOLFLAG_STATIC>>,
- ref_property<symbol_entry_prop::reserved, ELEMENT_EXP( AdsSymbolEntry, reserved, 0)>,
- ref_property<symbol_entry_prop::nameLen, ELEMENT( AdsSymbolEntry, nameLength)>,
- ref_property<symbol_entry_prop::typeLen, ELEMENT( AdsSymbolEntry, typeLength)>,
- ref_property<symbol_entry_prop::commentLen, ELEMENT( AdsSymbolEntry, commentLength)>,
- ref_property<symbol_entry_prop::nameData, next_data< AdsSymbolEntry, symbol_entry_prop::commentLen>>,
- ref_property<symbol_entry_prop::name, string< AdsSymbolEntry, symbol_entry_prop::nameData, symbol_entry_prop::nameLen>>,
- ref_property<symbol_entry_prop::nameTerminator, next_element<AdsSymbolEntry, symbol_entry_prop::name, char, 1, '\0'>>,
- ref_property<symbol_entry_prop::typeData, next_data< AdsSymbolEntry, symbol_entry_prop::nameTerminator>>,
- ref_property<symbol_entry_prop::type, string< AdsSymbolEntry, symbol_entry_prop::typeData, symbol_entry_prop::typeLen>>,
- ref_property<symbol_entry_prop::typeTerminator, next_element<AdsSymbolEntry, symbol_entry_prop::type, char, 1, '\0'>>,
- ref_property<symbol_entry_prop::commentData, next_data< AdsSymbolEntry, symbol_entry_prop::typeTerminator>>,
- ref_property<symbol_entry_prop::comment, string< AdsSymbolEntry, symbol_entry_prop::commentData, symbol_entry_prop::commentLen>>,
- ref_property<symbol_entry_prop::commentTerminator, next_element<AdsSymbolEntry, symbol_entry_prop::comment, char, 1, '\0'>>,
- ref_property<symbol_entry_prop::guid, optional< AdsSymbolEntry, symbol_entry_prop::hasTypeGuid, next_element<AdsSymbolEntry, symbol_entry_prop::commentTerminator, GUID>>>,
- ref_property<symbol_entry_prop::numAttributes, optional_def<AdsSymbolEntry, symbol_entry_prop::hasAttributes, next_element<AdsSymbolEntry, symbol_entry_prop::guid, ADS_UINT16>, 0>>,
- ref_property<symbol_entry_prop::attributeData, array< AdsSymbolEntry, symbol_entry_prop::numAttributes, symbol_entry_prop::numAttributes, AdsAttributeEntry>>,
- ref_property<symbol_entry_prop::expEntryLen, next_data_c< AdsSymbolEntry, symbol_entry_prop::attributeData, symbol_entry_prop::entryLen>>>
- {
- static constexpr ref_prop sort_prop = symbol_entry_prop::name;
- static constexpr auto cmp_less = icmp_less;
- static constexpr auto cmp_equal = icmp_equal;
- };
- struct attribute_entry_prop { enum { entryLen = entryLen_, nameLen = 3000, valueLen, nameData, name, nameTerminator, valueData, value, valueTerminator }; };
- template <>
- struct properties_of<AdsAttributeEntry>
- : property_ids<attribute_entry_prop>, structured_type<
- ref_property<attribute_entry_prop::nameLen, ELEMENT( AdsAttributeEntry, nameLength)>,
- ref_property<attribute_entry_prop::valueLen, ELEMENT( AdsAttributeEntry, valueLength)>,
- ref_property<attribute_entry_prop::nameData, next_data< AdsAttributeEntry, attribute_entry_prop::valueLen>>,
- ref_property<attribute_entry_prop::name, string< AdsAttributeEntry, attribute_entry_prop::nameData, attribute_entry_prop::nameLen>>,
- ref_property<attribute_entry_prop::nameTerminator, next_element<AdsAttributeEntry, attribute_entry_prop::name, char, 1, '\0'>>,
- ref_property<attribute_entry_prop::valueData, next_data< AdsAttributeEntry, attribute_entry_prop::nameTerminator>>,
- ref_property<attribute_entry_prop::value, string< AdsAttributeEntry, attribute_entry_prop::valueData, attribute_entry_prop::valueLen>>,
- ref_property<attribute_entry_prop::valueTerminator, next_element<AdsAttributeEntry, attribute_entry_prop::value, char, 1, '\0'>>,
- ref_property<attribute_entry_prop::entryLen, next_data< AdsAttributeEntry, attribute_entry_prop::valueTerminator>>>
- {};
- struct datatype_entry_prop {
- enum {
- entryLen = entryLen_, version = 4000, size, offset, typeId, flags,
- isDatatype, isDataitem, isReference, isMethodRef, isOversample, hasBitValues, isPropItem, hasTypeGuid, flagPersistent, containsPersistent, isPersistent,
- hasCopyMask, flagTcComInterfacePtr, containsTcComInterfacePtr, isTcComInterfacePtr, hasMethodInfos, hasAttributes, hasEnumInfos, isAligned, isStatic,
- nameLen, typeLen, commentLen, numArrayDims, numSubItems,
- nameData, name, nameTerminator, typeData, type, typeTerminator, commentData, comment, commentTerminator,
- arrayInfoData, subItemData, guid, copyMaskLen, copyMaskData, copyMaskBegin, copyMask,
- numMethods, methodData, numAttributes, attributeData,
- numEnumInfos, enumInfoData,
- expEntryLen
- };
- };
- template <>
- struct properties_of<AdsDatatypeEntry>
- : property_ids<datatype_entry_prop>, structured_type<
- ref_property<datatype_entry_prop::entryLen, ELEMENT( AdsDatatypeEntry, entryLength)>,
- ref_property<datatype_entry_prop::version, ELEMENT_EXP( AdsDatatypeEntry, version, 1)>,
- ref_property<datatype_entry_prop::size, ELEMENT( AdsDatatypeEntry, size)>,
- ref_property<datatype_entry_prop::offset, ELEMENT( AdsDatatypeEntry, offs)>,
- ref_property<datatype_entry_prop::typeId, ELEMENT_TYPE(AdsDatatypeEntry, dataType, adsDatatypeId)>,
- ref_property<datatype_entry_prop::flags, ELEMENT( AdsDatatypeEntry, flags)>,
- ref_property<datatype_entry_prop::isDatatype, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_DATATYPE>>,
- ref_property<datatype_entry_prop::isDataitem, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_DATAITEM>>,
- ref_property<datatype_entry_prop::isReference, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_REFERENCETO>>,
- ref_property<datatype_entry_prop::isMethodRef, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_METHODDEREF>>,
- ref_property<datatype_entry_prop::isOversample, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_OVERSAMPLE>>,
- ref_property<datatype_entry_prop::hasBitValues, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_BITVALUES>>,
- ref_property<datatype_entry_prop::isPropItem, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_PROPITEM>>,
- ref_property<datatype_entry_prop::hasTypeGuid, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_TYPEGUID>>,
- ref_property<datatype_entry_prop::flagPersistent, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_PERSISTENT>>,
- ref_property<datatype_entry_prop::containsPersistent, and_< AdsDatatypeEntry, datatype_entry_prop::flagPersistent, datatype_entry_prop::isDatatype>>,
- ref_property<datatype_entry_prop::isPersistent, and_< AdsDatatypeEntry, datatype_entry_prop::flagPersistent, datatype_entry_prop::isDataitem>>,
- ref_property<datatype_entry_prop::hasCopyMask, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_COPYMASK>>,
- ref_property<datatype_entry_prop::flagTcComInterfacePtr, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_TCCOMIFACEPTR>>,
- ref_property<datatype_entry_prop::containsTcComInterfacePtr, and_< AdsDatatypeEntry, datatype_entry_prop::flagTcComInterfacePtr, datatype_entry_prop::isDatatype>>,
- ref_property<datatype_entry_prop::isTcComInterfacePtr, and_< AdsDatatypeEntry, datatype_entry_prop::flagTcComInterfacePtr, datatype_entry_prop::isDataitem>>,
- ref_property<datatype_entry_prop::hasMethodInfos, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_METHODINFOS>>,
- ref_property<datatype_entry_prop::hasAttributes, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_ATTRIBUTES>>,
- ref_property<datatype_entry_prop::hasEnumInfos, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_ENUMINFOS>>,
- ref_property<datatype_entry_prop::isAligned, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_ALIGNED>>,
- ref_property<datatype_entry_prop::isStatic, flag< AdsDatatypeEntry, datatype_entry_prop::flags, ADSDATATYPEFLAG_STATIC>>,
- ref_property<datatype_entry_prop::nameLen, ELEMENT( AdsDatatypeEntry, nameLength)>,
- ref_property<datatype_entry_prop::typeLen, ELEMENT( AdsDatatypeEntry, typeLength)>,
- ref_property<datatype_entry_prop::commentLen, ELEMENT( AdsDatatypeEntry, commentLength)>,
- ref_property<datatype_entry_prop::numArrayDims, ELEMENT( AdsDatatypeEntry, arrayDim)>,
- ref_property<datatype_entry_prop::numSubItems, ELEMENT( AdsDatatypeEntry, subItems)>,
- ref_property<datatype_entry_prop::nameData, next_data< AdsDatatypeEntry, datatype_entry_prop::numSubItems>>,
- ref_property<datatype_entry_prop::name, string< AdsDatatypeEntry, datatype_entry_prop::nameData, datatype_entry_prop::nameLen>>,
- ref_property<datatype_entry_prop::nameTerminator, next_element<AdsDatatypeEntry, datatype_entry_prop::name, char, 1, '\0'>>,
- ref_property<datatype_entry_prop::typeData, next_data< AdsDatatypeEntry, datatype_entry_prop::nameTerminator>>,
- ref_property<datatype_entry_prop::type, string< AdsDatatypeEntry, datatype_entry_prop::typeData, datatype_entry_prop::typeLen>>,
- ref_property<datatype_entry_prop::typeTerminator, next_element<AdsDatatypeEntry, datatype_entry_prop::type, char, 1, '\0'>>,
- ref_property<datatype_entry_prop::commentData, next_data< AdsDatatypeEntry, datatype_entry_prop::typeTerminator>>,
- ref_property<datatype_entry_prop::comment, string< AdsDatatypeEntry, datatype_entry_prop::commentData, datatype_entry_prop::commentLen>>,
- ref_property<datatype_entry_prop::commentTerminator, next_element<AdsDatatypeEntry, datatype_entry_prop::comment, char, 1, '\0'>>,
- ref_property<datatype_entry_prop::arrayInfoData, array< AdsDatatypeEntry, datatype_entry_prop::commentTerminator, datatype_entry_prop::numArrayDims, AdsDatatypeArrayInfo>>,
- ref_property<datatype_entry_prop::subItemData, array< AdsDatatypeEntry, datatype_entry_prop::arrayInfoData, datatype_entry_prop::numSubItems, AdsDatatypeEntry>>,
- ref_property<datatype_entry_prop::guid, optional< AdsDatatypeEntry, datatype_entry_prop::hasTypeGuid, next_element<AdsDatatypeEntry, datatype_entry_prop::subItemData, GUID>>>,
- ref_property<datatype_entry_prop::copyMaskLen, optional_def<AdsDatatypeEntry, datatype_entry_prop::hasCopyMask, ELEMENT(AdsDatatypeEntry, size), 0>>,
- ref_property<datatype_entry_prop::copyMaskData, array< AdsDatatypeEntry, datatype_entry_prop::guid, datatype_entry_prop::copyMaskLen, copy_mask_byte>>,
- ref_property<datatype_entry_prop::copyMaskBegin, next_data< AdsDatatypeEntry, datatype_entry_prop::guid>>,
- ref_property<datatype_entry_prop::copyMask, var_data< AdsDatatypeEntry, datatype_entry_prop::copyMaskBegin, datatype_entry_prop::copyMaskLen, ADS_UINT8>>,
- ref_property<datatype_entry_prop::numMethods, optional_def<AdsDatatypeEntry, datatype_entry_prop::hasMethodInfos, next_element<AdsDatatypeEntry, datatype_entry_prop::copyMask, ADS_UINT16>, 0>>,
- ref_property<datatype_entry_prop::methodData, array< AdsDatatypeEntry, datatype_entry_prop::numMethods, datatype_entry_prop::numMethods, AdsMethodEntry>>,
- ref_property<datatype_entry_prop::numAttributes, optional_def<AdsDatatypeEntry, datatype_entry_prop::hasAttributes, next_element<AdsDatatypeEntry, datatype_entry_prop::methodData, ADS_UINT16>, 0>>,
- ref_property<datatype_entry_prop::attributeData, array< AdsDatatypeEntry, datatype_entry_prop::numAttributes, datatype_entry_prop::numAttributes, AdsAttributeEntry>>,
- ref_property<datatype_entry_prop::numEnumInfos, optional_def<AdsDatatypeEntry, datatype_entry_prop::hasEnumInfos, next_element<AdsDatatypeEntry, datatype_entry_prop::attributeData, ADS_UINT16>, 0>>,
- ref_property<datatype_entry_prop::enumInfoData, array< AdsDatatypeEntry, datatype_entry_prop::numEnumInfos, datatype_entry_prop::numEnumInfos, AdsEnumInfoEntry>>,
- ref_property<datatype_entry_prop::expEntryLen, next_data_c< AdsDatatypeEntry, datatype_entry_prop::enumInfoData, datatype_entry_prop::entryLen>>>
- {
- static constexpr ref_prop sort_prop = datatype_entry_prop::name;
- static constexpr auto cmp_less = std::less<>{};
- static constexpr auto cmp_equal = std::equal_to<>{};
- };
- struct method_para_entry_prop {
- enum {
- entryLen = entryLen_, size = 5000, alignSize, typeId, flags,
- isIn, isOut, isInOut, isReference,
- reserved, guid, lengthIsPara, nameLen, typeLen, commentLen,
- nameData, name, nameTerminator, typeData, type, typeTerminator, commentData, comment, commentTerminator,
- expEntryLen
- };
- };
- constexpr auto method_para_inoutreference_mask = ADSMETHODPARAFLAG_IN | ADSMETHODPARAFLAG_OUT | ADSMETHODPARAFLAG_INOUT | ADSMETHODPARAFLAG_BYREFERENCE;
- template <>
- struct properties_of<AdsMethodParaEntry>
- : property_ids<method_para_entry_prop>, structured_type<
- ref_property<method_para_entry_prop::entryLen, ELEMENT( AdsMethodParaEntry, entryLength)>,
- ref_property<method_para_entry_prop::size, ELEMENT( AdsMethodParaEntry, size)>,
- ref_property<method_para_entry_prop::alignSize, ELEMENT( AdsMethodParaEntry, alignSize)>,
- ref_property<method_para_entry_prop::typeId, ELEMENT_TYPE(AdsMethodParaEntry, dataType, adsDatatypeId)>,
- ref_property<method_para_entry_prop::flags, ELEMENT( AdsMethodParaEntry, flags)>,
- ref_property<method_para_entry_prop::isIn, flag< AdsMethodParaEntry, method_para_entry_prop::flags, method_para_inoutreference_mask, ADSMETHODPARAFLAG_IN>>,
- ref_property<method_para_entry_prop::isOut, flag< AdsMethodParaEntry, method_para_entry_prop::flags, method_para_inoutreference_mask, ADSMETHODPARAFLAG_OUT>>,
- ref_property<method_para_entry_prop::isInOut, flag< AdsMethodParaEntry, method_para_entry_prop::flags, method_para_inoutreference_mask, ADSMETHODPARAFLAG_INOUT>>,
- ref_property<method_para_entry_prop::isReference, flag< AdsMethodParaEntry, method_para_entry_prop::flags, method_para_inoutreference_mask, ADSMETHODPARAFLAG_BYREFERENCE>>,
- ref_property<method_para_entry_prop::reserved, ELEMENT_EXP( AdsMethodParaEntry, reserved, 0)>,
- ref_property<method_para_entry_prop::guid, ELEMENT( AdsMethodParaEntry, typeGuid)>,
- ref_property<method_para_entry_prop::lengthIsPara, ELEMENT( AdsMethodParaEntry, lengthIsPara)>,
- ref_property<method_para_entry_prop::nameLen, ELEMENT( AdsMethodParaEntry, nameLength)>,
- ref_property<method_para_entry_prop::typeLen, ELEMENT( AdsMethodParaEntry, typeLength)>,
- ref_property<method_para_entry_prop::commentLen, ELEMENT( AdsMethodParaEntry, commentLength)>,
- ref_property<method_para_entry_prop::nameData, next_data< AdsMethodParaEntry, method_para_entry_prop::commentLen>>,
- ref_property<method_para_entry_prop::name, string< AdsMethodParaEntry, method_para_entry_prop::nameData, method_para_entry_prop::nameLen>>,
- ref_property<method_para_entry_prop::nameTerminator, next_element<AdsMethodParaEntry, method_para_entry_prop::name, char, 1, '\0'>>,
- ref_property<method_para_entry_prop::typeData, next_data< AdsMethodParaEntry, method_para_entry_prop::nameTerminator>>,
- ref_property<method_para_entry_prop::type, string< AdsMethodParaEntry, method_para_entry_prop::typeData, method_para_entry_prop::typeLen>>,
- ref_property<method_para_entry_prop::typeTerminator, next_element<AdsMethodParaEntry, method_para_entry_prop::type, char, 1, '\0'>>,
- ref_property<method_para_entry_prop::commentData, next_data< AdsMethodParaEntry, method_para_entry_prop::typeTerminator>>,
- ref_property<method_para_entry_prop::comment, string< AdsMethodParaEntry, method_para_entry_prop::commentData, method_para_entry_prop::commentLen>>,
- ref_property<method_para_entry_prop::commentTerminator, next_element<AdsMethodParaEntry, method_para_entry_prop::comment, char, 1, '\0'>>,
- ref_property<method_para_entry_prop::expEntryLen, next_data_c< AdsMethodParaEntry, method_para_entry_prop::commentTerminator, method_para_entry_prop::entryLen>>>
- {};
- struct method_entry_prop {
- enum {
- entryLen = entryLen_, version = 6000, vTableIndex, returnSize, returnAlignSize, reserved, returnTypeGuid, returnTypeId, flags,
- isPlcCallingConvention, isCallUnlocked,
- nameLen, typeLen, commentLen, numParas,
- nameData, name, nameTerminator, typeData, type, typeTerminator, commentData, comment, commentTerminator, paraData,
- expEntryLen
- };
- };
- template <>
- struct properties_of<AdsMethodEntry>
- : property_ids<method_entry_prop>, structured_type<
- ref_property<method_entry_prop::entryLen, ELEMENT( AdsMethodEntry, entryLength)>,
- ref_property<method_entry_prop::version, ELEMENT_EXP( AdsMethodEntry, version, 1)>,
- ref_property<method_entry_prop::vTableIndex, ELEMENT( AdsMethodEntry, vTableIndex)>,
- ref_property<method_entry_prop::returnSize, ELEMENT( AdsMethodEntry, returnSize)>,
- ref_property<method_entry_prop::returnAlignSize, ELEMENT( AdsMethodEntry, returnAlignSize)>,
- ref_property<method_entry_prop::reserved, ELEMENT_EXP( AdsMethodEntry, reserved, 0)>,
- ref_property<method_entry_prop::returnTypeGuid, ELEMENT( AdsMethodEntry, returnTypeGuid)>,
- ref_property<method_entry_prop::returnTypeId, ELEMENT_TYPE(AdsMethodEntry, returnDataType, adsDatatypeId)>,
- ref_property<method_entry_prop::flags, ELEMENT( AdsMethodEntry, flags)>,
- ref_property<method_entry_prop::nameLen, ELEMENT( AdsMethodEntry, nameLength)>,
- ref_property<method_entry_prop::typeLen, ELEMENT( AdsMethodEntry, returnTypeLength)>,
- ref_property<method_entry_prop::commentLen, ELEMENT( AdsMethodEntry, commentLength)>,
- ref_property<method_entry_prop::numParas, ELEMENT( AdsMethodEntry, paras)>,
- ref_property<method_entry_prop::nameData, next_data< AdsMethodEntry, method_entry_prop::numParas>>,
- ref_property<method_entry_prop::name, string< AdsMethodEntry, method_entry_prop::nameData, method_entry_prop::nameLen>>,
- ref_property<method_entry_prop::nameTerminator, next_element<AdsMethodEntry, method_entry_prop::name, char, 1, '\0'>>,
- ref_property<method_entry_prop::typeData, next_data< AdsMethodEntry, method_entry_prop::nameTerminator>>,
- ref_property<method_entry_prop::type, string< AdsMethodEntry, method_entry_prop::typeData, method_entry_prop::typeLen>>,
- ref_property<method_entry_prop::typeTerminator, next_element<AdsMethodEntry, method_entry_prop::type, char, 1, '\0'>>,
- ref_property<method_entry_prop::commentData, next_data< AdsMethodEntry, method_entry_prop::typeTerminator>>,
- ref_property<method_entry_prop::comment, string< AdsMethodEntry, method_entry_prop::commentData, method_entry_prop::commentLen>>,
- ref_property<method_entry_prop::commentTerminator, next_element<AdsMethodEntry, method_entry_prop::comment, char, 1, '\0'>>,
- ref_property<method_entry_prop::paraData, array< AdsMethodEntry, method_entry_prop::commentTerminator, method_entry_prop::numParas, AdsMethodParaEntry>>,
- ref_property<method_entry_prop::expEntryLen, next_data_c< AdsMethodEntry, method_entry_prop::paraData, method_entry_prop::entryLen>>>
- {};
- struct enum_info_prop {
- enum {
- entryLen = entryLen_, nameLen = 7000, valueLen,
- nameData, name, nameTerminator, valueData, value
- };
- };
- template <>
- struct properties_of<AdsEnumInfoEntry>
- : property_ids<enum_info_prop>, structured_type<
- ref_property<enum_info_prop::nameLen, ELEMENT( AdsEnumInfoEntry, nameLength)>,
- ref_property<enum_info_prop::valueLen, parent_prop< AdsEnumInfoEntry, AdsDatatypeEntry, datatype_entry_prop::size>>,
- ref_property<enum_info_prop::nameData, next_data< AdsEnumInfoEntry, enum_info_prop::nameLen>>,
- ref_property<enum_info_prop::name, string< AdsEnumInfoEntry, enum_info_prop::nameData, enum_info_prop::nameLen>>,
- ref_property<enum_info_prop::nameTerminator, next_element<AdsEnumInfoEntry, enum_info_prop::name, char, 1, '\0'>>,
- ref_property<enum_info_prop::valueData, next_data< AdsEnumInfoEntry, enum_info_prop::nameTerminator>>,
- ref_property<enum_info_prop::value, var_data< AdsEnumInfoEntry, enum_info_prop::valueData, enum_info_prop::valueLen>>,
- ref_property<enum_info_prop::entryLen, next_data< AdsEnumInfoEntry, enum_info_prop::value>>>
- {};
- template <typename T>
- class ref {
- public:
- using prop_type = typename properties_of<T>::id_type;
- constexpr explicit ref(const char* data, by_size, std::size_t limit, const char* parent = nullptr) noexcept
- : data_(data), parent_data_(parent), limit_(limit), count_by_size_(true)
- {}
- constexpr explicit ref(const char* data, by_count, std::size_t limit, const char* parent = nullptr) noexcept
- : data_(data), parent_data_(parent), limit_(limit), count_by_size_(false)
- {}
- ref(const char* p, std::size_t entryLimit) : data(p) {
- }
- template <ref_prop prop>
- auto get() const noexcept {
- return properties_of<T>::template get<prop>(data_, parent_data_);
- }
- ref& operator++() noexcept {
- assert(*this);
- if (count_by_size_)
- limit_ -= get<entryLen_>();
- else
- --limit_;
- data_ += get<entryLen_>();
- return *this;
- }
- ref operator++(int) noexcept {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- explicit operator bool() const noexcept {
- return limit_ != 0;
- }
- const char* data() const noexcept {
- return data_;
- }
- std::size_t count() const noexcept {
- assert(!count_by_size_);
- return limit_;
- }
- // verify integrity of data
- void do_check() const noexcept {
- assert(*this);
- if (count_by_size_)
- properties_of<T>::check(data_, parent_data_, limit_);
- else
- properties_of<T>::check(data_, parent_data_, get<entryLen_>());
- }
- private:
- const char* data_;
- const char* parent_data_;
- std::size_t limit_;
- bool count_by_size_; // do we count down by entrySize (if unknown number of entries)
- // or else by 1 if the number is known ?
- friend bool operator<(const ref& lhs, const ref& rhs) noexcept {
- return properties_of<T>::cmp_less(lhs.get<properties_of<T>::sort_prop>(), rhs.get<properties_of<T>::sort_prop>());
- }
- template <typename U>
- friend bool operator<(const U& lhs, const ref& rhs) noexcept {
- return properties_of<T>::cmp_less(lhs, rhs.get<properties_of<T>::sort_prop>());
- }
- template <typename U>
- friend bool operator<(const ref& lhs, const U& rhs) noexcept {
- return properties_of<T>::cmp_less(lhs.get<properties_of<T>::sort_prop>(), rhs);
- }
- friend bool operator==(const ref& lhs, const ref& rhs) noexcept {
- return properties_of<T>::cmp_equal(lhs.get<properties_of<T>::sort_prop>(), rhs.get<properties_of<T>::sort_prop>());
- }
- template <typename U>
- friend bool operator==(const U& lhs, const ref& rhs) noexcept {
- return properties_of<T>::cmp_equal(lhs, rhs.get<properties_of<T>::sort_prop>());
- }
- template <typename U>
- friend bool operator==(const ref& lhs, const U& rhs) noexcept {
- return properties_of<T>::cmp_equal(lhs.get<properties_of<T>::sort_prop>(), rhs);
- }
- };
- } // namespace detail
- using detail::ref;
- template <typename T>
- struct reverse_view { T& iterable; };
- template <typename T>
- auto begin(reverse_view<T> w) {
- using std::rbegin;
- return rbegin(w.iterable);
- }
- template <typename T>
- auto end(reverse_view<T> w) {
- using std::rend;
- return rend(w.iterable);
- }
- template <typename T>
- reverse_view<T> reverse(T&& iterable) {
- return { iterable };
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- using refDT = ref<AdsDatatypeEntry>;
- using refSym = ref<AdsSymbolEntry>;
- using refArrayInfo = ref<AdsDatatypeArrayInfo>;
- using refAttribute = ref<AdsAttributeEntry>;
- using refEnumInfo = ref<AdsEnumInfoEntry>;
- class adsData::subSymbolInfo {
- public:
- subSymbolInfo(std::string_view name, std::string_view comment, sizeType offset, bool isStatic, adsData::datatypeInfo* typeData = nullptr)
- : name(name), comment(comment), offset(offset), isStatic(isStatic), typeData(typeData)
- {}
- subSymbolInfo(std::string_view name, std::string_view comment, sizeType offset, bool isStatic, adsData::datatypeInfo* typeData, refAttribute attr)
- : subSymbolInfo(name, comment, offset, isStatic, typeData)
- {
- attributes.reserve(attr.count());
- for (;attr; ++attr) {
- using attr_prop = refAttribute::prop_type;
- attributes.emplace_back(attr.get<attr_prop::name>(), attr.get<attr_prop::value>());
- }
- }
- std::string name;
- std::string comment;
- sizeType offset;
- bool isStatic;
- adsData::datatypeInfo* typeData;
- std::vector<attributeInfo> attributes{};
- friend bool operator==(const subSymbolInfo& lhs, const subSymbolInfo& rhs) {
- return icmp_equal(lhs.name, rhs.name);
- }
- friend bool operator==(const subSymbolInfo& lhs, std::string_view rhs) {
- return icmp_equal(lhs.name, rhs);
- }
- friend bool operator==(std::string_view lhs, const subSymbolInfo& rhs) {
- return icmp_equal(lhs, rhs.name);
- }
- };
- class adsData::symbolInfo {
- using prop = refSym::prop_type;
- public:
- subSymbolInfo baseInfo;
- sizeType group;
- symbolInfo(refSym sym, datatypeInfo* typeData)
- : baseInfo{ sym.get<prop::name>(), sym.get<prop::comment>(), sym.get<prop::offset>(), sym.get<prop::isStatic>(),
- typeData, sym.get<prop::attributeData>() },
- group{ sym.get<prop::group>() }
- {}
- friend bool operator<(const symbolInfo& lhs, const symbolInfo& rhs) {
- return icmp_less(lhs.baseInfo.name, rhs.baseInfo.name);
- }
- friend bool operator<(const symbolInfo& lhs, std::string_view rhs) {
- return icmp_less(lhs.baseInfo.name, rhs);
- }
- friend bool operator<(std::string_view lhs, const symbolInfo& rhs) {
- return icmp_less(lhs, rhs.baseInfo.name);
- }
- };
- class adsData::arrayInfo : public subSymbolInfo
- {
- using dt_prop = refDT::prop_type;
- using arr_prop = refArrayInfo::prop_type;
- std::vector<AdsDatatypeArrayInfo> arrayInfoData_;
- sizeType numElements_;
- public:
- explicit arrayInfo(refDT dt)
- : adsData::subSymbolInfo(""sv, dt.get<dt_prop::comment>(), 0, false), arrayInfoData_{}, numElements_{ 1 }
- {
- auto arrayInfoData = dt.get<dt_prop::arrayInfoData>();
- auto arraySize = dt.get<dt_prop::size>();
- assert(arrayInfoData.count() != 0);
- arrayInfoData_.reserve(arrayInfoData.count());
- for (; arrayInfoData; ++arrayInfoData) {
- using prop = refArrayInfo::prop_type;
- auto& info = arrayInfoData_.emplace_back(AdsDatatypeArrayInfo{
- arrayInfoData.get<arr_prop::lBound>(), arrayInfoData.get<arr_prop::elements>() });
- sizeType rBound = info.lBound + info.elements - 1;
- ASSERT_THROW("array info corrupted" && info.elements != 0 && rBound >= info.lBound && arraySize % info.elements == 0);
- arraySize /= info.elements;
- numElements_ *= info.elements;
- }
- }
- sizeType index(std::string_view i) const {
- auto workIndex = i;
- sizeType realIndex = 0;
- for (auto& info : arrayInfoData_) {
- auto pos = workIndex.find(',');
- if ((&info == &arrayInfoData_.back()) == (pos == workIndex.npos))
- throw std::out_of_range("index with wrong number of dimensions: "s + i);
- auto curIndex = workIndex;
- if (pos != workIndex.npos) {
- curIndex.remove_suffix(curIndex.size() - pos);
- workIndex.remove_prefix(pos + 1);
- }
- auto n = svtoi(curIndex);
- if (n < info.lBound || n - info.lBound >= info.elements)
- throw std::out_of_range("index out of range: "s + i);
- // we don't need to check for overflow here since the constructor already ensures that
- // indizes stay within proper bounds
- realIndex = realIndex * info.elements + (n - info.lBound);
- }
- return realIndex;
- }
- std::string toString(sizeType i) const {
- if (i >= numElements_)
- throw std::out_of_range("index out of range");
- std::string result = "]";
- for (auto& info : reverse(arrayInfoData_)) {
- auto curIndex = i % info.elements + info.lBound;
- i /= info.elements;
- do {
- result.push_back(static_cast<char>('0' + curIndex % 10));
- } while (curIndex /= 10);
- if (&info != &arrayInfoData_.front())
- result.push_back(',');
- }
- result.push_back('[');
- std::reverse(result.begin(), result.end());
- return result;
- }
- sizeType elemSize() const noexcept;
- sizeType numElements() const noexcept { return numElements_; }
- static sizeType svtoi(std::string_view s) {
- sizeType result = 0;
- if (s.empty())
- throw std::out_of_range("index corrupted");
- for (; !s.empty(); s.remove_prefix(1)) {
- if (s[0] < '0' || s[0] > '9' || (std::numeric_limits<sizeType>::max() - (s[0] - '0')) / 10 < result)
- throw std::out_of_range("index corrupted");
- result = result * 10 + (s[0] - '0');
- }
- return result;
- }
- };
- class adsData::datatypeInfo {
- using prop = refDT::prop_type;
- public:
- datatypeInfo(std::string_view name, sizeType size, adsDatatypeId id)
- : name(name), size(size), id(id)
- {}
- explicit datatypeInfo(refDT dt)
- : name(dt.get<prop::name>()), size(dt.get<prop::size>()), guid(dt.get<prop::guid>()), id(dt.get<prop::typeId>()),
- copyMask(dt.get<prop::copyMask>())
- {
- ASSERT_THROW(dt.get<prop::isDatatype>() != dt.get<prop::isDataitem>());
- ASSERT_THROW(!dt.get<prop::isDatatype>() || (dt.get<prop::numArrayDims>() == 0 || dt.get<prop::numSubItems>() == 0));
- ASSERT_THROW(!dt.get<prop::isDataitem>() || (dt.get<prop::numArrayDims>() == 0 && dt.get<prop::numSubItems>() == 0));
- if (dt.get<prop::numSubItems>() != 0) {
- auto& subs = typeSpecs.emplace<std::vector<subSymbolInfo>>();
- subs.reserve(dt.get<prop::numSubItems>());
- for (refDT sub = dt.get<prop::subItemData>(); sub; ++sub) {
- ASSERT_THROW(sub.get<prop::isDataitem>());
- subs.emplace_back(sub.get<prop::name>(), sub.get<prop::comment>(),
- sub.get<prop::offset>(), sub.get<prop::isStatic>(),
- nullptr, sub.get<prop::attributeData>());
- }
- } else if (dt.get<prop::numArrayDims>() != 0) {
- typeSpecs.emplace<arrayInfo>(dt);
- } else if (!dt.get<prop::type>().empty()) {
- typeSpecs.emplace<datatypeInfo*>();
- } else {
- typeSpecs.emplace<std::monostate>();
- }
- attributes.reserve(dt.get<prop::numAttributes>());
- for (refAttribute attr = dt.get<prop::attributeData>(); attr; ++attr) {
- using attr_prop = refAttribute::prop_type;
- attributes.emplace_back(attr.get<attr_prop::name>(), attr.get<attr_prop::value>());
- }
- enums.reserve(dt.get<prop::numEnumInfos>());
- for (refEnumInfo e = dt.get<prop::enumInfoData>(); e; ++e) {
- using enum_prop = refEnumInfo::prop_type;
- auto value = e.get<enum_prop::value>();
- switch (id) {
- case adsDatatypeId::int8_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::int8_t>(value.data()));
- break;
- case adsDatatypeId::uint8_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::uint8_t>(value.data()));
- break;
- case adsDatatypeId::int16_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::int16_t>(value.data()));
- break;
- case adsDatatypeId::uint16_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::uint16_t>(value.data()));
- break;
- case adsDatatypeId::int32_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::int32_t>(value.data()));
- break;
- case adsDatatypeId::uint32_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::uint32_t>(value.data()));
- break;
- case adsDatatypeId::int64_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::int64_t>(value.data()));
- break;
- case adsDatatypeId::uint64_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<std::uint64_t>(value.data()));
- break;
- case adsDatatypeId::bool_:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, readRaw<bool>(value.data()));
- break;
- case adsDatatypeId::float_:
- case adsDatatypeId::double_:
- case adsDatatypeId::void_:
- case adsDatatypeId::cstring_:
- case adsDatatypeId::wcstring_:
- case adsDatatypeId::ldouble_:
- case adsDatatypeId::blob_:
- default:
- enums.emplace_back(e.get<enum_prop::name>() + ""sv, value + ""sv);
- }
- }
- }
- std::string name;
- sizeType size;
- std::optional<GUID> guid;
- adsDatatypeId id;
- bool isPointer = false;
- bool visited = false; // used for cycle detection
- enum { baseSpec, compoundSpec, arraySpec, classSpec };
- std::variant<std::monostate, // base type
- datatypeInfo*, // compound type (alias or pointer)
- arrayInfo, // array
- std::vector<subSymbolInfo>> typeSpecs; // class
- ustring copyMask{};
- std::vector<attributeInfo> attributes{};
- std::vector<enumInfo> enums{};
- friend bool operator<(const adsData::datatypeInfo& lhs, const adsData::datatypeInfo& rhs) {
- return lhs.name < rhs.name;
- }
- friend bool operator<(const adsData::datatypeInfo& lhs, std::string_view rhs) {
- return lhs.name < rhs;
- }
- friend bool operator<(std::string_view lhs, const adsData::datatypeInfo& rhs) {
- return lhs == rhs.name;
- }
- friend bool operator==(const adsData::datatypeInfo& lhs, const adsData::datatypeInfo& rhs) {
- return lhs.name == rhs.name;
- }
- friend bool operator==(const adsData::datatypeInfo& lhs, std::string_view rhs) {
- return lhs.name < rhs;
- }
- friend bool operator==(std::string_view lhs, const adsData::datatypeInfo& rhs) {
- return lhs == rhs.name;
- }
- };
- sizeType adsData::arrayInfo::elemSize() const noexcept {
- return typeData->size;
- }
- namespace {
- template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
- std::string to_string_hex(T v) {
- auto val = static_cast<std::uint64_t>(v);
- char buf[2 * sizeof(val) + 1];
- std::snprintf(buf, sizeof(buf), "%llx", val);
- return buf;
- }
- void cycleCheck(adsData::datatypeInfo* p) {
- ASSERT_THROW("Datatypes corrupted: cycle detected" && !p->visited);
- p->visited = true;
- static constexpr auto deleter = [](auto* x) { x->visited = false; };
- std::unique_ptr<adsData::datatypeInfo, decltype(deleter)> guard(p, deleter);
- switch (p->typeSpecs.index()) {
- default:
- assert(false);
- case adsData::datatypeInfo::baseSpec:
- return;
- case adsData::datatypeInfo::compoundSpec:
- cycleCheck(std::get<adsData::datatypeInfo::compoundSpec>(p->typeSpecs));
- return;
- case adsData::datatypeInfo::arraySpec: {
- cycleCheck(std::get<adsData::datatypeInfo::arraySpec>(p->typeSpecs).typeData);
- return;
- }
- case adsData::datatypeInfo::classSpec: {
- for (auto& sub : std::get<adsData::datatypeInfo::classSpec>(p->typeSpecs))
- cycleCheck(sub.typeData);
- return;
- }
- }
- }
- const adsData::datatypeInfo* followAlias(const adsData::datatypeInfo* p) noexcept {
- while (p->typeSpecs.index() == adsData::datatypeInfo::compoundSpec && !p->isPointer)
- p = std::get<adsData::datatypeInfo::compoundSpec>(p->typeSpecs);
- return p;
- }
- } // namespace
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- adsData::adsData() noexcept = default;
- adsData::adsData(decltype(AmsAddr::port) port)
- : symbols_{}, types_{}
- {
- auto adsPort = tcAdsAPI::AdsPortOpenEx();
- ASSERT_THROW("cannot open ads port" && adsPort != 0);
- auto deleter = [=](auto) { tcAdsAPI::AdsPortCloseEx(adsPort); };
- std::unique_ptr<void, decltype(deleter)> portGuard(nullptr, deleter);
- tcAdsAPI::AmsAddr ams_addr{};
- if (auto err = tcAdsAPI::AdsGetLocalAddressEx(adsPort, &ams_addr); err != ADSERR_NOERR)
- throw std::runtime_error("cannot get local ams address: 0x" + to_string_hex(err));
- ams_addr.port = port;
- AdsSymbolUploadInfo2 info{};
- unsigned long bytes_read = 0;
- if (auto err = tcAdsAPI::AdsSyncReadReqEx2(adsPort, &ams_addr, ADSIGRP_SYM_UPLOADINFO2, 0, sizeof(info),
- &info, &bytes_read); err != ADSERR_NOERR)
- throw std::runtime_error("cannot read symbol upload info: 0x" + to_string_hex(err));
- if (bytes_read != sizeof(info))
- throw std::runtime_error("error reading sym_uploadinfo2: " + std::to_string(bytes_read) + " bytes read");
- std::vector<char> symData(info.nSymSize);
- std::vector<char> dtData(info.nDatatypeSize);
- if (auto err = tcAdsAPI::AdsSyncReadReqEx2(adsPort, &ams_addr, ADSIGRP_SYM_UPLOAD, 0, info.nSymSize,
- &symData[0], &bytes_read); err != ADSERR_NOERR)
- throw std::runtime_error("cannot read symbol info: 0x" + to_string_hex(err));
- if (bytes_read != info.nSymSize)
- throw std::runtime_error("error reading symbols: " + std::to_string(bytes_read) + " bytes read, "
- + std::to_string(info.nSymSize) + " expected");
- if (auto err = tcAdsAPI::AdsSyncReadReqEx2(adsPort, &ams_addr, ADSIGRP_SYM_DT_UPLOAD, 0, info.nDatatypeSize,
- &dtData[0], &bytes_read); err != ADSERR_NOERR)
- throw std::runtime_error("cannot read datatype info: 0x" + to_string_hex(err));
- if (bytes_read != info.nDatatypeSize)
- throw std::runtime_error("error reading datatypes: " + std::to_string(bytes_read) + " bytes read, "
- + std::to_string(info.nDatatypeSize) + " expected");
- portGuard.release();
- initialize(symData, dtData);
- }
- adsData::adsData(const std::vector<char>& symData, const std::vector<char>& dtData)
- : symbols_{}, types_{}
- {
- initialize(symData, dtData);
- }
- adsData::adsData(adsData&&) noexcept = default;
- adsData& adsData::operator=(adsData&&) noexcept = default;
- adsData::~adsData() noexcept = default;
- void adsData::initialize(const std::vector<char>& symData, const std::vector<char>& dtData) {
- using dtprop = refDT::prop_type;
- using symprop = refSym::prop_type;
- // count how many datatype entries we have and verify their integrity
- std::size_t dtCount = 0;
- for (refDT dt(&dtData[0], by_size{}, dtData.size()); dt; ++dt) {
- dt.do_check();
- ++dtCount;
- }
- // add to types_
- types_.reserve(dtCount);
- for (refDT dt(&dtData[0], by_count{}, dtCount); dt; ++dt) {
- types_.emplace_back(dt);
- }
- std::sort(types_.begin(), types_.end());
- // TwinCAT2 doesn't send info about basic datatypes so we add them here as needed
- // we don't link them yet, because adding to the types-vector might cause a reallocation,
- // invalidating references in the process
- for (refDT dt(&dtData[0], by_count{}, dtCount); dt; ++dt) {
- for (refDT sub = dt.get<dtprop::subItemData>(); sub; ++sub) {
- ASSERT_THROW("structure elements must have a type" && !sub.get<dtprop::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<dtprop::type>());
- if (it == types_.end() || it->name != sub.get<dtprop::type>())
- types_.emplace(it, sub.get<dtprop::type>(), sub.get<dtprop::size>(), sub.get<dtprop::typeId>());
- }
- if (dt.get<dtprop::type>().empty())
- continue; // base type or structure
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<dtprop::type>());
- if (it == types_.end() || it->name != dt.get<dtprop::type>()) {
- if (dt.get<dtprop::numArrayDims>() != 0) {
- types_.emplace(it, dt.get<dtprop::type>(), dt.get<dtprop::size>() / arrayInfo{ dt }.numElements(), dt.get<dtprop::typeId>());
- } else {
- types_.emplace(it, dt.get<dtprop::type>(), dt.get<dtprop::size>(), dt.get<dtprop::typeId>());
- }
- }
- }
- // count how many symbol entries we have and verify their integrity and add base types as needed
- std::size_t symCount = 0;
- for (refSym sym(&symData[0], by_size{}, symData.size()); sym; ++sym) {
- sym.do_check();
- ++symCount;
- ASSERT_THROW("symbols must have a type" && !sym.get<symprop::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<symprop::type>());
- if (it == types_.end() || it->name != sym.get<symprop::type>())
- types_.emplace(it, sym.get<symprop::type>(), sym.get<symprop::size>(), sym.get<symprop::typeId>());
- }
- // crosslink datatypes
- for (refDT dt(&dtData[0], by_count{}, dtCount); dt; ++dt) {
- auto type = std::lower_bound(types_.begin(), types_.end(), dt.get<dtprop::name>());
- switch (type->typeSpecs.index()) {
- default:
- assert(false);
- case adsData::datatypeInfo::baseSpec:
- break;
- case adsData::datatypeInfo::compoundSpec: {
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<dtprop::type>());
- static constexpr auto pt_str = "POINTER TO "sv;
- if (std::string_view{ type->name }.compare(0, pt_str.size(), pt_str) == 0) // starts_with
- type->isPointer = true;
- ASSERT_THROW(type->isPointer || dt.get<dtprop::size>() == it->size);
- std::get<adsData::datatypeInfo::compoundSpec>(type->typeSpecs) = &*it;
- break;
- }
- case adsData::datatypeInfo::arraySpec: {
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<dtprop::type>());
- auto& info = std::get<adsData::datatypeInfo::arraySpec>(type->typeSpecs);
- ASSERT_THROW("Datatypes corrupted: mismatched element size" && dt.get<dtprop::size>() / info.numElements() == it->size);
- info.typeData = &*it;
- break;
- }
- case adsData::datatypeInfo::classSpec: {
- refDT sub = dt.get<dtprop::subItemData>();
- for (auto& info : std::get<adsData::datatypeInfo::classSpec>(type->typeSpecs)) {
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<dtprop::type>());
- ASSERT_THROW("Datatypes corrupted: mismatched size" && sub.get<dtprop::size>() == it->size);
- info.typeData = &*it;
- ++sub;
- }
- break;
- }
- }
- }
- // make sure we didn't create a cycle, which should never happen,
- // an alias cannot refer to itself and a structure cannot contain itself
- for (auto& info : types_)
- cycleCheck(&info);
- symbols_.reserve(symCount);
- for (refSym sym(&symData[0], by_count{}, symCount); sym; ++sym) {
- using prop = refSym::prop_type;
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<prop::type>());
- ASSERT_THROW("Symboldata corrupted: mismatched size" && sym.get<prop::size>() == it->size);
- ASSERT_THROW("mismatched guid" && sym.get<prop::guid>() == it->guid);
- symbols_.emplace_back(sym, &*it);
- }
- std::sort(symbols_.begin(), symbols_.end());
- }
- adsVarData adsData::operator[](std::string_view name) const {
- auto curName = name;
- if (auto pos = curName.find('['); pos != curName.npos)
- curName.remove_suffix(curName.size() - pos);
- auto sym = std::lower_bound(symbols_.begin(), symbols_.end(), curName);
- if (sym == symbols_.end())
- throw std::out_of_range("var not found: "sv + name);
- auto group = sym->group;
- auto offset = sym->baseInfo.offset;
- if (name.size() == sym->baseInfo.name.size())
- return adsVarData{ &sym->baseInfo, group, offset };
- curName = std::string_view{ name.data() + sym->baseInfo.name.size(), name.size() - sym->baseInfo.name.size() };
- if (curName[0] != '.' && curName[0] != '[')
- throw std::out_of_range("var not found: "sv + name);
- auto dt = followAlias(sym->baseInfo.typeData);
- for (;;) {
- if (curName[0] == '.') {
- if (dt->typeSpecs.index() != adsData::datatypeInfo::classSpec)
- throw std::out_of_range("has no subobjects: "s
- + std::string_view{ name.data(), static_cast<std::size_t>(curName.data() - name.data()) }
- + " with "sv + curName);
- curName.remove_prefix(1); // '.'
- auto shortName = curName;
- auto pos = shortName.find_first_of(".["sv);
- if (pos != shortName.npos) {
- shortName.remove_suffix(shortName.size() - pos);
- }
- auto& subs = std::get<adsData::datatypeInfo::classSpec>(dt->typeSpecs);
- auto sub = std::find_if(subs.begin(), subs.end(), [=](auto& v) { return icmp_equal(shortName, v.name); });
- if (sub == subs.end())
- throw std::out_of_range("subobjects not found: "s + shortName + " of "sv
- + std::string_view{ name.data(), static_cast<std::size_t>(curName.data() - name.data()) }
- + " with "sv + name);
- if (sub->isStatic)
- offset = sub->offset;
- else
- offset += sub->offset;
- if (pos == shortName.npos)
- return adsVarData{ &*sub, group, offset };
- curName.remove_prefix(pos);
- dt = followAlias(sub->typeData);
- } else {
- // cur_name[0] == '['
- if (dt->typeSpecs.index() != adsData::datatypeInfo::arraySpec)
- throw std::out_of_range("is no array: "s
- + std::string_view{ name.data(), static_cast<std::size_t>(curName.data() - name.data()) }
- +" with "sv + curName);
- curName.remove_prefix(1); // '['
- auto pos = curName.find(']');
- if (pos == curName.npos)
- throw std::out_of_range("missing ]");
- auto index = curName;
- index.remove_suffix(index.size() - pos);
- auto& info = std::get<adsData::datatypeInfo::arraySpec>(dt->typeSpecs);
- auto i = info.index(index);
- offset += info.elemSize() * i;
- curName.remove_prefix(pos + 1); // "index]"
- if (curName.empty())
- return adsVarData{ &info, group, offset, i };
- if (curName[0] != '[' && curName[0] != '.')
- throw std::out_of_range("missing . or [");
- dt = followAlias(info.typeData);
- }
- }
- }
- adsData::iterator adsData::begin() const noexcept {
- return iterator{ symbols_.begin() };
- }
- adsData::iterator adsData::end() const noexcept {
- return iterator{ symbols_.end() };
- }
- adsData::iterator adsData::cbegin() const noexcept {
- return begin();
- }
- adsData::iterator adsData::cend() const noexcept {
- return end();
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- std::string adsData::enumInfo::valueToString() const {
- return std::visit([](const auto& value) -> std::string {
- if constexpr (std::is_arithmetic_v<std::decay_t<decltype(value)>>)
- return std::to_string(readRaw<std::decay_t<decltype(value)>>(reinterpret_cast<const char*>(&value))); // TODO
- else
- return value;
- }, second);
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- std::string adsVarData::name(std::string prefix) const {
- if (!info_->name.empty()) {
- prefix.reserve(prefix.size() + 1 + info_->name.size());
- prefix += '.';
- prefix += info_->name;
- return std::move(prefix);
- } else
- return std::move(prefix) + shortName();
- }
- std::string adsVarData::shortName() const {
- return info_->name.empty() ? static_cast<const adsData::arrayInfo*>(info_)->toString(index_) : info_->name;
- }
- const std::string& adsVarData::type() const noexcept {
- return info_->typeData->name;
- }
- const std::string& adsVarData::comment() const noexcept {
- return info_->comment;
- }
- adsDatatypeId adsVarData::typeId() const noexcept {
- return info_->typeData->id;
- }
- sizeType adsVarData::group() const noexcept {
- return group_;
- }
- sizeType adsVarData::offset() const noexcept {
- return offset_;
- }
- sizeType adsVarData::size() const noexcept {
- return info_->typeData->size;
- }
- bool adsVarData::isStatic() const noexcept {
- return info_->isStatic;
- }
- const GUID* adsVarData::typeGuid() const noexcept {
- return info_->typeData->guid.has_value() ? &*info_->typeData->guid : nullptr;
- }
- const ustring& adsVarData::copyMask() const noexcept {
- return info_->typeData->copyMask;
- }
- const std::vector<adsData::attributeInfo>& adsVarData::attributes() const noexcept {
- return info_->attributes;
- }
- const std::vector<adsData::attributeInfo>& adsVarData::typeAttributes() const noexcept {
- return info_->typeData->attributes;
- }
- const std::vector<adsData::enumInfo>& adsVarData::typeEnums() const noexcept {
- return info_->typeData->enums;
- }
- bool adsVarData::isScalar() const noexcept {
- auto real_type = followAlias(info_->typeData);
- return real_type->typeSpecs.index() == adsData::datatypeInfo::baseSpec
- || real_type->typeSpecs.index() == adsData::datatypeInfo::compoundSpec;
- }
- bool adsVarData::isPointer() const noexcept {
- return followAlias(info_->typeData)->isPointer;
- }
- bool adsVarData::isArray() const noexcept {
- return followAlias(info_->typeData)->typeSpecs.index() == adsData::datatypeInfo::arraySpec;
- }
- bool adsVarData::isStruct() const noexcept {
- return followAlias(info_->typeData)->typeSpecs.index() == adsData::datatypeInfo::classSpec;
- }
- bool adsVarData::empty() const noexcept {
- auto real_type = followAlias(info_->typeData);
- return isScalar() || isStruct() && std::get<adsData::datatypeInfo::classSpec>(real_type->typeSpecs).empty();
- }
- sizeType adsVarData::subElements() const noexcept {
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index()) {
- default:
- assert(false);
- case adsData::datatypeInfo::baseSpec:
- case adsData::datatypeInfo::compoundSpec:
- return 0;
- case adsData::datatypeInfo::arraySpec:
- return std::get<adsData::datatypeInfo::arraySpec>(real_type->typeSpecs).numElements();
- case adsData::datatypeInfo::classSpec:
- return static_cast<sizeType>(std::get<adsData::datatypeInfo::classSpec>(real_type->typeSpecs).size());
- }
- }
- adsVarData::iterator adsVarData::begin() const noexcept {
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index()) {
- default:
- assert(false);
- case adsData::datatypeInfo::baseSpec:
- case adsData::datatypeInfo::compoundSpec:
- return iterator{ nullptr, 0, 0, 0 };
- case adsData::datatypeInfo::arraySpec: {
- auto& info = std::get<adsData::datatypeInfo::arraySpec>(real_type->typeSpecs);
- return iterator{ &info, group_, offset_, 0 };
- }
- case adsData::datatypeInfo::classSpec: {
- auto& info = std::get<adsData::datatypeInfo::classSpec>(real_type->typeSpecs);
- return iterator{ info.empty() ? nullptr : &info.front(), group_, offset_, 0 };
- }
- }
- }
- adsVarData::iterator adsVarData::end() const noexcept {
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index()) {
- default:
- assert(false);
- case adsData::datatypeInfo::baseSpec:
- case adsData::datatypeInfo::compoundSpec:
- return iterator{ nullptr, 0, 0, 0 };
- case adsData::datatypeInfo::arraySpec: {
- auto& info = std::get<adsData::datatypeInfo::arraySpec>(real_type->typeSpecs);
- return iterator{ &info, group_, offset_, info.numElements() };
- }
- case adsData::datatypeInfo::classSpec: {
- auto& info = std::get<adsData::datatypeInfo::classSpec>(info_->typeData->typeSpecs);
- return iterator{ info.empty() ? nullptr : &info.back() + 1, group_, offset_, 0 };
- }
- }
- }
- adsVarData::iterator adsVarData::cbegin() const noexcept {
- return begin();
- }
- adsVarData::iterator adsVarData::cend() const noexcept {
- return end();
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- adsData::iterator::reference adsData::iterator::operator*() const noexcept {
- return adsVarData{ &iter_->baseInfo, iter_->group, iter_->baseInfo.offset };
- }
- adsData::iterator::pointer adsData::iterator::operator->() const noexcept {
- return **this;
- }
- bool operator==(adsData::iterator lhs, adsData::iterator rhs) noexcept {
- return lhs.iter_ == rhs.iter_;
- }
- bool operator!=(adsData::iterator lhs, adsData::iterator rhs) noexcept {
- return lhs.iter_ != rhs.iter_;
- }
- adsData::iterator& adsData::iterator::operator++() noexcept {
- ++iter_;
- return *this;
- }
- adsData::iterator adsData::iterator::operator++(int) noexcept {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- adsData::iterator::iterator(std::vector<adsData::symbolInfo>::const_iterator it) noexcept
- : iter_{ it }
- {}
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- adsVarData::iterator::reference adsVarData::iterator::operator*() const noexcept {
- if (info_->name.empty())
- return adsVarData{ info_, group_, offset_ + index_ * info_->typeData->size, index_ };
- else
- return adsVarData{ info_, group_, info_->isStatic ? offset_ + info_->offset : info_->offset };
- }
- adsVarData::iterator::pointer adsVarData::iterator::operator->() const noexcept {
- return **this;
- }
- bool operator==(const adsVarData::iterator& lhs, const adsVarData::iterator& rhs) noexcept {
- return lhs.info_ == rhs.info_ && lhs.index_ == rhs.index_
- && lhs.offset_ == rhs.offset_ && lhs.group_ == rhs.group_;
- }
- bool operator!=(const adsVarData::iterator& lhs, const adsVarData::iterator& rhs) noexcept {
- return !(lhs == rhs);
- }
- adsVarData::iterator& adsVarData::iterator::operator++() noexcept {
- if (info_->name.empty())
- ++index_;
- else
- ++info_;
- return *this;
- }
- adsVarData::iterator adsVarData::iterator::operator++(int) noexcept {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- adsVarData::iterator::iterator(const adsData::subSymbolInfo* info, sizeType group, sizeType offset, sizeType index) noexcept
- : info_{ info }, group_{ group }, offset_{ offset }, index_{ index }
- {}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement