Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cassert>
- #include <cctype>
- #include <cstring>
- #include <optional>
- #include <stdexcept>
- #include <string>
- #include <string_view>
- #include <type_traits>
- #include <variant>
- #include <vector>
- #include "adsData.h"
- using namespace std::literals::string_literals;
- using namespace std::literals::string_view_literals;
- AdsVarData::AdsVarData(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset, SizeType index = 0u - 1u)
- : 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); });
- }
- using adsDataCursor::AdsDataCursor;
- using adsDataCursor::AdsTypeTag;
- using adsDataCursor::DatatypeId;
- using adsDataCursor::IdList;
- using adsDataCursor::implicit_cast;
- using adsDataCursor::LimitMode;
- template <LimitMode limitMode = LimitMode::byCount>
- using DtCursor = AdsDataCursor<AdsTypeTag::datatypeEntry, limitMode, limitMode == LimitMode::bySize>;
- template <LimitMode limitMode = LimitMode::byCount>
- using SymCursor = AdsDataCursor<AdsTypeTag::symbolEntry, limitMode, limitMode == LimitMode::bySize>;
- using ArrayInfoCursor = AdsDataCursor<AdsTypeTag::datatypeArrayInfo, LimitMode::byCount, false>;
- using DtIds = IdList<AdsTypeTag::datatypeEntry>;
- using SymIds = IdList<AdsTypeTag::symbolEntry>;
- using ArrIds = IdList<AdsTypeTag::datatypeArrayInfo>;
- } // namespace
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- class AdsData::SubSymbolInfo
- {
- public:
- SubSymbolInfo(std::string_view name, std::string_view comment, SizeType offset, bool isStatic, bool isBit,
- AdsData::DatatypeInfo* typeData = nullptr)
- : name(name), comment(comment), offset(offset), isStatic(isStatic), isBit(isBit), typeData(typeData)
- {}
- std::string name;
- std::string comment;
- SizeType offset;
- bool isStatic;
- bool isBit;
- AdsData::DatatypeInfo* typeData;
- 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
- {
- public:
- SubSymbolInfo baseInfo;
- SizeType group;
- SymbolInfo(const SymCursor<>& sym, DatatypeInfo* typeData)
- : baseInfo(sym.get<SymIds::name>(), sym.get<SymIds::comment>(), sym.get<SymIds::offset>(),
- sym.get<SymIds::isStatic>(), sym.get<SymIds::isBitValue>(), typeData),
- group(sym.get<SymIds::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
- {
- struct AdsDatatypeArrayInfo
- {
- constexpr AdsDatatypeArrayInfo(const ArrayInfoCursor& cursor)
- : lBound(cursor.get<ArrIds::lBound>()), elements(cursor.get<ArrIds::elements>())
- {}
- std::uint32_t lBound;
- std::uint32_t elements;
- };
- std::vector<AdsDatatypeArrayInfo> arrayInfoData_;
- SizeType numElements_;
- public:
- explicit ArrayInfo(const DtCursor<>& dt)
- : AdsData::SubSymbolInfo(""sv, dt.get<DtIds::comment>(), 0, false, false), arrayInfoData_{}, numElements_{1}
- {
- auto arrayInfoData = dt.get<DtIds::arrayInfoData>();
- auto arraySize = dt.get<DtIds::size>();
- assert(arrayInfoData.count() != 0);
- arrayInfoData_.reserve(arrayInfoData.count());
- for (; arrayInfoData; ++arrayInfoData)
- {
- auto& info = arrayInfoData_.emplace_back(arrayInfoData);
- SizeType rBound = info.lBound + info.elements - 1;
- ADSDATACURSOR_VERIFY("%1%\narray info corrupted with\ninfo.elements == %2%\ninfo.lBound == %3%\nrBound == "
- "%4%\narraySize == %5%",
- info.elements != 0 && rBound >= info.lBound && arraySize % info.elements == 0,
- info.elements, info.lBound, rBound, arraySize);
- 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 it = arrayInfoData_.cend(); it != arrayInfoData_.cbegin();)
- {
- auto& info = *--it;
- 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')
- throw std::out_of_range("index corrupted");
- auto curDigit = static_cast<unsigned char>(s[0] - '0');
- if ((std::numeric_limits<SizeType>::max() - curDigit) / 10 < result)
- throw std::out_of_range("index corrupted");
- result = result * 10 + curDigit;
- }
- return result;
- }
- };
- class AdsData::DatatypeInfo
- {
- public:
- DatatypeInfo(std::string_view name, SizeType size, DatatypeId id) : name(name), size(size), id(id) {}
- explicit DatatypeInfo(const DtCursor<>& dt)
- : name(dt.get<DtIds::name>()), size(dt.get<DtIds::size>()), id(dt.get<DtIds::typeId>())
- {
- ADSDATACURSOR_VERIFY("%1%\nEntry must be either datatype or dataitem",
- dt.get<DtIds::isDatatype>() != dt.get<DtIds::isDataitem>());
- ADSDATACURSOR_VERIFY("%1%\ndatatype cannot be both array and struct/union at the same time",
- !dt.get<DtIds::isDatatype>()
- || (dt.get<DtIds::numArrayDims>() == 0 || dt.get<DtIds::numSubItems>() == 0));
- ADSDATACURSOR_VERIFY("%1%\ndataitem cannot contain subelements",
- !dt.get<DtIds::isDataitem>()
- || (dt.get<DtIds::numArrayDims>() == 0 && dt.get<DtIds::numSubItems>() == 0));
- if (dt.get<DtIds::numSubItems>() != 0)
- {
- auto& subs = typeSpecs.emplace<std::vector<SubSymbolInfo>>();
- subs.reserve(dt.get<DtIds::numSubItems>());
- for (auto sub = dt.get<DtIds::subItemData>(); sub; ++sub)
- {
- ADSDATACURSOR_VERIFY("%1%\nsubElements must be dataitems", sub.get<DtIds::isDataitem>());
- subs.emplace_back(sub.get<DtIds::name>(), sub.get<DtIds::comment>(), sub.get<DtIds::offset>(),
- sub.get<DtIds::isStatic>(), sub.get<DtIds::isBitValue>(), nullptr);
- }
- }
- else if (dt.get<DtIds::numArrayDims>() != 0)
- {
- typeSpecs.emplace<ArrayInfo>(dt);
- }
- else if (!dt.get<DtIds::type>().empty())
- {
- typeSpecs.emplace<DatatypeInfo*>();
- }
- else
- {
- typeSpecs.emplace<std::monostate>();
- }
- }
- std::string name;
- SizeType size;
- DatatypeId id;
- bool isPointer = false;
- bool isReference = 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
- 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
- {
- void cycleCheck(AdsData::DatatypeInfo* p)
- {
- ADSDATACURSOR_VERIFY("%1%\nDatatypes 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:
- if (!p->isPointer && !p->isReference)
- 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->isReference)
- p = std::get<AdsData::DatatypeInfo::compoundSpec>(p->typeSpecs);
- return p;
- }
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AdsData::AdsData() noexcept = default;
- AdsData::AdsData(AdsData&&) noexcept = default;
- AdsData& AdsData::operator=(AdsData&&) noexcept = default;
- AdsData::~AdsData() noexcept = default;
- AdsData::AdsData(const std::vector<char>& symData, const std::vector<char>& dtData) : symbols_{}, types_{}
- {
- // count how many datatype entries we have and verify their integrity
- DtCursor<> allDts(&dtData[0], DtCursor<LimitMode::bySize>(&dtData[0], dtData.size()).size());
- // add to types_
- types_.reserve(allDts.count());
- for (auto& dt : allDts)
- 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 (auto& dt : allDts)
- {
- for (auto& sub : dt.get<DtIds::subItemData>())
- {
- ADSDATACURSOR_VERIFY("%1%\nstructure elements must have a type", !sub.get<DtIds::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
- if (it == types_.end() || it->name != sub.get<DtIds::type>())
- types_.emplace(it, sub.get<DtIds::type>(), sub.get<DtIds::size>(), sub.get<DtIds::typeId>());
- }
- if (dt.get<DtIds::type>().empty())
- continue; // base type or structure
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
- if (it == types_.end() || it->name != dt.get<DtIds::type>())
- {
- if (dt.get<DtIds::numArrayDims>() != 0)
- {
- types_.emplace(it, dt.get<DtIds::type>(), dt.get<DtIds::size>() / ArrayInfo{dt}.numElements(),
- dt.get<DtIds::typeId>());
- }
- else
- {
- types_.emplace(it, dt.get<DtIds::type>(), dt.get<DtIds::size>(), dt.get<DtIds::typeId>());
- }
- }
- }
- // count how many symbol entries we have and verify their integrity
- SymCursor<> allSyms(&symData[0], SymCursor<LimitMode::bySize>(&symData[0], symData.size()).size());
- // add base types as needed (TwinCAT2)
- for (auto& sym : allSyms)
- {
- ADSDATACURSOR_VERIFY("%1%\nsymbols must have a type", !sym.get<SymIds::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
- if (it == types_.end() || it->name != sym.get<SymIds::type>())
- types_.emplace(it, sym.get<SymIds::type>(), sym.get<SymIds::size>(), sym.get<SymIds::typeId>());
- }
- // crosslink datatypes
- for (auto& dt : allDts)
- {
- auto type = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::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<DtIds::type>());
- static constexpr auto ptr_str = "POINTER TO "sv;
- static constexpr auto ref_str = "REFERENCE TO "sv;
- if (std::string_view{type->name}.compare(0, ptr_str.size(), ptr_str) == 0) // starts_with
- type->isPointer = true;
- else if (std::string_view{type->name}.compare(0, ref_str.size(), ref_str) == 0)
- type->isReference = true;
- ADSDATACURSOR_VERIFY("%1%", type->isPointer || type->isReference || dt.get<DtIds::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<DtIds::type>());
- auto& info = std::get<AdsData::DatatypeInfo::arraySpec>(type->typeSpecs);
- ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched element size",
- dt.get<DtIds::size>() / info.numElements() == it->size);
- info.typeData = &*it;
- break;
- }
- case AdsData::DatatypeInfo::classSpec:
- {
- auto sub = dt.get<DtIds::subItemData>();
- for (auto& info : std::get<AdsData::DatatypeInfo::classSpec>(type->typeSpecs))
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
- ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched size",
- sub.get<DtIds::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(allSyms.count());
- for (auto& sym : allSyms)
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
- ADSDATACURSOR_VERIFY("%1%\nSymboldata corrupted: mismatched size", sym.get<SymIds::size>() == it->size);
- symbols_.emplace_back(sym, &*it);
- }
- std::sort(symbols_.begin(), symbols_.end());
- // the offset of static vars in function blocks is not given in the datatype info and must therefore be derived from
- // the main symbol
- for (auto& type : types_)
- {
- if (type.typeSpecs.index() != AdsData::DatatypeInfo::classSpec)
- continue;
- for (auto& sub : std::get<AdsData::DatatypeInfo::classSpec>(type.typeSpecs))
- {
- if (!sub.isStatic)
- continue;
- auto mainSymbol = type.name + '.' + sub.name;
- auto sym = std::lower_bound(symbols_.begin(), symbols_.end(), mainSymbol);
- ADSDATACURSOR_VERIFY("%1%\nmain symbol for static var %2% not found",
- (sym != symbols_.end() && mainSymbol == sym->baseInfo.name), mainSymbol);
- // fix offset
- sub.offset = sym->baseInfo.offset;
- }
- }
- }
- 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::upper_bound(symbols_.begin(), symbols_.end(), curName);
- if (sym == symbols_.begin() || (--sym, curName.compare(0, sym->baseInfo.name.size(), sym->baseInfo.name) != 0))
- 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(), implicit_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(), implicit_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(), implicit_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 AdsVarData::name(std::string prefix) const
- {
- if (!info_->name.empty())
- {
- prefix.reserve(prefix.size() + 1 + info_->name.size());
- if (!prefix.empty())
- prefix += '.';
- prefix += info_->name;
- return 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; }
- DatatypeId 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::isPointer() const noexcept { return followAlias(info_->typeData)->isPointer; }
- bool AdsVarData::isReference() const noexcept { return followAlias(info_->typeData)->isReference; }
- bool AdsVarData::isStatic() const noexcept { return info_->isStatic; }
- bool AdsVarData::empty() const noexcept { return subElements() == 0; }
- 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>(real_type->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()) // array-element ?
- return AdsVarData{info_, group_, offset_ + index_ * info_->typeData->size, index_};
- else if (info_->isBit)
- return AdsVarData{info_, group_ + 1, info_->isStatic ? info_->offset : offset_ * 8 + info_->offset};
- else
- return AdsVarData{info_, group_, info_->isStatic ? info_->offset : 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()) // array-element ?
- ++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}
- {}
Add Comment
Please, Sign In to add comment