COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
ArrayList.h
1//
2// Copyright 2015 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8#pragma once
9
10#include "comms/Assert.h"
12#include "comms/details/detect.h"
13#include "comms/details/tag.h"
14#include "comms/ErrorStatus.h"
15#include "comms/field/basic/CommonFuncs.h"
16#include "comms/field/details/VersionStorage.h"
17#include "comms/field/tag.h"
18#include "comms/util/access.h"
19#include "comms/util/assign.h"
20#include "comms/util/detect.h"
21#include "comms/util/MaxSizeOf.h"
25
26#include <algorithm>
27#include <iterator>
28#include <limits>
29#include <numeric>
30#include <type_traits>
31#include <utility>
32
33namespace comms
34{
35
36namespace field
37{
38
39namespace basic
40{
41
42namespace details
43{
44
45template <typename TStorage>
46struct ArrayListMaxLengthRetrieveHelper
47{
48 static const std::size_t Value = CommonFuncs::maxSupportedLength();
49};
50
51template <typename T, std::size_t TSize>
52struct ArrayListMaxLengthRetrieveHelper<comms::util::StaticVector<T, TSize> >
53{
54 static const std::size_t Value = TSize;
55};
56
57template <std::size_t TSize>
58struct ArrayListMaxLengthRetrieveHelper<comms::util::StaticString<TSize> >
59{
60 static const std::size_t Value = TSize - 1;
61};
62
63template <typename TElem>
64using ArrayListFieldHasVarLengthBoolType =
65 typename comms::util::LazyDeepConditional<
66 std::is_integral<TElem>::value
67 >::template Type<
68 comms::util::FalseType,
69 comms::util::FieldCheckVarLength,
70 TElem
71 >;
72
73template <typename TElem>
74using HasArrayListElemNonDefaultRefreshBoolType =
75 typename comms::util::LazyDeepConditional<
76 std::is_integral<TElem>::value
77 >::template Type<
78 comms::util::FalseType,
79 comms::util::FieldCheckNonDefaultRefresh,
80 TElem
81 >;
82
83template <typename TElem>
84using IsArrayListElemVersionDependentBoolType =
85 typename comms::util::LazyDeepConditional<
86 std::is_integral<TElem>::value
87 >::template Type<
88 comms::util::FalseType,
89 comms::util::FieldCheckVersionDependent,
90 TElem
91 >;
92
93template <typename TFieldBase, typename TStorage>
94using ArrayListVersionStorageBase =
95 typename comms::util::LazyShallowConditional<
96 IsArrayListElemVersionDependentBoolType<typename TStorage::value_type>::value
97 >::template Type<
98 comms::field::details::VersionStorage,
99 comms::util::EmptyStruct,
100 typename TFieldBase::VersionType
101 >;
102
103} // namespace details
104
105template <typename TFieldBase, typename TStorage>
106class ArrayList :
107 public TFieldBase,
108 public details::ArrayListVersionStorageBase<TFieldBase, TStorage>
109{
110 using BaseImpl = TFieldBase;
111 using VersionBaseImpl = details::ArrayListVersionStorageBase<TFieldBase, TStorage>;
112
113public:
114 using Endian = typename BaseImpl::Endian;
115 using VersionType = typename BaseImpl::VersionType;
116 using ElementType = typename TStorage::value_type;
117 using ValueType = TStorage;
118 using CommsTag =
120 std::is_integral<ElementType>::value
121 >::template Type<
122 comms::field::tag::RawArrayList,
123 comms::field::tag::ArrayList
124 >;
125
126 ArrayList() = default;
127
128 explicit ArrayList(const ValueType& val)
129 : m_value(val)
130 {
131 }
132
133 explicit ArrayList(ValueType&& val)
134 : m_value(std::move(val))
135 {
136 }
137
138 ArrayList(const ArrayList&) = default;
139 ArrayList(ArrayList&&) = default;
140 ArrayList& operator=(const ArrayList&) = default;
141 ArrayList& operator=(ArrayList&&) = default;
142 ~ArrayList() noexcept = default;
143
144 const ValueType& value() const
145 {
146 return m_value;
147 }
148
149 ValueType& value()
150 {
151 return m_value;
152 }
153
154 const ValueType& getValue() const
155 {
156 return value();
157 }
158
159 template <typename T>
160 void setValue(T&& val)
161 {
162 value() = std::forward<T>(val);
163 }
164
165 ElementType& createBack()
166 {
167 COMMS_ASSERT(m_value.size() < m_value.max_size());
168 m_value.emplace_back();
169 updateElemVersion(m_value.back(), VersionTag<>());
170 return m_value.back();
171 }
172
173 void clear()
174 {
175 static_assert(comms::util::detect::hasClearFunc<ValueType>(),
176 "The used storage type for ArrayList must have clear() member function");
177
178 m_value.clear();
179 }
180
181 constexpr std::size_t length() const
182 {
183 return lengthInternal(ElemTag<>());
184 }
185
186 static constexpr std::size_t minLength()
187 {
188 return 0U;
189 }
190
191 static constexpr std::size_t maxLength()
192 {
193 return
194 details::ArrayListMaxLengthRetrieveHelper<TStorage>::Value *
195 maxLengthInternal(ElemTag<>());
196 }
197
198 constexpr bool valid() const
199 {
200 return validInternal(ElemTag<>());
201 }
202
203 bool refresh()
204 {
205 return refreshInternal(ElemTag<>());
206 }
207
208 static constexpr std::size_t minElementLength()
209 {
210 return minElemLengthInternal(ElemTag<>());
211 }
212
213 static constexpr std::size_t maxElementLength()
214 {
215 return maxElemLengthInternal(ElemTag<>());
216 }
217
218 static constexpr std::size_t elementLength(const ElementType& elem)
219 {
220 return elementLengthInternal(elem, ElemTag<>());
221 }
222
223 template <typename TIter>
224 static ErrorStatus readElement(ElementType& elem, TIter& iter, std::size_t& len)
225 {
226 return readElementInternal(elem, iter, len, ElemTag<>());
227 }
228
229 template <typename TIter>
230 static void readElementNoStatus(ElementType& elem, TIter& iter)
231 {
232 return readElementNoStatusInternal(elem, iter, ElemTag<>());
233 }
234
235 template <typename TIter>
236 ErrorStatus read(TIter& iter, std::size_t len)
237 {
238 using IterType = typename std::decay<decltype(iter)>::type;
239 using IterCategory =
240 typename std::iterator_traits<IterType>::iterator_category;
241 static const bool IsRandomAccessIter =
242 std::is_base_of<std::random_access_iterator_tag, IterCategory>::value;
243 static const bool IsRawData =
244 std::is_integral<ElementType>::value && (sizeof(ElementType) == sizeof(std::uint8_t));
245
246 using Tag =
247 typename comms::util::LazyShallowConditional<
248 IsRandomAccessIter && IsRawData
249 >::template Type<
250 RawDataTag,
251 FieldElemTag
252 >;
253 return readInternal(iter, len, Tag());
254 }
255
256 static constexpr bool hasReadNoStatus()
257 {
258 return false;
259 }
260
261 template <typename TIter>
262 void readNoStatus(TIter& iter) = delete;
263
264 template <typename TIter>
265 ErrorStatus readN(std::size_t count, TIter& iter, std::size_t& len)
266 {
267 using IterType = typename std::decay<decltype(iter)>::type;
268 using IterCategory =
269 typename std::iterator_traits<IterType>::iterator_category;
270 static const bool IsRandomAccessIter =
271 std::is_base_of<std::random_access_iterator_tag, IterCategory>::value;
272 static const bool IsRawData =
273 std::is_integral<ElementType>::value && (sizeof(ElementType) == sizeof(std::uint8_t));
274
275 using Tag =
276 typename comms::util::LazyShallowConditional<
277 IsRandomAccessIter && IsRawData
278 >::template Type<
279 RawDataTag,
280 FieldElemTag
281 >;
282
283 return readInternalN(count, iter, len, Tag());
284 }
285
286 template <typename TIter>
287 void readNoStatusN(std::size_t count, TIter& iter)
288 {
289 using IterType = typename std::decay<decltype(iter)>::type;
290 using IterCategory =
291 typename std::iterator_traits<IterType>::iterator_category;
292 static const bool IsRandomAccessIter =
293 std::is_base_of<std::random_access_iterator_tag, IterCategory>::value;
294 static const bool IsRawData =
295 std::is_integral<ElementType>::value && (sizeof(ElementType) == sizeof(std::uint8_t));
296
297 using Tag =
298 typename comms::util::LazyShallowConditional<
299 IsRandomAccessIter && IsRawData
300 >::template Type<
301 RawDataTag,
302 FieldElemTag
303 >;
304
305 return readNoStatusInternalN(count, iter, Tag());
306 }
307
308 static bool canWriteElement(const ElementType& elem)
309 {
310 return canWriteElementInternal(elem, ElemTag<>());
311 }
312
313 template <typename TIter>
314 static ErrorStatus writeElement(const ElementType& elem, TIter& iter, std::size_t& len)
315 {
316 return writeElementInternal(elem, iter, len, ElemTag<>());
317 }
318
319 template <typename TIter>
320 static void writeElementNoStatus(const ElementType& elem, TIter& iter)
321 {
322 return writeElementNoStatusInternal(elem, iter, ElemTag<>());
323 }
324
325 bool canWrite() const
326 {
327 return CommonFuncs::canWriteSequence(*this);
328 }
329
330 template <typename TIter>
331 ErrorStatus write(TIter& iter, std::size_t len) const
332 {
333 return CommonFuncs::writeSequence(*this, iter, len);
334 }
335
336 static constexpr bool hasWriteNoStatus()
337 {
338 return hasWriteNoStatusInternal(ElemTag<>());
339 }
340
341 template <typename TIter>
342 void writeNoStatus(TIter& iter) const
343 {
344 CommonFuncs::writeSequenceNoStatus(*this, iter);
345 }
346
347 template <typename TIter>
348 ErrorStatus writeN(std::size_t count, TIter& iter, std::size_t& len) const
349 {
350 return CommonFuncs::writeSequenceN(*this, count, iter, len);
351 }
352
353 template <typename TIter>
354 void writeNoStatusN(std::size_t count, TIter& iter) const
355 {
356 CommonFuncs::writeSequenceNoStatusN(*this, count, iter);
357 }
358
359 static constexpr bool isVersionDependent()
360 {
361 return details::IsArrayListElemVersionDependentBoolType<ElementType>::value;
362 }
363
364 static constexpr bool hasNonDefaultRefresh()
365 {
366 return details::HasArrayListElemNonDefaultRefreshBoolType<ElementType>::value;
367 }
368
369 bool setVersion(VersionType version)
370 {
371 return setVersionInternal(version, VersionTag<>());
372 }
373
374private:
375 template <typename... TParams>
376 using FieldElemTag = comms::details::tag::Tag1<>;
377
378 template <typename... TParams>
379 using IntegralElemTag = comms::details::tag::Tag2<>;
380
381 template <typename... TParams>
382 using FixedLengthTag = comms::details::tag::Tag3<>;
383
384 template <typename... TParams>
385 using VarLengthTag = comms::details::tag::Tag4<>;
386
387 template <typename... TParams>
388 using RawDataTag = comms::details::tag::Tag5<>;
389
390 template <typename... TParams>
391 using VersionDependentTag = comms::details::tag::Tag6<>;
392
393 template <typename... TParams>
394 using NoVersionDependencyTag = comms::details::tag::Tag7<>;
395
396 template <typename... TParams>
397 using ElemTag =
399 std::is_integral<ElementType>::value
400 >::template Type<
401 IntegralElemTag<TParams...>,
402 FieldElemTag<TParams...>
403 >;
404
405 template <typename... TParams>
406 using VersionTag =
408 details::IsArrayListElemVersionDependentBoolType<ElementType>::value
409 >::template Type<
410 VersionDependentTag<TParams...>,
411 NoVersionDependencyTag<TParams...>
412 >;
413
414 template <typename... TParams>
415 constexpr std::size_t lengthInternal(FieldElemTag<TParams...>) const
416 {
417 using Tag =
418 typename comms::util::LazyShallowConditional<
419 details::ArrayListFieldHasVarLengthBoolType<ElementType>::value
420 >::template Type<
421 VarLengthTag,
422 FixedLengthTag
423 >;
424
425 return fieldLength(Tag());
426 }
427
428 template <typename... TParams>
429 constexpr std::size_t lengthInternal(IntegralElemTag<TParams...>) const
430 {
431 return m_value.size() * sizeof(ElementType);
432 }
433
434 template <typename... TParams>
435 constexpr std::size_t fieldLength(FixedLengthTag<TParams...>) const
436 {
437 return ElementType().length() * m_value.size();
438 }
439
440 template <typename... TParams>
441 std::size_t fieldLength(VarLengthTag<TParams...>) const
442 {
443 return
444 std::accumulate(m_value.begin(), m_value.end(), std::size_t(0),
445 [](std::size_t sum, typename ValueType::const_reference e) -> std::size_t
446 {
447 return sum + e.length();
448 });
449 }
450
451 template <typename... TParams>
452 static constexpr std::size_t maxLengthInternal(FieldElemTag<TParams...>)
453 {
454 return ElementType::maxLength();
455 }
456
457 template <typename... TParams>
458 static constexpr std::size_t maxLengthInternal(IntegralElemTag<TParams...>)
459 {
460 return sizeof(ElementType);
461 }
462
463 template <typename TIter>
464 static ErrorStatus readFieldElement(ElementType& elem, TIter& iter, std::size_t& len)
465 {
466 auto fromIter = iter;
467 auto es = elem.read(iter, len);
468 if (es == ErrorStatus::Success) {
469 auto diff = static_cast<std::size_t>(std::distance(fromIter, iter));
470 COMMS_ASSERT(diff <= len);
471 len -= diff;
472 }
473 return es;
474 }
475
476 template <typename TIter>
477 static ErrorStatus readIntegralElement(ElementType& elem, TIter& iter, std::size_t& len)
478 {
479 if (len < sizeof(ElementType)) {
481 }
482
483 elem = comms::util::readData<ElementType>(iter, Endian());
484 len -= sizeof(ElementType);
486 }
487
488 template <typename TIter, typename... TParams>
489 static ErrorStatus readElementInternal(ElementType& elem, TIter& iter, std::size_t& len, FieldElemTag<TParams...>)
490 {
491 return readFieldElement(elem, iter, len);
492 }
493
494 template <typename TIter, typename... TParams>
495 static ErrorStatus readElementInternal(ElementType& elem, TIter& iter, std::size_t& len, IntegralElemTag<TParams...>)
496 {
497 return readIntegralElement(elem, iter, len);
498 }
499
500 template <typename TIter>
501 static void readNoStatusFieldElement(ElementType& elem, TIter& iter)
502 {
503 elem.readNoStatus(iter);
504 }
505
506 template <typename TIter>
507 static void readNoStatusIntegralElement(ElementType& elem, TIter& iter)
508 {
509 elem = comms::util::readData<ElementType>(iter, Endian());
510 }
511
512 template <typename TIter, typename... TParams>
513 static void readElementNoStatusInternal(ElementType& elem, TIter& iter, FieldElemTag<TParams...>)
514 {
515 readNoStatusFieldElement(elem, iter);
516 }
517
518 template <typename TIter, typename... TParams>
519 static void readElementNoStatusInternal(ElementType& elem, TIter& iter, IntegralElemTag<TParams...>)
520 {
521 readElementNoStatusInternal(elem, iter);
522 }
523
524 template <typename TIter>
525 static ErrorStatus writeFieldElement(const ElementType& elem, TIter& iter, std::size_t& len)
526 {
527 auto es = elem.write(iter, len);
528 if (es == ErrorStatus::Success) {
529 len -= elem.length();
530 }
531 return es;
532 }
533
534 template <typename TIter>
535 static ErrorStatus writeIntegralElement(const ElementType& elem, TIter& iter, std::size_t& len)
536 {
537 if (len < sizeof(ElementType)) {
539 }
540
541 BaseImpl::writeData(elem, iter);
542 len -= sizeof(ElementType);
544 }
545
546 template <typename TIter, typename... TParams>
547 static ErrorStatus writeElementInternal(const ElementType& elem, TIter& iter, std::size_t& len, FieldElemTag<TParams...>)
548 {
549 return writeFieldElement(elem, iter, len);
550 }
551
552 template <typename TIter, typename... TParams>
553 static ErrorStatus writeElementInternal(const ElementType& elem, TIter& iter, std::size_t& len, IntegralElemTag<TParams...>)
554 {
555 return writeIntegralElement(elem, iter, len);
556 }
557
558 template <typename TIter>
559 static void writeNoStatusFieldElement(const ElementType& elem, TIter& iter)
560 {
561 elem.writeNoStatus(iter);
562 }
563
564 template <typename TIter>
565 static void writeNoStatusIntegralElement(const ElementType& elem, TIter& iter)
566 {
567 BaseImpl::writeData(elem, iter);
568 }
569
570 template <typename TIter, typename... TParams>
571 static void writeElementNoStatusInternal(const ElementType& elem, TIter& iter, FieldElemTag<TParams...>)
572 {
573 return writeNoStatusFieldElement(elem, iter);
574 }
575
576 template <typename TIter, typename... TParams>
577 static void writeElementNoStatusInternal(const ElementType& elem, TIter& iter, IntegralElemTag<TParams...>)
578 {
579 return writeNoStatusIntegralElement(elem, iter);
580 }
581
582 template <typename... TParams>
583 constexpr bool validInternal(FieldElemTag<TParams...>) const
584 {
585 return std::all_of(
586 m_value.begin(), m_value.end(),
587 [](const ElementType& e) -> bool
588 {
589 return e.valid();
590 });
591 }
592
593 template <typename... TParams>
594 static constexpr bool validInternal(IntegralElemTag<TParams...>)
595 {
596 return true;
597 }
598
599 template <typename... TParams>
600 bool refreshInternal(FieldElemTag<TParams...>)
601 {
602 return
603 std::accumulate(
604 m_value.begin(), m_value.end(), false,
605 [](bool prev, typename ValueType::reference elem) -> bool
606 {
607 return elem.refresh() || prev;
608 });
609 }
610
611 template <typename... TParams>
612 static constexpr bool refreshInternal(IntegralElemTag<TParams...>)
613 {
614 return false;
615 }
616
617 template <typename... TParams>
618 static constexpr std::size_t minElemLengthInternal(IntegralElemTag<TParams...>)
619 {
620 return sizeof(ElementType);
621 }
622
623 template <typename... TParams>
624 static constexpr std::size_t minElemLengthInternal(FieldElemTag<TParams...>)
625 {
626 return ElementType::minLength();
627 }
628
629 template <typename... TParams>
630 static constexpr std::size_t maxElemLengthInternal(IntegralElemTag<TParams...>)
631 {
632 return sizeof(ElementType);
633 }
634
635 template <typename... TParams>
636 static constexpr std::size_t maxElemLengthInternal(FieldElemTag<TParams...>)
637 {
638 return ElementType::maxLength();
639 }
640
641 template <typename... TParams>
642 static constexpr std::size_t elementLengthInternal(const ElementType&, IntegralElemTag<TParams...>)
643 {
644 return sizeof(ElementType);
645 }
646
647 template <typename... TParams>
648 static constexpr std::size_t elementLengthInternal(const ElementType& elem, FieldElemTag<TParams...>)
649 {
650 return elem.length();
651 }
652
653 template <typename TIter, typename... TParams>
654 ErrorStatus readInternal(TIter& iter, std::size_t len, FieldElemTag<TParams...>)
655 {
656 static_assert(comms::util::detect::hasClearFunc<ValueType>(),
657 "The used storage type for ArrayList must have clear() member function");
658 m_value.clear();
659 auto remLen = len;
660 while (0 < remLen) {
661 auto es = createAndReadNextElementInternal(iter, remLen);
662 if (es != ErrorStatus::Success) {
663 return es;
664 }
665 }
666
668 }
669
670 template <typename TIter, typename... TParams>
671 ErrorStatus readInternal(TIter& iter, std::size_t len, RawDataTag<TParams...>)
672 {
673 comms::util::assign(value(), iter, iter + std::min(len, comms::util::maxSizeOf(value())));
674 std::advance(iter, len);
676 }
677
678 template <typename TIter, typename... TParams>
679 ErrorStatus readInternalN(std::size_t count, TIter& iter, std::size_t len, FieldElemTag<TParams...>)
680 {
681 clear();
682 while (0 < count) {
683 auto es = createAndReadNextElementInternal(iter, len);
684 if (es != ErrorStatus::Success) {
685 return es;
686 }
687
688 --count;
689 }
690
692 }
693
694 template <typename TIter, typename... TParams>
695 ErrorStatus readInternalN(std::size_t count, TIter& iter, std::size_t len, RawDataTag<TParams...>)
696 {
697 if (len < count) {
699 }
700
701 return readInternal(iter, count, RawDataTag<>());
702 }
703
704 template <typename TIter, typename... TParams>
705 void readNoStatusInternalN(std::size_t count, TIter& iter, FieldElemTag<TParams...>)
706 {
707 clear();
708 while (0 < count) {
709 if (m_value.size() < m_value.max_size()) {
710 auto& elem = createBack();
711 readElementNoStatus(elem, iter);
712 }
713 else {
714 ElementType elem;
715 readElementNoStatus(elem, iter);
716 }
717 --count;
718 }
719 }
720
721 template <typename TIter, typename... TParams>
722 void readNoStatusInternalN(std::size_t count, TIter& iter, RawDataTag<TParams...>)
723 {
724 readInternal(iter, count, RawDataTag<>());
725 }
726
727 template <typename... TParams>
728 bool updateElemVersion(ElementType& elem, VersionDependentTag<TParams...>)
729 {
730 return elem.setVersion(VersionBaseImpl::m_version);
731 }
732
733 template <typename... TParams>
734 static constexpr bool updateElemVersion(ElementType&, NoVersionDependencyTag<TParams...>)
735 {
736 return false;
737 }
738
739 template <typename... TParams>
740 bool setVersionInternal(VersionType version, VersionDependentTag<TParams...>)
741 {
742 VersionBaseImpl::m_version = version;
743 bool updated = false;
744 for (auto& elem : value()) {
745 updated = elem.setVersion(version) || updated;
746 }
747
748 return updated;
749 }
750
751 template <typename... TParams>
752 static constexpr bool setVersionInternal(VersionType, NoVersionDependencyTag<TParams...>)
753 {
754 return false;
755 }
756
757 template <typename... TParams>
758 static bool canWriteElementInternal(const ElementType& elem, FieldElemTag<TParams...>)
759 {
760 return elem.canWrite();
761 }
762
763 template <typename... TParams>
764 static bool canWriteElementInternal(const ElementType& elem, IntegralElemTag<TParams...>)
765 {
766 static_cast<void>(elem);
767 return true;
768 }
769
770 template <typename... TParams>
771 static constexpr bool hasWriteNoStatusInternal(FieldElemTag<TParams...>)
772 {
773 return ElementType::hasWriteNoStatus();
774 }
775
776 template <typename... TParams>
777 static constexpr bool hasWriteNoStatusInternal(IntegralElemTag<TParams...>)
778 {
779 return true;
780 }
781
782 template <typename TIter>
783 comms::ErrorStatus createAndReadNextElementInternal(TIter& iter, std::size_t& len)
784 {
785 if (m_value.size() < m_value.max_size()) {
786 auto& elem = createBack();
787 auto es = readElement(elem, iter, len);
788 if (es != ErrorStatus::Success) {
789 m_value.pop_back();
790 }
791
792 return es;
793 }
794
795 ElementType elem;
796 return readElement(elem, iter, len);
797 }
798
799 ValueType m_value;
800};
801
802} // namespace basic
803
804} // namespace field
805
806} // namespace comms
807
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:168
Contains various compiler related definitions.
This file contain definition of error statuses used by comms module.
Contains comms::util::StaticString class.
Contains comms::util::StaticVector class.
Contains functions for raw data access / (de)serialization.
Provides helper assign() function to allow easy assignment of values to collections or views.
Contains definition of various tag classes.
comms::option::def::VersionType< T > VersionType
Same as comms::option::def::VersionType.
Definition options.h:1928
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1471
void assign(T &obj, TIter from, TIter to)
Assigns a new value to provided object.
Definition assign.h:39
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
@ Success
Used to indicate successful outcome of the operation.
constexpr unsigned version()
Version of the COMMS library as single numeric value.
Definition version.h:64
STL namespace.
Replacement to std::conditional.
Definition type_traits.h:29
Replacement to some types from standard type_traits.
Various compile-time detection functions of whether specific member functions and/or types exist.