Give clearer names to template parameters

This commit is contained in:
Rangi
2025-10-08 14:52:34 -04:00
parent 711fba5e35
commit 23b9039716
13 changed files with 118 additions and 102 deletions

View File

@@ -71,6 +71,7 @@ Language: Cpp
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
PPIndentWidth: -1 PPIndentWidth: -1
PenaltyBreakScopeResolution: 1000
PointerAlignment: Right PointerAlignment: Right
QualifierAlignment: Right QualifierAlignment: Right
ReflowComments: true ReflowComments: true

View File

@@ -25,15 +25,15 @@ extern Tracing tracing;
bool trace_ParseTraceDepth(char const *arg); bool trace_ParseTraceDepth(char const *arg);
template<typename T, typename M, typename N> template<typename NodeT, typename NameFnT, typename LineNoFnT>
void trace_PrintBacktrace(std::vector<T> const &stack, M getName, N getLineNo) { void trace_PrintBacktrace(std::vector<NodeT> const &stack, NameFnT getName, LineNoFnT getLineNo) {
size_t n = stack.size(); size_t n = stack.size();
if (n == 0) { if (n == 0) {
return; // LCOV_EXCL_LINE return; // LCOV_EXCL_LINE
} }
auto printLocation = [&](size_t i) { auto printLocation = [&](size_t i) {
T const &item = stack[n - i - 1]; NodeT const &item = stack[n - i - 1];
style_Reset(stderr); style_Reset(stderr);
if (!tracing.collapse) { if (!tracing.collapse) {
fputs(" ", stderr); // Just three spaces; the fourth will be printed next fputs(" ", stderr); // Just three spaces; the fourth will be printed next

View File

@@ -30,35 +30,35 @@ struct WarningState {
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag); std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
template<typename L> template<typename LevelEnumT>
struct WarningFlag { struct WarningFlag {
char const *name; char const *name;
L level; LevelEnumT level;
}; };
enum WarningBehavior { DISABLED, ENABLED, ERROR }; enum WarningBehavior { DISABLED, ENABLED, ERROR };
template<typename W> template<typename WarningEnumT>
struct ParamWarning { struct ParamWarning {
W firstID; WarningEnumT firstID;
W lastID; WarningEnumT lastID;
uint8_t defaultLevel; uint8_t defaultLevel;
}; };
template<typename W> template<typename WarningEnumT>
struct DiagnosticsState { struct DiagnosticsState {
WarningState flagStates[W::NB_WARNINGS]; WarningState flagStates[WarningEnumT::NB_WARNINGS];
WarningState metaStates[W::NB_WARNINGS]; WarningState metaStates[WarningEnumT::NB_WARNINGS];
bool warningsEnabled = true; bool warningsEnabled = true;
bool warningsAreErrors = false; bool warningsAreErrors = false;
}; };
template<typename L, typename W> template<typename LevelEnumT, typename WarningEnumT>
struct Diagnostics { struct Diagnostics {
std::vector<WarningFlag<L>> metaWarnings; std::vector<WarningFlag<LevelEnumT>> metaWarnings;
std::vector<WarningFlag<L>> warningFlags; std::vector<WarningFlag<LevelEnumT>> warningFlags;
std::vector<ParamWarning<W>> paramWarnings; std::vector<ParamWarning<WarningEnumT>> paramWarnings;
DiagnosticsState<W> state; DiagnosticsState<WarningEnumT> state;
uint64_t nbErrors; uint64_t nbErrors;
void incrementErrors() { void incrementErrors() {
@@ -67,12 +67,12 @@ struct Diagnostics {
} }
} }
WarningBehavior getWarningBehavior(W id) const; WarningBehavior getWarningBehavior(WarningEnumT id) const;
void processWarningFlag(char const *flag); void processWarningFlag(char const *flag);
}; };
template<typename L, typename W> template<typename LevelEnumT, typename WarningEnumT>
WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const { WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(WarningEnumT id) const {
// Check if warnings are globally disabled // Check if warnings are globally disabled
if (!state.warningsEnabled) { if (!state.warningsEnabled) {
return WarningBehavior::DISABLED; return WarningBehavior::DISABLED;
@@ -112,7 +112,7 @@ WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const {
} }
// If no meta flag is specified, check the default state of this warning flag // If no meta flag is specified, check the default state of this warning flag
if (warningFlags[id].level == L::LEVEL_DEFAULT) { // enabled by default if (warningFlags[id].level == LevelEnumT::LEVEL_DEFAULT) { // enabled by default
return enabledBehavior; return enabledBehavior;
} }
@@ -120,8 +120,8 @@ WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const {
return WarningBehavior::DISABLED; return WarningBehavior::DISABLED;
} }
template<typename L, typename W> template<typename LevelEnumT, typename WarningEnumT>
void Diagnostics<L, W>::processWarningFlag(char const *flag) { void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag) {
std::string rootFlag = flag; std::string rootFlag = flag;
// Check for `-Werror` or `-Wno-error` to return early // Check for `-Werror` or `-Wno-error` to return early
@@ -140,8 +140,8 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
// Try to match the flag against a parametric warning // Try to match the flag against a parametric warning
// If there was an equals sign, it will have set `param`; if not, `param` will be 0, // If there was an equals sign, it will have set `param`; if not, `param` will be 0,
// which applies to all levels // which applies to all levels
for (ParamWarning<W> const &paramWarning : paramWarnings) { for (ParamWarning<WarningEnumT> const &paramWarning : paramWarnings) {
W baseID = paramWarning.firstID; WarningEnumT baseID = paramWarning.firstID;
uint8_t maxParam = paramWarning.lastID - baseID + 1; uint8_t maxParam = paramWarning.lastID - baseID + 1;
assume(paramWarning.defaultLevel <= maxParam); assume(paramWarning.defaultLevel <= maxParam);
@@ -183,13 +183,13 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
} }
// Try to match against a "meta" warning // Try to match against a "meta" warning
for (WarningFlag<L> const &metaWarning : metaWarnings) { for (WarningFlag<LevelEnumT> const &metaWarning : metaWarnings) {
if (rootFlag != metaWarning.name) { if (rootFlag != metaWarning.name) {
continue; continue;
} }
// Set each of the warning flags that meets this level // Set each of the warning flags that meets this level
for (W id : EnumSeq(W::NB_WARNINGS)) { for (WarningEnumT id : EnumSeq(WarningEnumT::NB_WARNINGS)) {
if (metaWarning.level >= warningFlags[id].level) { if (metaWarning.level >= warningFlags[id].level) {
state.metaStates[id].update(flagState); state.metaStates[id].update(flagState);
} }
@@ -198,7 +198,7 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
} }
// Try to match against a "normal" flag // Try to match against a "normal" flag
for (W id : EnumSeq(W::NB_PLAIN_WARNINGS)) { for (WarningEnumT id : EnumSeq(WarningEnumT::NB_PLAIN_WARNINGS)) {
if (rootFlag == warningFlags[id].name) { if (rootFlag == warningFlags[id].name) {
state.flagStates[id].update(flagState); state.flagStates[id].update(flagState);
return; return;

View File

@@ -100,16 +100,16 @@ static inline int clz(unsigned int x) {
#define RRANGE(s) std::rbegin(s), std::rend(s) #define RRANGE(s) std::rbegin(s), std::rend(s)
// MSVC does not inline `strlen()` or `.length()` of a constant string // MSVC does not inline `strlen()` or `.length()` of a constant string
template<int N> template<int SizeOfString>
static constexpr int literal_strlen(char const (&)[N]) { static constexpr int literal_strlen(char const (&)[SizeOfString]) {
return N - 1; return SizeOfString - 1; // Don't count the ending '\0'
} }
// For ad-hoc RAII in place of a `defer` statement or cross-platform `__attribute__((cleanup))` // For ad-hoc RAII in place of a `defer` statement or cross-platform `__attribute__((cleanup))`
template<typename T> template<typename DeferredFnT>
struct Defer { struct Defer {
T deferred; DeferredFnT deferred;
Defer(T func) : deferred(func) {} Defer(DeferredFnT func) : deferred(func) {}
~Defer() { deferred(); } ~Defer() { deferred(); }
}; };

View File

@@ -12,29 +12,31 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
template<typename T> // A wrapper around iterables to reverse their iteration order; used in `for`-each loops.
template<typename IterableT>
struct ReversedIterable { struct ReversedIterable {
T &_iterable; IterableT &_iterable;
}; };
template<typename T> template<typename IterableT>
auto begin(ReversedIterable<T> r) { auto begin(ReversedIterable<IterableT> r) {
return std::rbegin(r._iterable); return std::rbegin(r._iterable);
} }
template<typename T> template<typename IterableT>
auto end(ReversedIterable<T> r) { auto end(ReversedIterable<IterableT> r) {
return std::rend(r._iterable); return std::rend(r._iterable);
} }
template<typename T> template<typename IterableT>
ReversedIterable<T> reversed(T &&_iterable) { ReversedIterable<IterableT> reversed(IterableT &&_iterable) {
return {_iterable}; return {_iterable};
} }
template<typename T> // A map from `std::string` keys to `ItemT` items, iterable in the order the items were inserted.
template<typename ItemT>
class InsertionOrderedMap { class InsertionOrderedMap {
std::deque<T> list; std::deque<ItemT> list;
std::unordered_map<std::string, size_t> map; // Indexes into `list` std::unordered_map<std::string, size_t> map; // Indexes into `list`
public: public:
@@ -44,25 +46,25 @@ public:
bool contains(std::string const &name) const { return map.find(name) != map.end(); } bool contains(std::string const &name) const { return map.find(name) != map.end(); }
T &operator[](size_t i) { return list[i]; } ItemT &operator[](size_t i) { return list[i]; }
typename decltype(list)::iterator begin() { return list.begin(); } typename decltype(list)::iterator begin() { return list.begin(); }
typename decltype(list)::iterator end() { return list.end(); } typename decltype(list)::iterator end() { return list.end(); }
typename decltype(list)::const_iterator begin() const { return list.begin(); } typename decltype(list)::const_iterator begin() const { return list.begin(); }
typename decltype(list)::const_iterator end() const { return list.end(); } typename decltype(list)::const_iterator end() const { return list.end(); }
T &add(std::string const &name) { ItemT &add(std::string const &name) {
map[name] = list.size(); map[name] = list.size();
return list.emplace_back(); return list.emplace_back();
} }
T &add(std::string const &name, T &&value) { ItemT &add(std::string const &name, ItemT &&value) {
map[name] = list.size(); map[name] = list.size();
list.emplace_back(std::move(value)); list.emplace_back(std::move(value));
return list.back(); return list.back();
} }
T &addAnonymous() { ItemT &addAnonymous() {
// Add the new item to the list, but do not update the map // Add the new item to the list, but do not update the map
return list.emplace_back(); return list.emplace_back();
} }
@@ -75,43 +77,45 @@ public:
} }
}; };
template<typename T> // An iterable of `enum` values in the half-open range [start, stop).
template<typename EnumT>
class EnumSeq { class EnumSeq {
T _start; EnumT _start;
T _stop; EnumT _stop;
class Iterator { class Iterator {
T _value; EnumT _value;
public: public:
explicit Iterator(T value) : _value(value) {} explicit Iterator(EnumT value) : _value(value) {}
Iterator &operator++() { Iterator &operator++() {
_value = static_cast<T>(_value + 1); _value = static_cast<EnumT>(_value + 1);
return *this; return *this;
} }
T operator*() const { return _value; } EnumT operator*() const { return _value; }
bool operator==(Iterator const &rhs) const { return _value == rhs._value; } bool operator==(Iterator const &rhs) const { return _value == rhs._value; }
}; };
public: public:
explicit EnumSeq(T stop) : _start(static_cast<T>(0)), _stop(stop) {} explicit EnumSeq(EnumT stop) : _start(static_cast<EnumT>(0)), _stop(stop) {}
explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {} explicit EnumSeq(EnumT start, EnumT stop) : _start(start), _stop(stop) {}
Iterator begin() { return Iterator(_start); } Iterator begin() { return Iterator(_start); }
Iterator end() { return Iterator(_stop); } Iterator end() { return Iterator(_stop); }
}; };
// Only needed inside `ZipContainer` below.
// This is not a fully generic implementation; its current use cases only require for-loop behavior. // This is not a fully generic implementation; its current use cases only require for-loop behavior.
// We also assume that all iterators have the same length. // We also assume that all iterators have the same length.
template<typename... Ts> template<typename... IteratorTs>
class ZipIterator { class ZipIterator {
std::tuple<Ts...> _iters; std::tuple<IteratorTs...> _iters;
public: public:
explicit ZipIterator(std::tuple<Ts...> &&iters) : _iters(iters) {} explicit ZipIterator(std::tuple<IteratorTs...> &&iters) : _iters(iters) {}
ZipIterator &operator++() { ZipIterator &operator++() {
std::apply([](auto &&...it) { (++it, ...); }, _iters); std::apply([](auto &&...it) { (++it, ...); }, _iters);
@@ -129,12 +133,14 @@ public:
} }
}; };
template<typename... Ts> // Only needed inside `zip` below.
template<typename... IterableTs>
class ZipContainer { class ZipContainer {
std::tuple<Ts...> _containers; std::tuple<IterableTs...> _containers;
public: public:
explicit ZipContainer(Ts &&...containers) : _containers(std::forward<Ts>(containers)...) {} explicit ZipContainer(IterableTs &&...containers)
: _containers(std::forward<IterableTs>(containers)...) {}
auto begin() { auto begin() {
return ZipIterator(std::apply( return ZipIterator(std::apply(
@@ -157,15 +163,19 @@ public:
} }
}; };
// Only needed inside `zip` below.
// Take ownership of objects and rvalue refs passed to us, but not lvalue refs // Take ownership of objects and rvalue refs passed to us, but not lvalue refs
template<typename T> template<typename IterableT>
using Holder = std:: using ZipHolder = std::conditional_t<
conditional_t<std::is_lvalue_reference_v<T>, T, std::remove_cv_t<std::remove_reference_t<T>>>; std::is_lvalue_reference_v<IterableT>,
IterableT,
std::remove_cv_t<std::remove_reference_t<IterableT>>>;
// Iterates over N containers at once, yielding tuples of N items at a time.
// Does the same number of iterations as the first container's iterator! // Does the same number of iterations as the first container's iterator!
template<typename... Ts> template<typename... IterableTs>
static constexpr auto zip(Ts &&...cs) { static constexpr auto zip(IterableTs &&...containers) {
return ZipContainer<Holder<Ts>...>(std::forward<Ts>(cs)...); return ZipContainer<ZipHolder<IterableTs>...>(std::forward<IterableTs>(containers)...);
} }
#endif // RGBDS_ITERTOOLS_HPP #endif // RGBDS_ITERTOOLS_HPP

View File

@@ -52,28 +52,28 @@ struct Section {
private: private:
// Template class for both const and non-const iterators over the "pieces" of this section // Template class for both const and non-const iterators over the "pieces" of this section
template<typename T> template<typename SectionT>
class PiecesIterable { class PiecesIterable {
T *_firstPiece; SectionT *_firstPiece;
class Iterator { class Iterator {
T *_piece; SectionT *_piece;
public: public:
explicit Iterator(T *piece) : _piece(piece) {} explicit Iterator(SectionT *piece) : _piece(piece) {}
Iterator &operator++() { Iterator &operator++() {
_piece = _piece->nextPiece.get(); _piece = _piece->nextPiece.get();
return *this; return *this;
} }
T &operator*() const { return *_piece; } SectionT &operator*() const { return *_piece; }
bool operator==(Iterator const &rhs) const { return _piece == rhs._piece; } bool operator==(Iterator const &rhs) const { return _piece == rhs._piece; }
}; };
public: public:
explicit PiecesIterable(T *firstPiece) : _firstPiece(firstPiece) {} explicit PiecesIterable(SectionT *firstPiece) : _firstPiece(firstPiece) {}
Iterator begin() { return Iterator(_firstPiece); } Iterator begin() { return Iterator(_firstPiece); }
Iterator end() { return Iterator(nullptr); } Iterator end() { return Iterator(nullptr); }

View File

@@ -64,7 +64,8 @@ struct Uppercase {
} }
}; };
template<typename T> // An unordered map from case-insensitive `std::string` keys to `ItemT` items
using UpperMap = std::unordered_map<std::string, T, Uppercase, Uppercase>; template<typename ItemT>
using UpperMap = std::unordered_map<std::string, ItemT, Uppercase, Uppercase>;
#endif // RGBDS_UTIL_HPP #endif // RGBDS_UTIL_HPP

View File

@@ -38,8 +38,8 @@ struct Charmap {
}; };
// Traverse the trie depth-first to derive the character mappings in definition order // Traverse the trie depth-first to derive the character mappings in definition order
template<typename F> template<typename CallbackFnT>
bool forEachChar(Charmap const &charmap, F callback) { bool forEachChar(Charmap const &charmap, CallbackFnT callback) {
// clang-format off: nested initializers // clang-format off: nested initializers
for (std::stack<std::pair<size_t, std::string>> prefixes({{0, ""}}); !prefixes.empty();) { for (std::stack<std::pair<size_t, std::string>> prefixes({{0, ""}}); !prefixes.empty();) {
// clang-format on // clang-format on

View File

@@ -816,8 +816,8 @@ static int nextChar() {
return peek(); return peek();
} }
template<typename P> template<typename PredicateFnT>
static int skipChars(P predicate) { static int skipChars(PredicateFnT predicate) {
int c = peek(); int c = peek();
while (predicate(c)) { while (predicate(c)) {
c = nextChar(); c = nextChar();
@@ -2281,8 +2281,8 @@ yy::parser::symbol_type yylex() {
} }
} }
template<typename F> template<typename CallbackFnT>
static Capture makeCapture(char const *name, F callback) { static Capture makeCapture(char const *name, CallbackFnT callback) {
// Due to parser internals, it reads the EOL after the expression before calling this. // Due to parser internals, it reads the EOL after the expression before calling this.
// Thus, we don't need to keep one in the buffer afterwards. // Thus, we don't need to keep one in the buffer afterwards.
// The following assumption checks that. // The following assumption checks that.

View File

@@ -57,8 +57,10 @@
yy::parser::symbol_type yylex(); // Provided by lexer.cpp yy::parser::symbol_type yylex(); // Provided by lexer.cpp
template <typename N, typename S> template<typename NumCallbackFnT, typename StrCallbackFnT>
static auto handleSymbolByType(std::string const &symName, N numCallback, S strCallback) { static auto handleSymbolByType(
std::string const &symName, NumCallbackFnT numCallback, StrCallbackFnT strCallback
) {
if (Symbol *sym = sym_FindScopedSymbol(symName); sym && sym->type == SYM_EQUS) { if (Symbol *sym = sym_FindScopedSymbol(symName); sym && sym->type == SYM_EQUS) {
return strCallback(*sym->getEqus()); return strCallback(*sym->getEqus());
} else { } else {

View File

@@ -70,7 +70,7 @@ public:
private: private:
// Template class for both const and non-const iterators over the non-empty `_assigned` slots // Template class for both const and non-const iterators over the non-empty `_assigned` slots
template<typename I, template<typename> typename Constness> template<typename IteratorT, template<typename> typename Constness>
class AssignedSetsIter { class AssignedSetsIter {
public: public:
friend class AssignedSets; friend class AssignedSets;
@@ -84,7 +84,7 @@ private:
private: private:
Constness<decltype(_assigned)> *_array = nullptr; Constness<decltype(_assigned)> *_array = nullptr;
I _iter{}; IteratorT _iter{};
AssignedSetsIter(decltype(_array) array, decltype(_iter) &&iter) AssignedSetsIter(decltype(_array) array, decltype(_iter) &&iter)
: _array(array), _iter(iter) {} : _array(array), _iter(iter) {}
@@ -164,11 +164,11 @@ public:
size_t nbColorSets() const { return std::distance(RANGE(*this)); } size_t nbColorSets() const { return std::distance(RANGE(*this)); }
private: private:
template<typename I> template<typename IteratorT>
static void addUniqueColors( static void addUniqueColors(
std::unordered_set<uint16_t> &colors, std::unordered_set<uint16_t> &colors,
I iter, IteratorT iter,
I const &end, IteratorT const &end,
std::vector<ColorSet> const &colorSets std::vector<ColorSet> const &colorSets
) { ) {
for (; iter != end; ++iter) { for (; iter != end; ++iter) {
@@ -240,18 +240,20 @@ public:
} }
// Computes the "relative size" of a set of color sets on this palette // Computes the "relative size" of a set of color sets on this palette
template<typename I> template<typename IteratorT>
size_t combinedVolume(I &&begin, I const &end, std::vector<ColorSet> const &colorSets) const { size_t combinedVolume(
IteratorT &&begin, IteratorT const &end, std::vector<ColorSet> const &colorSets
) const {
std::unordered_set<uint16_t> &colors = uniqueColors(); std::unordered_set<uint16_t> &colors = uniqueColors();
addUniqueColors(colors, std::forward<I>(begin), end, colorSets); addUniqueColors(colors, std::forward<IteratorT>(begin), end, colorSets);
return colors.size(); return colors.size();
} }
// Computes the "relative size" of a set of colors on this palette // Computes the "relative size" of a set of colors on this palette
template<typename I> template<typename IteratorT>
size_t combinedVolume(I &&begin, I &&end) const { size_t combinedVolume(IteratorT &&begin, IteratorT &&end) const {
std::unordered_set<uint16_t> &colors = uniqueColors(); std::unordered_set<uint16_t> &colors = uniqueColors();
colors.insert(std::forward<I>(begin), std::forward<I>(end)); colors.insert(std::forward<IteratorT>(begin), std::forward<IteratorT>(end));
return colors.size(); return colors.size();
} }
}; };

View File

@@ -210,15 +210,15 @@ static void warnExtraColors(
} }
// Parses the initial part of a string_view, advancing the "read index" as it does // Parses the initial part of a string_view, advancing the "read index" as it does
template<typename U> // Should be uint*_t template<typename UintT> // Should be uint*_t
static std::optional<U> parseDec(std::string const &str, size_t &n) { static std::optional<UintT> parseDec(std::string const &str, size_t &n) {
uintmax_t value = 0; uintmax_t value = 0;
auto result = std::from_chars(str.data() + n, str.data() + str.length(), value); auto result = std::from_chars(str.data() + n, str.data() + str.length(), value);
if (static_cast<bool>(result.ec)) { if (static_cast<bool>(result.ec)) {
return std::nullopt; return std::nullopt;
} }
n = result.ptr - str.data(); n = result.ptr - str.data();
return std::optional<U>{value}; return std::optional<UintT>{value};
} }
static std::optional<Rgba> parseColor(std::string const &str, size_t &n, uint16_t i) { static std::optional<Rgba> parseColor(std::string const &str, size_t &n, uint16_t i) {

View File

@@ -314,8 +314,8 @@ static bool compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) {
< std::tie(sym2.addr, sym2_local, sym2.parentAddr, sym2_name); < std::tie(sym2.addr, sym2_local, sym2.parentAddr, sym2_name);
} }
template<typename F> template<typename CallbackFnT>
static void forEachSortedSection(SortedSections const &bankSections, F callback) { static void forEachSortedSection(SortedSections const &bankSections, CallbackFnT callback) {
for (Section const *sect : bankSections.zeroLenSections) { for (Section const *sect : bankSections.zeroLenSections) {
for (Section const &piece : sect->pieces()) { for (Section const &piece : sect->pieces()) {
callback(piece); callback(piece);
@@ -415,8 +415,8 @@ static void writeSectionName(std::string const &name, FILE *file) {
} }
} }
template<typename F> template<typename CallbackFnT>
uint16_t forEachSection(SortedSections const &sectList, F callback) { uint16_t forEachSection(SortedSections const &sectList, CallbackFnT callback) {
uint16_t used = 0; uint16_t used = 0;
auto section = sectList.sections.begin(); auto section = sectList.sections.begin();
auto zeroLenSection = sectList.zeroLenSections.begin(); auto zeroLenSection = sectList.zeroLenSections.begin();