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