sbepp
Loading...
Searching...
No Matches
sbepp.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2023, Oleksandr Koval
3
10#pragma once
11
12#include <array>
13#include <algorithm>
14#include <cstddef>
15#include <cstdint>
16#include <cstring>
17#include <iterator>
18#include <limits>
19#include <type_traits>
20#include <initializer_list>
21
22// Clang generates tons of warnings about code like `return {N};` where `N` is
23// calculated during generation or just a value from schema. Using braced
24// initialization syntax provides additional safety in such cases.
25#ifdef __clang__
26# define SBEPP_WARNINGS_OFF() \
27 _Pragma("clang diagnostic push"); \
28 _Pragma("clang diagnostic ignored \"-Wbraced-scalar-init\"")
29# define SBEPP_WARNINGS_ON() _Pragma("clang diagnostic pop")
30#else
31# define SBEPP_WARNINGS_OFF()
32# define SBEPP_WARNINGS_ON()
33#endif
34
35SBEPP_WARNINGS_OFF();
36
37#ifdef _MSVC_LANG
38# define SBEPP_CPLUSPLUS _MSVC_LANG
39#else
40# define SBEPP_CPLUSPLUS __cplusplus
41#endif
42
43#ifdef __has_include
44# if __has_include(<version>)
45# include <version>
46# endif
47#endif
48
58#if !defined(SBEPP_HAS_THREE_WAY_COMPARISON) \
59 && defined(__cpp_impl_three_way_comparison) \
60 && defined(__cpp_lib_three_way_comparison)
61# if(__cpp_impl_three_way_comparison >= 201907L) \
62 && (__cpp_lib_three_way_comparison >= 201907L)
63# define SBEPP_HAS_THREE_WAY_COMPARISON 1
64# include <compare>
65# endif
66#endif
67#ifndef SBEPP_HAS_THREE_WAY_COMPARISON
68# define SBEPP_HAS_THREE_WAY_COMPARISON 0
69#endif
70
72#if !defined(SBEPP_HAS_CONCEPTS) && defined(__cpp_concepts)
73# if(__cpp_concepts >= 201907L)
74# define SBEPP_HAS_CONCEPTS 1
75# endif
76#endif
77#ifndef SBEPP_HAS_CONCEPTS
78# define SBEPP_HAS_CONCEPTS 0
79#endif
80
82#if !defined(SBEPP_HAS_INLINE_VARS) && defined(__cpp_inline_variables)
83# if(__cpp_inline_variables >= 201606L)
84# define SBEPP_HAS_INLINE_VARS 1
85# define SBEPP_CPP17_INLINE_VAR inline
86# endif
87#endif
88#ifndef SBEPP_CPP17_INLINE_VAR
89# define SBEPP_HAS_INLINE_VARS 0
90# define SBEPP_CPP17_INLINE_VAR
91#endif
92
94#if !defined(SBEPP_HAS_ENDIAN) && defined(__cpp_lib_endian)
95# if(__cpp_lib_endian >= 201907L)
96# define SBEPP_HAS_ENDIAN 1
97# include <bit>
98# endif
99#endif
100#ifndef SBEPP_HAS_ENDIAN
101# define SBEPP_HAS_ENDIAN 0
102#endif
103
105#if !defined(SBEPP_HAS_BITCAST) && defined(__cpp_lib_bit_cast)
106# if(__cpp_lib_bit_cast >= 201806L)
107# define SBEPP_HAS_BITCAST 1
108# include <bit>
109# endif
110#endif
111#ifndef SBEPP_HAS_BITCAST
112# define SBEPP_HAS_BITCAST 0
113#endif
114
116#if !defined(SBEPP_HAS_BYTESWAP) && defined(__cpp_lib_byteswap)
117# if(__cpp_lib_byteswap >= 202110L)
118# define SBEPP_HAS_BYTESWAP 1
119# include <bit>
120# endif
121#endif
122#ifndef SBEPP_HAS_BYTESWAP
123# define SBEPP_HAS_BYTESWAP 0
124#endif
125
127#if !defined(SBEPP_HAS_CONSTEXPR_ALGORITHMS) \
128 && defined(__cpp_lib_constexpr_algorithms)
129# if(__cpp_lib_constexpr_algorithms >= 201806L)
130# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 1
131# endif
132#endif
133#ifndef SBEPP_HAS_CONSTEXPR_ALGORITHMS
134# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 0
135#endif
136
137#ifdef __has_cpp_attribute
138// Clang provides `nodiscard` in C++11 but then warns that it's a C++17 feature
139# if __has_cpp_attribute(nodiscard) \
140 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201703L))
141# define SBEPP_CPP17_NODISCARD [[nodiscard]]
142# endif
143
144# if __has_cpp_attribute(deprecated) \
145 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201402L))
146# define SBEPP_DEPRECATED [[deprecated]]
147# endif
148#endif
149
150#ifndef SBEPP_CPP17_NODISCARD
151# define SBEPP_CPP17_NODISCARD
152#endif
153
154#ifndef SBEPP_DEPRECATED
155# if defined(__GNUC__) || defined(__clang__)
156# define SBEPP_DEPRECATED __attribute__((deprecated))
157# elif defined(_MSC_VER)
158# define SBEPP_DEPRECATED __declspec(deprecated)
159# else
160# define SBEPP_DEPRECATED
161# endif
162#endif
163
165#if SBEPP_HAS_BITCAST && SBEPP_HAS_CONSTEXPR_ALGORITHMS
166# define SBEPP_HAS_CONSTEXPR_ACCESSORS 1
167#else
168# define SBEPP_HAS_CONSTEXPR_ACCESSORS 0
169#endif
170
171#if SBEPP_HAS_CONSTEXPR_ACCESSORS
172# include <bit>
173# define SBEPP_CPP20_CONSTEXPR constexpr
174#else
175# define SBEPP_CPP20_CONSTEXPR
176#endif
177
178#ifdef __cpp_constexpr
179# if(__cpp_constexpr >= 201304L)
180# define SBEPP_CPP14_CONSTEXPR constexpr
181# endif
182#else
183# if(SBEPP_CPLUSPLUS >= 201402L)
184# define SBEPP_CPP14_CONSTEXPR constexpr
185# endif
186#endif
187#ifndef SBEPP_CPP14_CONSTEXPR
188# define SBEPP_CPP14_CONSTEXPR
189#endif
190
192#if !defined(SBEPP_HAS_RANGES) && defined(__cpp_lib_ranges)
193# if(__cpp_lib_ranges >= 201911L)
194# define SBEPP_HAS_RANGES 1
195# include <ranges>
196# endif
197#endif
198#ifndef SBEPP_HAS_RANGES
199# define SBEPP_HAS_RANGES 0
200#endif
201
204#if !defined(SBEPP_HAS_IS_CONSTANT_EVALUATED) \
205 && defined(__cpp_lib_is_constant_evaluated) \
206 && (__cpp_lib_is_constant_evaluated >= 201811L)
207# define SBEPP_HAS_IS_CONSTANT_EVALUATED 1
208#endif
209#ifndef SBEPP_HAS_IS_CONSTANT_EVALUATED
210# define SBEPP_HAS_IS_CONSTANT_EVALUATED 0
211#endif
212
214
215#ifdef SBEPP_DOXYGEN
217# define SBEPP_DISABLE_ASSERTS
218
223# define SBEPP_ASSERT_HANDLER
224
229# define SBEPP_ENABLE_ASSERTS_WITH_HANDLER
230
231namespace sbepp
232{
243[[noreturn]] void assertion_failed(
244 char const* expr, char const* function, char const* file, long line);
245} // namespace sbepp
246#endif
247
248#ifdef SBEPP_DISABLE_ASSERTS
249# define SBEPP_SIZE_CHECKS_ENABLED 0
250# define SBEPP_ASSERT(expr) ((void)0)
251#elif defined(SBEPP_ASSERT_HANDLER) \
252 || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
253# if !defined(NDEBUG) || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
254namespace sbepp
255{
256// must be defined by user
257[[noreturn]] void assertion_failed(
258 char const* expr, char const* function, char const* file, long line);
259} // namespace sbepp
260
261# define SBEPP_SIZE_CHECKS_ENABLED 1
262# define SBEPP_ASSERT(expr) \
263 (static_cast<bool>(expr) \
264 ? ((void)0) \
265 : ::sbepp::assertion_failed( \
266 #expr, __func__, __FILE__, __LINE__))
267# else
268# define SBEPP_SIZE_CHECKS_ENABLED 0
269# define SBEPP_ASSERT(expr) ((void)0)
270# endif
271#else
272# include <cassert>
273# ifdef NDEBUG
274# define SBEPP_SIZE_CHECKS_ENABLED 0
275# else
276# define SBEPP_SIZE_CHECKS_ENABLED 1
277# endif
278# define SBEPP_ASSERT(expr) assert(expr)
279#endif
280
281#define SBEPP_SIZE_CHECK(begin, end, offset, size) \
282 SBEPP_ASSERT( \
283 (begin) \
284 && (((offset) + (size)) <= static_cast<std::size_t>((end) - (begin))))
285
287namespace sbepp
288{
290using length_t = std::uint64_t;
291// for unknown reasons, in the SBE standard `offset` is specified as an unsigned
292// 32-bit integer which makes no sense since `length` has 64 bits
294using offset_t = std::uint64_t;
297using version_t = std::uint64_t;
299using schema_id_t = std::uint32_t;
301using message_id_t = std::uint32_t;
304using block_length_t = std::uint64_t;
306using member_id_t = std::uint16_t;
308using choice_index_t = std::uint8_t;
309
313{
315 required,
317 optional,
320};
321
322#ifdef SBEPP_DOXYGEN
327# define SBEPP_BYTE_ORDER
328#endif
329
335#ifdef SBEPP_DOXYGEN
336enum class endian
337{
339 little,
341 big,
343 native
344};
345#elif SBEPP_HAS_ENDIAN
346using endian = std::endian;
347#else
348// https://en.cppreference.com/w/cpp/types/endian
349enum class endian
350{
351# if defined(_WIN32) || defined(WIN32)
352 little = 0,
353 big = 1,
354 native = little
355# elif defined(__BYTE_ORDER__)
356 little = __ORDER_LITTLE_ENDIAN__,
357 big = __ORDER_BIG_ENDIAN__,
358 native = __BYTE_ORDER__
359# elif defined(SBEPP_BYTE_ORDER)
360 little = 0,
361 big = 1,
363# else
364# error "Byte order cannot be detected.\
365 Define SBEPP_BYTE_ORDER to 'little' or 'big'"
366# endif
367};
368#endif
369
370static_assert(
372 "Mixed-endian is not supported");
373
376namespace detail
377{
378// modern C++ bits
379template<bool B, typename T = void>
380using enable_if_t = typename std::enable_if<B, T>::type;
381
382template<typename T>
383using remove_cv_t = typename std::remove_cv<T>::type;
384
385template<typename T>
386using remove_reference_t = typename std::remove_reference<T>::type;
387
388template<typename ByteFrom, typename ByteTo>
389using enable_if_convertible_t =
390 enable_if_t<std::is_convertible<ByteFrom*, ByteTo*>::value>;
391
392template<typename Byte, typename T = void>
393using enable_if_writable_t = enable_if_t<!std::is_const<Byte>::value, T>;
394
395template<typename...>
396using void_t = void;
397
398template<typename T, typename = enable_if_t<!std::is_floating_point<T>::value>>
399constexpr typename std::make_unsigned<T>::type to_unsigned(T v) noexcept
400{
401 return static_cast<typename std::make_unsigned<T>::type>(v);
402}
403
404inline std::uint64_t to_unsigned(double v) noexcept
405{
406 std::uint64_t res{};
407 std::memcpy(&res, &v, sizeof(res));
408 return res;
409}
410
411inline std::uint32_t to_unsigned(float v) noexcept
412{
413 std::uint32_t res{};
414 std::memcpy(&res, &v, sizeof(res));
415 return res;
416}
417
418template<typename To>
419struct from_unsigned
420{
421 constexpr To
422 operator()(typename std::make_unsigned<To>::type from) const noexcept
423 {
424 return static_cast<To>(from);
425 }
426};
427
428template<>
429struct from_unsigned<double>
430{
431 double operator()(std::uint64_t from) const noexcept
432 {
433 double res{};
434 std::memcpy(&res, &from, sizeof(res));
435 return res;
436 }
437};
438
439template<>
440struct from_unsigned<float>
441{
442 float operator()(std::uint32_t from) const noexcept
443 {
444 float res{};
445 std::memcpy(&res, &from, sizeof(res));
446 return res;
447 }
448};
449
450// intrinsics detection is taken from <boost/endian/detail/intrinsic.hpp>
451#ifndef __has_builtin // Optional of course
452# define __has_builtin(x) 0 // Compatibility with non-clang compilers
453#endif
454
455#if SBEPP_HAS_BYTESWAP
456
457using std::byteswap;
458
459#else
460
461// because `if((E == endian::native) || (sizeof(T) == 1))` is not a constexpr-if
462// this function has to be declared for single byte types even if it will never
463// be used
464template<typename T>
465T byteswap(T) noexcept;
466
467# if defined(_MSC_VER) && (!defined(__clang__) || defined(__c2__))
468
469# include <cstdlib>
470
471inline std::uint64_t byteswap(std::uint64_t v) noexcept
472{
473 return _byteswap_uint64(v);
474}
475
476inline std::uint32_t byteswap(std::uint32_t v) noexcept
477{
478 return _byteswap_ulong(v);
479}
480
481inline std::uint16_t byteswap(std::uint16_t v) noexcept
482{
483 return _byteswap_ushort(v);
484}
485
486# elif( \
487 defined(__clang__) && __has_builtin(__builtin_bswap32) \
488 && __has_builtin(__builtin_bswap64)) \
489 || (defined(__GNUC__) \
490 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
491
492# if(defined(__clang__) && __has_builtin(__builtin_bswap16)) \
493 || (defined(__GNUC__) \
494 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
495
496inline std::uint16_t byteswap(std::uint16_t v) noexcept
497{
498 return __builtin_bswap16(v);
499}
500
501# else
502
503inline std::uint16_t byteswap(std::uint16_t v) noexcept
504{
505 return __builtin_bswap32(v) << 16;
506}
507
508# endif
509
510inline std::uint64_t byteswap(std::uint64_t v) noexcept
511{
512 return __builtin_bswap64(v);
513}
514
515inline std::uint32_t byteswap(std::uint32_t v) noexcept
516{
517 return __builtin_bswap32(v);
518}
519
520# else
521
522constexpr std::uint64_t byteswap(std::uint64_t v) noexcept
523{
524 return ((v & UINT64_C(0x00000000000000FF)) << 56)
525 | ((v & UINT64_C(0x000000000000FF00)) << 40)
526 | ((v & UINT64_C(0x0000000000FF0000)) << 24)
527 | ((v & UINT64_C(0x00000000FF000000)) << 8)
528 | ((v & UINT64_C(0x000000FF00000000)) >> 8)
529 | ((v & UINT64_C(0x0000FF0000000000)) >> 24)
530 | ((v & UINT64_C(0x00FF000000000000)) >> 40)
531 | ((v & UINT64_C(0xFF00000000000000)) >> 56);
532}
533
534constexpr std::uint32_t byteswap(std::uint32_t v) noexcept
535{
536 return ((v & UINT32_C(0x000000FF)) << 24)
537 | ((v & UINT32_C(0x0000FF00)) << 8)
538 | ((v & UINT32_C(0x00FF0000)) >> 8)
539 | ((v & UINT32_C(0xFF000000)) >> 24);
540}
541
542constexpr std::uint16_t byteswap(std::uint16_t v) noexcept
543{
544 return ((v & UINT16_C(0x00FF)) << 8) | ((v & UINT16_C(0xFF00)) >> 8);
545}
546
547# endif
548#endif
549
550template<typename T, endian E, typename Byte>
551SBEPP_CPP20_CONSTEXPR T get_primitive(const Byte* ptr)
552{
553#if SBEPP_HAS_BITCAST
554 std::array<Byte, sizeof(T)> arr;
555 if((E == endian::native) || (sizeof(T) == 1))
556 {
557 std::copy(ptr, ptr + sizeof(T), std::begin(arr));
558 }
559 else
560 {
561 std::reverse_copy(ptr, ptr + sizeof(T), std::begin(arr));
562 }
563 return std::bit_cast<T>(arr);
564#else
565 // old compilers don't optimize `std::copy` approach good enough, that's
566 // why explicit `std::memcpy` call is required
567 T res;
568 std::memcpy(&res, ptr, sizeof(T));
569 if((E == endian::native) || (sizeof(T) == 1))
570 {
571 return res;
572 }
573 else
574 {
575 return from_unsigned<T>{}(byteswap(to_unsigned(res)));
576 }
577#endif
578}
579
580template<endian E, typename T, typename Byte>
581SBEPP_CPP20_CONSTEXPR void set_primitive(Byte* ptr, T value)
582{
583#if SBEPP_HAS_BITCAST
584 auto arr = std::bit_cast<std::array<Byte, sizeof(T)>>(value);
585 if((E == endian::native) || (sizeof(T) == 1))
586 {
587 std::copy(std::begin(arr), std::end(arr), ptr);
588 }
589 else
590 {
591 std::reverse_copy(std::begin(arr), std::end(arr), ptr);
592 }
593#else
594 // old compilers don't optimize `std::copy` approach good enough, that's
595 // why explicit `std::memcpy` call is required
596 if((E != endian::native) && (sizeof(T) != 1))
597 {
598 value = from_unsigned<T>{}(byteswap(to_unsigned(value)));
599 }
600 std::memcpy(ptr, &value, sizeof(T));
601#endif
602}
603
604struct fill_message_header_tag
605{
606 explicit fill_message_header_tag() = default;
607};
608
609struct fill_group_header_tag
610{
611 explicit fill_group_header_tag() = default;
612};
613
614struct size_bytes_tag
615{
616 explicit size_bytes_tag() = default;
617};
618
619struct addressof_tag
620{
621 explicit addressof_tag() = default;
622};
623
624struct end_ptr_tag
625{
626 explicit end_ptr_tag() = default;
627};
628
629struct get_header_tag
630{
631 explicit get_header_tag() = default;
632};
633
634struct get_block_length_tag
635{
636 explicit get_block_length_tag() = default;
637};
638
639struct get_bit_tag
640{
641 explicit get_bit_tag() = default;
642};
643
644struct set_bit_tag
645{
646 explicit set_bit_tag() = default;
647};
648
649struct get_level_tag
650{
651 explicit get_level_tag() = default;
652};
653
654struct visit_tag
655{
656 explicit visit_tag() = default;
657};
658
659struct visit_children_tag
660{
661 explicit visit_children_tag() = default;
662};
663
664struct enum_to_str_tag
665{
666 explicit enum_to_str_tag() = default;
667};
668
669struct visit_set_tag
670{
671 explicit visit_set_tag() = default;
672};
673
674template<typename T, typename U, endian E, typename View>
675SBEPP_CPP20_CONSTEXPR T
676 get_value(const View view, const std::size_t offset) noexcept
677{
678 SBEPP_SIZE_CHECK(
679 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(U));
680 return T{get_primitive<U, E>(view(addressof_tag{}) + offset)};
681}
682
683template<endian E, typename T, typename View>
684SBEPP_CPP20_CONSTEXPR void
685 set_value(const View view, const std::size_t offset, const T value) noexcept
686{
687 SBEPP_SIZE_CHECK(
688 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(T));
689 set_primitive<E>(view(addressof_tag{}) + offset, value);
690}
691
692template<typename Res, typename View>
693SBEPP_CPP20_CONSTEXPR Res
694 get_static_field_view(const View view, const std::size_t offset) noexcept
695{
696 SBEPP_SIZE_CHECK(view(addressof_tag{}), view(end_ptr_tag{}), offset, 0);
697 return {view(addressof_tag{}) + offset, view(end_ptr_tag{})};
698}
699
700template<typename Group, typename View>
701SBEPP_CPP20_CONSTEXPR Group
702 get_first_dynamic_field_view(const View view) noexcept
703{
704 return {
705 view(get_level_tag{}) + view(get_block_length_tag{}),
706 view(end_ptr_tag{})};
707}
708
709template<typename Group, typename View, typename Prev>
710SBEPP_CPP20_CONSTEXPR Group
711 get_dynamic_field_view(const View view, const Prev prev) noexcept
712{
713 return {
714 prev(addressof_tag{}) + prev(size_bytes_tag{}), view(end_ptr_tag{})};
715}
716
719template<typename Byte>
721{
722public:
723 static_assert(sizeof(Byte) == 1, "Byte must represent a single byte");
724
725 template<typename Byte2>
726 friend class byte_range;
727
729 byte_range() = default;
730
732 SBEPP_CPP14_CONSTEXPR byte_range(Byte* begin, Byte* end) noexcept
733 : begin{begin}
734#if SBEPP_SIZE_CHECKS_ENABLED
735 ,
736 end{end}
737#endif
738 {
739 (void)end;
740 }
741
743 constexpr byte_range(Byte* ptr, const std::size_t size) noexcept
744 : byte_range{ptr, ptr + size}
745 {
746 }
747
749 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
750 // NOLINTNEXTLINE: intentionally implicit
751 constexpr byte_range(const byte_range<Byte2>& other) noexcept
752 : begin{other.begin}
753#if SBEPP_SIZE_CHECKS_ENABLED
754 ,
755 end{other.end}
756#endif
757 {
758 }
759
760 constexpr Byte* operator()(addressof_tag) const noexcept
761 {
762 return begin;
763 }
764
765 constexpr Byte* operator()(end_ptr_tag) const noexcept
766 {
767#if SBEPP_SIZE_CHECKS_ENABLED
768 return end;
769#else
770 return nullptr;
771#endif
772 }
773
774private:
775 Byte* begin{};
776#if SBEPP_SIZE_CHECKS_ENABLED
777 Byte* end{};
778#endif
779};
780} // namespace detail
781
788template<typename Byte>
790{
791public:
793 using byte_type = Byte;
794
795 // in accessors we have to use trailing return type because in "skip" mode
796 // they should return `void`. In most cases it's not a problem but
797 // `get_group_view` and `get_data_view` take lambdas which were not allowed
798 // in unevaluated context (e.g. decltype) prior to C++20 so we need this
799 // alias to specify return types for them. First attempt used
800 // pointer-to-member instead of lambda but GCC doesn't support it so I
801 // switched to simpler approach with lambda and trait.
802 template<typename T>
803 using result_type = T;
804
806 cursor() = default;
807
815 template<
816 typename Byte2,
817 typename = detail::enable_if_convertible_t<Byte2, Byte>>
818 // NOLINTNEXTLINE: implicit conversion is intentional
819 constexpr cursor(cursor<Byte2> other) noexcept : ptr{other.ptr}
820 {
821 }
822
831 template<
832 typename Byte2,
833 typename = detail::enable_if_convertible_t<Byte2, Byte>>
834 SBEPP_CPP14_CONSTEXPR cursor& operator=(cursor<Byte2> other) noexcept
835 {
836 ptr = other.ptr;
837 return *this;
838 }
839
846 SBEPP_CPP14_CONSTEXPR Byte*& pointer() noexcept
847 {
848 return ptr;
849 }
850
856 SBEPP_CPP14_CONSTEXPR Byte* pointer() const noexcept
857 {
858 return ptr;
859 }
860
861 template<typename T, typename U, endian E, typename View>
862 SBEPP_CPP20_CONSTEXPR T get_value(
863 const View view,
864 const std::size_t offset,
865 const std::size_t /*absolute_offset*/) noexcept
866 {
867 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
868 T res{detail::get_primitive<U, E>(ptr + offset)};
869 ptr += offset + sizeof(U);
870 return res;
871 }
872
873 template<endian E, typename T, typename View>
874 SBEPP_CPP20_CONSTEXPR void set_value(
875 const View view,
876 const std::size_t offset,
877 const std::size_t /*absolute_offset*/,
878 const T value) noexcept
879 {
880 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
881 detail::set_primitive<E>(ptr + offset, value);
882 ptr += offset + sizeof(T);
883 }
884
885 template<typename T, typename U, endian E, typename View>
886 SBEPP_CPP20_CONSTEXPR T get_last_value(
887 const View view,
888 const std::size_t offset,
889 const std::size_t /*absolute_offset*/) noexcept
890 {
891 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
892 auto res = T{detail::get_primitive<U, E>(ptr + offset)};
893 ptr = view(detail::get_level_tag{})
894 + view(detail::get_block_length_tag{});
895 return res;
896 }
897
898 template<endian E, typename T, typename View>
899 SBEPP_CPP20_CONSTEXPR void set_last_value(
900 const View view,
901 const std::size_t offset,
902 const std::size_t /*absolute_offset*/,
903 const T value) noexcept
904 {
905 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
906 detail::set_primitive<E>(ptr + offset, value);
907 ptr = view(detail::get_level_tag{})
908 + view(detail::get_block_length_tag{});
909 }
910
911 template<typename Res, typename View>
912 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
913 const View view,
914 const std::size_t offset,
915 const std::size_t /*absolute_offset*/) noexcept
916 {
917 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
918 Res res{ptr + offset, view(detail::end_ptr_tag{})};
919 ptr += offset + res(detail::size_bytes_tag{});
920 return res;
921 }
922
923 template<typename Res, typename View>
924 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
925 const View view,
926 const std::size_t offset,
927 const std::size_t /*absolute_offset*/) noexcept
928 {
929 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
930 Res res{ptr + offset, view(detail::end_ptr_tag{})};
931 ptr = view(detail::get_level_tag{})
932 + view(detail::get_block_length_tag{});
933 return res;
934 }
935
936 template<typename ResView, typename View>
937 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
938 {
939 ptr = view(detail::get_level_tag{})
940 + view(detail::get_block_length_tag{});
941 ResView g{ptr, view(detail::end_ptr_tag{})};
942 ptr += g(detail::get_header_tag{})(detail::size_bytes_tag{});
943
944 return g;
945 }
946
947 template<typename ResView, typename View>
948 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
949 {
950 ptr = view(detail::get_level_tag{})
951 + view(detail::get_block_length_tag{});
952 ResView d{ptr, view(detail::end_ptr_tag{})};
953 ptr += d(detail::size_bytes_tag{});
954
955 return d;
956 }
957
958 template<typename ResView, typename View, typename Getter>
959 SBEPP_CPP20_CONSTEXPR ResView
960 get_group_view(const View view, Getter&& /*getter*/) noexcept
961 {
962 ResView res{ptr, view(detail::end_ptr_tag{})};
963 auto header = res(detail::get_header_tag{});
964 ptr += header(detail::size_bytes_tag{});
965 return res;
966 }
967
968 template<typename ResView, typename View, typename Getter>
969 SBEPP_CPP20_CONSTEXPR ResView
970 get_data_view(const View view, Getter&& /*getter*/) noexcept
971 {
972 ResView res{ptr, view(detail::end_ptr_tag{})};
973 ptr += res(detail::size_bytes_tag{});
974 return res;
975 }
976
977private:
978 template<typename T>
979 friend class cursor;
980
981 Byte* ptr{};
982};
983
984namespace detail
985{
986template<typename Byte>
987class init_cursor_wrapper
988{
989public:
990 using byte_type = Byte;
991
992 template<typename T>
993 using result_type = T;
994
995 init_cursor_wrapper() = default;
996
997 explicit constexpr init_cursor_wrapper(sbepp::cursor<Byte>& cursor)
998 : cursor{&cursor}
999 {
1000 }
1001
1002 template<typename T, typename U, endian E, typename View>
1003 SBEPP_CPP20_CONSTEXPR T get_value(
1004 const View view,
1005 const std::size_t /*offset*/,
1006 const std::size_t absolute_offset) noexcept
1007 {
1008 SBEPP_SIZE_CHECK(
1009 view(addressof_tag{}),
1010 view(end_ptr_tag{}),
1011 absolute_offset,
1012 sizeof(U));
1013 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1014 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(U);
1015 return res;
1016 }
1017
1018 template<endian E, typename T, typename View>
1019 SBEPP_CPP20_CONSTEXPR void set_value(
1020 const View view,
1021 const std::size_t /*offset*/,
1022 const std::size_t absolute_offset,
1023 const T value) noexcept
1024 {
1025 SBEPP_SIZE_CHECK(
1026 view(addressof_tag{}),
1027 view(end_ptr_tag{}),
1028 absolute_offset,
1029 sizeof(T));
1030 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1031 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(T);
1032 }
1033
1034 template<typename T, typename U, endian E, typename View>
1035 SBEPP_CPP20_CONSTEXPR T get_last_value(
1036 const View view,
1037 const std::size_t /*offset*/,
1038 const std::size_t absolute_offset) noexcept
1039 {
1040 SBEPP_SIZE_CHECK(
1041 view(addressof_tag{}),
1042 view(end_ptr_tag{}),
1043 absolute_offset,
1044 sizeof(U));
1045 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1046 cursor->pointer() =
1047 view(get_level_tag{}) + view(get_block_length_tag{});
1048 return res;
1049 }
1050
1051 template<endian E, typename T, typename View>
1052 SBEPP_CPP20_CONSTEXPR void set_last_value(
1053 const View view,
1054 const std::size_t /*offset*/,
1055 const std::size_t absolute_offset,
1056 const T value) noexcept
1057 {
1058 SBEPP_SIZE_CHECK(
1059 view(addressof_tag{}),
1060 view(end_ptr_tag{}),
1061 absolute_offset,
1062 sizeof(T));
1063 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1064 cursor->pointer() =
1065 view(get_level_tag{}) + view(get_block_length_tag{});
1066 }
1067
1068 template<typename Res, typename View>
1069 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1070 const View view,
1071 const std::size_t /*offset*/,
1072 const std::size_t absolute_offset) noexcept
1073 {
1074 SBEPP_SIZE_CHECK(
1075 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1076 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1077 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1078 return res;
1079 }
1080
1081 template<typename Res, typename View>
1082 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1083 const View view,
1084 const std::size_t /*offset*/,
1085 const std::size_t absolute_offset) noexcept
1086 {
1087 SBEPP_SIZE_CHECK(
1088 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1089 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1090 cursor->pointer() =
1091 view(get_level_tag{}) + view(get_block_length_tag{});
1092 return res;
1093 }
1094
1095 template<typename ResView, typename View>
1096 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1097 {
1098 return cursor->template get_first_group_view<ResView>(view);
1099 }
1100
1101 template<typename ResView, typename View>
1102 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1103 {
1104 return cursor->template get_first_data_view<ResView>(view);
1105 }
1106
1107 template<typename ResView, typename View, typename Getter>
1108 SBEPP_CPP20_CONSTEXPR ResView
1109 get_group_view(const View /*view*/, Getter&& getter) noexcept
1110 {
1111 auto res = getter();
1112 auto header = res(get_header_tag{});
1113 cursor->pointer() = res(addressof_tag{}) + header(size_bytes_tag{});
1114 return res;
1115 }
1116
1117 template<typename ResView, typename View, typename Getter>
1118 SBEPP_CPP20_CONSTEXPR ResView
1119 get_data_view(const View /*view*/, Getter&& getter) noexcept
1120 {
1121 auto res = getter();
1122 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1123 return res;
1124 }
1125
1126private:
1127 sbepp::cursor<Byte>* cursor{};
1128};
1129
1130template<typename Byte>
1131class init_dont_move_cursor_wrapper
1132{
1133public:
1134 using byte_type = Byte;
1135
1136 template<typename T>
1137 using result_type = T;
1138
1139 init_dont_move_cursor_wrapper() = default;
1140
1141 explicit constexpr init_dont_move_cursor_wrapper(
1142 sbepp::cursor<Byte>& cursor)
1143 : cursor{&cursor}
1144 {
1145 }
1146
1147 template<typename T, typename U, endian E, typename View>
1148 SBEPP_CPP20_CONSTEXPR T get_value(
1149 const View view,
1150 const std::size_t offset,
1151 const std::size_t absolute_offset) noexcept
1152 {
1153 SBEPP_SIZE_CHECK(
1154 view(addressof_tag{}),
1155 view(end_ptr_tag{}),
1156 absolute_offset,
1157 sizeof(U));
1158 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1159 return T{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1160 }
1161
1162 template<endian E, typename T, typename View>
1163 SBEPP_CPP20_CONSTEXPR void set_value(
1164 const View view,
1165 const std::size_t offset,
1166 const std::size_t absolute_offset,
1167 const T value) noexcept
1168 {
1169 SBEPP_SIZE_CHECK(
1170 view(addressof_tag{}),
1171 view(end_ptr_tag{}),
1172 absolute_offset,
1173 sizeof(T));
1174 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1175 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1176 }
1177
1178 template<typename T, typename U, endian E, typename View>
1179 SBEPP_CPP20_CONSTEXPR T get_last_value(
1180 const View view,
1181 const std::size_t offset,
1182 const std::size_t absolute_offset) noexcept
1183 {
1184 return get_value<T, U, E>(view, offset, absolute_offset);
1185 }
1186
1187 template<endian E, typename T, typename View>
1188 SBEPP_CPP20_CONSTEXPR void set_last_value(
1189 const View view,
1190 const std::size_t offset,
1191 const std::size_t absolute_offset,
1192 const T value) noexcept
1193 {
1194 return set_value<E>(view, offset, absolute_offset, value);
1195 }
1196
1197 template<typename Res, typename View>
1198 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1199 const View view,
1200 const std::size_t offset,
1201 const std::size_t absolute_offset) noexcept
1202 {
1203 SBEPP_SIZE_CHECK(
1204 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1205 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1206 return {view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1207 }
1208
1209 template<typename Res, typename View>
1210 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1211 const View view,
1212 const std::size_t offset,
1213 const std::size_t absolute_offset) noexcept
1214 {
1215 return get_static_field_view<Res>(view, offset, absolute_offset);
1216 }
1217
1218 template<typename ResView, typename View>
1219 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1220 {
1221 cursor->pointer() =
1222 view(get_level_tag{}) + view(get_block_length_tag{});
1223 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1224
1225 return g;
1226 }
1227
1228 template<typename ResView, typename View>
1229 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1230 {
1231 cursor->pointer() =
1232 view(get_level_tag{}) + view(get_block_length_tag{});
1233 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1234
1235 return d;
1236 }
1237
1238 template<typename ResView, typename View, typename Getter>
1239 SBEPP_CPP20_CONSTEXPR ResView
1240 get_group_view(const View /*view*/, Getter&& getter) noexcept
1241 {
1242 auto res = getter();
1243 cursor->pointer() = res(addressof_tag{});
1244 return res;
1245 }
1246
1247 template<typename ResView, typename View, typename Getter>
1248 SBEPP_CPP20_CONSTEXPR ResView
1249 get_data_view(const View /*view*/, Getter&& getter) noexcept
1250 {
1251 auto res = getter();
1252 cursor->pointer() = res(addressof_tag{});
1253 return res;
1254 }
1255
1256private:
1257 sbepp::cursor<Byte>* cursor{};
1258};
1259
1260template<typename Byte>
1261class dont_move_cursor_wrapper
1262{
1263public:
1264 using byte_type = Byte;
1265
1266 template<typename T>
1267 using result_type = T;
1268
1269 dont_move_cursor_wrapper() = default;
1270
1271 explicit constexpr dont_move_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1272 : cursor{&cursor}
1273 {
1274 }
1275
1276 template<typename T, typename U, endian E, typename View>
1277 SBEPP_CPP20_CONSTEXPR T get_value(
1278 const View view,
1279 const std::size_t offset,
1280 const std::size_t /*absolute_offset*/) noexcept
1281 {
1282 SBEPP_SIZE_CHECK(
1283 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1284 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1285 }
1286
1287 template<endian E, typename T, typename View>
1288 SBEPP_CPP20_CONSTEXPR void set_value(
1289 const View view,
1290 const std::size_t offset,
1291 const std::size_t /*absolute_offset*/,
1292 const T value) noexcept
1293 {
1294 SBEPP_SIZE_CHECK(
1295 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1296 set_primitive<E>(cursor->pointer() + offset, value);
1297 }
1298
1299 template<typename T, typename U, endian E, typename View>
1300 SBEPP_CPP20_CONSTEXPR T get_last_value(
1301 const View view,
1302 const std::size_t offset,
1303 const std::size_t /*absolute_offset*/) noexcept
1304 {
1305 SBEPP_SIZE_CHECK(
1306 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1307 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1308 }
1309
1310 template<endian E, typename T, typename View>
1311 SBEPP_CPP20_CONSTEXPR void set_last_value(
1312 const View view,
1313 const std::size_t offset,
1314 const std::size_t /*absolute_offset*/,
1315 const T value) noexcept
1316 {
1317 SBEPP_SIZE_CHECK(
1318 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1319 set_primitive<E>(cursor->pointer() + offset, value);
1320 }
1321
1322 template<typename Res, typename View>
1323 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1324 const View view,
1325 const std::size_t offset,
1326 const std::size_t /*absolute_offset*/) noexcept
1327 {
1328 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1329 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1330 }
1331
1332 template<typename Res, typename View>
1333 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1334 const View view,
1335 const std::size_t offset,
1336 const std::size_t /*absolute_offset*/) noexcept
1337 {
1338 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1339 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1340 }
1341
1342 template<typename ResView, typename View>
1343 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1344 {
1345 cursor->pointer() =
1346 view(get_level_tag{}) + view(get_block_length_tag{});
1347 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1348
1349 return g;
1350 }
1351
1352 template<typename ResView, typename View>
1353 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1354 {
1355 cursor->pointer() =
1356 view(get_level_tag{}) + view(get_block_length_tag{});
1357 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1358
1359 return d;
1360 }
1361
1362 template<typename ResView, typename View, typename Getter>
1363 SBEPP_CPP20_CONSTEXPR ResView
1364 get_group_view(const View view, Getter&& /*getter*/) noexcept
1365 {
1366 return {cursor->pointer(), view(end_ptr_tag{})};
1367 }
1368
1369 template<typename ResView, typename View, typename Getter>
1370 SBEPP_CPP20_CONSTEXPR ResView
1371 get_data_view(const View view, Getter&& /*getter*/) noexcept
1372 {
1373 return {cursor->pointer(), view(end_ptr_tag{})};
1374 }
1375
1376private:
1377 sbepp::cursor<Byte>* cursor{};
1378};
1379
1380template<typename Byte>
1381class skip_cursor_wrapper
1382{
1383public:
1384 using byte_type = Byte;
1385
1386 template<typename T>
1387 using result_type = void;
1388
1389 skip_cursor_wrapper() = default;
1390
1391 explicit constexpr skip_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1392 : cursor{&cursor}
1393 {
1394 }
1395
1396 template<typename T, typename U, endian E, typename View>
1397 SBEPP_CPP20_CONSTEXPR void get_value(
1398 const View view,
1399 const std::size_t offset,
1400 const std::size_t /*absolute_offset*/) noexcept
1401 {
1402 SBEPP_SIZE_CHECK(
1403 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1404 cursor->pointer() += offset + sizeof(U);
1405 }
1406
1407 template<typename T, typename U, endian E, typename View>
1408 SBEPP_CPP20_CONSTEXPR void get_last_value(
1409 const View view,
1410 const std::size_t offset,
1411 const std::size_t /*absolute_offset*/) noexcept
1412 {
1413 SBEPP_SIZE_CHECK(
1414 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1415 cursor->pointer() =
1416 view(get_level_tag{}) + view(get_block_length_tag{});
1417 }
1418
1419 template<typename Res, typename View>
1420 SBEPP_CPP20_CONSTEXPR void get_static_field_view(
1421 const View view,
1422 const std::size_t offset,
1423 const std::size_t /*absolute_offset*/) noexcept
1424 {
1425 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1426 Res res{cursor->pointer(), view(end_ptr_tag{})};
1427 cursor->pointer() += offset + res(size_bytes_tag{});
1428 }
1429
1430 template<typename Res, typename View>
1431 SBEPP_CPP20_CONSTEXPR void get_last_static_field_view(
1432 const View view,
1433 const std::size_t offset,
1434 const std::size_t /*absolute_offset*/) noexcept
1435 {
1436 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1437 cursor->pointer() =
1438 view(get_level_tag{}) + view(get_block_length_tag{});
1439 }
1440
1441 template<typename ResView, typename View>
1442 SBEPP_CPP20_CONSTEXPR void get_first_group_view(const View view) noexcept
1443 {
1444 cursor->pointer() =
1445 view(get_level_tag{}) + view(get_block_length_tag{});
1446 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1447 cursor->pointer() += g(size_bytes_tag{});
1448 }
1449
1450 template<typename ResView, typename View>
1451 SBEPP_CPP20_CONSTEXPR void get_first_data_view(const View view) noexcept
1452 {
1453 cursor->pointer() =
1454 view(get_level_tag{}) + view(get_block_length_tag{});
1455 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1456 cursor->pointer() += d(size_bytes_tag{});
1457 }
1458
1459 template<typename ResView, typename View, typename Getter>
1460 SBEPP_CPP20_CONSTEXPR void
1461 get_group_view(const View view, Getter&& /*getter*/) noexcept
1462 {
1463 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1464 cursor->pointer() += res(size_bytes_tag{});
1465 }
1466
1467 template<typename ResView, typename View, typename Getter>
1468 SBEPP_CPP20_CONSTEXPR void
1469 get_data_view(const View view, Getter&& /*getter*/) noexcept
1470 {
1471 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1472 cursor->pointer() += res(size_bytes_tag{});
1473 }
1474
1475private:
1476 sbepp::cursor<Byte>* cursor{};
1477};
1478
1479template<typename Cursor, typename T>
1480using cursor_result_type_t =
1481 typename remove_reference_t<Cursor>::template result_type<T>;
1482
1483template<typename Cursor>
1484using cursor_byte_type_t = typename remove_reference_t<Cursor>::byte_type;
1485
1486template<typename MessageByte, typename CursorByte>
1487using enable_if_cursor_compatible_t =
1488 enable_if_convertible_t<MessageByte, CursorByte>;
1489
1490template<typename MessageByte, typename CursorByte>
1491using enable_if_cursor_writeable_t = enable_if_t<
1492 std::is_convertible<MessageByte*, CursorByte*>::value
1493 && !std::is_const<MessageByte>::value && !std::is_const<CursorByte>::value>;
1494} // namespace detail
1495
1506template<typename T>
1507constexpr std::size_t size_bytes(T v) noexcept
1508{
1509 return v(detail::size_bytes_tag{});
1510}
1511
1521template<typename T, typename Byte>
1522constexpr std::size_t size_bytes(T v, cursor<Byte> c) noexcept
1523{
1524 return v(detail::size_bytes_tag{}, c);
1525}
1526
1533template<typename T>
1534constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
1535{
1536 return v(detail::get_header_tag{});
1537}
1538
1545template<typename T>
1546constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
1547{
1548 return v(detail::addressof_tag{});
1549}
1550
1556template<typename View>
1558{
1560 using type = typename std::remove_pointer<decltype(sbepp::addressof(
1561 std::declval<View>()))>::type;
1562};
1563
1565template<typename View>
1567
1572namespace cursor_ops
1573{
1591template<typename Byte>
1592constexpr detail::init_cursor_wrapper<Byte> init(cursor<Byte>& c) noexcept
1593{
1594 return detail::init_cursor_wrapper<Byte>{c};
1595}
1596
1619template<typename Byte>
1620constexpr detail::dont_move_cursor_wrapper<Byte>
1622{
1623 return detail::dont_move_cursor_wrapper<Byte>{c};
1624}
1625
1633template<typename Byte>
1634constexpr detail::init_dont_move_cursor_wrapper<Byte>
1636{
1637 return detail::init_dont_move_cursor_wrapper<Byte>{c};
1638}
1639
1654template<typename Byte>
1655constexpr detail::skip_cursor_wrapper<Byte> skip(cursor<Byte>& c) noexcept
1656{
1657 return detail::skip_cursor_wrapper<Byte>{c};
1658}
1659} // namespace cursor_ops
1660
1661namespace detail
1662{
1663// the only purpose of this class is to implement `is_composite` trait
1665template<typename Byte>
1666class composite_base : public byte_range<Byte>
1667{
1668public:
1669 using byte_range<Byte>::byte_range;
1670 using byte_range<Byte>::operator();
1671};
1672
1674template<typename Byte, typename Header>
1675class message_base : public byte_range<Byte>
1676{
1677public:
1678 using byte_range<Byte>::byte_range;
1679 using byte_range<Byte>::operator();
1680
1681 SBEPP_CPP14_CONSTEXPR Header operator()(get_header_tag) const noexcept
1682 {
1683 Header header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
1684 SBEPP_SIZE_CHECK(
1685 (*this)(addressof_tag{}),
1686 (*this)(end_ptr_tag{}),
1687 0,
1688 sbepp::size_bytes(header));
1689 return header;
1690 }
1691
1692 SBEPP_CPP14_CONSTEXPR Byte* operator()(get_level_tag) const noexcept
1693 {
1694 auto header = (*this)(get_header_tag{});
1695 return header(addressof_tag{}) + header(size_bytes_tag{});
1696 }
1697
1698 constexpr typename std::decay<
1699 decltype(std::declval<Header>().blockLength().value())>::type
1700 operator()(get_block_length_tag) const noexcept
1701 {
1702 return operator()(get_header_tag{}).blockLength().value();
1703 }
1704
1705 template<
1706 typename Byte2,
1707 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
1708 SBEPP_CPP20_CONSTEXPR std::size_t
1709 operator()(size_bytes_tag, cursor<Byte2>& c) const noexcept
1710 {
1711 return c.pointer() - (*this)(addressof_tag{});
1712 }
1713};
1714
1716template<typename Byte, typename BlockLengthType>
1717class entry_base : public byte_range<Byte>
1718{
1719public:
1720 using byte_range<Byte>::operator();
1721
1722 template<typename Byte2, typename BlockLengthType2>
1723 friend class entry_base;
1724
1726 entry_base() = default;
1727
1729 constexpr entry_base(
1730 Byte* ptr, Byte* end, BlockLengthType block_length) noexcept
1731 : byte_range<Byte>{ptr, end}, block_length{block_length}
1732 {
1733 }
1734
1736 constexpr entry_base(
1737 Byte* ptr,
1738 const std::size_t size,
1739 const BlockLengthType block_length) noexcept
1740 : entry_base{ptr, ptr + size, block_length}
1741 {
1742 }
1743
1745 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1746 constexpr entry_base(
1747 cursor<Byte2>& c, Byte* end_ptr, BlockLengthType block_length) noexcept
1748 : entry_base{c.pointer(), end_ptr, block_length}
1749 {
1750 // forwards to the above one for non-empty entries. Empty entries have
1751 // implementation in the derived class which advances cursor up to
1752 // `block_length`.
1753 }
1754
1757 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1758 constexpr entry_base(
1759 const entry_base<Byte2, BlockLengthType>& other) noexcept
1760 : byte_range<Byte>{other}, block_length{other.block_length}
1761 {
1762 }
1763
1764 constexpr BlockLengthType operator()(get_block_length_tag) const noexcept
1765 {
1766 return block_length;
1767 }
1768
1769 constexpr Byte* operator()(get_level_tag) const noexcept
1770 {
1771 return (*this)(addressof_tag{});
1772 }
1773
1774private:
1775 BlockLengthType block_length{};
1776};
1777
1778template<typename Entry>
1779class arrow_proxy
1780{
1781public:
1782 explicit constexpr arrow_proxy(Entry entry) noexcept : entry{entry}
1783 {
1784 }
1785
1786 constexpr const Entry* operator->() const noexcept
1787 {
1788 return &entry;
1789 }
1790
1791private:
1792 Entry entry;
1793};
1794
1795template<
1796 typename Byte,
1797 typename ValueType,
1798 typename IndexType,
1799 typename DifferenceType,
1800 typename BlockLengthType>
1801class forward_iterator
1802{
1803public:
1804 using iterator_category = std::forward_iterator_tag;
1805 using value_type = ValueType;
1806 using reference = value_type;
1807 using difference_type = DifferenceType;
1808 using pointer = arrow_proxy<value_type>;
1809
1810 forward_iterator() = default;
1811
1812 SBEPP_CPP14_CONSTEXPR forward_iterator(
1813 Byte* ptr,
1814 const IndexType index,
1815 const BlockLengthType block_length,
1816 Byte* end) noexcept
1817 : ptr{ptr},
1818 index{index},
1819 block_length{block_length}
1820#if SBEPP_SIZE_CHECKS_ENABLED
1821 ,
1822 end{end}
1823#endif
1824 {
1825 (void)end;
1826 }
1827
1828 constexpr reference operator*() const noexcept
1829 {
1830#if SBEPP_SIZE_CHECKS_ENABLED
1831 return {ptr, end, block_length};
1832#else
1833 return {ptr, nullptr, block_length};
1834#endif
1835 }
1836
1837 constexpr pointer operator->() const noexcept
1838 {
1839 return pointer{operator*()};
1840 }
1841
1842 SBEPP_CPP14_CONSTEXPR forward_iterator& operator++() noexcept
1843 {
1844 SBEPP_SIZE_CHECK(ptr, end, 0, sbepp::size_bytes(operator*()));
1845 ptr += sbepp::size_bytes(operator*());
1846 index++;
1847 return *this;
1848 }
1849
1850 SBEPP_CPP14_CONSTEXPR forward_iterator operator++(int) noexcept
1851 {
1852 auto old = *this;
1853 operator++();
1854 return old;
1855 }
1856
1857 friend constexpr bool operator==(
1858 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1859 {
1860 return lhs.index == rhs.index;
1861 }
1862
1863 friend constexpr bool operator!=(
1864 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1865 {
1866 return lhs.index != rhs.index;
1867 }
1868
1869private:
1870 Byte* ptr{};
1871 IndexType index{};
1872 BlockLengthType block_length{};
1873#if SBEPP_SIZE_CHECKS_ENABLED
1874 Byte* end{};
1875#endif
1876};
1877
1878template<
1879 typename Byte,
1880 typename ValueType,
1881 typename BlockLengthType,
1882 typename DifferenceType,
1883 typename IndexType>
1884class random_access_iterator
1885{
1886public:
1887 using iterator_category = std::random_access_iterator_tag;
1888 using value_type = ValueType;
1889 using reference = value_type;
1890 using difference_type = DifferenceType;
1891 using pointer = arrow_proxy<value_type>;
1892
1893 random_access_iterator() = default;
1894
1895 SBEPP_CPP14_CONSTEXPR random_access_iterator(
1896 Byte* ptr,
1897 const BlockLengthType block_length,
1898 const IndexType index,
1899 Byte* end) noexcept
1900 : ptr{ptr},
1901 block_length{block_length},
1902 index{index}
1903#if SBEPP_SIZE_CHECKS_ENABLED
1904 ,
1905 end{end}
1906#endif
1907 {
1908 (void)end;
1909 }
1910
1911 constexpr reference operator*() const noexcept
1912 {
1913#if SBEPP_SIZE_CHECKS_ENABLED
1914 return {ptr, end, block_length};
1915#else
1916 return {ptr, nullptr, block_length};
1917#endif
1918 }
1919
1920 constexpr pointer operator->() const noexcept
1921 {
1922 return pointer{operator*()};
1923 }
1924
1925 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator++() noexcept
1926 {
1927 SBEPP_SIZE_CHECK(ptr, end, 0, block_length);
1928 ptr += block_length;
1929 index++;
1930 return *this;
1931 }
1932
1933 SBEPP_CPP14_CONSTEXPR random_access_iterator operator++(int) noexcept
1934 {
1935 auto old = *this;
1936 operator++();
1937 return old;
1938 }
1939
1940 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator--() noexcept
1941 {
1942 ptr -= block_length;
1943 index--;
1944 return *this;
1945 }
1946
1947 SBEPP_CPP14_CONSTEXPR random_access_iterator operator--(int) noexcept
1948 {
1949 auto old = *this;
1950 operator--();
1951 return old;
1952 }
1953
1954 SBEPP_CPP14_CONSTEXPR random_access_iterator&
1955 operator+=(difference_type n) noexcept
1956 {
1957 ptr += n * block_length;
1958 index += n;
1959 return *this;
1960 }
1961
1962 SBEPP_CPP14_CONSTEXPR random_access_iterator
1963 operator+(difference_type n) const noexcept
1964 {
1965 auto tmp = *this;
1966 return tmp += n;
1967 }
1968
1969 friend constexpr random_access_iterator
1970 operator+(difference_type n, const random_access_iterator& it) noexcept
1971 {
1972 return it + n;
1973 }
1974
1975 SBEPP_CPP14_CONSTEXPR random_access_iterator&
1976 operator-=(difference_type n) noexcept
1977 {
1978 return *this += -n;
1979 }
1980
1981 SBEPP_CPP14_CONSTEXPR random_access_iterator
1982 operator-(difference_type n) const noexcept
1983 {
1984 auto tmp = *this;
1985 return tmp -= n;
1986 }
1987
1988 constexpr difference_type
1989 operator-(const random_access_iterator& rhs) const noexcept
1990 {
1991 return index - rhs.index;
1992 }
1993
1994 constexpr reference operator[](difference_type n) const noexcept
1995 {
1996 return *(*this + n);
1997 }
1998
1999 friend constexpr bool operator==(
2000 const random_access_iterator& lhs,
2001 const random_access_iterator& rhs) noexcept
2002 {
2003 return lhs.index == rhs.index;
2004 }
2005
2006 friend constexpr bool operator!=(
2007 const random_access_iterator& lhs,
2008 const random_access_iterator& rhs) noexcept
2009 {
2010 return lhs.index != rhs.index;
2011 }
2012
2013 friend constexpr bool operator<(
2014 const random_access_iterator& lhs,
2015 const random_access_iterator& rhs) noexcept
2016 {
2017 return lhs.index < rhs.index;
2018 }
2019
2020 friend constexpr bool operator<=(
2021 const random_access_iterator& lhs,
2022 const random_access_iterator& rhs) noexcept
2023 {
2024 return lhs.index <= rhs.index;
2025 }
2026
2027 friend constexpr bool operator>(
2028 const random_access_iterator& lhs,
2029 const random_access_iterator& rhs) noexcept
2030 {
2031 return lhs.index > rhs.index;
2032 }
2033
2034 friend constexpr bool operator>=(
2035 const random_access_iterator& lhs,
2036 const random_access_iterator& rhs) noexcept
2037 {
2038 return lhs.index >= rhs.index;
2039 }
2040
2041private:
2042 Byte* ptr{};
2043 BlockLengthType block_length{};
2044 // iterator should be index-based instead of just pointer-based to support
2045 // groups with empty entries, i.e. when `block_length == 0`
2046 IndexType index{};
2047#if SBEPP_SIZE_CHECKS_ENABLED
2048 Byte* end{};
2049#endif
2050};
2051
2052template<
2053 typename ValueType,
2054 typename IndexType,
2055 typename CursorType,
2056 typename BlockLengthType,
2057 typename Byte>
2058class input_iterator
2059{
2060public:
2061 using iterator_category = std::input_iterator_tag;
2062 using value_type = ValueType;
2063 using reference = value_type;
2064 using difference_type = typename std::make_signed<IndexType>::type;
2065 using pointer = arrow_proxy<value_type>;
2066
2067 input_iterator() = default;
2068
2069 SBEPP_CPP14_CONSTEXPR input_iterator(
2070 const IndexType index,
2071 CursorType* cursor,
2072 BlockLengthType block_length,
2073 Byte* end) noexcept
2074 : index{index},
2075 cursor{cursor},
2076 block_length{block_length}
2077#if SBEPP_SIZE_CHECKS_ENABLED
2078 ,
2079 end{end}
2080#endif
2081 {
2082 (void)end;
2083 }
2084
2085 constexpr reference operator*() const noexcept
2086 {
2087#if SBEPP_SIZE_CHECKS_ENABLED
2088 return {*cursor, end, block_length};
2089#else
2090 return {*cursor, nullptr, block_length};
2091#endif
2092 }
2093
2094 constexpr pointer operator->() const noexcept
2095 {
2096 return pointer{operator*()};
2097 }
2098
2099 SBEPP_CPP14_CONSTEXPR input_iterator& operator++() noexcept
2100 {
2101 index++;
2102 return *this;
2103 }
2104
2105 SBEPP_CPP14_CONSTEXPR input_iterator operator++(int) noexcept
2106 {
2107 auto old = *this;
2108 operator++();
2109 return old;
2110 }
2111
2112 friend constexpr bool operator==(
2113 const input_iterator& lhs, const input_iterator& rhs) noexcept
2114 {
2115 return lhs.index == rhs.index;
2116 }
2117
2118 friend constexpr bool operator!=(
2119 const input_iterator& lhs, const input_iterator& rhs) noexcept
2120 {
2121 return lhs.index != rhs.index;
2122 }
2123
2124private:
2125 IndexType index{};
2126 CursorType* cursor{};
2127 BlockLengthType block_length{};
2128#if SBEPP_SIZE_CHECKS_ENABLED
2129 Byte* end{};
2130#endif
2131};
2132
2133template<
2134 typename ValueType,
2135 typename IndexType,
2136 typename CursorType,
2137 typename BlockLengthType,
2138 typename Byte>
2139class cursor_range
2140{
2141public:
2142 SBEPP_CPP14_CONSTEXPR cursor_range(
2143 CursorType& cursor,
2144 BlockLengthType block_length,
2145 Byte* end,
2146 IndexType start_pos,
2147 IndexType length) noexcept
2148 : cursor{&cursor},
2149 block_length{block_length},
2150 start_pos{start_pos},
2151#if SBEPP_SIZE_CHECKS_ENABLED
2152 end_ptr{end},
2153#endif
2154 length{length}
2155 {
2156 (void)end;
2157 }
2158
2159 using iterator =
2160 input_iterator<ValueType, IndexType, CursorType, BlockLengthType, Byte>;
2161
2162 constexpr iterator begin() const noexcept
2163 {
2164#if SBEPP_SIZE_CHECKS_ENABLED
2165 return {start_pos, cursor, block_length, end_ptr};
2166#else
2167 return {start_pos, cursor, block_length, nullptr};
2168#endif
2169 }
2170
2171 constexpr iterator end() const noexcept
2172 {
2173#if SBEPP_SIZE_CHECKS_ENABLED
2174 return {
2175 static_cast<IndexType>(start_pos + size()),
2176 cursor,
2177 block_length,
2178 end_ptr};
2179#else
2180 return {
2181 static_cast<IndexType>(start_pos + size()),
2182 cursor,
2183 block_length,
2184 nullptr};
2185#endif
2186 }
2187
2188 constexpr IndexType size() const noexcept
2189 {
2190 return length;
2191 }
2192
2193private:
2194 CursorType* cursor{};
2195 BlockLengthType block_length{};
2196 IndexType start_pos{};
2197#if SBEPP_SIZE_CHECKS_ENABLED
2198 Byte* end_ptr{};
2199#endif
2200 IndexType length{};
2201};
2202
2204template<typename Byte, typename Entry, typename Dimension>
2205class flat_group_base : public byte_range<Byte>
2206{
2207public:
2209 using value_type = Entry;
2213 using sbe_size_type = typename std::decay<
2214 decltype(std::declval<Dimension>().numInGroup())>::type;
2216 using size_type = typename sbe_size_type::value_type;
2218 using difference_type = typename std::make_signed<size_type>::type;
2221 using iterator = random_access_iterator<
2222 Byte,
2223 Entry,
2224 typename std::decay<
2225 decltype(std::declval<Dimension>().blockLength().value())>::type,
2227 size_type>;
2228
2229 using byte_range<Byte>::byte_range;
2230 using byte_range<Byte>::operator();
2231
2232 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2233 {
2234 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2235 SBEPP_SIZE_CHECK(
2236 (*this)(addressof_tag{}),
2237 (*this)(end_ptr_tag{}),
2238 0,
2239 sbepp::size_bytes(header));
2240 return header;
2241 }
2242
2243 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2244 {
2245 auto dimension = (*this)(get_header_tag{});
2246 return sbepp::size_bytes(dimension)
2247 + dimension.numInGroup().value()
2248 * dimension.blockLength().value();
2249 }
2250
2252 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2253 {
2254 return (*this)(get_header_tag{}).numInGroup();
2255 }
2256
2258 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2259 {
2260 return sbe_size().value();
2261 }
2262
2264 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2265 {
2266 (*this)(get_header_tag{}).numInGroup(count);
2267 }
2268
2270 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2271 {
2272 return !size();
2273 }
2274
2276 constexpr static size_type max_size() noexcept
2277 {
2278 return sbe_size_type::max_value();
2279 }
2280
2282 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2283 {
2284 auto dimension = (*this)(get_header_tag{});
2285 return iterator{
2286 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2287 dimension.blockLength().value(),
2288 0,
2289 (*this)(end_ptr_tag{})};
2290 }
2291
2293 constexpr iterator end() const noexcept
2294 {
2295 return iterator{
2296 (*this)(addressof_tag{}) + (*this)(size_bytes_tag{}),
2297 (*this)(get_header_tag{}).blockLength().value(),
2298 size(),
2299 (*this)(end_ptr_tag{})};
2300 }
2301
2304 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
2305 {
2306 SBEPP_ASSERT(pos < size());
2307 return *(begin() + pos);
2308 }
2309
2312 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2313 {
2314 SBEPP_ASSERT(!empty());
2315 return *begin();
2316 }
2317
2320 SBEPP_CPP14_CONSTEXPR reference back() const noexcept
2321 {
2322 SBEPP_ASSERT(!empty());
2323 return *(--end());
2324 }
2325
2328 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2329 {
2330 resize(0);
2331 }
2332
2334 template<typename Byte2>
2335 using cursor_range_t = detail::cursor_range<
2336 value_type,
2337 size_type,
2339 typename std::decay<
2340 decltype(std::declval<Dimension>().blockLength().value())>::type,
2341 Byte>;
2342
2344 template<
2345 typename Byte2,
2346 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2347 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2348 cursor_range(cursor<Byte2>& c) const noexcept
2349 {
2350 return {
2351 c,
2352 (*this)(get_header_tag{}).blockLength().value(),
2353 (*this)(end_ptr_tag{}),
2354 0,
2355 size()};
2356 }
2357
2360 template<
2361 typename Byte2,
2362 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2363 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2364 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2365 {
2366 SBEPP_ASSERT(pos < size());
2367
2368 return {
2369 c,
2370 (*this)(get_header_tag{}).blockLength().value(),
2371 (*this)(end_ptr_tag{}),
2372 pos,
2373 static_cast<size_type>(size() - pos)};
2374 }
2375
2379 template<
2380 typename Byte2,
2381 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2383 cursor<Byte2>& c,
2384 const size_type pos,
2385 const size_type count) const noexcept
2386 {
2387 SBEPP_ASSERT(pos < size());
2388 SBEPP_ASSERT(count <= (size() - pos));
2389
2390 return {
2391 c,
2392 (*this)(get_header_tag{}).blockLength().value(),
2393 (*this)(end_ptr_tag{}),
2394 pos,
2395 count};
2396 }
2397
2399 template<typename Byte2>
2400 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2401
2403 template<
2404 typename Byte2,
2405 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2406 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2407 cursor_begin(cursor<Byte2>& c) const noexcept
2408 {
2409 return cursor_range(c).begin();
2410 }
2411
2413 template<
2414 typename Byte2,
2415 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2416 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2417 cursor_end(cursor<Byte2>& c) const noexcept
2418 {
2419 return cursor_range(c).end();
2420 }
2421
2422 template<typename Visitor, typename Cursor>
2423 SBEPP_CPP14_CONSTEXPR bool
2424 operator()(visit_children_tag, Visitor& v, Cursor& c)
2425 {
2426 for(const auto entry : this->cursor_range(c))
2427 {
2428 if(v.template on_entry(entry, c))
2429 {
2430 return true;
2431 }
2432 }
2433 return false;
2434 }
2435};
2436
2438template<typename Byte, typename Entry, typename Dimension>
2439class nested_group_base : public byte_range<Byte>
2440{
2441public:
2443 using value_type = Entry;
2447 using sbe_size_type = typename std::decay<
2448 decltype(std::declval<Dimension>().numInGroup())>::type;
2450 using size_type = typename sbe_size_type::value_type;
2452 using difference_type = typename std::make_signed<size_type>::type;
2453
2456 using iterator = forward_iterator<
2457 Byte,
2458 Entry,
2459 size_type,
2461 typename std::decay<
2462 decltype(std::declval<Dimension>().blockLength().value())>::type>;
2463
2464 using byte_range<Byte>::byte_range;
2465 using byte_range<Byte>::operator();
2466
2467 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2468 {
2469 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2470 SBEPP_SIZE_CHECK(
2471 (*this)(addressof_tag{}),
2472 (*this)(end_ptr_tag{}),
2473 0,
2474 sbepp::size_bytes(header));
2475 return header;
2476 }
2477
2478 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2479 {
2480 std::size_t size{sbepp::size_bytes((*this)(get_header_tag{}))};
2481 for(const auto entry : *this)
2482 {
2483 size += sbepp::size_bytes(entry);
2484 }
2485
2486 return size;
2487 }
2488
2490 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2491 {
2492 return (*this)(get_header_tag{}).numInGroup();
2493 }
2494
2496 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2497 {
2498 return sbe_size().value();
2499 }
2500
2502 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2503 {
2504 (*this)(get_header_tag{}).numInGroup(count);
2505 }
2506
2508 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2509 {
2510 return !size();
2511 }
2512
2514 constexpr static size_type max_size() noexcept
2515 {
2516 return sbe_size_type::max_value();
2517 }
2518
2520 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2521 {
2522 auto dimension = (*this)(get_header_tag{});
2523 return iterator{
2524 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2525 0,
2526 dimension.blockLength().value(),
2527 (*this)(end_ptr_tag{})};
2528 }
2529
2531 constexpr iterator end() const noexcept
2532 {
2533 return iterator{
2534 nullptr,
2535 (*this)(get_header_tag{}).numInGroup().value(),
2536 (*this)(get_header_tag{}).blockLength().value(),
2537 (*this)(end_ptr_tag{})};
2538 }
2539
2542 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2543 {
2544 SBEPP_ASSERT(!empty());
2545 return *begin();
2546 }
2547
2550 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2551 {
2552 resize(0);
2553 }
2554
2556 template<typename Byte2>
2557 using cursor_range_t = detail::cursor_range<
2558 value_type,
2559 size_type,
2561 typename std::decay<
2562 decltype(std::declval<Dimension>().blockLength().value())>::type,
2563 Byte>;
2564
2566 template<
2567 typename Byte2,
2568 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2569 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2570 cursor_range(cursor<Byte2>& c) const noexcept
2571 {
2572 return {
2573 c,
2574 (*this)(get_header_tag{}).blockLength().value(),
2575 (*this)(end_ptr_tag{}),
2576 0,
2577 size()};
2578 }
2579
2582 template<
2583 typename Byte2,
2584 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2585 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2586 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2587 {
2588 SBEPP_ASSERT(pos < size());
2589
2590 return {
2591 c,
2592 (*this)(get_header_tag{}).blockLength().value(),
2593 (*this)(end_ptr_tag{}),
2594 pos,
2595 static_cast<size_type>(size() - pos)};
2596 }
2597
2601 template<
2602 typename Byte2,
2603 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2605 cursor<Byte2>& c,
2606 const size_type pos,
2607 const size_type count) const noexcept
2608 {
2609 SBEPP_ASSERT(pos < size());
2610 SBEPP_ASSERT(count <= (size() - pos));
2611
2612 return {
2613 c,
2614 (*this)(get_header_tag{}).blockLength().value(),
2615 (*this)(end_ptr_tag{}),
2616 pos,
2617 count};
2618 }
2619
2621 template<typename Byte2>
2622 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2623
2625 template<
2626 typename Byte2,
2627 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2628 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2629 cursor_begin(cursor<Byte2>& c) const noexcept
2630 {
2631 return cursor_range(c).begin();
2632 }
2633
2635 template<
2636 typename Byte2,
2637 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2638 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2639 cursor_end(cursor<Byte2>& c) const noexcept
2640 {
2641 return cursor_range(c).end();
2642 }
2643
2644 template<typename Visitor, typename Cursor>
2645 SBEPP_CPP14_CONSTEXPR bool
2646 operator()(visit_children_tag, Visitor& v, Cursor& c)
2647 {
2648 for(const auto entry : this->cursor_range(c))
2649 {
2650 if(v.template on_entry(entry, c))
2651 {
2652 return true;
2653 }
2654 }
2655 return false;
2656 }
2657};
2658
2661template<typename T>
2663{
2664public:
2666 bitset_base() = default;
2667
2669 explicit constexpr bitset_base(T value) noexcept : bits{value}
2670 {
2671 }
2672
2674 SBEPP_CPP14_CONSTEXPR T& operator*() noexcept
2675 {
2676 return bits;
2677 }
2678
2680 constexpr T operator*() const noexcept
2681 {
2682 return bits;
2683 }
2684
2685 constexpr bool
2686 operator()(get_bit_tag, const choice_index_t n) const noexcept
2687 {
2688 return bits & (1 << n);
2689 }
2690
2691 SBEPP_CPP14_CONSTEXPR void
2692 operator()(set_bit_tag, const choice_index_t n, const bool b) noexcept
2693 {
2694 bits = ((bits & ~(1 << n)) | (b << n));
2695 }
2696
2698 constexpr friend bool
2699 operator==(const bitset_base& lhs, const bitset_base& rhs) noexcept
2700 {
2701 return *lhs == *rhs;
2702 }
2703
2705 constexpr friend bool
2706 operator!=(const bitset_base& lhs, const bitset_base& rhs) noexcept
2707 {
2708 return *lhs != *rhs;
2709 }
2710
2711private:
2712 T bits{};
2713};
2714
2715template<typename View, typename = void_t<>>
2716struct has_get_header : std::false_type
2717{
2718};
2719
2720template<typename View>
2721struct has_get_header<
2722 View,
2723 void_t<decltype(sbepp::get_header(std::declval<View>()))>> : std::true_type
2724{
2725};
2726
2727template<
2728 typename View,
2729 typename = detail::enable_if_t<detail::has_get_header<View>::value>>
2730constexpr std::size_t get_header_size(View view) noexcept
2731{
2733}
2734
2735template<
2736 typename View,
2737 typename = detail::enable_if_t<!detail::has_get_header<View>::value>,
2738 typename = int>
2739constexpr std::size_t get_header_size(View) noexcept
2740{
2741 return 0;
2742}
2743} // namespace detail
2744
2752template<typename Enum>
2753constexpr typename std::underlying_type<Enum>::type
2754 to_underlying(Enum e) noexcept
2755{
2756 return static_cast<typename std::underlying_type<Enum>::type>(e);
2757}
2758
2772template<typename View>
2773SBEPP_CPP14_CONSTEXPR cursor<byte_type_t<View>> init_cursor(View view) noexcept
2774{
2776 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2777 return c;
2778}
2779
2794template<typename View>
2795SBEPP_CPP14_CONSTEXPR cursor<typename std::add_const<byte_type_t<View>>::type>
2796 init_const_cursor(View view) noexcept
2797{
2799 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2800 return c;
2801}
2802
2808{
2809 explicit default_init_t() = default;
2810};
2811
2817SBEPP_CPP17_INLINE_VAR constexpr default_init_t default_init{};
2818
2821enum class eos_null
2822{
2825 none,
2829 single,
2831 all
2832};
2833
2834namespace detail
2835{
2836template<typename From, typename To>
2837struct copy_cv_qualifiers
2838{
2839 using copy_const_t = typename std::
2840 conditional<std::is_const<From>::value, const To, To>::type;
2841
2842 using type = typename std::conditional<
2843 std::is_volatile<From>::value,
2844 volatile copy_const_t,
2845 copy_const_t>::type;
2846};
2847
2848template<typename From, typename To>
2849using apply_cv_qualifiers_t = typename copy_cv_qualifiers<From, To>::type;
2850
2851#if SBEPP_HAS_RANGES
2852template<typename R>
2853using is_range = std::bool_constant<std::ranges::range<R>>;
2854#else
2855template<typename R, typename = void_t<>>
2856struct is_range : std::false_type
2857{
2858};
2859
2860template<typename R>
2861struct is_range<
2862 R,
2863 void_t<
2864 decltype(std::begin(std::declval<R>())),
2865 decltype(std::end(std::declval<R>()))>> : std::true_type
2866{
2867};
2868#endif
2869
2870constexpr bool is_constant_evaluated() noexcept
2871{
2872 // it's possible to use `__builtin_is_constant_evaluated` with lower C++
2873 // versions but I see no reason for this since it's only used for
2874 // `assign_string` and other accessors are not be `constexpr` until C++20
2875#if SBEPP_HAS_IS_CONSTANT_EVALUATED
2876 return std::is_constant_evaluated();
2877#else
2878 return false;
2879#endif
2880}
2881
2882inline SBEPP_CPP20_CONSTEXPR std::size_t string_length(const char* str) noexcept
2883{
2884 if(is_constant_evaluated())
2885 {
2886 std::size_t length{};
2887 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2888 for(; *str != '\0'; str++, length++)
2889 {
2890 }
2891
2892 return length;
2893 }
2894 else
2895 {
2896 return std::strlen(str);
2897 }
2898}
2899
2907template<typename Byte, typename Value, std::size_t N, typename Tag>
2909{
2910public:
2913 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
2915 using value_type = Value;
2917 using size_type = std::size_t;
2919 using difference_type = std::ptrdiff_t;
2927 using reverse_iterator = std::reverse_iterator<iterator>;
2929 using tag = Tag;
2930
2931 using detail::byte_range<Byte>::byte_range;
2932 using detail::byte_range<Byte>::operator();
2933
2934 constexpr std::size_t operator()(detail::size_bytes_tag) const noexcept
2935 {
2936 return size();
2937 }
2938
2941 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
2942 {
2943 SBEPP_ASSERT(pos < size());
2944 return data()[pos];
2945 }
2946
2948 constexpr reference front() const noexcept
2949 {
2950 return *data();
2951 }
2952
2954 constexpr reference back() const noexcept
2955 {
2956 return data()[size() - 1];
2957 }
2958
2960 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
2961 {
2962 // it would be nice to use `reinterpret_cast` here but it's not allowed
2963 // in constexpr context
2964 SBEPP_SIZE_CHECK(
2965 (*this)(detail::addressof_tag{}),
2966 (*this)(detail::end_ptr_tag{}),
2967 0,
2968 N);
2969 return (pointer)(*this)(detail::addressof_tag{}); // NOLINT
2970 }
2971
2973 SBEPP_CPP17_NODISCARD static constexpr bool empty() noexcept
2974 {
2975 return !size();
2976 }
2977
2979 static constexpr size_type size() noexcept
2980 {
2981 return N;
2982 }
2983
2985 static constexpr size_type max_size() noexcept
2986 {
2987 return size();
2988 }
2989
2991 constexpr iterator begin() const noexcept
2992 {
2993 return data();
2994 }
2995
2997 constexpr iterator end() const noexcept
2998 {
2999 return data() + size();
3000 }
3001
3003 constexpr reverse_iterator rbegin() const noexcept
3004 {
3005 return reverse_iterator{end()};
3006 }
3007
3009 constexpr reverse_iterator rend() const noexcept
3010 {
3011 return reverse_iterator{begin()};
3012 }
3013
3026 raw() const noexcept
3027 {
3029 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3030 }
3031
3038 SBEPP_CPP20_CONSTEXPR std::size_t strlen() const noexcept
3039 {
3040 if(is_constant_evaluated())
3041 {
3042 return string_length(data());
3043 }
3044 else
3045 {
3046 const auto first_null = static_cast<const value_type*>(
3047 std::memchr(data(), '\0', size()));
3048 if(first_null)
3049 {
3050 return first_null - data();
3051 }
3052
3053 return size();
3054 }
3055 }
3056
3063 SBEPP_CPP20_CONSTEXPR std::size_t strlen_r() const noexcept
3064 {
3065 const auto last_non_null = std::find_if(
3066 rbegin(),
3067 rend(),
3068 [](const value_type value)
3069 {
3070 return value != '\0';
3071 });
3072 return size() - (last_non_null - rbegin());
3073 }
3074
3086 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3087 SBEPP_CPP20_CONSTEXPR iterator assign_string(
3088 const char* str, const eos_null eos_mode = eos_null::all) const noexcept
3089 {
3090 SBEPP_ASSERT(str != nullptr);
3091 const auto length = string_length(str);
3092 SBEPP_ASSERT(length <= size());
3093 const auto eos_pos = std::copy_n(str, length, begin());
3094 pad(eos_mode, eos_pos);
3095 return eos_pos;
3096 }
3097
3110 template<
3111 typename R,
3112 typename =
3113 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3114 SBEPP_CPP20_CONSTEXPR iterator
3115 assign_string(R&& r, const eos_null eos_mode = eos_null::all) const
3116 {
3117 auto eos_pos = assign_range(std::forward<R>(r));
3118 pad(eos_mode, eos_pos);
3119 return eos_pos;
3120 }
3121
3131 template<
3132 typename R,
3133 typename =
3134 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3135 SBEPP_CPP20_CONSTEXPR iterator assign_range(R&& r) const
3136 {
3137#if SBEPP_HAS_RANGES
3138 auto res = std::ranges::copy(std::forward<R>(r), begin()).out;
3139#else
3140 auto res = std::copy(std::begin(r), std::end(r), begin());
3141#endif
3142 SBEPP_ASSERT(res <= end());
3143 return res;
3144 }
3145
3151 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3152 SBEPP_CPP20_CONSTEXPR void fill(const value_type value) const noexcept
3153 {
3154 std::fill_n(begin(), size(), value);
3155 }
3156
3165 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3166 SBEPP_CPP20_CONSTEXPR iterator
3167 assign(size_type count, const value_type value) const noexcept
3168 {
3169 SBEPP_ASSERT(count <= size());
3170 return std::fill_n(begin(), count, value);
3171 }
3172
3176 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3177 SBEPP_CPP20_CONSTEXPR iterator assign(InputIt first, InputIt last) const
3178 {
3179 const auto last_out = std::copy(first, last, begin());
3180 SBEPP_ASSERT(static_cast<size_type>(last_out - begin()) <= size());
3181 return last_out;
3182 }
3183
3191 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3192 SBEPP_CPP20_CONSTEXPR iterator
3193 assign(std::initializer_list<value_type> ilist) const noexcept
3194 {
3195 SBEPP_ASSERT(ilist.size() <= size());
3196 return assign(std::begin(ilist), std::end(ilist));
3197 }
3198
3199private:
3200 SBEPP_CPP20_CONSTEXPR void
3201 pad(const eos_null mode, iterator eos_pos) const noexcept
3202 {
3203 if(mode == eos_null::all)
3204 {
3205 std::fill(eos_pos, end(), '\0');
3206 }
3207 else if(mode == eos_null::single)
3208 {
3209 if(eos_pos != end())
3210 {
3211 *eos_pos = '\0';
3212 }
3213 }
3214 else
3215 {
3216 SBEPP_ASSERT(mode == eos_null::none);
3217 return;
3218 }
3219 }
3220};
3221
3229template<typename Byte, typename Value, typename Length, endian E>
3231{
3232public:
3233 static_assert(
3234 std::is_unsigned<typename Length::value_type>::value,
3235 "Length must be unsigned");
3236
3239 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
3241 using value_type = Value;
3243 using sbe_size_type = Length;
3245 using size_type = typename sbe_size_type::value_type;
3247 using difference_type = std::ptrdiff_t;
3255 using reverse_iterator = std::reverse_iterator<iterator>;
3256
3257 using detail::byte_range<Byte>::byte_range;
3258 using detail::byte_range<Byte>::operator();
3259
3261 constexpr iterator begin() const noexcept
3262 {
3263 return data_checked();
3264 }
3265
3267 SBEPP_CPP20_CONSTEXPR iterator end() const noexcept
3268 {
3269 return begin() + size();
3270 }
3271
3273 SBEPP_CPP20_CONSTEXPR reverse_iterator rbegin() const noexcept
3274 {
3275 return reverse_iterator{end()};
3276 }
3277
3279 constexpr reverse_iterator rend() const noexcept
3280 {
3281 return reverse_iterator{begin()};
3282 }
3283
3286 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
3287 {
3288 SBEPP_ASSERT(!empty());
3289 return *data();
3290 }
3291
3294 SBEPP_CPP20_CONSTEXPR reference back() const noexcept
3295 {
3296 SBEPP_ASSERT(!empty());
3297 return *(data() + size() - 1);
3298 }
3299
3307 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3308 {
3309 return data_checked();
3310 }
3311
3314 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3315 {
3316 SBEPP_ASSERT(pos < size());
3317 return *(data() + pos);
3318 }
3319
3321 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
3322 {
3323 return detail::get_value<size_type, size_type, E>(*this, 0);
3324 }
3325
3327 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
3328 {
3329 return sbe_size().value();
3330 }
3331
3333 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
3334 {
3335 return !size();
3336 }
3337
3339 constexpr static size_type max_size() noexcept
3340 {
3341 return sbe_size_type::max_value();
3342 }
3343
3345 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3346 SBEPP_CPP20_CONSTEXPR void clear() const noexcept
3347 {
3348 resize(0, default_init);
3349 }
3350
3352 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3353 SBEPP_CPP20_CONSTEXPR void resize(size_type count) const noexcept
3354 {
3355 const auto old_size = size();
3356 resize(count, default_init);
3357 if(count > old_size)
3358 {
3359 for(auto i = old_size; i != count; i++)
3360 {
3361 operator[](i) = {};
3362 }
3363 }
3364 }
3365
3367 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3368 SBEPP_CPP20_CONSTEXPR void
3369 resize(size_type count, value_type value) const noexcept
3370 {
3371 const auto old_size = size();
3372 resize(count, default_init);
3373 if(count > old_size)
3374 {
3375 for(auto i = old_size; i != count; i++)
3376 {
3377 operator[](i) = value;
3378 }
3379 }
3380 }
3381
3383 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3384 SBEPP_CPP20_CONSTEXPR void
3386 {
3387 // can't use `detail::set_value()` here because its size check checks
3388 // only `sizeof(T)`, here we need `sizeof(size_type) + count`
3389 SBEPP_SIZE_CHECK(
3390 (*this)(addressof_tag{}),
3391 (*this)(end_ptr_tag{}),
3392 0,
3393 sizeof(size_type) + count);
3394 set_primitive<E>((*this)(addressof_tag{}), count);
3395 }
3396
3398 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3399 SBEPP_CPP20_CONSTEXPR void push_back(value_type value) const noexcept
3400 {
3401 const auto current_size = size();
3402 resize(current_size + 1, default_init);
3403 (*this)[current_size] = value;
3404 }
3405
3407 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3408 SBEPP_CPP20_CONSTEXPR void pop_back() const noexcept
3409 {
3410 SBEPP_ASSERT(!empty());
3411 resize(size() - 1, default_init);
3412 }
3413
3415 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3416 SBEPP_CPP20_CONSTEXPR iterator erase(iterator pos) const noexcept
3417 {
3418 SBEPP_ASSERT(pos >= begin() && pos < end());
3419 std::copy(pos + 1, end(), pos);
3420 resize(size() - 1, default_init);
3421 return pos;
3422 }
3423
3425 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3426 SBEPP_CPP20_CONSTEXPR iterator
3427 erase(iterator first, iterator last) const noexcept
3428 {
3429 SBEPP_ASSERT(first >= begin() && last < end());
3430 std::copy(last, end(), first);
3431 resize(size() - (last - first), default_init);
3432 return first;
3433 }
3434
3436 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3437 SBEPP_CPP20_CONSTEXPR iterator
3438 insert(iterator pos, const value_type value) const noexcept
3439 {
3440 SBEPP_ASSERT(pos >= begin() && pos <= end());
3441 const auto old_end = end();
3442 resize(size() + 1, default_init);
3443 std::copy_backward(pos, old_end, end());
3444 *pos = value;
3445 return pos;
3446 }
3447
3449 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3450 SBEPP_CPP20_CONSTEXPR iterator insert(
3451 iterator pos, size_type count, const value_type value) const noexcept
3452 {
3453 SBEPP_ASSERT(pos >= begin() && pos <= end());
3454 const auto old_end = end();
3455 resize(size() + count, default_init);
3456 std::copy_backward(pos, old_end, end());
3457 std::fill_n(pos, count, value);
3458 return pos;
3459 }
3460
3462 template<
3463 typename InputIt,
3464 typename = detail::enable_if_t<
3465 !std::is_const<Byte>::value
3466 && std::is_convertible<
3467 typename std::iterator_traits<InputIt>::iterator_category,
3468 std::input_iterator_tag>::value>>
3469 SBEPP_CPP14_CONSTEXPR iterator
3470 insert(iterator pos, InputIt first, InputIt last) const
3471 {
3472 SBEPP_ASSERT(pos >= begin() && pos <= end());
3473 using category_t =
3474 typename std::iterator_traits<InputIt>::iterator_category;
3475 return insert_impl(pos, first, last, category_t{});
3476 }
3477
3479 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3480 constexpr iterator insert(
3481 iterator pos, std::initializer_list<value_type> ilist) const noexcept
3482 {
3483 return insert(pos, std::begin(ilist), std::end(ilist));
3484 }
3485
3488 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3489 SBEPP_CPP20_CONSTEXPR void
3490 assign(size_type count, const value_type value) const noexcept
3491 {
3492 resize(count, default_init);
3493 std::fill_n(begin(), count, value);
3494 }
3495
3498 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3499 SBEPP_CPP20_CONSTEXPR void assign(InputIt first, InputIt last) const
3500 {
3501 auto begin = data_unchecked();
3502 const auto new_end = std::copy(first, last, begin);
3503 resize(new_end - begin, default_init);
3504 }
3505
3508 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3509 SBEPP_CPP20_CONSTEXPR void
3510 assign(std::initializer_list<value_type> ilist) const noexcept
3511 {
3512 SBEPP_SIZE_CHECK(
3513 (*this)(detail::addressof_tag{}),
3514 (*this)(detail::end_ptr_tag{}),
3515 0,
3516 sizeof(size_type) + ilist.size());
3517 assign(std::begin(ilist), std::end(ilist));
3518 }
3519
3527 raw() const noexcept
3528 {
3530 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3531 }
3532
3533 SBEPP_CPP20_CONSTEXPR std::size_t
3534 operator()(detail::size_bytes_tag) const noexcept
3535 {
3536 return sizeof(size_type) + size();
3537 }
3538
3545 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3546 SBEPP_CPP20_CONSTEXPR void assign_string(const char* str) const noexcept
3547 {
3548 SBEPP_ASSERT(str != nullptr);
3549 const auto length = string_length(str);
3550 resize(length, default_init);
3551 std::copy_n(str, length, begin());
3552 }
3553
3561 template<
3562 typename R,
3563 typename =
3564 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3565 SBEPP_CPP20_CONSTEXPR void assign_range(R&& r) const
3566 {
3567 const auto begin = data_unchecked();
3568#if SBEPP_HAS_RANGES
3569 const auto new_end = std::ranges::copy(std::forward<R>(r), begin).out;
3570#else
3571 const auto new_end = std::copy(std::begin(r), std::end(r), begin);
3572#endif
3573 resize(new_end - begin, default_init);
3574 }
3575
3576private:
3577 SBEPP_CPP14_CONSTEXPR pointer data_checked() const noexcept
3578 {
3579 SBEPP_SIZE_CHECK(
3580 (*this)(detail::addressof_tag{}),
3581 (*this)(detail::end_ptr_tag{}),
3582 0,
3583 sizeof(size_type) + size());
3584 return data_unchecked();
3585 }
3586
3587 SBEPP_CPP14_CONSTEXPR pointer data_unchecked() const noexcept
3588 {
3589 SBEPP_SIZE_CHECK(
3590 (*this)(detail::addressof_tag{}),
3591 (*this)(detail::end_ptr_tag{}),
3592 0,
3593 sizeof(size_type));
3594 // cast is conditionally required here when `Byte` is different type
3595 // from `Value`. `reinterpret_cast` is not allowed in constexpr context
3596 // even when it's an identity cast. On the other hand, C-style cast
3597 // is allowed in constexpr context when it renders to an identity cast
3598 // which effectively makes this and other functions conditionally
3599 // `constexpr` when `Byte` is equal to `Value`.
3600 // NOLINTNEXTLINE: see above
3601 return (pointer)((*this)(detail::addressof_tag{}) + sizeof(size_type));
3602 }
3603
3604 template<typename It>
3605 SBEPP_CPP14_CONSTEXPR iterator insert_impl(
3606 iterator pos, It first, It last, std::input_iterator_tag) const
3607 {
3608 auto out = pos;
3609 for(; first != last; ++first, ++out)
3610 {
3611 insert(out, *first);
3612 }
3613
3614 return pos;
3615 }
3616
3617 template<typename It>
3618 SBEPP_CPP20_CONSTEXPR iterator insert_impl(
3619 iterator pos, It first, It last, std::forward_iterator_tag) const
3620 {
3621 const auto in_size = std::distance(first, last);
3622 auto old_end = end();
3623 resize(size() + in_size, default_init);
3624 std::copy_backward(pos, old_end, end());
3625 std::copy(first, last, pos);
3626 return pos;
3627 }
3628};
3629} // namespace detail
3630
3633{
3634 explicit constexpr nullopt_t(int)
3635 {
3636 }
3637};
3638
3644SBEPP_CPP17_INLINE_VAR constexpr nullopt_t nullopt{0};
3645
3646namespace detail
3647{
3648// see `optional_base` note about explicit `alignas`
3652template<typename T, typename Derived>
3653class alignas(T) required_base
3654{
3655public:
3657 using value_type = T;
3658
3660 required_base() = default;
3661
3663 // NOLINTNEXTLINE: it should be implicit
3664 constexpr required_base(value_type val) noexcept : val{val}
3665 {
3666 }
3667
3669 constexpr value_type value() const noexcept
3670 {
3671 return **this;
3672 }
3673
3675 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3676 {
3677 return val;
3678 }
3679
3681 constexpr value_type operator*() const noexcept
3682 {
3683 return val;
3684 }
3685
3688 constexpr bool in_range() const noexcept
3689 {
3690 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3691 }
3692
3696#ifdef SBEPP_DOXYGEN
3698 friend auto
3699 operator<=>(const required_base&, const required_base&) = default;
3700#endif
3701
3702#if SBEPP_HAS_THREE_WAY_COMPARISON
3703 friend auto
3704 operator<=>(const required_base&, const required_base&) = default;
3705#else
3707 constexpr friend bool
3708 operator==(const required_base& lhs, const required_base& rhs) noexcept
3709 {
3710 return *lhs == *rhs;
3711 }
3712
3714 constexpr friend bool
3715 operator!=(const required_base& lhs, const required_base& rhs) noexcept
3716 {
3717 return *lhs != *rhs;
3718 }
3719
3721 constexpr friend bool
3722 operator<(const required_base& lhs, const required_base& rhs) noexcept
3723 {
3724 return *lhs < *rhs;
3725 }
3726
3728 constexpr friend bool
3729 operator<=(const required_base& lhs, const required_base& rhs) noexcept
3730 {
3731 return *lhs <= *rhs;
3732 }
3733
3735 constexpr friend bool
3736 operator>(const required_base& lhs, const required_base& rhs) noexcept
3737 {
3738 return *lhs > *rhs;
3739 }
3740
3742 constexpr friend bool
3743 operator>=(const required_base& lhs, const required_base& rhs) noexcept
3744 {
3745 return *lhs >= *rhs;
3746 }
3747#endif
3749
3750private:
3751 value_type val{};
3752};
3753
3754// old compilers might generate wrong alignment for classes which contain
3755// `double` member. To overcome this, explicit alignment is provided.
3759template<typename T, typename Derived>
3760class alignas(T) optional_base
3761{
3762public:
3764 using value_type = T;
3765
3767 optional_base() = default;
3768
3770 // NOLINTNEXTLINE: it's intentionally implicit
3771 constexpr optional_base(nullopt_t) noexcept : optional_base{}
3772 {
3773 }
3774
3776 // NOLINTNEXTLINE: it's intentionally implicit
3777 constexpr optional_base(value_type val) noexcept : val{val}
3778 {
3779 }
3780
3782 constexpr value_type value() const noexcept
3783 {
3784 return **this;
3785 }
3786
3788 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3789 {
3790 return val;
3791 }
3792
3794 constexpr value_type operator*() const noexcept
3795 {
3796 return val;
3797 }
3798
3801 constexpr bool in_range() const noexcept
3802 {
3803 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3804 }
3805
3807 SBEPP_CPP14_CONSTEXPR value_type value_or(T default_value) const noexcept
3808 {
3809 if(*this)
3810 {
3811 return value();
3812 }
3813 return default_value;
3814 }
3815
3817 constexpr bool has_value() const noexcept
3818 {
3819 return (val != Derived::null_value());
3820 }
3821
3823 constexpr explicit operator bool() const noexcept
3824 {
3825 return has_value();
3826 }
3827
3834
3836 constexpr friend bool
3837 operator==(const optional_base& lhs, const optional_base& rhs) noexcept
3838 {
3839 return *lhs == *rhs;
3840 }
3841
3842#ifdef SBEPP_DOXYGEN
3844 constexpr friend std::strong_ordering operator<=>(
3845 const optional_base& lhs, const optional_base& rhs) noexcept;
3846#endif
3847
3848#if SBEPP_HAS_THREE_WAY_COMPARISON
3849 constexpr friend std::strong_ordering
3850 operator<=>(const optional_base& lhs, const optional_base& rhs) noexcept
3851 {
3852 if(lhs && rhs)
3853 {
3854 return *lhs <=> *rhs;
3855 }
3856 return lhs.has_value() <=> rhs.has_value();
3857 }
3858#else
3859
3861 constexpr friend bool
3862 operator!=(const optional_base& lhs, const optional_base& rhs) noexcept
3863 {
3864 return *lhs != *rhs;
3865 }
3866
3868 constexpr friend bool
3869 operator<(const optional_base& lhs, const optional_base& rhs) noexcept
3870 {
3871 return rhs && (!lhs || (*lhs < *rhs));
3872 }
3873
3875 constexpr friend bool
3876 operator<=(const optional_base& lhs, const optional_base& rhs) noexcept
3877 {
3878 return !lhs || (rhs && (*lhs <= *rhs));
3879 }
3880
3882 constexpr friend bool
3883 operator>(const optional_base& lhs, const optional_base& rhs) noexcept
3884 {
3885 return lhs && (!rhs || (*lhs > *rhs));
3886 }
3887
3889 constexpr friend bool
3890 operator>=(const optional_base& lhs, const optional_base& rhs) noexcept
3891 {
3892 return !rhs || (lhs && (*lhs >= *rhs));
3893 }
3894#endif
3896
3897private:
3898 value_type val{Derived::null_value()};
3899};
3900} // namespace detail
3901
3916template<typename Message>
3917constexpr auto fill_message_header(Message m) noexcept
3918 -> decltype(m(detail::fill_message_header_tag{}))
3919{
3920 return m(detail::fill_message_header_tag{});
3921}
3922
3936template<typename Group, typename Size>
3937constexpr auto fill_group_header(Group g, Size num_in_group) noexcept
3938 -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
3939{
3940 return g(detail::fill_group_header_tag{}, num_in_group);
3941}
3942
3956template<typename T>
3957class type_traits;
3958
3959#ifdef SBEPP_DOXYGEN
3960template<typename T>
3962{
3963public:
3965 using primitive_type = PrimitiveType;
3966
3968 using value_type = ValueType;
3969
3975 template<typename Byte>
3976 using value_type = ArrayType<Byte>;
3977
3979 static constexpr const char* name() noexcept;
3980
3982 static constexpr const char* description() noexcept;
3983
3985 static constexpr field_presence presence() noexcept;
3986
3991 static constexpr primitive_type min_value() noexcept;
3992
3997 static constexpr primitive_type max_value() noexcept;
3998
4003 static constexpr primitive_type null_value() noexcept;
4004
4006 static constexpr length_t length() noexcept;
4007
4012 static constexpr offset_t offset() noexcept;
4013
4015 static constexpr const char* semantic_type() noexcept;
4016
4018 static constexpr version_t since_version() noexcept;
4019
4022 static constexpr version_t deprecated() noexcept;
4023
4025 static constexpr const char* character_encoding() noexcept;
4026};
4027#endif
4028
4037template<typename T>
4038class schema_traits;
4039
4040#ifdef SBEPP_DOXYGEN
4041template<typename T>
4043{
4044public:
4046 static constexpr const char* package() noexcept;
4048 static constexpr schema_id_t id() noexcept;
4050 static constexpr version_t version() noexcept;
4052 static constexpr const char* semantic_version() noexcept;
4054 static constexpr endian byte_order() noexcept;
4056 static constexpr const char* description() noexcept;
4062 template<typename Byte>
4063 using header_type = HeaderComposite<Byte>;
4065 using header_type_tag = HeaderTypeTag;
4066};
4067#endif
4068
4077template<typename T>
4078class enum_traits;
4079
4080#ifdef SBEPP_DOXYGEN
4081template<typename T>
4083{
4084public:
4086 static constexpr const char* name() noexcept;
4088 static constexpr const char* description() noexcept;
4090 using encoding_type = EncodingType;
4095 static constexpr offset_t offset() noexcept;
4097 static constexpr version_t since_version() noexcept;
4100 static constexpr version_t deprecated() noexcept;
4102 using value_type = ScopedEnumType;
4103};
4104#endif
4105
4114template<typename T>
4115class enum_value_traits;
4116
4117#ifdef SBEPP_DOXYGEN
4118template<typename T>
4120{
4121public:
4123 static constexpr const char* name() noexcept;
4125 static constexpr const char* description() noexcept;
4127 static constexpr version_t since_version() noexcept;
4130 static constexpr version_t deprecated() noexcept;
4132 static constexpr ScopedEnumType value() noexcept;
4133};
4134#endif
4135
4144template<typename T>
4145class set_traits;
4146
4147#ifdef SBEPP_DOXYGEN
4148template<typename T>
4150{
4151public:
4153 static constexpr const char* name() noexcept;
4155 static constexpr const char* description() noexcept;
4157 static constexpr version_t since_version() noexcept;
4160 static constexpr version_t deprecated() noexcept;
4162 using encoding_type = EncodingType;
4167 static constexpr offset_t offset() noexcept;
4169 using value_type = SetType;
4170};
4171#endif
4172
4181template<typename T>
4182class set_choice_traits;
4183
4184#ifdef SBEPP_DOXYGEN
4185template<typename T>
4187{
4188public:
4190 static constexpr const char* name() noexcept;
4192 static constexpr const char* description() noexcept;
4194 static constexpr version_t since_version() noexcept;
4197 static constexpr version_t deprecated() noexcept;
4199 static constexpr choice_index_t index() noexcept;
4200};
4201#endif
4202
4211template<typename T>
4212class composite_traits;
4213
4214#ifdef SBEPP_DOXYGEN
4215template<typename T>
4217{
4218public:
4220 static constexpr const char* name() noexcept;
4222 static constexpr const char* description() noexcept;
4227 static constexpr offset_t offset() noexcept;
4229 static constexpr const char* semantic_type() noexcept;
4231 static constexpr version_t since_version() noexcept;
4233 // !schema
4234 static constexpr version_t deprecated() noexcept;
4240 template<typename Byte>
4241 using value_type = CompositeType<Byte>;
4243 static constexpr std::size_t size_bytes() noexcept;
4244};
4245#endif
4246
4255template<typename T>
4256class message_traits;
4257
4258#ifdef SBEPP_DOXYGEN
4259template<typename T>
4261{
4262public:
4264 static constexpr const char* name() noexcept;
4266 static constexpr const char* description() noexcept;
4268 static constexpr message_id_t id() noexcept;
4270 static constexpr block_length_t block_length() noexcept;
4272 static constexpr const char* semantic_type() noexcept;
4274 static constexpr version_t since_version() noexcept;
4277 static constexpr version_t deprecated() noexcept;
4283 template<typename Byte>
4284 using value_type = MessageType<Byte>;
4286 using schema_tag = SchemaTag;
4287
4365 static constexpr std::size_t size_bytes(...) noexcept;
4366};
4367#endif
4368
4377template<typename T>
4378class field_traits;
4379
4380#ifdef SBEPP_DOXYGEN
4381template<typename T>
4383{
4384public:
4386 static constexpr const char* name() noexcept;
4388 static constexpr member_id_t id() noexcept;
4390 static constexpr const char* description() noexcept;
4396 static constexpr field_presence presence() noexcept;
4398 static constexpr offset_t offset() noexcept;
4400 static constexpr version_t since_version() noexcept;
4403 static constexpr version_t deprecated() noexcept;
4405 using value_type = ValueType;
4411 template<typename Byte>
4412 using value_type = Type<Byte>;
4414 using value_type_tag = TypeTag;
4415};
4416#endif
4417
4426template<typename T>
4427class group_traits;
4428
4429#ifdef SBEPP_DOXYGEN
4430template<typename T>
4432{
4433public:
4435 static constexpr const char* name() noexcept;
4437 static constexpr const char* description() noexcept;
4439 static constexpr member_id_t id() noexcept;
4441 static constexpr block_length_t block_length() noexcept;
4443 static constexpr const char* semantic_type() noexcept;
4445 static constexpr version_t since_version() noexcept;
4448 static constexpr version_t deprecated() noexcept;
4454 template<typename Byte>
4455 using value_type = GroupType<Byte>;
4461 template<typename Byte>
4462 using dimension_type = HeaderType<Byte>;
4464 using dimension_type_tag = HeaderTag;
4470 template<typename Byte>
4471 using entry_type = EntryType<Byte>;
4483 static constexpr std::size_t
4484 size_bytes(const NumInGroupType num_in_group, ...) noexcept;
4485};
4486#endif
4487
4496template<typename T>
4497class data_traits;
4498
4499#ifdef SBEPP_DOXYGEN
4500template<typename T>
4502{
4503public:
4505 static constexpr const char* name() noexcept;
4507 static constexpr member_id_t id() noexcept;
4509 static constexpr const char* description() noexcept;
4511 static constexpr version_t since_version() noexcept;
4514 static constexpr version_t deprecated() noexcept;
4520 template<typename Byte>
4521 using value_type = DataType;
4523 using length_type = LengthType;
4525 using length_type_tag = LengthTypeTag;
4532 static constexpr std::size_t
4533 size_bytes(const length_type::value_type size) noexcept;
4534};
4535#endif
4560template<typename ValueType>
4561struct traits_tag;
4562
4563#ifdef SBEPP_DOXYGEN
4564template<typename ValueType>
4566{
4568 using type = Tag;
4569};
4570#endif
4571
4573template<typename ValueType>
4575
4576template<typename Byte, typename Value, std::size_t N, typename Tag>
4577struct traits_tag<detail::static_array_ref<Byte, Value, N, Tag>>
4578{
4579 using type = Tag;
4580};
4581
4582// NOLINTNEXTLINE: macro is required here
4583#define SBEPP_BUILT_IN_IMPL(NAME, TYPE, MIN, MAX, NULL) \
4584 \
4585 \
4586 class NAME##_t : public detail::required_base<TYPE, NAME##_t> \
4587 { \
4588 public: \
4589 using detail::required_base<TYPE, NAME##_t>::required_base; \
4590 \
4591 \
4592 static constexpr value_type min_value() noexcept \
4593 { \
4594 return {MIN}; \
4595 } \
4596 \
4597 \
4598 static constexpr value_type max_value() noexcept \
4599 { \
4600 return {MAX}; \
4601 } \
4602 }; \
4603 \
4604
4605 \
4606 class NAME##_opt_t : public detail::optional_base<TYPE, NAME##_opt_t> \
4607 { \
4608 public: \
4609 using detail::optional_base<TYPE, NAME##_opt_t>::optional_base; \
4610 \
4611 \
4612 static constexpr value_type min_value() noexcept \
4613 { \
4614 return {MIN}; \
4615 } \
4616 \
4617 \
4618 static constexpr value_type max_value() noexcept \
4619 { \
4620 return {MAX}; \
4621 } \
4622 \
4623 \
4624 static constexpr value_type null_value() noexcept \
4625 { \
4626 return {NULL}; \
4627 } \
4628 }; \
4629 \
4630 template<> \
4631 class type_traits<NAME##_t> \
4632 { \
4633 public: \
4634 static constexpr const char* name() noexcept \
4635 { \
4636 return #NAME; \
4637 } \
4638 \
4639 static constexpr const char* description() noexcept \
4640 { \
4641 return ""; \
4642 } \
4643 \
4644 static constexpr field_presence presence() noexcept \
4645 { \
4646 return field_presence::required; \
4647 } \
4648 \
4649 static constexpr TYPE min_value() noexcept \
4650 { \
4651 return NAME##_t::min_value(); \
4652 } \
4653 \
4654 static constexpr TYPE max_value() noexcept \
4655 { \
4656 return NAME##_t::max_value(); \
4657 } \
4658 \
4659 static constexpr length_t length() noexcept \
4660 { \
4661 return 1; \
4662 } \
4663 \
4664 static constexpr const char* semantic_type() noexcept \
4665 { \
4666 return ""; \
4667 } \
4668 \
4669 static constexpr version_t since_version() noexcept \
4670 { \
4671 return 0; \
4672 } \
4673 \
4674 using value_type = NAME##_t; \
4675 using primitive_type = value_type::value_type; \
4676 }; \
4677 \
4678 template<> \
4679 struct traits_tag<NAME##_t> \
4680 { \
4681 using type = NAME##_t; \
4682 }; \
4683 \
4684 template<> \
4685 class type_traits<NAME##_opt_t> \
4686 { \
4687 public: \
4688 static constexpr const char* name() noexcept \
4689 { \
4690 return #NAME; \
4691 } \
4692 \
4693 static constexpr const char* description() noexcept \
4694 { \
4695 return ""; \
4696 } \
4697 \
4698 static constexpr field_presence presence() noexcept \
4699 { \
4700 return field_presence::optional; \
4701 } \
4702 \
4703 static constexpr TYPE min_value() noexcept \
4704 { \
4705 return NAME##_opt_t::min_value(); \
4706 } \
4707 \
4708 static constexpr TYPE max_value() noexcept \
4709 { \
4710 return NAME##_opt_t::max_value(); \
4711 } \
4712 \
4713 static constexpr TYPE null_value() noexcept \
4714 { \
4715 return NAME##_opt_t::null_value(); \
4716 } \
4717 \
4718 static constexpr length_t length() noexcept \
4719 { \
4720 return 1; \
4721 } \
4722 \
4723 static constexpr const char* semantic_type() noexcept \
4724 { \
4725 return ""; \
4726 } \
4727 \
4728 static constexpr version_t since_version() noexcept \
4729 { \
4730 return 0; \
4731 } \
4732 \
4733 using value_type = NAME##_opt_t; \
4734 using primitive_type = value_type::value_type; \
4735 }; \
4736 \
4737 template<> \
4738 struct traits_tag<NAME##_opt_t> \
4739 { \
4740 using type = NAME##_opt_t; \
4741 }
4743SBEPP_BUILT_IN_IMPL(char, char, 0x20, 0x7E, 0);
4744SBEPP_BUILT_IN_IMPL(
4745 int8,
4746 std::int8_t,
4747 std::numeric_limits<std::int8_t>::min() + 1,
4748 std::numeric_limits<std::int8_t>::max(),
4749 std::numeric_limits<std::int8_t>::min());
4750SBEPP_BUILT_IN_IMPL(
4751 uint8,
4752 std::uint8_t,
4753 std::numeric_limits<std::uint8_t>::min(),
4754 std::numeric_limits<std::uint8_t>::max() - 1,
4755 std::numeric_limits<std::uint8_t>::max());
4756SBEPP_BUILT_IN_IMPL(
4757 int16,
4758 std::int16_t,
4759 std::numeric_limits<std::int16_t>::min() + 1,
4760 std::numeric_limits<std::int16_t>::max(),
4761 std::numeric_limits<std::int16_t>::min());
4762SBEPP_BUILT_IN_IMPL(
4763 uint16,
4764 std::uint16_t,
4765 std::numeric_limits<std::uint16_t>::min(),
4766 std::numeric_limits<std::uint16_t>::max() - 1,
4767 std::numeric_limits<std::uint16_t>::max());
4768SBEPP_BUILT_IN_IMPL(
4769 int32,
4770 std::int32_t,
4771 std::numeric_limits<std::int32_t>::min() + 1,
4772 std::numeric_limits<std::int32_t>::max(),
4773 std::numeric_limits<std::int32_t>::min());
4774SBEPP_BUILT_IN_IMPL(
4775 uint32,
4776 std::uint32_t,
4777 std::numeric_limits<std::uint32_t>::min(),
4778 std::numeric_limits<std::uint32_t>::max() - 1,
4779 std::numeric_limits<std::uint32_t>::max());
4780SBEPP_BUILT_IN_IMPL(
4781 int64,
4782 std::int64_t,
4783 std::numeric_limits<std::int64_t>::min() + 1,
4784 std::numeric_limits<std::int64_t>::max(),
4785 std::numeric_limits<std::int64_t>::min());
4786SBEPP_BUILT_IN_IMPL(
4787 uint64,
4788 std::uint64_t,
4789 std::numeric_limits<std::uint64_t>::min(),
4790 std::numeric_limits<std::uint64_t>::max() - 1,
4791 std::numeric_limits<std::uint64_t>::max());
4792SBEPP_BUILT_IN_IMPL(
4793 float,
4794 float,
4795 std::numeric_limits<float>::min(),
4796 std::numeric_limits<float>::max(),
4797 std::numeric_limits<float>::quiet_NaN());
4798SBEPP_BUILT_IN_IMPL(
4799 double,
4800 double,
4801 std::numeric_limits<double>::min(),
4802 std::numeric_limits<double>::max(),
4803 std::numeric_limits<double>::quiet_NaN());
4804
4805#undef SBEPP_BUILT_IN_IMPL
4806
4824template<template<typename> class View, typename Byte>
4825constexpr View<Byte> make_view(Byte* ptr, const std::size_t size) noexcept
4826{
4827 return {ptr, size};
4828}
4829
4848template<template<typename> class View, typename Byte>
4849constexpr View<typename std::add_const<Byte>::type>
4850 make_const_view(Byte* ptr, const std::size_t size) noexcept
4851{
4852 return {ptr, size};
4853}
4854
4861struct unknown_enum_value_tag
4862{
4863};
4864
4865namespace detail
4866{
4867// taken from https://stackoverflow.com/a/34672753
4868template<template<typename...> class Base, typename Derived>
4869struct is_base_of_tmp_impl
4870{
4871 static constexpr std::false_type test(...);
4872
4873 template<typename... Ts>
4874 static constexpr std::true_type test(Base<Ts...>*);
4875
4876 using type = decltype(test(std::declval<Derived*>()));
4877};
4878
4879template<template<typename...> class Base, typename Derived>
4880using is_base_of_tmp = typename is_base_of_tmp_impl<Base, Derived>::type;
4881
4882#if SBEPP_HAS_CONCEPTS
4883template<typename Derived, template<typename...> class Base>
4884concept derived_from_tmp = is_base_of_tmp<Base, Derived>::value;
4885#endif
4886} // namespace detail
4887
4888namespace detail
4889{
4890template<typename Derived>
4891struct is_array_type_impl
4892{
4893 static constexpr std::false_type test(...);
4894
4895 template<typename T1, typename T2, std::size_t N, typename T3>
4896 static constexpr std::true_type
4897 test(detail::static_array_ref<T1, T2, N, T3>*);
4898
4899 using type = decltype(test(std::declval<Derived*>()));
4900};
4901} // namespace detail
4902
4904template<typename T>
4905using is_array_type = typename detail::is_array_type_impl<T>::type;
4906
4908template<typename T>
4909using is_required_type = detail::is_base_of_tmp<detail::required_base, T>;
4910
4912template<typename T>
4913using is_optional_type = detail::is_base_of_tmp<detail::optional_base, T>;
4914
4916template<typename T>
4917using is_non_array_type = std::integral_constant<
4918 bool,
4920
4922template<typename T>
4923using is_type = std::integral_constant<
4924 bool,
4927
4929template<typename T, typename = void>
4930struct is_enum : std::false_type
4931{
4932};
4933
4934template<typename T>
4935struct is_enum<
4936 T,
4937 detail::void_t<decltype(tag_invoke(
4938 std::declval<detail::visit_tag>(),
4939 std::declval<T>(),
4940 std::declval<int&>()))>> : std::true_type
4941{
4942};
4943
4945template<typename T>
4946using is_set = detail::is_base_of_tmp<detail::bitset_base, T>;
4947
4949template<typename T>
4950using is_composite = detail::is_base_of_tmp<detail::composite_base, T>;
4951
4953template<typename T>
4954using is_message = detail::is_base_of_tmp<detail::message_base, T>;
4955
4957template<typename T>
4958using is_flat_group = detail::is_base_of_tmp<detail::flat_group_base, T>;
4959
4961template<typename T>
4962using is_nested_group = detail::is_base_of_tmp<detail::nested_group_base, T>;
4963
4965template<typename T>
4966using is_group = std::integral_constant<
4967 bool,
4969
4971template<typename T>
4972using is_group_entry = detail::is_base_of_tmp<detail::entry_base, T>;
4973
4974namespace detail
4975{
4976template<typename Derived>
4977struct is_data_impl
4978{
4979 static constexpr std::false_type test(...);
4980
4981 template<typename T1, typename T2, typename T3, endian E>
4982 static constexpr std::true_type
4984
4985 using type = decltype(test(std::declval<Derived*>()));
4986};
4987} // namespace detail
4988
4990template<typename T>
4991using is_data = typename detail::is_data_impl<T>::type;
4992
4993#if SBEPP_HAS_INLINE_VARS
4995template<typename T>
4996inline constexpr auto is_array_type_v = is_array_type<T>::value;
4997
4999template<typename T>
5000inline constexpr auto is_required_type_v = is_required_type<T>::value;
5001
5003template<typename T>
5004inline constexpr auto is_optional_type_v = is_optional_type<T>::value;
5005
5007template<typename T>
5008inline constexpr auto is_non_array_type_v = is_non_array_type<T>::value;
5009
5011template<typename T>
5012inline constexpr auto is_type_v = is_type<T>::value;
5013
5015template<typename T>
5016inline constexpr auto is_enum_v = is_enum<T>::value;
5017
5019template<typename T>
5020inline constexpr auto is_set_v = is_set<T>::value;
5021
5023template<typename T>
5024inline constexpr auto is_composite_v = is_composite<T>::value;
5025
5027template<typename T>
5028inline constexpr auto is_message_v = is_message<T>::value;
5029
5031template<typename T>
5032inline constexpr auto is_flat_group_v = is_flat_group<T>::value;
5033
5035template<typename T>
5036inline constexpr auto is_nested_group_v = is_nested_group<T>::value;
5037
5039template<typename T>
5040inline constexpr auto is_group_v = is_group<T>::value;
5041
5043template<typename T>
5044inline constexpr auto is_data_v = is_data<T>::value;
5045#endif
5046
5047#if SBEPP_HAS_CONCEPTS
5049template<typename T>
5050concept array_type = is_array_type_v<T>;
5051
5053template<typename T>
5054concept required_type = is_required_type_v<T>;
5055
5057template<typename T>
5058concept optional_type = is_optional_type_v<T>;
5059
5061template<typename T>
5062concept non_array_type = is_non_array_type_v<T>;
5063
5065template<typename T>
5066concept type = is_type_v<T>;
5067
5069template<typename T>
5070concept enumeration = is_enum_v<T>;
5071
5073template<typename T>
5074concept set = is_set_v<T>;
5075
5077template<typename T>
5078concept composite = is_composite_v<T>;
5079
5081template<typename T>
5082concept message = is_message_v<T>;
5083
5085template<typename T>
5086concept flat_group = is_flat_group_v<T>;
5087
5089template<typename T>
5090concept nested_group = is_nested_group_v<T>;
5091
5093template<typename T>
5094concept group = is_group_v<T>;
5095
5097template<typename T>
5098concept data = is_data_v<T>;
5099#endif
5100
5101namespace detail
5102{
5103template<typename T>
5104using is_visitable_view = std::integral_constant<
5105 bool,
5106 is_message<T>::value || is_group<T>::value || is_group_entry<T>::value
5107 || is_composite<T>::value>;
5108}
5109
5121template<
5122 typename Visitor,
5123 typename View,
5124 typename Cursor,
5125 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5126SBEPP_CPP14_CONSTEXPR Visitor&&
5127 visit(View view, Cursor& c, Visitor&& visitor = {})
5128{
5129 view(detail::visit_tag{}, visitor, c);
5130 return std::forward<Visitor>(visitor);
5131}
5132
5143template<
5144 typename Visitor,
5145 typename View,
5146 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5147SBEPP_CPP14_CONSTEXPR Visitor&& visit(View view, Visitor&& visitor = {})
5148{
5149 auto c = sbepp::init_cursor(view);
5150 return sbepp::visit(view, c, std::forward<Visitor>(visitor));
5151}
5152
5153#ifndef SBEPP_DOXYGEN
5154template<typename Visitor, typename Set>
5155SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_set<Set>::value, Visitor&&>
5156 visit(Set s, Visitor&& visitor = {})
5157{
5158 s(detail::visit_tag{}, visitor);
5159 return std::forward<Visitor>(visitor);
5160}
5161
5162template<typename Visitor, typename Enum>
5163SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_enum<Enum>::value, Visitor&&>
5164 visit(Enum e, Visitor&& visitor = {})
5165{
5166 tag_invoke(detail::visit_tag{}, e, visitor);
5167 return std::forward<Visitor>(visitor);
5168}
5169
5170#else
5171
5188template<typename Visitor, typename Set>
5189SBEPP_CPP14_CONSTEXPR Visitor&& visit(Set s, Visitor&& visitor = {});
5190
5207template<typename Visitor, typename Enum>
5208SBEPP_CPP14_CONSTEXPR Visitor&& visit(Enum e, Visitor&& visitor = {});
5209#endif
5210
5223template<
5224 typename Visitor,
5225 typename View,
5226 typename Cursor,
5227 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5228SBEPP_CPP14_CONSTEXPR Visitor&&
5229 visit_children(View view, Cursor& c, Visitor&& visitor = {})
5230{
5231 view(detail::visit_children_tag{}, visitor, c);
5232 return std::forward<Visitor>(visitor);
5233}
5234
5245template<
5246 typename Visitor,
5247 typename View,
5248 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5249SBEPP_CPP14_CONSTEXPR Visitor&&
5250 visit_children(View view, Visitor&& visitor = {})
5251{
5252 auto c = sbepp::init_cursor(view);
5253 return sbepp::visit_children(view, c, std::forward<Visitor>(visitor));
5254}
5255
5256namespace detail
5257{
5258class enum_to_string_visitor
5259{
5260public:
5261 template<typename Enum, typename Tag>
5262 SBEPP_CPP14_CONSTEXPR void on_enum_value(Enum /*e*/, Tag) noexcept
5263 {
5265 }
5266
5267 template<typename Enum>
5268 SBEPP_CPP14_CONSTEXPR void
5269 on_enum_value(Enum /*e*/, sbepp::unknown_enum_value_tag) noexcept
5270 {
5271 name_value = nullptr;
5272 }
5273
5274 constexpr const char* name() const noexcept
5275 {
5276 return name_value;
5277 }
5278
5279private:
5280 const char* name_value;
5281};
5282} // namespace detail
5283
5294template<typename E, typename = detail::enable_if_t<is_enum<E>::value>>
5295SBEPP_DEPRECATED constexpr const char* enum_to_string(const E e) noexcept
5296{
5297 return visit<detail::enum_to_string_visitor>(e).name();
5298}
5299
5311template<typename Set, typename Visitor>
5312SBEPP_DEPRECATED constexpr auto
5313 visit_set(const Set s, Visitor&& visitor) noexcept
5314 -> decltype(s(detail::visit_set_tag{}, std::forward<Visitor>(visitor)))
5315{
5316 return s(detail::visit_set_tag{}, std::forward<Visitor>(visitor));
5317}
5318
5319namespace detail
5320{
5321class size_bytes_checked_visitor
5322{
5323public:
5324 constexpr explicit size_bytes_checked_visitor(
5325 const std::size_t size) noexcept
5326 : size{size}
5327 {
5328 }
5329
5330 template<typename T, typename Cursor, typename Tag>
5331 SBEPP_CPP14_CONSTEXPR void on_message(T m, Cursor& c, Tag) noexcept
5332 {
5333 const auto header = sbepp::get_header(m);
5334 const auto header_size = sbepp::size_bytes(header);
5335 if(!validate_and_subtract(header_size))
5336 {
5337 return;
5338 }
5339
5340 if(!validate_and_subtract(*header.blockLength()))
5341 {
5342 return;
5343 }
5344
5345 sbepp::visit_children(m, c, *this);
5346 }
5347
5348 template<typename T, typename Cursor, typename Tag>
5349 SBEPP_CPP14_CONSTEXPR bool on_group(T g, Cursor& c, Tag) noexcept
5350 {
5351 const auto header = sbepp::get_header(g);
5352 const auto header_size = sbepp::size_bytes(header);
5353 if(!validate_and_subtract(header_size))
5354 {
5355 return true;
5356 }
5357
5358 const auto prev_block_length =
5359 set_group_block_length(*header.blockLength());
5360 sbepp::visit_children(g, c, *this);
5361 set_group_block_length(prev_block_length);
5362
5363 return !is_valid();
5364 }
5365
5366 template<typename T, typename Cursor>
5367 SBEPP_CPP14_CONSTEXPR bool on_entry(T e, Cursor& c) noexcept
5368 {
5369 if(!validate_and_subtract(group_block_length))
5370 {
5371 return true;
5372 }
5373
5374 return !sbepp::visit_children(e, c, *this).is_valid();
5375 }
5376
5377 template<typename T, typename Tag>
5378 SBEPP_CPP14_CONSTEXPR bool on_data(T d, Tag) noexcept
5379 {
5380 return !validate_and_subtract(sbepp::size_bytes(d));
5381 }
5382
5383 // ignore them all because we validate `blockLength`
5384 template<typename T, typename Tag>
5385 constexpr bool on_field(T, Tag) const noexcept
5386 {
5387 return {};
5388 }
5389
5390 constexpr bool is_valid() const noexcept
5391 {
5392 return valid;
5393 }
5394
5395 // returns previous value
5396 SBEPP_CPP14_CONSTEXPR std::size_t
5397 set_group_block_length(const std::size_t block_length) noexcept
5398 {
5399 auto prev = group_block_length;
5400 group_block_length = block_length;
5401 return prev;
5402 }
5403
5404 constexpr std::size_t get_size() const noexcept
5405 {
5406 return size;
5407 }
5408
5409private:
5410 std::size_t size;
5411 bool valid{true};
5412 // current group's blockLength, used to validate entry
5413 std::size_t group_block_length{};
5414
5415 SBEPP_CPP14_CONSTEXPR bool
5416 validate_and_subtract(const std::size_t n) noexcept
5417 {
5418 if(size < n)
5419 {
5420 valid = false;
5421 }
5422 else
5423 {
5424 size -= n;
5425 }
5426
5427 return valid;
5428 }
5429};
5430} // namespace detail
5431
5433struct size_bytes_checked_result
5434{
5436 bool valid;
5438 std::size_t size;
5439};
5440
5441// can be used with message/group
5452template<typename View>
5453SBEPP_CPP20_CONSTEXPR size_bytes_checked_result
5454 size_bytes_checked(View view, std::size_t size) noexcept
5455{
5456 // `init_cursor` skips header, we need to ensure there's enough space for it
5457 if(!sbepp::addressof(view) || (size < detail::get_header_size(view)))
5458 {
5459 return {};
5460 }
5461
5462 detail::size_bytes_checked_visitor visitor{size};
5463 auto c = sbepp::init_cursor(view);
5464 sbepp::visit(view, c, visitor);
5465 if(visitor.is_valid())
5466 {
5467 return {true, size - visitor.get_size()};
5468 }
5469 return {};
5470}
5471} // namespace sbepp
5472
5473#if SBEPP_HAS_RANGES && SBEPP_HAS_CONCEPTS
5474
5475template<typename Byte, typename Value, std::size_t N, typename Tag>
5476inline constexpr bool std::ranges::enable_borrowed_range<
5478
5479template<typename Byte, typename Value, typename Length, sbepp::endian E>
5480inline constexpr bool std::ranges::enable_borrowed_range<
5482
5483template<sbepp::detail::derived_from_tmp<sbepp::detail::flat_group_base> T>
5484inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5485
5486template<sbepp::detail::derived_from_tmp<sbepp::detail::nested_group_base> T>
5487inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5488#endif
5489
5490#undef SBEPP_CPP17_INLINE_VAR
5491#undef SBEPP_DEPRECATED
5492#undef SBEPP_CPLUSPLUS
5493
5494SBEPP_WARNINGS_ON();
Provides various traits/attributes of a <composite> element.
Definition sbepp.hpp:4217
CompositeType< Byte > value_type
Representation type.
Definition sbepp.hpp:4241
static constexpr const char * name() noexcept
Returns name attribute.
Represents cursor which is used in cursor-based API. Clients should not use undocumented methods.
Definition sbepp.hpp:790
constexpr Byte * pointer() const noexcept
access underlying pointer
Definition sbepp.hpp:856
constexpr cursor(cursor< Byte2 > other) noexcept
Construct from another cursor. Enabled only if Byte2* is convertible to Byte*.
Definition sbepp.hpp:819
Byte byte_type
same as Byte
Definition sbepp.hpp:793
cursor()=default
Construct a new cursor object initialized with nullptr
constexpr Byte *& pointer() noexcept
access underlying pointer. Might be useful in rare cases to initialize cursor with a particular value...
Definition sbepp.hpp:846
constexpr cursor & operator=(cursor< Byte2 > other) noexcept
Assign from another cursor. Enabled only if Byte2* is convertible to Byte
Definition sbepp.hpp:834
Provides various traits/attributes of a <data> element.
Definition sbepp.hpp:4502
static constexpr const char * name() noexcept
Returns name attribute.
DataType value_type
Representation type.
Definition sbepp.hpp:4521
LengthTypeTag length_type_tag
length_type tag
Definition sbepp.hpp:4525
LengthType length_type
Length type.
Definition sbepp.hpp:4523
Base class for bitsets.
Definition sbepp.hpp:2663
constexpr T operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:2680
constexpr friend bool operator==(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are equal.
Definition sbepp.hpp:2699
constexpr T & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:2674
constexpr bitset_base(T value) noexcept
Constructs from given value.
Definition sbepp.hpp:2669
constexpr friend bool operator!=(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are not equal.
Definition sbepp.hpp:2706
bitset_base()=default
Default constructs underlying value to 0
Base class for all reference semantics types.
Definition sbepp.hpp:721
constexpr byte_range(Byte *ptr, const std::size_t size) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:743
constexpr byte_range(const byte_range< Byte2 > &other) noexcept
Copy constructor. Available if Byte2* is convertible to Byte*
Definition sbepp.hpp:751
byte_range()=default
Initializes to nullptr
constexpr byte_range(Byte *begin, Byte *end) noexcept
Constructs from a pair of pointers.
Definition sbepp.hpp:732
Base class for composites.
Definition sbepp.hpp:1667
Represents reference to dynamic arrays used for <data> elements.
Definition sbepp.hpp:3231
constexpr sbe_size_type sbe_size() const noexcept
Returns SBE size representation.
Definition sbepp.hpp:3321
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3253
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:3255
constexpr iterator insert(iterator pos, std::initializer_list< value_type > ilist) const noexcept
Inserts elements from ilist before pos
Definition sbepp.hpp:3480
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3279
static constexpr size_type max_size() noexcept
Returns max value of SBE length representation.
Definition sbepp.hpp:3339
constexpr iterator erase(iterator first, iterator last) const noexcept
Erases elements in [first; last) range.
Definition sbepp.hpp:3427
constexpr void assign_string(const char *str) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3546
constexpr iterator insert(iterator pos, InputIt first, InputIt last) const
Inserts elements from [first; last) range before pos
Definition sbepp.hpp:3470
constexpr void assign(std::initializer_list< value_type > ilist) const noexcept
Replaces the contents of the container with the elements from ilist
Definition sbepp.hpp:3510
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:3294
constexpr void resize(size_type count, sbepp::default_init_t) const noexcept
Sets size to count, default initializes new elements.
Definition sbepp.hpp:3385
element_type * pointer
element pointer type
Definition sbepp.hpp:3251
constexpr void push_back(value_type value) const noexcept
Adds new element to the end.
Definition sbepp.hpp:3399
constexpr iterator insert(iterator pos, const value_type value) const noexcept
Inserts value before pos
Definition sbepp.hpp:3438
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:3314
constexpr void resize(size_type count) const noexcept
Sets size to count, value initializes new elements.
Definition sbepp.hpp:3353
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:3286
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:3247
constexpr void pop_back() const noexcept
Removes the last element.
Definition sbepp.hpp:3408
Value value_type
same as Value
Definition sbepp.hpp:3241
constexpr dynamic_array_ref< Byte, detail::remove_cv_t< Byte >, Length, E > raw() const noexcept
Returns dynamic_array_ref<Byte, Byte, Length, E>.
Definition sbepp.hpp:3527
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:3239
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3261
constexpr void assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3565
constexpr iterator insert(iterator pos, size_type count, const value_type value) const noexcept
Inserts count copies of value before pos
Definition sbepp.hpp:3450
constexpr void assign(size_type count, const value_type value) const noexcept
Replaces the contents of the container with count copies of value
Definition sbepp.hpp:3490
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:3307
constexpr iterator erase(iterator pos) const noexcept
Erases element at pos
Definition sbepp.hpp:3416
constexpr void clear() const noexcept
Sets size to 0.
Definition sbepp.hpp:3346
constexpr bool empty() const noexcept
Checks if size() != 0
Definition sbepp.hpp:3333
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3273
constexpr void resize(size_type count, value_type value) const noexcept
Sets size to count, initializes new elements with value
Definition sbepp.hpp:3369
constexpr void assign(InputIt first, InputIt last) const
Replaces the contents of the container with the elements from [first; last) range.
Definition sbepp.hpp:3499
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3267
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:3327
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:3245
Length sbe_size_type
length SBE representation of data's encoding
Definition sbepp.hpp:3243
element_type & reference
element reference type
Definition sbepp.hpp:3249
Base class for group entries.
Definition sbepp.hpp:1718
constexpr entry_base(cursor< Byte2 > &c, Byte *end_ptr, BlockLengthType block_length) noexcept
Constructs from cursor.
Definition sbepp.hpp:1746
constexpr entry_base(const entry_base< Byte2, BlockLengthType > &other) noexcept
Constructs from entry_base of compatible byte type. Available if Byte2* is convertible to Byte*
Definition sbepp.hpp:1758
constexpr entry_base(Byte *ptr, const std::size_t size, const BlockLengthType block_length) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:1736
entry_base()=default
Constructs using nullptr
constexpr entry_base(Byte *ptr, Byte *end, BlockLengthType block_length) noexcept
Constructs from two pointers.
Definition sbepp.hpp:1729
Base class for a flat group.
Definition sbepp.hpp:2206
random_access_iterator< Byte, Entry, typename std::decay< decltype(std::declval< Dimension >().blockLength().value())>::type, difference_type, size_type > iterator
Random access iterator to value_type. Satisfies std::random_access_iterator
Definition sbepp.hpp:2221
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2328
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2252
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2400
constexpr reference front() const noexcept
Returns the first entry.
Definition sbepp.hpp:2312
constexpr cursor_range_t< Byte2 > cursor_subrange(cursor< Byte2 > &c, const size_type pos) const noexcept
Returns cursor range to [pos; size()) entries.
Definition sbepp.hpp:2364
detail::cursor_range< value_type, size_type, cursor< Byte2 >, typename std::decay< decltype(std::declval< Dimension >().blockLength().value())>::type, Byte > cursor_range_t
Type of a cursor range. Satisfies std::ranges::input_range
Definition sbepp.hpp:2335
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2213
Entry value_type
Entry type.
Definition sbepp.hpp:2209
constexpr reference operator[](size_type pos) const noexcept
Access group entry at pos
Definition sbepp.hpp:2304
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2258
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2282
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2407
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2348
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2270
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2293
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2264
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2417
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2276
constexpr reference back() const noexcept
Returns the last entry.
Definition sbepp.hpp:2320
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2218
constexpr cursor_range_t< Byte2 > cursor_subrange(cursor< Byte2 > &c, const size_type pos, const size_type count) const noexcept
Returns cursor range to [pos; pos+count) entries.
Definition sbepp.hpp:2382
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:2216
value_type reference
value_type
Definition sbepp.hpp:2211
Base class for messages.
Definition sbepp.hpp:1676
Base class for a nested group.
Definition sbepp.hpp:2440
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2496
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2531
constexpr cursor_range_t< Byte2 > cursor_subrange(cursor< Byte2 > &c, const size_type pos) const noexcept
Returns cursor range to [pos; size()) entries.
Definition sbepp.hpp:2586
Entry value_type
entry type
Definition sbepp.hpp:2443
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2514
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2622
value_type reference
value_type
Definition sbepp.hpp:2445
detail::cursor_range< value_type, size_type, cursor< Byte2 >, typename std::decay< decltype(std::declval< Dimension >().blockLength().value())>::type, Byte > cursor_range_t
Type of a cursor range. Satisfies std::ranges::input_range
Definition sbepp.hpp:2557
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:2450
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2452
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2490
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2502
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:2542
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2639
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2550
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2629
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2508
forward_iterator< Byte, Entry, size_type, difference_type, typename std::decay< decltype(std::declval< Dimension >().blockLength().value())>::type > iterator
Forward iterator to value_type. Satisfies std::forward_iterator
Definition sbepp.hpp:2456
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2570
constexpr cursor_range_t< Byte2 > cursor_subrange(cursor< Byte2 > &c, const size_type pos, const size_type count) const noexcept
Returns cursor range to [pos; pos+count) entries.
Definition sbepp.hpp:2604
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2520
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2447
Base class for optional types.
Definition sbepp.hpp:3761
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3782
constexpr friend bool operator!=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3862
constexpr optional_base(nullopt_t) noexcept
Constructs null object.
Definition sbepp.hpp:3771
optional_base()=default
Constructs null object.
constexpr value_type value_or(T default_value) const noexcept
Returns value if not null, default_value otherwise.
Definition sbepp.hpp:3807
constexpr friend bool operator>=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is greater than or equal to rhs
Definition sbepp.hpp:3890
T value_type
Underlying type.
Definition sbepp.hpp:3764
constexpr bool in_range() const noexcept
Checks if value is in [Derived::min_value(); Derived::max_value()] range.
Definition sbepp.hpp:3801
constexpr optional_base(value_type val) noexcept
Constructs object from given value.
Definition sbepp.hpp:3777
constexpr bool has_value() const noexcept
Checks if has value.
Definition sbepp.hpp:3817
constexpr friend bool operator>(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3883
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3794
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3788
constexpr friend bool operator==(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3837
constexpr friend std::strong_ordering operator<=>(const optional_base &lhs, const optional_base &rhs) noexcept
Available only if SBEPP_HAS_THREE_WAY_COMPARISON == 1.
Base class for required types.
Definition sbepp.hpp:3654
constexpr friend bool operator>(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3736
constexpr friend bool operator>=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is greater than or equal to rhs
Definition sbepp.hpp:3743
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3669
constexpr friend bool operator!=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3715
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3675
constexpr friend bool operator==(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3708
required_base()=default
Default constructor. Constructs value-initialized object.
constexpr bool in_range() const noexcept
Checks if value is in [Derived::min_value(); Derived::max_value()] range.
Definition sbepp.hpp:3688
T value_type
Underlying type.
Definition sbepp.hpp:3657
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3681
constexpr required_base(value_type val) noexcept
Constructs from given value.
Definition sbepp.hpp:3664
Represents reference to fixed-size array.
Definition sbepp.hpp:2909
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:2925
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3009
static constexpr bool empty() noexcept
Checks if size() != 0
Definition sbepp.hpp:2973
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:2913
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:2941
constexpr std::size_t strlen() const noexcept
Calculates string length from left to right.
Definition sbepp.hpp:3038
constexpr iterator assign_string(const char *str, const eos_null eos_mode=eos_null::all) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3087
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:2948
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2991
static constexpr size_type size() noexcept
Returns N
Definition sbepp.hpp:2979
constexpr static_array_ref< Byte, detail::remove_cv_t< Byte >, N, Tag > raw() const noexcept
Returns static_array_ref<Byte, Byte, N, Tag>.
Definition sbepp.hpp:3026
constexpr iterator assign(std::initializer_list< value_type > ilist) const noexcept
Assigns initializer list to first elements.
Definition sbepp.hpp:3193
element_type & reference
element reference type
Definition sbepp.hpp:2921
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:2927
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:2954
Value value_type
same as Value
Definition sbepp.hpp:2915
Tag tag
type tag
Definition sbepp.hpp:2929
element_type * pointer
element pointer type
Definition sbepp.hpp:2923
constexpr std::size_t strlen_r() const noexcept
Calculates string length from right to left.
Definition sbepp.hpp:3063
std::size_t size_type
std::size_t
Definition sbepp.hpp:2917
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2997
constexpr iterator assign_string(R &&r, const eos_null eos_mode=eos_null::all) const
Assigns string represented by a range.
Definition sbepp.hpp:3115
constexpr void fill(const value_type value) const noexcept
Assigns value to all elements.
Definition sbepp.hpp:3152
constexpr iterator assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3135
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3003
constexpr iterator assign(InputIt first, InputIt last) const
Assigns elements from [first; last) range to first elements.
Definition sbepp.hpp:3177
static constexpr size_type max_size() noexcept
Returns size()
Definition sbepp.hpp:2985
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:2919
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:2960
constexpr iterator assign(size_type count, const value_type value) const noexcept
Assigns value to first count elements.
Definition sbepp.hpp:3167
Provides various traits/attributes of an <enum> element.
Definition sbepp.hpp:4083
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4090
static constexpr const char * name() noexcept
Returns name attribute.
ScopedEnumType value_type
Representation type.
Definition sbepp.hpp:4102
Provides various traits/attributes of a <validValue> element.
Definition sbepp.hpp:4120
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <field> element.
Definition sbepp.hpp:4383
static constexpr const char * name() noexcept
Returns name attribute.
ValueType value_type
Representation type.
Definition sbepp.hpp:4405
TypeTag value_type_tag
value_type's tag. Not available for constants of numeric types
Definition sbepp.hpp:4414
Provides various traits/attributes of a <group> element.
Definition sbepp.hpp:4432
HeaderType< Byte > dimension_type
Group dimension composite type.
Definition sbepp.hpp:4462
HeaderTag dimension_type_tag
Dimension composite tag.
Definition sbepp.hpp:4464
GroupType< Byte > value_type
Representation type.
Definition sbepp.hpp:4455
EntryType< Byte > entry_type
Group entry type.
Definition sbepp.hpp:4471
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <message> element.
Definition sbepp.hpp:4261
static constexpr const char * name() noexcept
Returns name attribute.
SchemaTag schema_tag
Schema tag.
Definition sbepp.hpp:4286
MessageType< Byte > value_type
Representation type.
Definition sbepp.hpp:4284
Provides various traits/attributes of a <messageSchema> element.
Definition sbepp.hpp:4043
HeaderTypeTag header_type_tag
Message header composite tag. Can be used to access its traits.
Definition sbepp.hpp:4065
static constexpr const char * package() noexcept
Returns package attribute.
HeaderComposite< Byte > header_type
Message header composite type.
Definition sbepp.hpp:4063
Provides various traits/attributes of a <choice> element.
Definition sbepp.hpp:4187
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <set> element.
Definition sbepp.hpp:4150
SetType value_type
Representation type.
Definition sbepp.hpp:4169
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4162
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits and attributes of a <type> element.
Definition sbepp.hpp:3962
ValueType value_type
Representation type.
Definition sbepp.hpp:3968
PrimitiveType primitive_type
Underlying type.
Definition sbepp.hpp:3965
static constexpr const char * name() noexcept
Returns name attribute.
Concept for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5049
Concept for sbepp::is_composite<T>::value
Definition sbepp.hpp:5077
Concept for sbepp::is_data<T>::value
Definition sbepp.hpp:5097
Concept for sbepp::is_enum<T>::value
Definition sbepp.hpp:5069
Concept for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5085
Concept for sbepp::is_group<T>::value
Definition sbepp.hpp:5093
Concept for sbepp::is_message<T>::value
Definition sbepp.hpp:5081
Concept for sbepp::is_nested_group<T>::value
Definition sbepp.hpp:5089
Concept for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5061
Concept for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5057
Concept for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5053
Concept for sbepp::is_set<T>::value
Definition sbepp.hpp:5073
Concept for sbepp::is_type<T>::value
Definition sbepp.hpp:5065
constexpr detail::skip_cursor_wrapper< Byte > skip(cursor< Byte > &c) noexcept
Returns a wrapper which moves the cursor to the end of field/group/data without returning the accesse...
Definition sbepp.hpp:1655
constexpr detail::dont_move_cursor_wrapper< Byte > dont_move(cursor< Byte > &c) noexcept
Returns a wrapper which doesn't advance the cursor when it's used.
Definition sbepp.hpp:1621
constexpr detail::init_cursor_wrapper< Byte > init(cursor< Byte > &c) noexcept
Returns a wrapper which will initialize the cursor when it's used and advance after the usage.
Definition sbepp.hpp:1592
constexpr detail::init_dont_move_cursor_wrapper< Byte > init_dont_move(cursor< Byte > &c) noexcept
Returns a wrapper which initializes the cursor but doesn't move it. Behaves like a combination of ini...
Definition sbepp.hpp:1635
The main sbepp namespace.
Definition sbepp.hpp:232
constexpr auto is_composite_v
Shorthand for sbepp::is_composite<T>::value
Definition sbepp.hpp:5023
constexpr auto is_required_type_v
Shorthand for sbepp::is_required_type<T>::value
Definition sbepp.hpp:4999
constexpr auto is_type_v
Shorthand for sbepp::is_type<T>::value
Definition sbepp.hpp:5011
constexpr std::underlying_type< Enum >::type to_underlying(Enum e) noexcept
Converts an enumeration to its underlying type. Equivalent to C++23 std::to_underlying()
Definition sbepp.hpp:2754
detail::is_base_of_tmp< detail::optional_base, T > is_optional_type
Checks if T is a non-array optional type.
Definition sbepp.hpp:4912
constexpr View< Byte > make_view(Byte *ptr, const std::size_t size) noexcept
Construct view from memory buffer.
Definition sbepp.hpp:4824
typename traits_tag< ValueType >::type traits_tag_t
Shorthand for sbepp::traits_tag<T>::type
Definition sbepp.hpp:4574
constexpr auto is_flat_group_v
Shorthand for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5031
eos_null
Represents number of null bytes that can be added after the end-of-string by detail::static_array_ref...
Definition sbepp.hpp:2822
@ all
All bytes after the last string character will be set to null.
constexpr cursor< byte_type_t< View > > init_cursor(View view) noexcept
Initializes cursor from a message/group view with the same byte type.
Definition sbepp.hpp:2773
constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
Returns the header of a message/group.
Definition sbepp.hpp:1534
detail::is_base_of_tmp< detail::required_base, T > is_required_type
Checks if T is a non-array required type.
Definition sbepp.hpp:4908
std::integral_constant< bool, is_flat_group< T >::value||is_nested_group< T >::value > is_group
Checks if T is a group of any kind.
Definition sbepp.hpp:4965
detail::is_base_of_tmp< detail::flat_group_base, T > is_flat_group
Checks if T is a flat group.
Definition sbepp.hpp:4957
constexpr auto is_array_type_v
Shorthand for sbepp::is_array_type<T>::value
Definition sbepp.hpp:4995
constexpr nullopt_t nullopt
Helper constant used to initialize optional types with null value.
Definition sbepp.hpp:3644
field_presence
Represents presence trait value type, e.g. type_traits::presence()
Definition sbepp.hpp:313
@ constant
field is constant
@ required
field is required
@ optional
field is optional
constexpr Visitor && visit_children(View view, Cursor &c, Visitor &&visitor={})
Visit view's children using provided cursor.
Definition sbepp.hpp:5228
constexpr auto is_enum_v
Shorthand for sbepp::is_enum<T>::value
Definition sbepp.hpp:5015
constexpr cursor< typename std::add_const< byte_type_t< View > >::type > init_const_cursor(View view) noexcept
Initializes cursor from a message/group view with const byte type.
Definition sbepp.hpp:2796
constexpr auto fill_message_header(Message m) noexcept -> decltype(m(detail::fill_message_header_tag{}))
Fill message header.
Definition sbepp.hpp:3917
constexpr auto is_non_array_type_v
Shorthand for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5007
constexpr Visitor && visit(View view, Cursor &c, Visitor &&visitor={})
Visit a view using given cursor.
Definition sbepp.hpp:5126
std::uint8_t choice_index_t
Represents set_choice_traits::index() value type.
Definition sbepp.hpp:308
typename detail::is_data_impl< T >::type is_data
Checks if T is a data.
Definition sbepp.hpp:4990
typename byte_type< View >::type byte_type_t
Shortcut for byte_type<T>::type
Definition sbepp.hpp:1566
detail::is_base_of_tmp< detail::nested_group_base, T > is_nested_group
Checks if T is a nested group.
Definition sbepp.hpp:4961
constexpr const char * enum_to_string(const E e) noexcept
Converts enum to string.
Definition sbepp.hpp:5294
detail::is_base_of_tmp< detail::message_base, T > is_message
Checks if T is a message.
Definition sbepp.hpp:4953
constexpr auto fill_group_header(Group g, Size num_in_group) noexcept -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
Fill group header.
Definition sbepp.hpp:3937
constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
Returns pointer to the underlying data referenced by a view.
Definition sbepp.hpp:1546
std::uint64_t offset_t
Represents offset trait value type, e.g. type_traits::offset()
Definition sbepp.hpp:294
std::uint32_t message_id_t
Represents message_traits::id() value type.
Definition sbepp.hpp:301
void assertion_failed(char const *expr, char const *function, char const *file, long line)
When SBEPP_ASSERT_HANDLER or SBEPP_ENABLE_ASSERTS_WITH_HANDLER is defined, this function is called fo...
constexpr std::size_t size_bytes(T v) noexcept
Returns the size of the underlying data represented by message/group/entry/data/composite view,...
Definition sbepp.hpp:1507
std::uint64_t version_t
Represents version trait value type, e.g. type_traits::since_version()
Definition sbepp.hpp:297
detail::is_base_of_tmp< detail::bitset_base, T > is_set
Checks if T is a set.
Definition sbepp.hpp:4945
std::integral_constant< bool, is_required_type< T >::value||is_optional_type< T >::value||is_array_type< T >::value > is_type
Checks if T is a type of any kind.
Definition sbepp.hpp:4922
constexpr auto is_group_v
Shorthand for sbepp::is_group<T>::value
Definition sbepp.hpp:5039
constexpr auto visit_set(const Set s, Visitor &&visitor) noexcept -> decltype(s(detail::visit_set_tag{}, std::forward< Visitor >(visitor)))
Visits set choices in order of their declaration.
Definition sbepp.hpp:5312
constexpr default_init_t default_init
helper to pass default_init_t to dynamic_array_ref::resize().
Definition sbepp.hpp:2817
std::integral_constant< bool, is_required_type< T >::value||is_optional_type< T >::value > is_non_array_type
Checks if T is a non-array type.
Definition sbepp.hpp:4916
std::uint16_t member_id_t
Represents id trait value type, e.g. field_traits::id()
Definition sbepp.hpp:306
constexpr auto is_optional_type_v
Shorthand for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5003
std::uint64_t length_t
Represents type_traits::length() value type.
Definition sbepp.hpp:290
constexpr size_bytes_checked_result size_bytes_checked(View view, std::size_t size) noexcept
Calculate view size with additional safety checks.
Definition sbepp.hpp:5453
constexpr auto is_message_v
Shorthand for sbepp::is_message<T>::value
Definition sbepp.hpp:5027
std::uint64_t block_length_t
Represents block_length trait value type, e.g. message_traits::block_length()
Definition sbepp.hpp:304
constexpr auto is_set_v
Shorthand for sbepp::is_set<T>::value
Definition sbepp.hpp:5019
detail::is_base_of_tmp< detail::entry_base, T > is_group_entry
Checks if T is a group entry.
Definition sbepp.hpp:4971
std::uint32_t schema_id_t
Represents schema_traits::id() value type.
Definition sbepp.hpp:299
constexpr auto is_nested_group_v
Shorthand for sbepp::is_nested_group<T>::value
Definition sbepp.hpp:5035
constexpr View< typename std::add_const< Byte >::type > make_const_view(Byte *ptr, const std::size_t size) noexcept
Construct read-only view from memory buffer.
Definition sbepp.hpp:4849
constexpr auto is_data_v
Shorthand for sbepp::is_data<T>::value
Definition sbepp.hpp:5043
endian
Represents schema_traits::byte_order() value type. When SBEPP_HAS_ENDIAN is 1, it's just an alias to ...
Definition sbepp.hpp:337
@ native
current platform endianness
@ little
little-endian
@ big
big-endian
typename detail::is_array_type_impl< T >::type is_array_type
Checks is T is an array type.
Definition sbepp.hpp:4904
detail::is_base_of_tmp< detail::composite_base, T > is_composite
Checks if T is a composite.
Definition sbepp.hpp:4949
#define SBEPP_BYTE_ORDER
Must be defined to either little or big when native endianness cannot be detected automatically.
Definition sbepp.hpp:327
Trait to get view's byte type.
Definition sbepp.hpp:1558
typename std::remove_pointer< decltype(sbepp::addressof( std::declval< View >()))>::type type
holds View's byte type
Definition sbepp.hpp:1560
tag for dynamic_array_ref::resize(). Used to skip value initialization.
Definition sbepp.hpp:2808
Checks if T is an enumeration.
Definition sbepp.hpp:4930
Tag type used to initialize optional types with null value.
Definition sbepp.hpp:3633
Result type of size_bytes_checked
Definition sbepp.hpp:5433
Maps representation type to its tag.
Definition sbepp.hpp:4566
Tag type
Tag to access ValueType's traits.
Definition sbepp.hpp:4568
Tag for unknown enum values.
Definition sbepp.hpp:4861