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
9
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
56
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
321
322#ifdef SBEPP_DOXYGEN
327# define SBEPP_BYTE_ORDER
328#endif
329
335#ifdef SBEPP_DOXYGEN
336enum class endian
337{
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
376template<typename... Ts>
378{
379};
380
383namespace detail
384{
385// modern C++ bits
386template<bool B, typename T = void>
387using enable_if_t = typename std::enable_if<B, T>::type;
388
389template<typename T>
390using remove_cv_t = typename std::remove_cv<T>::type;
391
392template<typename T>
393using remove_reference_t = typename std::remove_reference<T>::type;
394
395template<typename ByteFrom, typename ByteTo>
396using enable_if_convertible_t =
397 enable_if_t<std::is_convertible<ByteFrom*, ByteTo*>::value>;
398
399template<typename Byte, typename T = void>
400using enable_if_writable_t = enable_if_t<!std::is_const<Byte>::value, T>;
401
402template<typename...>
403using void_t = void;
404
405#if !SBEPP_HAS_BYTESWAP
406
407// intrinsics detection is taken from <boost/endian/detail/intrinsic.hpp>
408# ifndef __has_builtin // Optional of course
409# define __has_builtin(x) 0 // Compatibility with non-clang compilers
410# endif
411
412# if defined(_MSC_VER) && (!defined(__clang__) || defined(__c2__))
413
414# include <cstdlib>
415
416inline std::uint64_t byteswap(std::uint64_t v) noexcept
417{
418 return _byteswap_uint64(v);
419}
420
421inline std::uint32_t byteswap(std::uint32_t v) noexcept
422{
423 return _byteswap_ulong(v);
424}
425
426inline std::uint16_t byteswap(std::uint16_t v) noexcept
427{
428 return _byteswap_ushort(v);
429}
430
431# elif ( \
432 defined(__clang__) && __has_builtin(__builtin_bswap32) \
433 && __has_builtin(__builtin_bswap64)) \
434 || (defined(__GNUC__) \
435 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
436
437# if (defined(__clang__) && __has_builtin(__builtin_bswap16)) \
438 || (defined(__GNUC__) \
439 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
440
441inline std::uint16_t byteswap(std::uint16_t v) noexcept
442{
443 return __builtin_bswap16(v);
444}
445
446# else
447
448inline std::uint16_t byteswap(std::uint16_t v) noexcept
449{
450 return __builtin_bswap32(v) << 16;
451}
452
453# endif
454
455inline std::uint64_t byteswap(std::uint64_t v) noexcept
456{
457 return __builtin_bswap64(v);
458}
459
460inline std::uint32_t byteswap(std::uint32_t v) noexcept
461{
462 return __builtin_bswap32(v);
463}
464
465# else
466
467constexpr std::uint64_t byteswap(std::uint64_t v) noexcept
468{
469 return ((v & UINT64_C(0x00000000000000FF)) << 56)
470 | ((v & UINT64_C(0x000000000000FF00)) << 40)
471 | ((v & UINT64_C(0x0000000000FF0000)) << 24)
472 | ((v & UINT64_C(0x00000000FF000000)) << 8)
473 | ((v & UINT64_C(0x000000FF00000000)) >> 8)
474 | ((v & UINT64_C(0x0000FF0000000000)) >> 24)
475 | ((v & UINT64_C(0x00FF000000000000)) >> 40)
476 | ((v & UINT64_C(0xFF00000000000000)) >> 56);
477}
478
479constexpr std::uint32_t byteswap(std::uint32_t v) noexcept
480{
481 return ((v & UINT32_C(0x000000FF)) << 24)
482 | ((v & UINT32_C(0x0000FF00)) << 8)
483 | ((v & UINT32_C(0x00FF0000)) >> 8)
484 | ((v & UINT32_C(0xFF000000)) >> 24);
485}
486
487constexpr std::uint16_t byteswap(std::uint16_t v) noexcept
488{
489 return ((v & UINT16_C(0x00FF)) << 8) | ((v & UINT16_C(0xFF00)) >> 8);
490}
491
492# endif
493#endif
494
495template<typename T>
496struct fp_underlying_type;
497
498template<typename T>
499using fp_underlying_type_t = typename fp_underlying_type<T>::type;
500
501template<>
502struct fp_underlying_type<float>
503{
504 using type = std::uint32_t;
505};
506
507template<>
508struct fp_underlying_type<double>
509{
510 using type = std::uint64_t;
511};
512
513// usually, I don't like putting `enable_if` into return type but these
514// overloads are not public and it looks better than adding `typename = void` to
515// template headers
516template<typename T>
517constexpr enable_if_t<sizeof(T) == 1, T> byteswap(T value) noexcept
518{
519 return value;
520}
521
522template<typename T>
523SBEPP_CPP20_CONSTEXPR
524 enable_if_t<!std::is_floating_point<T>::value && (sizeof(T) != 1), T>
525 byteswap(T value) noexcept
526{
527#if SBEPP_HAS_BYTESWAP
528 // casts are required because this overload is selected for enums which are
529 // not integral and can't be passed to `std::byteswap` as is
530 return static_cast<T>(std::byteswap(
531 static_cast<typename std::make_unsigned<T>::type>(value)));
532#else
533 return static_cast<T>(
534 byteswap(static_cast<typename std::make_unsigned<T>::type>(value)));
535#endif
536}
537
538template<typename T>
539enable_if_t<std::is_floating_point<T>::value, T> byteswap(T value) noexcept
540{
541 fp_underlying_type_t<T> underlying{};
542 std::memcpy(&underlying, &value, sizeof(underlying));
543 underlying = byteswap(underlying);
544
545 std::memcpy(&value, &underlying, sizeof(underlying));
546
547 return value;
548}
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)
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)
570 {
571 return res;
572 }
573 else
574 {
575 return byteswap(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)
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)
597 {
598 value = byteswap(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
674struct access_by_tag_tag
675{
676 explicit access_by_tag_tag() = default;
677};
678
679template<typename T, typename U, endian E, typename View>
680SBEPP_CPP20_CONSTEXPR T
681 get_value(const View view, const std::size_t offset) noexcept
682{
683 SBEPP_SIZE_CHECK(
684 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(U));
685 return T{get_primitive<U, E>(view(addressof_tag{}) + offset)};
686}
687
688template<endian E, typename T, typename View>
689SBEPP_CPP20_CONSTEXPR void
690 set_value(const View view, const std::size_t offset, const T value) noexcept
691{
692 SBEPP_SIZE_CHECK(
693 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(T));
694 set_primitive<E>(view(addressof_tag{}) + offset, value);
695}
696
697template<typename Res, typename View>
698SBEPP_CPP20_CONSTEXPR Res
699 get_static_field_view(const View view, const std::size_t offset) noexcept
700{
701 SBEPP_SIZE_CHECK(view(addressof_tag{}), view(end_ptr_tag{}), offset, 0);
702 return {view(addressof_tag{}) + offset, view(end_ptr_tag{})};
703}
704
705template<typename Group, typename View>
706SBEPP_CPP20_CONSTEXPR Group
707 get_first_dynamic_field_view(const View view) noexcept
708{
709 return {
710 view(get_level_tag{}) + view(get_block_length_tag{}),
711 view(end_ptr_tag{})};
712}
713
714template<typename Group, typename View, typename Prev>
715SBEPP_CPP20_CONSTEXPR Group
716 get_dynamic_field_view(const View view, const Prev prev) noexcept
717{
718 return {
719 prev(addressof_tag{}) + prev(size_bytes_tag{}), view(end_ptr_tag{})};
720}
721
724template<typename Byte>
725class byte_range
726{
727public:
728 static_assert(sizeof(Byte) == 1, "Byte must represent a single byte");
729
730 template<typename Byte2>
731 friend class byte_range;
732
734 byte_range() = default;
735
737 SBEPP_CPP14_CONSTEXPR byte_range(Byte* begin, Byte* end) noexcept
738 : begin{begin}
739#if SBEPP_SIZE_CHECKS_ENABLED
740 ,
741 end{end}
742#endif
743 {
744 (void)end;
745 }
746
748 constexpr byte_range(Byte* ptr, const std::size_t size) noexcept
749 : byte_range{ptr, ptr + size}
750 {
751 }
752
754 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
755 // NOLINTNEXTLINE: intentionally implicit
756 constexpr byte_range(const byte_range<Byte2>& other) noexcept
757 : begin{other.begin}
758#if SBEPP_SIZE_CHECKS_ENABLED
759 ,
760 end{other.end}
761#endif
762 {
763 }
764
765 constexpr Byte* operator()(addressof_tag) const noexcept
766 {
767 return begin;
768 }
769
770 constexpr Byte* operator()(end_ptr_tag) const noexcept
771 {
772#if SBEPP_SIZE_CHECKS_ENABLED
773 return end;
774#else
775 return nullptr;
776#endif
777 }
778
779private:
780 Byte* begin{};
781#if SBEPP_SIZE_CHECKS_ENABLED
782 Byte* end{};
783#endif
784};
785} // namespace detail
786
793template<typename Byte>
794class cursor
795{
796public:
798 using byte_type = Byte;
799
800 // in accessors we have to use trailing return type because in "skip" mode
801 // they should return `void`. In most cases it's not a problem but
802 // `get_group_view` and `get_data_view` take lambdas which were not allowed
803 // in unevaluated context (e.g. decltype) prior to C++20 so we need this
804 // alias to specify return types for them. First attempt used
805 // pointer-to-member instead of lambda but GCC doesn't support it so I
806 // switched to simpler approach with lambda and trait.
807 template<typename T>
808 using result_type = T;
809
811 cursor() = default;
812
820 template<
821 typename Byte2,
822 typename = detail::enable_if_convertible_t<Byte2, Byte>>
823 // NOLINTNEXTLINE: implicit conversion is intentional
824 constexpr cursor(cursor<Byte2> other) noexcept : ptr{other.ptr}
825 {
826 }
827
836 template<
837 typename Byte2,
838 typename = detail::enable_if_convertible_t<Byte2, Byte>>
839 SBEPP_CPP14_CONSTEXPR cursor& operator=(cursor<Byte2> other) noexcept
840 {
841 ptr = other.ptr;
842 return *this;
843 }
844
851 SBEPP_CPP14_CONSTEXPR Byte*& pointer() noexcept
852 {
853 return ptr;
854 }
855
861 SBEPP_CPP14_CONSTEXPR Byte* pointer() const noexcept
862 {
863 return ptr;
864 }
865
866 template<typename T, typename U, endian E, typename View>
867 SBEPP_CPP20_CONSTEXPR T get_value(
868 const View view,
869 const std::size_t offset,
870 const std::size_t absolute_offset) noexcept
871 {
872 SBEPP_ASSERT(
873 ((view(detail::addressof_tag{}) + absolute_offset)
874 == (ptr + offset))
875 && "Wrong cursor value");
876 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
877 T res{detail::get_primitive<U, E>(ptr + offset)};
878 ptr += offset + sizeof(U);
879 return res;
880 }
881
882 template<endian E, typename T, typename View>
883 SBEPP_CPP20_CONSTEXPR void set_value(
884 const View view,
885 const std::size_t offset,
886 const std::size_t absolute_offset,
887 const T value) noexcept
888 {
889 SBEPP_ASSERT(
890 ((view(detail::addressof_tag{}) + absolute_offset)
891 == (ptr + offset))
892 && "Wrong cursor value");
893 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
894 detail::set_primitive<E>(ptr + offset, value);
895 ptr += offset + sizeof(T);
896 }
897
898 template<typename T, typename U, endian E, typename View>
899 SBEPP_CPP20_CONSTEXPR T get_last_value(
900 const View view,
901 const std::size_t offset,
902 const std::size_t absolute_offset) noexcept
903 {
904 SBEPP_ASSERT(
905 ((view(detail::addressof_tag{}) + absolute_offset)
906 == (ptr + offset))
907 && "Wrong cursor value");
908 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
909 auto res = T{detail::get_primitive<U, E>(ptr + offset)};
910 ptr = view(detail::get_level_tag{})
911 + view(detail::get_block_length_tag{});
912 return res;
913 }
914
915 template<endian E, typename T, typename View>
916 SBEPP_CPP20_CONSTEXPR void set_last_value(
917 const View view,
918 const std::size_t offset,
919 const std::size_t absolute_offset,
920 const T value) noexcept
921 {
922 SBEPP_ASSERT(
923 ((view(detail::addressof_tag{}) + absolute_offset)
924 == (ptr + offset))
925 && "Wrong cursor value");
926 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
927 detail::set_primitive<E>(ptr + offset, value);
928 ptr = view(detail::get_level_tag{})
929 + view(detail::get_block_length_tag{});
930 }
931
932 template<typename Res, typename View>
933 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
934 const View view,
935 const std::size_t offset,
936 const std::size_t absolute_offset) noexcept
937 {
938 SBEPP_ASSERT(
939 ((view(detail::addressof_tag{}) + absolute_offset)
940 == (ptr + offset))
941 && "Wrong cursor value");
942 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
943 Res res{ptr + offset, view(detail::end_ptr_tag{})};
944 ptr += offset + res(detail::size_bytes_tag{});
945 return res;
946 }
947
948 template<typename Res, typename View>
949 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
950 const View view,
951 const std::size_t offset,
952 const std::size_t absolute_offset) noexcept
953 {
954 SBEPP_ASSERT(
955 ((view(detail::addressof_tag{}) + absolute_offset)
956 == (ptr + offset))
957 && "Wrong cursor value");
958 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
959 Res res{ptr + offset, view(detail::end_ptr_tag{})};
960 ptr = view(detail::get_level_tag{})
961 + view(detail::get_block_length_tag{});
962 return res;
963 }
964
965 template<typename ResView, typename View>
966 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
967 {
968 ptr = view(detail::get_level_tag{})
969 + view(detail::get_block_length_tag{});
970 ResView g{ptr, view(detail::end_ptr_tag{})};
971 ptr += g(detail::get_header_tag{})(detail::size_bytes_tag{});
972
973 return g;
974 }
975
976 template<typename ResView, typename View>
977 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
978 {
979 ptr = view(detail::get_level_tag{})
980 + view(detail::get_block_length_tag{});
981 ResView d{ptr, view(detail::end_ptr_tag{})};
982 ptr += d(detail::size_bytes_tag{});
983
984 return d;
985 }
986
987 template<typename ResView, typename View, typename Getter>
988 SBEPP_CPP20_CONSTEXPR ResView
989 get_group_view(const View view, Getter&& getter) noexcept
990 {
991 SBEPP_ASSERT(
992 (getter()(detail::addressof_tag{}) == ptr) && "Wrong cursor value");
993 ResView res{ptr, view(detail::end_ptr_tag{})};
994 auto header = res(detail::get_header_tag{});
995 ptr += header(detail::size_bytes_tag{});
996 return res;
997 }
998
999 template<typename ResView, typename View, typename Getter>
1000 SBEPP_CPP20_CONSTEXPR ResView
1001 get_data_view(const View view, Getter&& getter) noexcept
1002 {
1003 SBEPP_ASSERT(
1004 (getter()(detail::addressof_tag{}) == ptr) && "Wrong cursor value");
1005 ResView res{ptr, view(detail::end_ptr_tag{})};
1006 ptr += res(detail::size_bytes_tag{});
1007 return res;
1008 }
1009
1010private:
1011 template<typename T>
1012 friend class cursor;
1013
1014 Byte* ptr{};
1015};
1016
1017namespace detail
1018{
1019template<typename Byte>
1020class init_cursor_wrapper
1021{
1022public:
1023 using byte_type = Byte;
1024
1025 template<typename T>
1026 using result_type = T;
1027
1028 init_cursor_wrapper() = default;
1029
1030 explicit constexpr init_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1031 : cursor{&cursor}
1032 {
1033 }
1034
1035 template<typename T, typename U, endian E, typename View>
1036 SBEPP_CPP20_CONSTEXPR T get_value(
1037 const View view,
1038 const std::size_t /*offset*/,
1039 const std::size_t absolute_offset) noexcept
1040 {
1041 SBEPP_SIZE_CHECK(
1042 view(addressof_tag{}),
1043 view(end_ptr_tag{}),
1044 absolute_offset,
1045 sizeof(U));
1046 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1047 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(U);
1048 return res;
1049 }
1050
1051 template<endian E, typename T, typename View>
1052 SBEPP_CPP20_CONSTEXPR void set_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() = view(addressof_tag{}) + absolute_offset + sizeof(T);
1065 }
1066
1067 template<typename T, typename U, endian E, typename View>
1068 SBEPP_CPP20_CONSTEXPR T get_last_value(
1069 const View view,
1070 const std::size_t /*offset*/,
1071 const std::size_t absolute_offset) noexcept
1072 {
1073 SBEPP_SIZE_CHECK(
1074 view(addressof_tag{}),
1075 view(end_ptr_tag{}),
1076 absolute_offset,
1077 sizeof(U));
1078 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1079 cursor->pointer() =
1080 view(get_level_tag{}) + view(get_block_length_tag{});
1081 return res;
1082 }
1083
1084 template<endian E, typename T, typename View>
1085 SBEPP_CPP20_CONSTEXPR void set_last_value(
1086 const View view,
1087 const std::size_t /*offset*/,
1088 const std::size_t absolute_offset,
1089 const T value) noexcept
1090 {
1091 SBEPP_SIZE_CHECK(
1092 view(addressof_tag{}),
1093 view(end_ptr_tag{}),
1094 absolute_offset,
1095 sizeof(T));
1096 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1097 cursor->pointer() =
1098 view(get_level_tag{}) + view(get_block_length_tag{});
1099 }
1100
1101 template<typename Res, typename View>
1102 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1103 const View view,
1104 const std::size_t /*offset*/,
1105 const std::size_t absolute_offset) noexcept
1106 {
1107 SBEPP_SIZE_CHECK(
1108 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1109 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1110 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1111 return res;
1112 }
1113
1114 template<typename Res, typename View>
1115 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1116 const View view,
1117 const std::size_t /*offset*/,
1118 const std::size_t absolute_offset) noexcept
1119 {
1120 SBEPP_SIZE_CHECK(
1121 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1122 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1123 cursor->pointer() =
1124 view(get_level_tag{}) + view(get_block_length_tag{});
1125 return res;
1126 }
1127
1128 template<typename ResView, typename View>
1129 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1130 {
1131 return cursor->template get_first_group_view<ResView>(view);
1132 }
1133
1134 template<typename ResView, typename View>
1135 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1136 {
1137 return cursor->template get_first_data_view<ResView>(view);
1138 }
1139
1140 template<typename ResView, typename View, typename Getter>
1141 SBEPP_CPP20_CONSTEXPR ResView
1142 get_group_view(const View /*view*/, Getter&& getter) noexcept
1143 {
1144 auto res = getter();
1145 auto header = res(get_header_tag{});
1146 cursor->pointer() = res(addressof_tag{}) + header(size_bytes_tag{});
1147 return res;
1148 }
1149
1150 template<typename ResView, typename View, typename Getter>
1151 SBEPP_CPP20_CONSTEXPR ResView
1152 get_data_view(const View /*view*/, Getter&& getter) noexcept
1153 {
1154 auto res = getter();
1155 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1156 return res;
1157 }
1158
1159private:
1160 sbepp::cursor<Byte>* cursor{};
1161};
1162
1163template<typename Byte>
1164class init_dont_move_cursor_wrapper
1165{
1166public:
1167 using byte_type = Byte;
1168
1169 template<typename T>
1170 using result_type = T;
1171
1172 init_dont_move_cursor_wrapper() = default;
1173
1174 explicit constexpr init_dont_move_cursor_wrapper(
1175 sbepp::cursor<Byte>& cursor)
1176 : cursor{&cursor}
1177 {
1178 }
1179
1180 template<typename T, typename U, endian E, typename View>
1181 SBEPP_CPP20_CONSTEXPR T get_value(
1182 const View view,
1183 const std::size_t offset,
1184 const std::size_t absolute_offset) noexcept
1185 {
1186 SBEPP_SIZE_CHECK(
1187 view(addressof_tag{}),
1188 view(end_ptr_tag{}),
1189 absolute_offset,
1190 sizeof(U));
1191 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1192 return T{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1193 }
1194
1195 template<endian E, typename T, typename View>
1196 SBEPP_CPP20_CONSTEXPR void set_value(
1197 const View view,
1198 const std::size_t offset,
1199 const std::size_t absolute_offset,
1200 const T value) noexcept
1201 {
1202 SBEPP_SIZE_CHECK(
1203 view(addressof_tag{}),
1204 view(end_ptr_tag{}),
1205 absolute_offset,
1206 sizeof(T));
1207 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1208 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1209 }
1210
1211 template<typename T, typename U, endian E, typename View>
1212 SBEPP_CPP20_CONSTEXPR T get_last_value(
1213 const View view,
1214 const std::size_t offset,
1215 const std::size_t absolute_offset) noexcept
1216 {
1217 return get_value<T, U, E>(view, offset, absolute_offset);
1218 }
1219
1220 template<endian E, typename T, typename View>
1221 SBEPP_CPP20_CONSTEXPR void set_last_value(
1222 const View view,
1223 const std::size_t offset,
1224 const std::size_t absolute_offset,
1225 const T value) noexcept
1226 {
1227 return set_value<E>(view, offset, absolute_offset, value);
1228 }
1229
1230 template<typename Res, typename View>
1231 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1232 const View view,
1233 const std::size_t offset,
1234 const std::size_t absolute_offset) noexcept
1235 {
1236 SBEPP_SIZE_CHECK(
1237 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1238 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1239 return {view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1240 }
1241
1242 template<typename Res, typename View>
1243 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1244 const View view,
1245 const std::size_t offset,
1246 const std::size_t absolute_offset) noexcept
1247 {
1248 return get_static_field_view<Res>(view, offset, absolute_offset);
1249 }
1250
1251 template<typename ResView, typename View>
1252 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1253 {
1254 cursor->pointer() =
1255 view(get_level_tag{}) + view(get_block_length_tag{});
1256 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1257
1258 return g;
1259 }
1260
1261 template<typename ResView, typename View>
1262 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1263 {
1264 cursor->pointer() =
1265 view(get_level_tag{}) + view(get_block_length_tag{});
1266 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1267
1268 return d;
1269 }
1270
1271 template<typename ResView, typename View, typename Getter>
1272 SBEPP_CPP20_CONSTEXPR ResView
1273 get_group_view(const View /*view*/, Getter&& getter) noexcept
1274 {
1275 auto res = getter();
1276 cursor->pointer() = res(addressof_tag{});
1277 return res;
1278 }
1279
1280 template<typename ResView, typename View, typename Getter>
1281 SBEPP_CPP20_CONSTEXPR ResView
1282 get_data_view(const View /*view*/, Getter&& getter) noexcept
1283 {
1284 auto res = getter();
1285 cursor->pointer() = res(addressof_tag{});
1286 return res;
1287 }
1288
1289private:
1290 sbepp::cursor<Byte>* cursor{};
1291};
1292
1293template<typename Byte>
1294class dont_move_cursor_wrapper
1295{
1296public:
1297 using byte_type = Byte;
1298
1299 template<typename T>
1300 using result_type = T;
1301
1302 dont_move_cursor_wrapper() = default;
1303
1304 explicit constexpr dont_move_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1305 : cursor{&cursor}
1306 {
1307 }
1308
1309 template<typename T, typename U, endian E, typename View>
1310 SBEPP_CPP20_CONSTEXPR T get_value(
1311 const View view,
1312 const std::size_t offset,
1313 const std::size_t absolute_offset) noexcept
1314 {
1315 SBEPP_ASSERT(
1316 ((view(detail::addressof_tag{}) + absolute_offset)
1317 == (cursor->pointer() + offset))
1318 && "Wrong cursor value");
1319 SBEPP_SIZE_CHECK(
1320 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1321 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1322 }
1323
1324 template<endian E, typename T, typename View>
1325 SBEPP_CPP20_CONSTEXPR void set_value(
1326 const View view,
1327 const std::size_t offset,
1328 const std::size_t absolute_offset,
1329 const T value) noexcept
1330 {
1331 SBEPP_ASSERT(
1332 ((view(detail::addressof_tag{}) + absolute_offset)
1333 == (cursor->pointer() + offset))
1334 && "Wrong cursor value");
1335 SBEPP_SIZE_CHECK(
1336 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1337 set_primitive<E>(cursor->pointer() + offset, value);
1338 }
1339
1340 template<typename T, typename U, endian E, typename View>
1341 SBEPP_CPP20_CONSTEXPR T get_last_value(
1342 const View view,
1343 const std::size_t offset,
1344 const std::size_t absolute_offset) noexcept
1345 {
1346 SBEPP_ASSERT(
1347 ((view(detail::addressof_tag{}) + absolute_offset)
1348 == (cursor->pointer() + offset))
1349 && "Wrong cursor value");
1350 SBEPP_SIZE_CHECK(
1351 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1352 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1353 }
1354
1355 template<endian E, typename T, typename View>
1356 SBEPP_CPP20_CONSTEXPR void set_last_value(
1357 const View view,
1358 const std::size_t offset,
1359 const std::size_t absolute_offset,
1360 const T value) noexcept
1361 {
1362 SBEPP_ASSERT(
1363 ((view(detail::addressof_tag{}) + absolute_offset)
1364 == (cursor->pointer() + offset))
1365 && "Wrong cursor value");
1366 SBEPP_SIZE_CHECK(
1367 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1368 set_primitive<E>(cursor->pointer() + offset, value);
1369 }
1370
1371 template<typename Res, typename View>
1372 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1373 const View view,
1374 const std::size_t offset,
1375 const std::size_t absolute_offset) noexcept
1376 {
1377 SBEPP_ASSERT(
1378 ((view(detail::addressof_tag{}) + absolute_offset)
1379 == (cursor->pointer() + offset))
1380 && "Wrong cursor value");
1381 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1382 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1383 }
1384
1385 template<typename Res, typename View>
1386 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1387 const View view,
1388 const std::size_t offset,
1389 const std::size_t absolute_offset) noexcept
1390 {
1391 SBEPP_ASSERT(
1392 ((view(detail::addressof_tag{}) + absolute_offset)
1393 == (cursor->pointer() + offset))
1394 && "Wrong cursor value");
1395 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1396 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1397 }
1398
1399 template<typename ResView, typename View>
1400 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1401 {
1402 cursor->pointer() =
1403 view(get_level_tag{}) + view(get_block_length_tag{});
1404 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1405
1406 return g;
1407 }
1408
1409 template<typename ResView, typename View>
1410 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1411 {
1412 cursor->pointer() =
1413 view(get_level_tag{}) + view(get_block_length_tag{});
1414 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1415
1416 return d;
1417 }
1418
1419 template<typename ResView, typename View, typename Getter>
1420 SBEPP_CPP20_CONSTEXPR ResView
1421 get_group_view(const View view, Getter&& getter) noexcept
1422 {
1423 SBEPP_ASSERT(
1424 (getter()(detail::addressof_tag{}) == cursor->pointer())
1425 && "Wrong cursor value");
1426 return {cursor->pointer(), view(end_ptr_tag{})};
1427 }
1428
1429 template<typename ResView, typename View, typename Getter>
1430 SBEPP_CPP20_CONSTEXPR ResView
1431 get_data_view(const View view, Getter&& getter) noexcept
1432 {
1433 SBEPP_ASSERT(
1434 (getter()(detail::addressof_tag{}) == cursor->pointer())
1435 && "Wrong cursor value");
1436 return {cursor->pointer(), view(end_ptr_tag{})};
1437 }
1438
1439private:
1440 sbepp::cursor<Byte>* cursor{};
1441};
1442
1443template<typename Byte>
1444class skip_cursor_wrapper
1445{
1446public:
1447 using byte_type = Byte;
1448
1449 template<typename T>
1450 using result_type = void;
1451
1452 skip_cursor_wrapper() = default;
1453
1454 explicit constexpr skip_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1455 : cursor{&cursor}
1456 {
1457 }
1458
1459 template<typename T, typename U, endian E, typename View>
1460 SBEPP_CPP20_CONSTEXPR void get_value(
1461 const View view,
1462 const std::size_t offset,
1463 const std::size_t absolute_offset) noexcept
1464 {
1465 SBEPP_ASSERT(
1466 ((view(detail::addressof_tag{}) + absolute_offset)
1467 == (cursor->pointer() + offset))
1468 && "Wrong cursor value");
1469 SBEPP_SIZE_CHECK(
1470 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1471 cursor->pointer() += offset + sizeof(U);
1472 }
1473
1474 template<typename T, typename U, endian E, typename View>
1475 SBEPP_CPP20_CONSTEXPR void get_last_value(
1476 const View view,
1477 const std::size_t offset,
1478 const std::size_t absolute_offset) noexcept
1479 {
1480 SBEPP_ASSERT(
1481 ((view(detail::addressof_tag{}) + absolute_offset)
1482 == (cursor->pointer() + offset))
1483 && "Wrong cursor value");
1484 SBEPP_SIZE_CHECK(
1485 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1486 cursor->pointer() =
1487 view(get_level_tag{}) + view(get_block_length_tag{});
1488 }
1489
1490 template<typename Res, typename View>
1491 SBEPP_CPP20_CONSTEXPR void get_static_field_view(
1492 const View view,
1493 const std::size_t offset,
1494 const std::size_t absolute_offset) noexcept
1495 {
1496 SBEPP_ASSERT(
1497 ((view(detail::addressof_tag{}) + absolute_offset)
1498 == (cursor->pointer() + offset))
1499 && "Wrong cursor value");
1500 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1501 Res res{cursor->pointer(), view(end_ptr_tag{})};
1502 cursor->pointer() += offset + res(size_bytes_tag{});
1503 }
1504
1505 template<typename Res, typename View>
1506 SBEPP_CPP20_CONSTEXPR void get_last_static_field_view(
1507 const View view,
1508 const std::size_t offset,
1509 const std::size_t absolute_offset) noexcept
1510 {
1511 SBEPP_ASSERT(
1512 ((view(detail::addressof_tag{}) + absolute_offset)
1513 == (cursor->pointer() + offset))
1514 && "Wrong cursor value");
1515 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1516 cursor->pointer() =
1517 view(get_level_tag{}) + view(get_block_length_tag{});
1518 }
1519
1520 template<typename ResView, typename View>
1521 SBEPP_CPP20_CONSTEXPR void get_first_group_view(const View view) noexcept
1522 {
1523 cursor->pointer() =
1524 view(get_level_tag{}) + view(get_block_length_tag{});
1525 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1526 cursor->pointer() += g(size_bytes_tag{});
1527 }
1528
1529 template<typename ResView, typename View>
1530 SBEPP_CPP20_CONSTEXPR void get_first_data_view(const View view) noexcept
1531 {
1532 cursor->pointer() =
1533 view(get_level_tag{}) + view(get_block_length_tag{});
1534 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1535 cursor->pointer() += d(size_bytes_tag{});
1536 }
1537
1538 template<typename ResView, typename View, typename Getter>
1539 SBEPP_CPP20_CONSTEXPR void
1540 get_group_view(const View view, Getter&& getter) noexcept
1541 {
1542 SBEPP_ASSERT(
1543 (getter()(detail::addressof_tag{}) == cursor->pointer())
1544 && "Wrong cursor value");
1545 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1546 cursor->pointer() += res(size_bytes_tag{});
1547 }
1548
1549 template<typename ResView, typename View, typename Getter>
1550 SBEPP_CPP20_CONSTEXPR void
1551 get_data_view(const View view, Getter&& getter) noexcept
1552 {
1553 SBEPP_ASSERT(
1554 (getter()(detail::addressof_tag{}) == cursor->pointer())
1555 && "Wrong cursor value");
1556 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1557 cursor->pointer() += res(size_bytes_tag{});
1558 }
1559
1560private:
1561 sbepp::cursor<Byte>* cursor{};
1562};
1563
1564template<typename Cursor, typename T>
1565using cursor_result_type_t =
1566 typename remove_reference_t<Cursor>::template result_type<T>;
1567
1568template<typename Cursor>
1569using cursor_byte_type_t = typename remove_reference_t<Cursor>::byte_type;
1570
1571template<typename MessageByte, typename CursorByte>
1572using enable_if_cursor_compatible_t =
1573 enable_if_convertible_t<MessageByte, CursorByte>;
1574
1575template<typename MessageByte, typename CursorByte>
1576using enable_if_cursor_writeable_t = enable_if_t<
1577 std::is_convertible<MessageByte*, CursorByte*>::value
1578 && !std::is_const<MessageByte>::value && !std::is_const<CursorByte>::value>;
1579} // namespace detail
1580
1591template<typename T>
1592constexpr std::size_t size_bytes(T v) noexcept
1593{
1594 return v(detail::size_bytes_tag{});
1595}
1596
1606template<typename T, typename Byte>
1607constexpr std::size_t size_bytes(T v, cursor<Byte> c) noexcept
1608{
1609 return v(detail::size_bytes_tag{}, c);
1610}
1611
1618template<typename T>
1619constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
1620{
1621 return v(detail::get_header_tag{});
1622}
1623
1630template<typename T>
1631constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
1632{
1633 return v(detail::addressof_tag{});
1634}
1635
1641template<typename View>
1643{
1645 using type = typename std::remove_pointer<decltype(sbepp::addressof(
1646 std::declval<View>()))>::type;
1647};
1648
1650template<typename View>
1652
1657namespace cursor_ops
1658{
1676template<typename Byte>
1677constexpr detail::init_cursor_wrapper<Byte> init(cursor<Byte>& c) noexcept
1678{
1679 return detail::init_cursor_wrapper<Byte>{c};
1680}
1681
1704template<typename Byte>
1705constexpr detail::dont_move_cursor_wrapper<Byte>
1707{
1708 return detail::dont_move_cursor_wrapper<Byte>{c};
1709}
1710
1718template<typename Byte>
1719constexpr detail::init_dont_move_cursor_wrapper<Byte>
1721{
1722 return detail::init_dont_move_cursor_wrapper<Byte>{c};
1723}
1724
1739template<typename Byte>
1740constexpr detail::skip_cursor_wrapper<Byte> skip(cursor<Byte>& c) noexcept
1741{
1742 return detail::skip_cursor_wrapper<Byte>{c};
1743}
1744} // namespace cursor_ops
1745
1746namespace detail
1747{
1748// the only purpose of this class is to implement `is_composite` trait
1750template<typename Byte>
1751class composite_base : public byte_range<Byte>
1752{
1753public:
1754 using byte_range<Byte>::byte_range;
1755 using byte_range<Byte>::operator();
1756};
1757
1759template<typename Byte, typename Header>
1760class message_base : public byte_range<Byte>
1761{
1762public:
1763 using byte_range<Byte>::byte_range;
1764 using byte_range<Byte>::operator();
1765
1766 SBEPP_CPP14_CONSTEXPR Header operator()(get_header_tag) const noexcept
1767 {
1768 Header header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
1769 SBEPP_SIZE_CHECK(
1770 (*this)(addressof_tag{}),
1771 (*this)(end_ptr_tag{}),
1772 0,
1773 sbepp::size_bytes(header));
1774 return header;
1775 }
1776
1777 SBEPP_CPP14_CONSTEXPR Byte* operator()(get_level_tag) const noexcept
1778 {
1779 auto header = (*this)(get_header_tag{});
1780 return header(addressof_tag{}) + header(size_bytes_tag{});
1781 }
1782
1783 constexpr typename std::decay<
1784 decltype(std::declval<Header>().blockLength().value())>::type
1785 operator()(get_block_length_tag) const noexcept
1786 {
1787 return operator()(get_header_tag{}).blockLength().value();
1788 }
1789
1790 template<
1791 typename Byte2,
1792 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
1793 SBEPP_CPP20_CONSTEXPR std::size_t
1794 operator()(size_bytes_tag, cursor<Byte2>& c) const noexcept
1795 {
1796 return c.pointer() - (*this)(addressof_tag{});
1797 }
1798};
1799
1801template<typename Byte, typename BlockLengthType>
1802class entry_base : public byte_range<Byte>
1803{
1804public:
1805 using byte_range<Byte>::operator();
1806
1807 template<typename Byte2, typename BlockLengthType2>
1808 friend class entry_base;
1809
1811 entry_base() = default;
1812
1814 constexpr entry_base(
1815 Byte* ptr, Byte* end, BlockLengthType block_length) noexcept
1816 : byte_range<Byte>{ptr, end}, block_length{block_length}
1817 {
1818 }
1819
1821 constexpr entry_base(
1822 Byte* ptr,
1823 const std::size_t size,
1824 const BlockLengthType block_length) noexcept
1825 : entry_base{ptr, ptr + size, block_length}
1826 {
1827 }
1828
1830 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1831 constexpr entry_base(
1832 cursor<Byte2>& c, Byte* end_ptr, BlockLengthType block_length) noexcept
1833 : entry_base{c.pointer(), end_ptr, block_length}
1834 {
1835 // forwards to the above one for non-empty entries. Empty entries have
1836 // implementation in the derived class which advances cursor up to
1837 // `block_length`.
1838 }
1839
1842 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1843 constexpr entry_base(
1844 const entry_base<Byte2, BlockLengthType>& other) noexcept
1845 : byte_range<Byte>{other}, block_length{other.block_length}
1846 {
1847 }
1848
1849 constexpr BlockLengthType operator()(get_block_length_tag) const noexcept
1850 {
1851 return block_length;
1852 }
1853
1854 constexpr Byte* operator()(get_level_tag) const noexcept
1855 {
1856 return (*this)(addressof_tag{});
1857 }
1858
1859private:
1860 BlockLengthType block_length{};
1861};
1862
1863template<typename Entry>
1864class arrow_proxy
1865{
1866public:
1867 explicit constexpr arrow_proxy(Entry entry) noexcept : entry{entry}
1868 {
1869 }
1870
1871 constexpr const Entry* operator->() const noexcept
1872 {
1873 return &entry;
1874 }
1875
1876private:
1877 Entry entry;
1878};
1879
1880template<
1881 typename Byte,
1882 typename ValueType,
1883 typename IndexType,
1884 typename DifferenceType,
1885 typename BlockLengthType>
1886class forward_iterator
1887{
1888public:
1889 using iterator_category = std::forward_iterator_tag;
1890 using value_type = ValueType;
1891 using reference = value_type;
1892 using difference_type = DifferenceType;
1893 using pointer = arrow_proxy<value_type>;
1894
1895 forward_iterator() = default;
1896
1897 SBEPP_CPP14_CONSTEXPR forward_iterator(
1898 Byte* ptr,
1899 const IndexType index,
1900 const BlockLengthType block_length,
1901 Byte* end) noexcept
1902 : ptr{ptr},
1903 index{index},
1904 block_length{block_length}
1905#if SBEPP_SIZE_CHECKS_ENABLED
1906 ,
1907 end{end}
1908#endif
1909 {
1910 (void)end;
1911 }
1912
1913 constexpr reference operator*() const noexcept
1914 {
1915#if SBEPP_SIZE_CHECKS_ENABLED
1916 return {ptr, end, block_length};
1917#else
1918 return {ptr, nullptr, block_length};
1919#endif
1920 }
1921
1922 constexpr pointer operator->() const noexcept
1923 {
1924 return pointer{operator*()};
1925 }
1926
1927 SBEPP_CPP14_CONSTEXPR forward_iterator& operator++() noexcept
1928 {
1929 SBEPP_SIZE_CHECK(ptr, end, 0, sbepp::size_bytes(operator*()));
1930 ptr += sbepp::size_bytes(operator*());
1931 index++;
1932 return *this;
1933 }
1934
1935 SBEPP_CPP14_CONSTEXPR forward_iterator operator++(int) noexcept
1936 {
1937 auto old = *this;
1938 operator++();
1939 return old;
1940 }
1941
1942 friend constexpr bool operator==(
1943 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1944 {
1945 return lhs.index == rhs.index;
1946 }
1947
1948 friend constexpr bool operator!=(
1949 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1950 {
1951 return lhs.index != rhs.index;
1952 }
1953
1954private:
1955 Byte* ptr{};
1956 IndexType index{};
1957 BlockLengthType block_length{};
1958#if SBEPP_SIZE_CHECKS_ENABLED
1959 Byte* end{};
1960#endif
1961};
1962
1963template<
1964 typename Byte,
1965 typename ValueType,
1966 typename BlockLengthType,
1967 typename DifferenceType,
1968 typename IndexType>
1969class random_access_iterator
1970{
1971public:
1972 using iterator_category = std::random_access_iterator_tag;
1973 using value_type = ValueType;
1974 using reference = value_type;
1975 using difference_type = DifferenceType;
1976 using pointer = arrow_proxy<value_type>;
1977
1978 random_access_iterator() = default;
1979
1980 SBEPP_CPP14_CONSTEXPR random_access_iterator(
1981 Byte* ptr,
1982 const BlockLengthType block_length,
1983 const IndexType index,
1984 Byte* end) noexcept
1985 : ptr{ptr},
1986 block_length{block_length},
1987 index{index}
1988#if SBEPP_SIZE_CHECKS_ENABLED
1989 ,
1990 end{end}
1991#endif
1992 {
1993 (void)end;
1994 }
1995
1996 constexpr reference operator*() const noexcept
1997 {
1998#if SBEPP_SIZE_CHECKS_ENABLED
1999 return {ptr, end, block_length};
2000#else
2001 return {ptr, nullptr, block_length};
2002#endif
2003 }
2004
2005 constexpr pointer operator->() const noexcept
2006 {
2007 return pointer{operator*()};
2008 }
2009
2010 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator++() noexcept
2011 {
2012 SBEPP_SIZE_CHECK(ptr, end, 0, block_length);
2013 ptr += block_length;
2014 index++;
2015 return *this;
2016 }
2017
2018 SBEPP_CPP14_CONSTEXPR random_access_iterator operator++(int) noexcept
2019 {
2020 auto old = *this;
2021 operator++();
2022 return old;
2023 }
2024
2025 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator--() noexcept
2026 {
2027 ptr -= block_length;
2028 index--;
2029 return *this;
2030 }
2031
2032 SBEPP_CPP14_CONSTEXPR random_access_iterator operator--(int) noexcept
2033 {
2034 auto old = *this;
2035 operator--();
2036 return old;
2037 }
2038
2039 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2040 operator+=(difference_type n) noexcept
2041 {
2042 ptr += n * block_length;
2043 index += n;
2044 return *this;
2045 }
2046
2047 SBEPP_CPP14_CONSTEXPR random_access_iterator
2048 operator+(difference_type n) const noexcept
2049 {
2050 auto tmp = *this;
2051 return tmp += n;
2052 }
2053
2054 friend constexpr random_access_iterator
2055 operator+(difference_type n, const random_access_iterator& it) noexcept
2056 {
2057 return it + n;
2058 }
2059
2060 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2061 operator-=(difference_type n) noexcept
2062 {
2063 return *this += -n;
2064 }
2065
2066 SBEPP_CPP14_CONSTEXPR random_access_iterator
2067 operator-(difference_type n) const noexcept
2068 {
2069 auto tmp = *this;
2070 return tmp -= n;
2071 }
2072
2073 constexpr difference_type
2074 operator-(const random_access_iterator& rhs) const noexcept
2075 {
2076 return index - rhs.index;
2077 }
2078
2079 constexpr reference operator[](difference_type n) const noexcept
2080 {
2081 return *(*this + n);
2082 }
2083
2084 friend constexpr bool operator==(
2085 const random_access_iterator& lhs,
2086 const random_access_iterator& rhs) noexcept
2087 {
2088 return lhs.index == rhs.index;
2089 }
2090
2091 friend constexpr bool operator!=(
2092 const random_access_iterator& lhs,
2093 const random_access_iterator& rhs) noexcept
2094 {
2095 return lhs.index != rhs.index;
2096 }
2097
2098 friend constexpr bool operator<(
2099 const random_access_iterator& lhs,
2100 const random_access_iterator& rhs) noexcept
2101 {
2102 return lhs.index < rhs.index;
2103 }
2104
2105 friend constexpr bool operator<=(
2106 const random_access_iterator& lhs,
2107 const random_access_iterator& rhs) noexcept
2108 {
2109 return lhs.index <= rhs.index;
2110 }
2111
2112 friend constexpr bool operator>(
2113 const random_access_iterator& lhs,
2114 const random_access_iterator& rhs) noexcept
2115 {
2116 return lhs.index > rhs.index;
2117 }
2118
2119 friend constexpr bool operator>=(
2120 const random_access_iterator& lhs,
2121 const random_access_iterator& rhs) noexcept
2122 {
2123 return lhs.index >= rhs.index;
2124 }
2125
2126private:
2127 Byte* ptr{};
2128 BlockLengthType block_length{};
2129 // iterator should be index-based instead of just pointer-based to support
2130 // groups with empty entries, i.e. when `block_length == 0`
2131 IndexType index{};
2132#if SBEPP_SIZE_CHECKS_ENABLED
2133 Byte* end{};
2134#endif
2135};
2136
2137template<
2138 typename ValueType,
2139 typename IndexType,
2140 typename CursorType,
2141 typename BlockLengthType,
2142 typename Byte>
2143class input_iterator
2144{
2145public:
2146 using iterator_category = std::input_iterator_tag;
2147 using value_type = ValueType;
2148 using reference = value_type;
2149 using difference_type = typename std::make_signed<IndexType>::type;
2150 using pointer = arrow_proxy<value_type>;
2151
2152 input_iterator() = default;
2153
2154 SBEPP_CPP14_CONSTEXPR input_iterator(
2155 const IndexType index,
2156 CursorType* cursor,
2157 BlockLengthType block_length,
2158 Byte* end) noexcept
2159 : index{index},
2160 cursor{cursor},
2161 block_length{block_length}
2162#if SBEPP_SIZE_CHECKS_ENABLED
2163 ,
2164 end{end}
2165#endif
2166 {
2167 (void)end;
2168 }
2169
2170 constexpr reference operator*() const noexcept
2171 {
2172#if SBEPP_SIZE_CHECKS_ENABLED
2173 return {*cursor, end, block_length};
2174#else
2175 return {*cursor, nullptr, block_length};
2176#endif
2177 }
2178
2179 constexpr pointer operator->() const noexcept
2180 {
2181 return pointer{operator*()};
2182 }
2183
2184 SBEPP_CPP14_CONSTEXPR input_iterator& operator++() noexcept
2185 {
2186 index++;
2187 return *this;
2188 }
2189
2190 SBEPP_CPP14_CONSTEXPR input_iterator operator++(int) noexcept
2191 {
2192 auto old = *this;
2193 operator++();
2194 return old;
2195 }
2196
2197 friend constexpr bool operator==(
2198 const input_iterator& lhs, const input_iterator& rhs) noexcept
2199 {
2200 return lhs.index == rhs.index;
2201 }
2202
2203 friend constexpr bool operator!=(
2204 const input_iterator& lhs, const input_iterator& rhs) noexcept
2205 {
2206 return lhs.index != rhs.index;
2207 }
2208
2209private:
2210 IndexType index{};
2211 CursorType* cursor{};
2212 BlockLengthType block_length{};
2213#if SBEPP_SIZE_CHECKS_ENABLED
2214 Byte* end{};
2215#endif
2216};
2217
2218template<
2219 typename ValueType,
2220 typename IndexType,
2221 typename CursorType,
2222 typename BlockLengthType,
2223 typename Byte>
2224class cursor_range
2225{
2226public:
2227 SBEPP_CPP14_CONSTEXPR cursor_range(
2228 CursorType& cursor,
2229 BlockLengthType block_length,
2230 Byte* end,
2231 IndexType start_pos,
2232 IndexType length) noexcept
2233 : cursor{&cursor},
2234 block_length{block_length},
2235 start_pos{start_pos},
2236#if SBEPP_SIZE_CHECKS_ENABLED
2237 end_ptr{end},
2238#endif
2239 length{length}
2240 {
2241 (void)end;
2242 }
2243
2244 using iterator =
2245 input_iterator<ValueType, IndexType, CursorType, BlockLengthType, Byte>;
2246
2247 constexpr iterator begin() const noexcept
2248 {
2249#if SBEPP_SIZE_CHECKS_ENABLED
2250 return {start_pos, cursor, block_length, end_ptr};
2251#else
2252 return {start_pos, cursor, block_length, nullptr};
2253#endif
2254 }
2255
2256 constexpr iterator end() const noexcept
2257 {
2258#if SBEPP_SIZE_CHECKS_ENABLED
2259 return {
2260 static_cast<IndexType>(start_pos + size()),
2261 cursor,
2262 block_length,
2263 end_ptr};
2264#else
2265 return {
2266 static_cast<IndexType>(start_pos + size()),
2267 cursor,
2268 block_length,
2269 nullptr};
2270#endif
2271 }
2272
2273 constexpr IndexType size() const noexcept
2274 {
2275 return length;
2276 }
2277
2278private:
2279 CursorType* cursor{};
2280 BlockLengthType block_length{};
2281 IndexType start_pos{};
2282#if SBEPP_SIZE_CHECKS_ENABLED
2283 Byte* end_ptr{};
2284#endif
2285 IndexType length{};
2286};
2287
2289template<typename Byte, typename Entry, typename Dimension>
2290class flat_group_base : public byte_range<Byte>
2291{
2292public:
2294 using value_type = Entry;
2298 using sbe_size_type = typename std::decay<
2299 decltype(std::declval<Dimension>().numInGroup())>::type;
2301 using size_type = typename sbe_size_type::value_type;
2303 using difference_type = typename std::make_signed<size_type>::type;
2306 using iterator = random_access_iterator<
2307 Byte,
2308 Entry,
2309 typename std::decay<
2310 decltype(std::declval<Dimension>().blockLength().value())>::type,
2312 size_type>;
2313
2314 using byte_range<Byte>::byte_range;
2315 using byte_range<Byte>::operator();
2316
2317 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2318 {
2319 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2320 SBEPP_SIZE_CHECK(
2321 (*this)(addressof_tag{}),
2322 (*this)(end_ptr_tag{}),
2323 0,
2324 sbepp::size_bytes(header));
2325 return header;
2326 }
2327
2328 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2329 {
2330 auto dimension = (*this)(get_header_tag{});
2331 return sbepp::size_bytes(dimension)
2332 + dimension.numInGroup().value()
2333 * dimension.blockLength().value();
2334 }
2335
2337 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2338 {
2339 return (*this)(get_header_tag{}).numInGroup();
2340 }
2341
2343 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2344 {
2345 return sbe_size().value();
2346 }
2347
2349 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2350 {
2351 (*this)(get_header_tag{}).numInGroup(count);
2352 }
2353
2355 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2356 {
2357 return !size();
2358 }
2359
2361 constexpr static size_type max_size() noexcept
2362 {
2363 return sbe_size_type::max_value();
2364 }
2365
2367 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2368 {
2369 auto dimension = (*this)(get_header_tag{});
2370 return iterator{
2371 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2372 dimension.blockLength().value(),
2373 0,
2374 (*this)(end_ptr_tag{})};
2375 }
2376
2378 constexpr iterator end() const noexcept
2379 {
2380 return iterator{
2381 (*this)(addressof_tag{}) + (*this)(size_bytes_tag{}),
2382 (*this)(get_header_tag{}).blockLength().value(),
2383 size(),
2384 (*this)(end_ptr_tag{})};
2385 }
2386
2389 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
2390 {
2391 SBEPP_ASSERT(pos < size());
2392 return *(begin() + pos);
2393 }
2394
2397 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2398 {
2399 SBEPP_ASSERT(!empty());
2400 return *begin();
2401 }
2402
2405 SBEPP_CPP14_CONSTEXPR reference back() const noexcept
2406 {
2407 SBEPP_ASSERT(!empty());
2408 return *(--end());
2409 }
2410
2413 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2414 {
2415 resize(0);
2416 }
2417
2419 template<typename Byte2>
2420 using cursor_range_t = detail::cursor_range<
2421 value_type,
2422 size_type,
2424 typename std::decay<
2425 decltype(std::declval<Dimension>().blockLength().value())>::type,
2426 Byte>;
2427
2429 template<
2430 typename Byte2,
2431 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2432 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2433 cursor_range(cursor<Byte2>& c) const noexcept
2434 {
2435 return {
2436 c,
2437 (*this)(get_header_tag{}).blockLength().value(),
2438 (*this)(end_ptr_tag{}),
2439 0,
2440 size()};
2441 }
2442
2445 template<
2446 typename Byte2,
2447 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2448 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2449 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2450 {
2451 SBEPP_ASSERT(pos < size());
2452
2453 return {
2454 c,
2455 (*this)(get_header_tag{}).blockLength().value(),
2456 (*this)(end_ptr_tag{}),
2457 pos,
2458 static_cast<size_type>(size() - pos)};
2459 }
2460
2464 template<
2465 typename Byte2,
2466 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2468 cursor<Byte2>& c,
2469 const size_type pos,
2470 const size_type count) const noexcept
2471 {
2472 SBEPP_ASSERT(pos < size());
2473 SBEPP_ASSERT(count <= (size() - pos));
2474
2475 return {
2476 c,
2477 (*this)(get_header_tag{}).blockLength().value(),
2478 (*this)(end_ptr_tag{}),
2479 pos,
2480 count};
2481 }
2482
2484 template<typename Byte2>
2485 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2486
2488 template<
2489 typename Byte2,
2490 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2491 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2492 cursor_begin(cursor<Byte2>& c) const noexcept
2493 {
2494 return cursor_range(c).begin();
2495 }
2496
2498 template<
2499 typename Byte2,
2500 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2501 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2502 cursor_end(cursor<Byte2>& c) const noexcept
2503 {
2504 return cursor_range(c).end();
2505 }
2506
2507 template<typename Visitor, typename Cursor>
2508 SBEPP_CPP14_CONSTEXPR bool
2509 operator()(visit_children_tag, Visitor& v, Cursor& c)
2510 {
2511 for(const auto entry : this->cursor_range(c))
2512 {
2513 if(v.on_entry(entry, c))
2514 {
2515 return true;
2516 }
2517 }
2518 return false;
2519 }
2520};
2521
2523template<typename Byte, typename Entry, typename Dimension>
2524class nested_group_base : public byte_range<Byte>
2525{
2526public:
2528 using value_type = Entry;
2532 using sbe_size_type = typename std::decay<
2533 decltype(std::declval<Dimension>().numInGroup())>::type;
2535 using size_type = typename sbe_size_type::value_type;
2537 using difference_type = typename std::make_signed<size_type>::type;
2538
2541 using iterator = forward_iterator<
2542 Byte,
2543 Entry,
2544 size_type,
2546 typename std::decay<
2547 decltype(std::declval<Dimension>().blockLength().value())>::type>;
2548
2549 using byte_range<Byte>::byte_range;
2550 using byte_range<Byte>::operator();
2551
2552 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2553 {
2554 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2555 SBEPP_SIZE_CHECK(
2556 (*this)(addressof_tag{}),
2557 (*this)(end_ptr_tag{}),
2558 0,
2559 sbepp::size_bytes(header));
2560 return header;
2561 }
2562
2563 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2564 {
2565 std::size_t size{sbepp::size_bytes((*this)(get_header_tag{}))};
2566 for(const auto entry : *this)
2567 {
2568 size += sbepp::size_bytes(entry);
2569 }
2570
2571 return size;
2572 }
2573
2575 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2576 {
2577 return (*this)(get_header_tag{}).numInGroup();
2578 }
2579
2581 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2582 {
2583 return sbe_size().value();
2584 }
2585
2587 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2588 {
2589 (*this)(get_header_tag{}).numInGroup(count);
2590 }
2591
2593 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2594 {
2595 return !size();
2596 }
2597
2599 constexpr static size_type max_size() noexcept
2600 {
2601 return sbe_size_type::max_value();
2602 }
2603
2605 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2606 {
2607 auto dimension = (*this)(get_header_tag{});
2608 return iterator{
2609 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2610 0,
2611 dimension.blockLength().value(),
2612 (*this)(end_ptr_tag{})};
2613 }
2614
2616 constexpr iterator end() const noexcept
2617 {
2618 return iterator{
2619 nullptr,
2620 (*this)(get_header_tag{}).numInGroup().value(),
2621 (*this)(get_header_tag{}).blockLength().value(),
2622 (*this)(end_ptr_tag{})};
2623 }
2624
2627 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2628 {
2629 SBEPP_ASSERT(!empty());
2630 return *begin();
2631 }
2632
2635 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2636 {
2637 resize(0);
2638 }
2639
2641 template<typename Byte2>
2642 using cursor_range_t = detail::cursor_range<
2643 value_type,
2644 size_type,
2646 typename std::decay<
2647 decltype(std::declval<Dimension>().blockLength().value())>::type,
2648 Byte>;
2649
2651 template<
2652 typename Byte2,
2653 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2654 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2655 cursor_range(cursor<Byte2>& c) const noexcept
2656 {
2657 return {
2658 c,
2659 (*this)(get_header_tag{}).blockLength().value(),
2660 (*this)(end_ptr_tag{}),
2661 0,
2662 size()};
2663 }
2664
2667 template<
2668 typename Byte2,
2669 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2670 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2671 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2672 {
2673 SBEPP_ASSERT(pos < size());
2674
2675 return {
2676 c,
2677 (*this)(get_header_tag{}).blockLength().value(),
2678 (*this)(end_ptr_tag{}),
2679 pos,
2680 static_cast<size_type>(size() - pos)};
2681 }
2682
2686 template<
2687 typename Byte2,
2688 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2690 cursor<Byte2>& c,
2691 const size_type pos,
2692 const size_type count) const noexcept
2693 {
2694 SBEPP_ASSERT(pos < size());
2695 SBEPP_ASSERT(count <= (size() - pos));
2696
2697 return {
2698 c,
2699 (*this)(get_header_tag{}).blockLength().value(),
2700 (*this)(end_ptr_tag{}),
2701 pos,
2702 count};
2703 }
2704
2706 template<typename Byte2>
2707 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2708
2710 template<
2711 typename Byte2,
2712 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2713 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2714 cursor_begin(cursor<Byte2>& c) const noexcept
2715 {
2716 return cursor_range(c).begin();
2717 }
2718
2720 template<
2721 typename Byte2,
2722 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2723 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2724 cursor_end(cursor<Byte2>& c) const noexcept
2725 {
2726 return cursor_range(c).end();
2727 }
2728
2729 template<typename Visitor, typename Cursor>
2730 SBEPP_CPP14_CONSTEXPR bool
2731 operator()(visit_children_tag, Visitor& v, Cursor& c)
2732 {
2733 for(const auto entry : this->cursor_range(c))
2734 {
2735 if(v.on_entry(entry, c))
2736 {
2737 return true;
2738 }
2739 }
2740 return false;
2741 }
2742};
2743
2746template<typename T>
2748{
2749public:
2751 bitset_base() = default;
2752
2754 explicit constexpr bitset_base(T value) noexcept : bits{value}
2755 {
2756 }
2757
2759 SBEPP_CPP14_CONSTEXPR T& operator*() noexcept
2760 {
2761 return bits;
2762 }
2763
2765 constexpr T operator*() const noexcept
2766 {
2767 return bits;
2768 }
2769
2770 constexpr bool
2771 operator()(get_bit_tag, const choice_index_t n) const noexcept
2772 {
2773 return bits & (1 << n);
2774 }
2775
2776 SBEPP_CPP14_CONSTEXPR void
2777 operator()(set_bit_tag, const choice_index_t n, const bool b) noexcept
2778 {
2779 bits = ((bits & ~(1 << n)) | (b << n));
2780 }
2781
2783 constexpr friend bool
2784 operator==(const bitset_base& lhs, const bitset_base& rhs) noexcept
2785 {
2786 return *lhs == *rhs;
2787 }
2788
2790 constexpr friend bool
2791 operator!=(const bitset_base& lhs, const bitset_base& rhs) noexcept
2792 {
2793 return *lhs != *rhs;
2794 }
2795
2796private:
2797 T bits{};
2798};
2799
2800template<typename View, typename = void_t<>>
2801struct has_get_header : std::false_type
2802{
2803};
2804
2805template<typename View>
2806struct has_get_header<
2807 View,
2808 void_t<decltype(sbepp::get_header(std::declval<View>()))>> : std::true_type
2809{
2810};
2811
2812template<
2813 typename View,
2814 typename = detail::enable_if_t<detail::has_get_header<View>::value>>
2815constexpr std::size_t get_header_size(View view) noexcept
2816{
2818}
2819
2820template<
2821 typename View,
2822 typename = detail::enable_if_t<!detail::has_get_header<View>::value>,
2823 typename = int>
2824constexpr std::size_t get_header_size(View) noexcept
2825{
2826 return 0;
2827}
2828} // namespace detail
2829
2837template<typename Enum>
2838constexpr typename std::underlying_type<Enum>::type
2839 to_underlying(Enum e) noexcept
2840{
2841 return static_cast<typename std::underlying_type<Enum>::type>(e);
2842}
2843
2857template<typename View>
2858SBEPP_CPP14_CONSTEXPR cursor<byte_type_t<View>> init_cursor(View view) noexcept
2859{
2861 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2862 return c;
2863}
2864
2879template<typename View>
2880SBEPP_CPP14_CONSTEXPR cursor<typename std::add_const<byte_type_t<View>>::type>
2881 init_const_cursor(View view) noexcept
2882{
2884 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2885 return c;
2886}
2887
2892struct default_init_t
2893{
2894 explicit default_init_t() = default;
2895};
2896
2902SBEPP_CPP17_INLINE_VAR constexpr default_init_t default_init{};
2903
2906enum class eos_null
2907{
2917};
2918
2919namespace detail
2920{
2921template<typename From, typename To>
2922struct copy_cv_qualifiers
2923{
2924 using copy_const_t = typename std::
2925 conditional<std::is_const<From>::value, const To, To>::type;
2926
2927 using type = typename std::conditional<
2928 std::is_volatile<From>::value,
2929 volatile copy_const_t,
2930 copy_const_t>::type;
2931};
2932
2933template<typename From, typename To>
2934using apply_cv_qualifiers_t = typename copy_cv_qualifiers<From, To>::type;
2935
2936#if SBEPP_HAS_RANGES
2937template<typename R>
2938using is_range = std::bool_constant<std::ranges::range<R>>;
2939#else
2940template<typename R, typename = void_t<>>
2941struct is_range : std::false_type
2942{
2943};
2944
2945template<typename R>
2946struct is_range<
2947 R,
2948 void_t<
2949 decltype(std::begin(std::declval<R>())),
2950 decltype(std::end(std::declval<R>()))>> : std::true_type
2951{
2952};
2953#endif
2954
2955constexpr bool is_constant_evaluated() noexcept
2956{
2957 // it's possible to use `__builtin_is_constant_evaluated` with lower C++
2958 // versions but I see no reason for this since it's only used for
2959 // `assign_string` and other accessors are not be `constexpr` until C++20
2960#if SBEPP_HAS_IS_CONSTANT_EVALUATED
2961 return std::is_constant_evaluated();
2962#else
2963 return false;
2964#endif
2965}
2966
2967inline SBEPP_CPP20_CONSTEXPR std::size_t string_length(const char* str) noexcept
2968{
2969 if(is_constant_evaluated())
2970 {
2971 std::size_t length{};
2972 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2973 for(; *str != '\0'; str++, length++)
2974 {
2975 }
2976
2977 return length;
2978 }
2979 else
2980 {
2981 return std::strlen(str);
2982 }
2983}
2984
2992template<typename Byte, typename Value, std::size_t N, typename Tag>
2994{
2995public:
2998 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
3000 using value_type = Value;
3002 using size_type = std::size_t;
3004 using difference_type = std::ptrdiff_t;
3012 using reverse_iterator = std::reverse_iterator<iterator>;
3014 using tag = Tag;
3015
3016 using detail::byte_range<Byte>::byte_range;
3017 using detail::byte_range<Byte>::operator();
3018
3019 constexpr std::size_t operator()(detail::size_bytes_tag) const noexcept
3020 {
3021 return size();
3022 }
3023
3026 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3027 {
3028 SBEPP_ASSERT(pos < size());
3029 return data()[pos];
3030 }
3031
3033 constexpr reference front() const noexcept
3034 {
3035 return *data();
3036 }
3037
3039 constexpr reference back() const noexcept
3040 {
3041 return data()[size() - 1];
3042 }
3043
3045 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3046 {
3047 // it would be nice to use `reinterpret_cast` here but it's not allowed
3048 // in constexpr context
3049 SBEPP_SIZE_CHECK(
3050 (*this)(detail::addressof_tag{}),
3051 (*this)(detail::end_ptr_tag{}),
3052 0,
3053 N);
3054 return (pointer)(*this)(detail::addressof_tag{}); // NOLINT
3055 }
3056
3058 SBEPP_CPP17_NODISCARD static constexpr bool empty() noexcept
3059 {
3060 return !size();
3061 }
3062
3064 static constexpr size_type size() noexcept
3065 {
3066 return N;
3067 }
3068
3070 static constexpr size_type max_size() noexcept
3071 {
3072 return size();
3073 }
3074
3076 constexpr iterator begin() const noexcept
3077 {
3078 return data();
3079 }
3080
3082 constexpr iterator end() const noexcept
3083 {
3084 return data() + size();
3085 }
3086
3088 constexpr reverse_iterator rbegin() const noexcept
3089 {
3090 return reverse_iterator{end()};
3091 }
3092
3094 constexpr reverse_iterator rend() const noexcept
3095 {
3096 return reverse_iterator{begin()};
3097 }
3098
3111 raw() const noexcept
3112 {
3114 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3115 }
3116
3123 SBEPP_CPP20_CONSTEXPR std::size_t strlen() const noexcept
3124 {
3125 if(is_constant_evaluated())
3126 {
3127 return string_length(data());
3128 }
3129 else
3130 {
3131 const auto first_null = static_cast<const value_type*>(
3132 std::memchr(data(), '\0', size()));
3133 if(first_null)
3134 {
3135 return first_null - data();
3136 }
3137
3138 return size();
3139 }
3140 }
3141
3148 SBEPP_CPP20_CONSTEXPR std::size_t strlen_r() const noexcept
3149 {
3150 const auto last_non_null = std::find_if(
3151 rbegin(),
3152 rend(),
3153 [](const value_type value)
3154 {
3155 return value != '\0';
3156 });
3157 return size() - (last_non_null - rbegin());
3158 }
3159
3171 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3172 SBEPP_CPP20_CONSTEXPR iterator assign_string(
3173 const char* str, const eos_null eos_mode = eos_null::all) const noexcept
3174 {
3175 SBEPP_ASSERT(str != nullptr);
3176 const auto length = string_length(str);
3177 SBEPP_ASSERT(length <= size());
3178 const auto eos_pos = std::copy_n(str, length, begin());
3179 pad(eos_mode, eos_pos);
3180 return eos_pos;
3181 }
3182
3195 template<
3196 typename R,
3197 typename =
3198 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3199 SBEPP_CPP20_CONSTEXPR iterator
3200 assign_string(R&& r, const eos_null eos_mode = eos_null::all) const
3201 {
3202 auto eos_pos = assign_range(std::forward<R>(r));
3203 pad(eos_mode, eos_pos);
3204 return eos_pos;
3205 }
3206
3216 template<
3217 typename R,
3218 typename =
3219 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3220 SBEPP_CPP20_CONSTEXPR iterator assign_range(R&& r) const
3221 {
3222#if SBEPP_HAS_RANGES
3223 auto res = std::ranges::copy(std::forward<R>(r), begin()).out;
3224#else
3225 auto res = std::copy(std::begin(r), std::end(r), begin());
3226#endif
3227 SBEPP_ASSERT(res <= end());
3228 return res;
3229 }
3230
3236 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3237 SBEPP_CPP20_CONSTEXPR void fill(const value_type value) const noexcept
3238 {
3239 std::fill_n(begin(), size(), value);
3240 }
3241
3250 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3251 SBEPP_CPP20_CONSTEXPR iterator
3252 assign(size_type count, const value_type value) const noexcept
3253 {
3254 SBEPP_ASSERT(count <= size());
3255 return std::fill_n(begin(), count, value);
3256 }
3257
3261 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3262 SBEPP_CPP20_CONSTEXPR iterator assign(InputIt first, InputIt last) const
3263 {
3264 const auto last_out = std::copy(first, last, begin());
3265 SBEPP_ASSERT(static_cast<size_type>(last_out - begin()) <= size());
3266 return last_out;
3267 }
3268
3276 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3277 SBEPP_CPP20_CONSTEXPR iterator
3278 assign(std::initializer_list<value_type> ilist) const noexcept
3279 {
3280 SBEPP_ASSERT(ilist.size() <= size());
3281 return assign(std::begin(ilist), std::end(ilist));
3282 }
3283
3284private:
3285 SBEPP_CPP20_CONSTEXPR void
3286 pad(const eos_null mode, iterator eos_pos) const noexcept
3287 {
3288 if(mode == eos_null::all)
3289 {
3290 std::fill(eos_pos, end(), '\0');
3291 }
3292 else if(mode == eos_null::single)
3293 {
3294 if(eos_pos != end())
3295 {
3296 *eos_pos = '\0';
3297 }
3298 }
3299 else
3300 {
3301 SBEPP_ASSERT(mode == eos_null::none);
3302 return;
3303 }
3304 }
3305};
3306
3314template<typename Byte, typename Value, typename Length, endian E>
3316{
3317public:
3320 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
3322 using value_type = Value;
3324 using sbe_size_type = Length;
3326 using size_type = typename sbe_size_type::value_type;
3328 using difference_type = std::ptrdiff_t;
3336 using reverse_iterator = std::reverse_iterator<iterator>;
3337
3338 using detail::byte_range<Byte>::byte_range;
3339 using detail::byte_range<Byte>::operator();
3340
3342 constexpr iterator begin() const noexcept
3343 {
3344 return data_checked();
3345 }
3346
3348 SBEPP_CPP20_CONSTEXPR iterator end() const noexcept
3349 {
3350 return begin() + size();
3351 }
3352
3354 SBEPP_CPP20_CONSTEXPR reverse_iterator rbegin() const noexcept
3355 {
3356 return reverse_iterator{end()};
3357 }
3358
3360 constexpr reverse_iterator rend() const noexcept
3361 {
3362 return reverse_iterator{begin()};
3363 }
3364
3367 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
3368 {
3369 SBEPP_ASSERT(!empty());
3370 return *data();
3371 }
3372
3375 SBEPP_CPP20_CONSTEXPR reference back() const noexcept
3376 {
3377 SBEPP_ASSERT(!empty());
3378 return *(data() + size() - 1);
3379 }
3380
3388 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3389 {
3390 return data_checked();
3391 }
3392
3395 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3396 {
3397 SBEPP_ASSERT(pos < size());
3398 return *(data() + pos);
3399 }
3400
3402 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
3403 {
3404 return detail::get_value<size_type, size_type, E>(*this, 0);
3405 }
3406
3408 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
3409 {
3410 return sbe_size().value();
3411 }
3412
3414 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
3415 {
3416 return !size();
3417 }
3418
3420 constexpr static size_type max_size() noexcept
3421 {
3422 return sbe_size_type::max_value();
3423 }
3424
3426 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3427 SBEPP_CPP20_CONSTEXPR void clear() const noexcept
3428 {
3429 resize(0, default_init);
3430 }
3431
3433 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3434 SBEPP_CPP20_CONSTEXPR void resize(size_type count) const noexcept
3435 {
3436 const auto old_size = size();
3437 resize(count, default_init);
3438 if(count > old_size)
3439 {
3440 for(auto i = old_size; i != count; i++)
3441 {
3442 operator[](i) = {};
3443 }
3444 }
3445 }
3446
3448 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3449 SBEPP_CPP20_CONSTEXPR void
3450 resize(size_type count, value_type value) const noexcept
3451 {
3452 const auto old_size = size();
3453 resize(count, default_init);
3454 if(count > old_size)
3455 {
3456 for(auto i = old_size; i != count; i++)
3457 {
3458 operator[](i) = value;
3459 }
3460 }
3461 }
3462
3464 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3465 SBEPP_CPP20_CONSTEXPR void
3467 {
3468 // can't use `detail::set_value()` here because its size check checks
3469 // only `sizeof(T)`, here we need `sizeof(size_type) + count`
3470 SBEPP_SIZE_CHECK(
3471 (*this)(addressof_tag{}),
3472 (*this)(end_ptr_tag{}),
3473 0,
3474 sizeof(size_type) + count);
3475 set_primitive<E>((*this)(addressof_tag{}), count);
3476 }
3477
3479 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3480 SBEPP_CPP20_CONSTEXPR void push_back(value_type value) const noexcept
3481 {
3482 const auto current_size = size();
3483 resize(current_size + 1, default_init);
3484 (*this)[current_size] = value;
3485 }
3486
3488 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3489 SBEPP_CPP20_CONSTEXPR void pop_back() const noexcept
3490 {
3491 SBEPP_ASSERT(!empty());
3492 resize(size() - 1, default_init);
3493 }
3494
3496 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3497 SBEPP_CPP20_CONSTEXPR iterator erase(iterator pos) const noexcept
3498 {
3499 SBEPP_ASSERT(pos >= begin() && pos < end());
3500 std::copy(pos + 1, end(), pos);
3501 resize(size() - 1, default_init);
3502 return pos;
3503 }
3504
3506 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3507 SBEPP_CPP20_CONSTEXPR iterator
3508 erase(iterator first, iterator last) const noexcept
3509 {
3510 SBEPP_ASSERT(first >= begin() && last < end());
3511 std::copy(last, end(), first);
3512 resize(size() - (last - first), default_init);
3513 return first;
3514 }
3515
3517 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3518 SBEPP_CPP20_CONSTEXPR iterator
3519 insert(iterator pos, const value_type value) const noexcept
3520 {
3521 SBEPP_ASSERT(pos >= begin() && pos <= end());
3522 const auto old_end = end();
3523 resize(size() + 1, default_init);
3524 std::copy_backward(pos, old_end, end());
3525 *pos = value;
3526 return pos;
3527 }
3528
3530 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3531 SBEPP_CPP20_CONSTEXPR iterator insert(
3532 iterator pos, size_type count, const value_type value) const noexcept
3533 {
3534 SBEPP_ASSERT(pos >= begin() && pos <= end());
3535 const auto old_end = end();
3536 resize(size() + count, default_init);
3537 std::copy_backward(pos, old_end, end());
3538 std::fill_n(pos, count, value);
3539 return pos;
3540 }
3541
3543 template<
3544 typename InputIt,
3545 typename = detail::enable_if_t<
3546 !std::is_const<Byte>::value
3547 && std::is_convertible<
3548 typename std::iterator_traits<InputIt>::iterator_category,
3549 std::input_iterator_tag>::value>>
3550 SBEPP_CPP14_CONSTEXPR iterator
3551 insert(iterator pos, InputIt first, InputIt last) const
3552 {
3553 SBEPP_ASSERT(pos >= begin() && pos <= end());
3554 using category_t =
3555 typename std::iterator_traits<InputIt>::iterator_category;
3556 return insert_impl(pos, first, last, category_t{});
3557 }
3558
3560 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3561 constexpr iterator insert(
3562 iterator pos, std::initializer_list<value_type> ilist) const noexcept
3563 {
3564 return insert(pos, std::begin(ilist), std::end(ilist));
3565 }
3566
3569 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3570 SBEPP_CPP20_CONSTEXPR void
3571 assign(size_type count, const value_type value) const noexcept
3572 {
3573 resize(count, default_init);
3574 std::fill_n(begin(), count, value);
3575 }
3576
3579 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3580 SBEPP_CPP20_CONSTEXPR void assign(InputIt first, InputIt last) const
3581 {
3582 auto begin = data_unchecked();
3583 const auto new_end = std::copy(first, last, begin);
3584 resize(new_end - begin, default_init);
3585 }
3586
3589 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3590 SBEPP_CPP20_CONSTEXPR void
3591 assign(std::initializer_list<value_type> ilist) const noexcept
3592 {
3593 SBEPP_SIZE_CHECK(
3594 (*this)(detail::addressof_tag{}),
3595 (*this)(detail::end_ptr_tag{}),
3596 0,
3597 sizeof(size_type) + ilist.size());
3598 assign(std::begin(ilist), std::end(ilist));
3599 }
3600
3608 raw() const noexcept
3609 {
3611 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3612 }
3613
3614 SBEPP_CPP20_CONSTEXPR std::size_t
3615 operator()(detail::size_bytes_tag) const noexcept
3616 {
3617 return sizeof(size_type) + size();
3618 }
3619
3626 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3627 SBEPP_CPP20_CONSTEXPR void assign_string(const char* str) const noexcept
3628 {
3629 SBEPP_ASSERT(str != nullptr);
3630 const auto length = string_length(str);
3631 resize(length, default_init);
3632 std::copy_n(str, length, begin());
3633 }
3634
3642 template<
3643 typename R,
3644 typename =
3645 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3646 SBEPP_CPP20_CONSTEXPR void assign_range(R&& r) const
3647 {
3648 const auto begin = data_unchecked();
3649#if SBEPP_HAS_RANGES
3650 const auto new_end = std::ranges::copy(std::forward<R>(r), begin).out;
3651#else
3652 const auto new_end = std::copy(std::begin(r), std::end(r), begin);
3653#endif
3654 resize(new_end - begin, default_init);
3655 }
3656
3657private:
3658 SBEPP_CPP14_CONSTEXPR pointer data_checked() const noexcept
3659 {
3660 SBEPP_SIZE_CHECK(
3661 (*this)(detail::addressof_tag{}),
3662 (*this)(detail::end_ptr_tag{}),
3663 0,
3664 sizeof(size_type) + size());
3665 return data_unchecked();
3666 }
3667
3668 SBEPP_CPP14_CONSTEXPR pointer data_unchecked() const noexcept
3669 {
3670 SBEPP_SIZE_CHECK(
3671 (*this)(detail::addressof_tag{}),
3672 (*this)(detail::end_ptr_tag{}),
3673 0,
3674 sizeof(size_type));
3675 // cast is conditionally required here when `Byte` is different type
3676 // from `Value`. `reinterpret_cast` is not allowed in constexpr context
3677 // even when it's an identity cast. On the other hand, C-style cast
3678 // is allowed in constexpr context when it renders to an identity cast
3679 // which effectively makes this and other functions conditionally
3680 // `constexpr` when `Byte` is equal to `Value`.
3681 // NOLINTNEXTLINE: see above
3682 return (pointer)((*this)(detail::addressof_tag{}) + sizeof(size_type));
3683 }
3684
3685 template<typename It>
3686 SBEPP_CPP14_CONSTEXPR iterator insert_impl(
3687 iterator pos, It first, It last, std::input_iterator_tag) const
3688 {
3689 auto out = pos;
3690 for(; first != last; ++first, ++out)
3691 {
3692 insert(out, *first);
3693 }
3694
3695 return pos;
3696 }
3697
3698 template<typename It>
3699 SBEPP_CPP20_CONSTEXPR iterator insert_impl(
3700 iterator pos, It first, It last, std::forward_iterator_tag) const
3701 {
3702 const auto in_size = std::distance(first, last);
3703 auto old_end = end();
3704 resize(size() + in_size, default_init);
3705 std::copy_backward(pos, old_end, end());
3706 std::copy(first, last, pos);
3707 return pos;
3708 }
3709};
3710} // namespace detail
3711
3713struct nullopt_t
3714{
3715 explicit constexpr nullopt_t(int)
3716 {
3717 }
3718};
3719
3725SBEPP_CPP17_INLINE_VAR constexpr nullopt_t nullopt{0};
3726
3727namespace detail
3728{
3729// see `optional_base` note about explicit `alignas`
3733template<typename T, typename Derived>
3734class alignas(T) required_base
3735{
3736public:
3738 using value_type = T;
3739
3741 required_base() = default;
3742
3744 // NOLINTNEXTLINE: it should be implicit
3745 constexpr required_base(value_type val) noexcept : val{val}
3746 {
3747 }
3748
3750 constexpr value_type value() const noexcept
3751 {
3752 return **this;
3753 }
3754
3756 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3757 {
3758 return val;
3759 }
3760
3762 constexpr value_type operator*() const noexcept
3763 {
3764 return val;
3765 }
3766
3769 constexpr bool in_range() const noexcept
3770 {
3771 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3772 }
3773
3777#ifdef SBEPP_DOXYGEN
3779 friend auto
3780 operator<=>(const required_base&, const required_base&) = default;
3781#endif
3782
3783#if SBEPP_HAS_THREE_WAY_COMPARISON
3784 friend auto
3785 operator<=>(const required_base&, const required_base&) = default;
3786#else
3788 constexpr friend bool
3789 operator==(const required_base& lhs, const required_base& rhs) noexcept
3790 {
3791 return *lhs == *rhs;
3792 }
3793
3795 constexpr friend bool
3796 operator!=(const required_base& lhs, const required_base& rhs) noexcept
3797 {
3798 return *lhs != *rhs;
3799 }
3800
3802 constexpr friend bool
3803 operator<(const required_base& lhs, const required_base& rhs) noexcept
3804 {
3805 return *lhs < *rhs;
3806 }
3807
3809 constexpr friend bool
3810 operator<=(const required_base& lhs, const required_base& rhs) noexcept
3811 {
3812 return *lhs <= *rhs;
3813 }
3814
3816 constexpr friend bool
3817 operator>(const required_base& lhs, const required_base& rhs) noexcept
3818 {
3819 return *lhs > *rhs;
3820 }
3821
3823 constexpr friend bool
3824 operator>=(const required_base& lhs, const required_base& rhs) noexcept
3825 {
3826 return *lhs >= *rhs;
3827 }
3828#endif
3830
3831private:
3832 value_type val{};
3833};
3834
3835// old compilers might generate wrong alignment for classes which contain
3836// `double` member. To overcome this, explicit alignment is provided.
3840template<typename T, typename Derived>
3841class alignas(T) optional_base
3842{
3843public:
3845 using value_type = T;
3846
3848 optional_base() = default;
3849
3851 // NOLINTNEXTLINE: it's intentionally implicit
3852 constexpr optional_base(nullopt_t) noexcept : optional_base{}
3853 {
3854 }
3855
3857 // NOLINTNEXTLINE: it's intentionally implicit
3858 constexpr optional_base(value_type val) noexcept : val{val}
3859 {
3860 }
3861
3863 constexpr value_type value() const noexcept
3864 {
3865 return **this;
3866 }
3867
3869 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3870 {
3871 return val;
3872 }
3873
3875 constexpr value_type operator*() const noexcept
3876 {
3877 return val;
3878 }
3879
3882 constexpr bool in_range() const noexcept
3883 {
3884 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3885 }
3886
3888 SBEPP_CPP14_CONSTEXPR value_type value_or(T default_value) const noexcept
3889 {
3890 if(*this)
3891 {
3892 return value();
3893 }
3894 return default_value;
3895 }
3896
3898 constexpr bool has_value() const noexcept
3899 {
3900 return (val != Derived::null_value());
3901 }
3902
3904 constexpr explicit operator bool() const noexcept
3905 {
3906 return has_value();
3907 }
3908
3915
3917 constexpr friend bool
3918 operator==(const optional_base& lhs, const optional_base& rhs) noexcept
3919 {
3920 return *lhs == *rhs;
3921 }
3922
3923#ifdef SBEPP_DOXYGEN
3925 constexpr friend std::strong_ordering operator<=>(
3926 const optional_base& lhs, const optional_base& rhs) noexcept;
3927#endif
3928
3929#if SBEPP_HAS_THREE_WAY_COMPARISON
3930 constexpr friend std::strong_ordering
3931 operator<=>(const optional_base& lhs, const optional_base& rhs) noexcept
3932 {
3933 if(lhs && rhs)
3934 {
3935 return *lhs <=> *rhs;
3936 }
3937 return lhs.has_value() <=> rhs.has_value();
3938 }
3939#else
3940
3942 constexpr friend bool
3943 operator!=(const optional_base& lhs, const optional_base& rhs) noexcept
3944 {
3945 return *lhs != *rhs;
3946 }
3947
3949 constexpr friend bool
3950 operator<(const optional_base& lhs, const optional_base& rhs) noexcept
3951 {
3952 return rhs && (!lhs || (*lhs < *rhs));
3953 }
3954
3956 constexpr friend bool
3957 operator<=(const optional_base& lhs, const optional_base& rhs) noexcept
3958 {
3959 return !lhs || (rhs && (*lhs <= *rhs));
3960 }
3961
3963 constexpr friend bool
3964 operator>(const optional_base& lhs, const optional_base& rhs) noexcept
3965 {
3966 return lhs && (!rhs || (*lhs > *rhs));
3967 }
3968
3970 constexpr friend bool
3971 operator>=(const optional_base& lhs, const optional_base& rhs) noexcept
3972 {
3973 return !rhs || (lhs && (*lhs >= *rhs));
3974 }
3975#endif
3977
3978private:
3979 value_type val{Derived::null_value()};
3980};
3981} // namespace detail
3982
3997template<typename Message>
3998constexpr auto fill_message_header(Message m) noexcept
3999 -> decltype(m(detail::fill_message_header_tag{}))
4000{
4001 return m(detail::fill_message_header_tag{});
4002}
4003
4017template<typename Group, typename Size>
4018constexpr auto fill_group_header(Group g, Size num_in_group) noexcept
4019 -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
4020{
4021 return g(detail::fill_group_header_tag{}, num_in_group);
4022}
4023
4037template<typename T>
4038class type_traits;
4039
4040#ifdef SBEPP_DOXYGEN
4041template<typename T>
4043{
4044public:
4046 using primitive_type = PrimitiveType;
4047
4049 using value_type = ValueType;
4050
4056 template<typename Byte>
4057 using value_type = ArrayType<Byte>;
4058
4060 static constexpr const char* name() noexcept;
4061
4063 static constexpr const char* description() noexcept;
4064
4066 static constexpr field_presence presence() noexcept;
4067
4072 static constexpr primitive_type min_value() noexcept;
4073
4078 static constexpr primitive_type max_value() noexcept;
4079
4084 static constexpr primitive_type null_value() noexcept;
4085
4087 static constexpr length_t length() noexcept;
4088
4093 static constexpr offset_t offset() noexcept;
4094
4096 static constexpr const char* semantic_type() noexcept;
4097
4099 static constexpr version_t since_version() noexcept;
4100
4103 static constexpr version_t deprecated() noexcept;
4104
4106 static constexpr const char* character_encoding() noexcept;
4107};
4108#endif
4109
4118template<typename T>
4119class schema_traits;
4120
4121#ifdef SBEPP_DOXYGEN
4122template<typename T>
4124{
4125public:
4127 static constexpr const char* package() noexcept;
4129 static constexpr schema_id_t id() noexcept;
4131 static constexpr version_t version() noexcept;
4133 static constexpr const char* semantic_version() noexcept;
4135 static constexpr endian byte_order() noexcept;
4137 static constexpr const char* description() noexcept;
4143 template<typename Byte>
4144 using header_type = HeaderComposite<Byte>;
4146 using header_type_tag = HeaderTypeTag;
4148 using type_tags = sbepp::type_list<TypeTags...>;
4150 using message_tags = sbepp::type_list<MessageTags...>;
4151};
4152#endif
4153
4162template<typename T>
4163class enum_traits;
4164
4165#ifdef SBEPP_DOXYGEN
4166template<typename T>
4168{
4169public:
4171 static constexpr const char* name() noexcept;
4173 static constexpr const char* description() noexcept;
4175 using encoding_type = EncodingType;
4180 static constexpr offset_t offset() noexcept;
4182 static constexpr version_t since_version() noexcept;
4185 static constexpr version_t deprecated() noexcept;
4187 using value_type = ScopedEnumType;
4189 using value_tags = sbepp::type_list<ValueTags...>;
4190};
4191#endif
4192
4201template<typename T>
4202class enum_value_traits;
4203
4204#ifdef SBEPP_DOXYGEN
4205template<typename T>
4207{
4208public:
4210 static constexpr const char* name() noexcept;
4212 static constexpr const char* description() noexcept;
4214 static constexpr version_t since_version() noexcept;
4217 static constexpr version_t deprecated() noexcept;
4219 static constexpr ScopedEnumType value() noexcept;
4220};
4221#endif
4222
4231template<typename T>
4232class set_traits;
4233
4234#ifdef SBEPP_DOXYGEN
4235template<typename T>
4237{
4238public:
4240 static constexpr const char* name() noexcept;
4242 static constexpr const char* description() noexcept;
4244 static constexpr version_t since_version() noexcept;
4247 static constexpr version_t deprecated() noexcept;
4249 using encoding_type = EncodingType;
4254 static constexpr offset_t offset() noexcept;
4256 using value_type = SetType;
4258 using choice_tags = sbepp::type_list<ChoiceTags...>;
4259};
4260#endif
4261
4270template<typename T>
4271class set_choice_traits;
4272
4273#ifdef SBEPP_DOXYGEN
4274template<typename T>
4276{
4277public:
4279 static constexpr const char* name() noexcept;
4281 static constexpr const char* description() noexcept;
4283 static constexpr version_t since_version() noexcept;
4286 static constexpr version_t deprecated() noexcept;
4288 static constexpr choice_index_t index() noexcept;
4289};
4290#endif
4291
4300template<typename T>
4301class composite_traits;
4302
4303#ifdef SBEPP_DOXYGEN
4304template<typename T>
4306{
4307public:
4309 static constexpr const char* name() noexcept;
4311 static constexpr const char* description() noexcept;
4316 static constexpr offset_t offset() noexcept;
4318 static constexpr const char* semantic_type() noexcept;
4320 static constexpr version_t since_version() noexcept;
4322 // !schema
4323 static constexpr version_t deprecated() noexcept;
4329 template<typename Byte>
4330 using value_type = CompositeType<Byte>;
4332 static constexpr std::size_t size_bytes() noexcept;
4334 using element_tags = sbepp::type_list<ElementTags...>;
4335};
4336#endif
4337
4346template<typename T>
4347class message_traits;
4348
4349#ifdef SBEPP_DOXYGEN
4350template<typename T>
4352{
4353public:
4355 static constexpr const char* name() noexcept;
4357 static constexpr const char* description() noexcept;
4359 static constexpr message_id_t id() noexcept;
4361 static constexpr block_length_t block_length() noexcept;
4363 static constexpr const char* semantic_type() noexcept;
4365 static constexpr version_t since_version() noexcept;
4368 static constexpr version_t deprecated() noexcept;
4374 template<typename Byte>
4375 using value_type = MessageType<Byte>;
4377 using schema_tag = SchemaTag;
4378
4456 static constexpr std::size_t size_bytes(...) noexcept;
4458 using field_tags = sbepp::type_list<FieldTags...>;
4460 using group_tags = sbepp::type_list<GroupTags...>;
4462 using data_tags = sbepp::type_list<DataTags...>;
4463};
4464#endif
4465
4474template<typename T>
4475class field_traits;
4476
4477#ifdef SBEPP_DOXYGEN
4478template<typename T>
4480{
4481public:
4483 static constexpr const char* name() noexcept;
4485 static constexpr member_id_t id() noexcept;
4487 static constexpr const char* description() noexcept;
4493 static constexpr field_presence presence() noexcept;
4495 static constexpr offset_t offset() noexcept;
4497 static constexpr version_t since_version() noexcept;
4500 static constexpr version_t deprecated() noexcept;
4502 using value_type = ValueType;
4508 template<typename Byte>
4509 using value_type = Type<Byte>;
4511 using value_type_tag = TypeTag;
4512};
4513#endif
4514
4523template<typename T>
4524class group_traits;
4525
4526#ifdef SBEPP_DOXYGEN
4527template<typename T>
4529{
4530public:
4532 static constexpr const char* name() noexcept;
4534 static constexpr const char* description() noexcept;
4536 static constexpr member_id_t id() noexcept;
4538 static constexpr block_length_t block_length() noexcept;
4540 static constexpr const char* semantic_type() noexcept;
4542 static constexpr version_t since_version() noexcept;
4545 static constexpr version_t deprecated() noexcept;
4551 template<typename Byte>
4552 using value_type = GroupType<Byte>;
4558 template<typename Byte>
4559 using dimension_type = HeaderType<Byte>;
4561 using dimension_type_tag = HeaderTag;
4567 template<typename Byte>
4568 using entry_type = EntryType<Byte>;
4580 static constexpr std::size_t
4581 size_bytes(const NumInGroupType num_in_group, ...) noexcept;
4583 using field_tags = sbepp::type_list<FieldTags...>;
4585 using group_tags = sbepp::type_list<GroupTags...>;
4587 using data_tags = sbepp::type_list<DataTags...>;
4588};
4589#endif
4590
4599template<typename T>
4600class data_traits;
4601
4602#ifdef SBEPP_DOXYGEN
4603template<typename T>
4605{
4606public:
4608 static constexpr const char* name() noexcept;
4610 static constexpr member_id_t id() noexcept;
4612 static constexpr const char* description() noexcept;
4614 static constexpr version_t since_version() noexcept;
4617 static constexpr version_t deprecated() noexcept;
4623 template<typename Byte>
4624 using value_type = DataType;
4626 using length_type = LengthType;
4628 using length_type_tag = LengthTypeTag;
4635 static constexpr std::size_t
4636 size_bytes(const length_type::value_type size) noexcept;
4637};
4638#endif
4640
4663template<typename ValueType>
4664struct traits_tag;
4665
4666#ifdef SBEPP_DOXYGEN
4667template<typename ValueType>
4669{
4671 using type = Tag;
4672};
4673#endif
4674
4676template<typename ValueType>
4678
4679template<typename Byte, typename Value, std::size_t N, typename Tag>
4680struct traits_tag<detail::static_array_ref<Byte, Value, N, Tag>>
4681{
4682 using type = Tag;
4683};
4684
4685// NOLINTNEXTLINE: macro is required here
4686#define SBEPP_BUILT_IN_IMPL(NAME, TYPE, MIN, MAX, NULL) \
4687 \
4688 \
4689 class NAME##_t : public detail::required_base<TYPE, NAME##_t> \
4690 { \
4691 public: \
4692 using detail::required_base<TYPE, NAME##_t>::required_base; \
4693 \
4694 \
4695 static constexpr value_type min_value() noexcept \
4696 { \
4697 return {MIN}; \
4698 } \
4699 \
4700 \
4701 static constexpr value_type max_value() noexcept \
4702 { \
4703 return {MAX}; \
4704 } \
4705 }; \
4706 \
4707 \
4709 class NAME##_opt_t : public detail::optional_base<TYPE, NAME##_opt_t> \
4710 { \
4711 public: \
4712 using detail::optional_base<TYPE, NAME##_opt_t>::optional_base; \
4713 \
4714 \
4715 static constexpr value_type min_value() noexcept \
4716 { \
4717 return {MIN}; \
4718 } \
4719 \
4720 \
4721 static constexpr value_type max_value() noexcept \
4722 { \
4723 return {MAX}; \
4724 } \
4725 \
4726 \
4727 static constexpr value_type null_value() noexcept \
4728 { \
4729 return {NULL}; \
4730 } \
4731 }; \
4732 \
4733 template<> \
4734 class type_traits<NAME##_t> \
4735 { \
4736 public: \
4737 static constexpr const char* name() noexcept \
4738 { \
4739 return #NAME; \
4740 } \
4741 \
4742 static constexpr const char* description() noexcept \
4743 { \
4744 return ""; \
4745 } \
4746 \
4747 static constexpr field_presence presence() noexcept \
4748 { \
4749 return field_presence::required; \
4750 } \
4751 \
4752 static constexpr TYPE min_value() noexcept \
4753 { \
4754 return NAME##_t::min_value(); \
4755 } \
4756 \
4757 static constexpr TYPE max_value() noexcept \
4758 { \
4759 return NAME##_t::max_value(); \
4760 } \
4761 \
4762 static constexpr length_t length() noexcept \
4763 { \
4764 return 1; \
4765 } \
4766 \
4767 static constexpr const char* semantic_type() noexcept \
4768 { \
4769 return ""; \
4770 } \
4771 \
4772 static constexpr version_t since_version() noexcept \
4773 { \
4774 return 0; \
4775 } \
4776 \
4777 using value_type = NAME##_t; \
4778 using primitive_type = value_type::value_type; \
4779 }; \
4780 \
4781 template<> \
4782 struct traits_tag<NAME##_t> \
4783 { \
4784 using type = NAME##_t; \
4785 }; \
4786 \
4787 template<> \
4788 class type_traits<NAME##_opt_t> \
4789 { \
4790 public: \
4791 static constexpr const char* name() noexcept \
4792 { \
4793 return #NAME; \
4794 } \
4795 \
4796 static constexpr const char* description() noexcept \
4797 { \
4798 return ""; \
4799 } \
4800 \
4801 static constexpr field_presence presence() noexcept \
4802 { \
4803 return field_presence::optional; \
4804 } \
4805 \
4806 static constexpr TYPE min_value() noexcept \
4807 { \
4808 return NAME##_opt_t::min_value(); \
4809 } \
4810 \
4811 static constexpr TYPE max_value() noexcept \
4812 { \
4813 return NAME##_opt_t::max_value(); \
4814 } \
4815 \
4816 static constexpr TYPE null_value() noexcept \
4817 { \
4818 return NAME##_opt_t::null_value(); \
4819 } \
4820 \
4821 static constexpr length_t length() noexcept \
4822 { \
4823 return 1; \
4824 } \
4825 \
4826 static constexpr const char* semantic_type() noexcept \
4827 { \
4828 return ""; \
4829 } \
4830 \
4831 static constexpr version_t since_version() noexcept \
4832 { \
4833 return 0; \
4834 } \
4835 \
4836 using value_type = NAME##_opt_t; \
4837 using primitive_type = value_type::value_type; \
4838 }; \
4839 \
4840 template<> \
4841 struct traits_tag<NAME##_opt_t> \
4842 { \
4843 using type = NAME##_opt_t; \
4844 }
4846SBEPP_BUILT_IN_IMPL(char, char, 0x20, 0x7E, 0);
4847SBEPP_BUILT_IN_IMPL(
4848 int8,
4849 std::int8_t,
4850 std::numeric_limits<std::int8_t>::min() + 1,
4851 std::numeric_limits<std::int8_t>::max(),
4852 std::numeric_limits<std::int8_t>::min());
4853SBEPP_BUILT_IN_IMPL(
4854 uint8,
4855 std::uint8_t,
4856 std::numeric_limits<std::uint8_t>::min(),
4857 std::numeric_limits<std::uint8_t>::max() - 1,
4858 std::numeric_limits<std::uint8_t>::max());
4859SBEPP_BUILT_IN_IMPL(
4860 int16,
4861 std::int16_t,
4862 std::numeric_limits<std::int16_t>::min() + 1,
4863 std::numeric_limits<std::int16_t>::max(),
4864 std::numeric_limits<std::int16_t>::min());
4865SBEPP_BUILT_IN_IMPL(
4866 uint16,
4867 std::uint16_t,
4868 std::numeric_limits<std::uint16_t>::min(),
4869 std::numeric_limits<std::uint16_t>::max() - 1,
4870 std::numeric_limits<std::uint16_t>::max());
4871SBEPP_BUILT_IN_IMPL(
4872 int32,
4873 std::int32_t,
4874 std::numeric_limits<std::int32_t>::min() + 1,
4875 std::numeric_limits<std::int32_t>::max(),
4876 std::numeric_limits<std::int32_t>::min());
4877SBEPP_BUILT_IN_IMPL(
4878 uint32,
4879 std::uint32_t,
4880 std::numeric_limits<std::uint32_t>::min(),
4881 std::numeric_limits<std::uint32_t>::max() - 1,
4882 std::numeric_limits<std::uint32_t>::max());
4883SBEPP_BUILT_IN_IMPL(
4884 int64,
4885 std::int64_t,
4886 std::numeric_limits<std::int64_t>::min() + 1,
4887 std::numeric_limits<std::int64_t>::max(),
4888 std::numeric_limits<std::int64_t>::min());
4889SBEPP_BUILT_IN_IMPL(
4890 uint64,
4891 std::uint64_t,
4892 std::numeric_limits<std::uint64_t>::min(),
4893 std::numeric_limits<std::uint64_t>::max() - 1,
4894 std::numeric_limits<std::uint64_t>::max());
4895SBEPP_BUILT_IN_IMPL(
4896 float,
4897 float,
4898 std::numeric_limits<float>::min(),
4899 std::numeric_limits<float>::max(),
4900 std::numeric_limits<float>::quiet_NaN());
4901SBEPP_BUILT_IN_IMPL(
4902 double,
4903 double,
4904 std::numeric_limits<double>::min(),
4905 std::numeric_limits<double>::max(),
4906 std::numeric_limits<double>::quiet_NaN());
4907
4908#undef SBEPP_BUILT_IN_IMPL
4909
4927template<template<typename> class View, typename Byte>
4928constexpr View<Byte> make_view(Byte* ptr, const std::size_t size) noexcept
4929{
4930 return {ptr, size};
4931}
4932
4951template<template<typename> class View, typename Byte>
4952constexpr View<typename std::add_const<Byte>::type>
4953 make_const_view(Byte* ptr, const std::size_t size) noexcept
4954{
4955 return {ptr, size};
4956}
4957
4965{
4966};
4967
4968namespace detail
4969{
4970// taken from https://stackoverflow.com/a/34672753
4971template<template<typename...> class Base, typename Derived>
4972struct is_base_of_tmp_impl
4973{
4974 static constexpr std::false_type test(...);
4975
4976 template<typename... Ts>
4977 static constexpr std::true_type test(Base<Ts...>*);
4978
4979 using type = decltype(test(std::declval<Derived*>()));
4980};
4981
4982template<template<typename...> class Base, typename Derived>
4983using is_base_of_tmp = typename is_base_of_tmp_impl<Base, Derived>::type;
4984
4985#if SBEPP_HAS_CONCEPTS
4986template<typename Derived, template<typename...> class Base>
4987concept derived_from_tmp = is_base_of_tmp<Base, Derived>::value;
4988#endif
4989} // namespace detail
4990
4991namespace detail
4992{
4993template<typename Derived>
4994struct is_array_type_impl
4995{
4996 static constexpr std::false_type test(...);
4997
4998 template<typename T1, typename T2, std::size_t N, typename T3>
4999 static constexpr std::true_type
5000 test(detail::static_array_ref<T1, T2, N, T3>*);
5001
5002 using type = decltype(test(std::declval<Derived*>()));
5003};
5004} // namespace detail
5005
5007template<typename T>
5008using is_array_type = typename detail::is_array_type_impl<T>::type;
5009
5011template<typename T>
5012using is_required_type = detail::is_base_of_tmp<detail::required_base, T>;
5013
5015template<typename T>
5016using is_optional_type = detail::is_base_of_tmp<detail::optional_base, T>;
5017
5019template<typename T>
5020using is_non_array_type = std::integral_constant<
5021 bool,
5023
5025template<typename T>
5026using is_type = std::integral_constant<
5027 bool,
5030
5032template<typename T, typename = void>
5033struct is_enum : std::false_type
5034{
5035};
5036
5037template<typename T>
5038struct is_enum<
5039 T,
5040 detail::void_t<decltype(tag_invoke(
5041 std::declval<detail::visit_tag>(),
5042 std::declval<T>(),
5043 std::declval<int&>()))>> : std::true_type
5044{
5045};
5046
5048template<typename T>
5049using is_set = detail::is_base_of_tmp<detail::bitset_base, T>;
5050
5052template<typename T>
5053using is_composite = detail::is_base_of_tmp<detail::composite_base, T>;
5054
5056template<typename T>
5057using is_message = detail::is_base_of_tmp<detail::message_base, T>;
5058
5060template<typename T>
5061using is_flat_group = detail::is_base_of_tmp<detail::flat_group_base, T>;
5062
5064template<typename T>
5065using is_nested_group = detail::is_base_of_tmp<detail::nested_group_base, T>;
5066
5068template<typename T>
5069using is_group = std::integral_constant<
5070 bool,
5072
5074template<typename T>
5075using is_group_entry = detail::is_base_of_tmp<detail::entry_base, T>;
5076
5077namespace detail
5078{
5079template<typename Derived>
5080struct is_data_impl
5081{
5082 static constexpr std::false_type test(...);
5083
5084 template<typename T1, typename T2, typename T3, endian E>
5085 static constexpr std::true_type
5087
5088 using type = decltype(test(std::declval<Derived*>()));
5089};
5090} // namespace detail
5091
5093template<typename T>
5094using is_data = typename detail::is_data_impl<T>::type;
5095
5096#if SBEPP_HAS_INLINE_VARS
5098template<typename T>
5099inline constexpr auto is_array_type_v = is_array_type<T>::value;
5100
5102template<typename T>
5103inline constexpr auto is_required_type_v = is_required_type<T>::value;
5104
5106template<typename T>
5107inline constexpr auto is_optional_type_v = is_optional_type<T>::value;
5108
5110template<typename T>
5111inline constexpr auto is_non_array_type_v = is_non_array_type<T>::value;
5112
5114template<typename T>
5115inline constexpr auto is_type_v = is_type<T>::value;
5116
5118template<typename T>
5119inline constexpr auto is_enum_v = is_enum<T>::value;
5120
5122template<typename T>
5123inline constexpr auto is_set_v = is_set<T>::value;
5124
5126template<typename T>
5127inline constexpr auto is_composite_v = is_composite<T>::value;
5128
5130template<typename T>
5131inline constexpr auto is_message_v = is_message<T>::value;
5132
5134template<typename T>
5135inline constexpr auto is_flat_group_v = is_flat_group<T>::value;
5136
5138template<typename T>
5139inline constexpr auto is_nested_group_v = is_nested_group<T>::value;
5140
5142template<typename T>
5143inline constexpr auto is_group_v = is_group<T>::value;
5144
5146template<typename T>
5147inline constexpr auto is_data_v = is_data<T>::value;
5148#endif
5149
5150#if SBEPP_HAS_CONCEPTS
5152template<typename T>
5154
5156template<typename T>
5158
5160template<typename T>
5162
5164template<typename T>
5166
5168template<typename T>
5169concept type = is_type_v<T>;
5170
5172template<typename T>
5173concept enumeration = is_enum_v<T>;
5174
5176template<typename T>
5177concept set = is_set_v<T>;
5178
5180template<typename T>
5182
5184template<typename T>
5185concept message = is_message_v<T>;
5186
5188template<typename T>
5190
5192template<typename T>
5194
5196template<typename T>
5197concept group = is_group_v<T>;
5198
5200template<typename T>
5201concept data = is_data_v<T>;
5202#endif
5203
5204namespace detail
5205{
5206template<typename T>
5207using is_cursor_visitable_view = std::integral_constant<
5208 bool,
5210}
5211
5223template<
5224 typename Visitor,
5225 typename View,
5226 typename Cursor,
5227 typename =
5228 detail::enable_if_t<detail::is_cursor_visitable_view<View>::value>>
5229SBEPP_CPP14_CONSTEXPR Visitor&&
5230 visit(View view, Cursor& c, Visitor&& visitor = {})
5231{
5232 view(detail::visit_tag{}, visitor, c);
5233 return std::forward<Visitor>(visitor);
5234}
5235
5246template<
5247 typename Visitor,
5248 typename View,
5249 typename =
5250 detail::enable_if_t<detail::is_cursor_visitable_view<View>::value>>
5251SBEPP_CPP14_CONSTEXPR Visitor&& visit(View view, Visitor&& visitor = {})
5252{
5253 auto c = sbepp::init_cursor(view);
5254 return sbepp::visit(view, c, std::forward<Visitor>(visitor));
5255}
5256
5257#ifndef SBEPP_DOXYGEN
5258template<typename Visitor, typename SetOrComposite>
5259SBEPP_CPP14_CONSTEXPR detail::enable_if_t<
5260 is_set<SetOrComposite>::value || is_composite<SetOrComposite>::value,
5261 Visitor&&>
5262 visit(SetOrComposite setOrComposite, Visitor&& visitor = {})
5263{
5264 setOrComposite(detail::visit_tag{}, visitor);
5265 return std::forward<Visitor>(visitor);
5266}
5267
5268template<typename Visitor, typename Enum>
5269SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_enum<Enum>::value, Visitor&&>
5270 visit(Enum e, Visitor&& visitor = {})
5271{
5272 tag_invoke(detail::visit_tag{}, e, visitor);
5273 return std::forward<Visitor>(visitor);
5274}
5275
5276#else
5277
5288template<typename Visitor, typename Composite>
5289SBEPP_CPP14_CONSTEXPR Visitor&& visit(Composite view, Visitor&& visitor = {});
5290
5307template<typename Visitor, typename Set>
5308SBEPP_CPP14_CONSTEXPR Visitor&& visit(Set s, Visitor&& visitor = {});
5309
5326template<typename Visitor, typename Enum>
5327SBEPP_CPP14_CONSTEXPR Visitor&& visit(Enum e, Visitor&& visitor = {});
5328#endif
5329
5343template<typename Visitor, typename View, typename Cursor>
5344SBEPP_DEPRECATED SBEPP_CPP14_CONSTEXPR
5345 detail::enable_if_t<is_composite<View>::value, Visitor&&>
5346 visit(View view, Cursor& c, Visitor&& visitor = {})
5347{
5348 (void)c;
5349 return sbepp::visit(view, std::forward<Visitor>(visitor));
5350}
5351
5363template<
5364 typename Visitor,
5365 typename View,
5366 typename Cursor,
5367 typename =
5368 detail::enable_if_t<detail::is_cursor_visitable_view<View>::value>>
5369SBEPP_CPP14_CONSTEXPR Visitor&&
5370 visit_children(View view, Cursor& c, Visitor&& visitor = {})
5371{
5372 view(detail::visit_children_tag{}, visitor, c);
5373 return std::forward<Visitor>(visitor);
5374}
5375
5386template<
5387 typename Visitor,
5388 typename View,
5389 typename =
5390 detail::enable_if_t<detail::is_cursor_visitable_view<View>::value>>
5391SBEPP_CPP14_CONSTEXPR Visitor&&
5392 visit_children(View view, Visitor&& visitor = {})
5393{
5394 auto c = sbepp::init_cursor(view);
5395 return sbepp::visit_children(view, c, std::forward<Visitor>(visitor));
5396}
5397
5408template<typename Visitor, typename View>
5409SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_composite<View>::value, Visitor&&>
5410 visit_children(View view, Visitor&& visitor = {})
5411{
5412 view(detail::visit_children_tag{}, visitor);
5413 return std::forward<Visitor>(visitor);
5414}
5415
5429template<typename Visitor, typename View, typename Cursor>
5430SBEPP_DEPRECATED SBEPP_CPP14_CONSTEXPR
5431 detail::enable_if_t<is_composite<View>::value, Visitor&&>
5432 visit_children(View view, Cursor& c, Visitor&& visitor = {})
5433{
5434 (void)c;
5435 return visit_children(view, std::forward<Visitor>(visitor));
5436}
5437
5438namespace detail
5439{
5440class enum_to_string_visitor
5441{
5442public:
5443 template<typename Enum, typename Tag>
5444 SBEPP_CPP14_CONSTEXPR void on_enum_value(Enum /*e*/, Tag) noexcept
5445 {
5447 }
5448
5449 template<typename Enum>
5450 SBEPP_CPP14_CONSTEXPR void
5451 on_enum_value(Enum /*e*/, sbepp::unknown_enum_value_tag) noexcept
5452 {
5453 name_value = nullptr;
5454 }
5455
5456 constexpr const char* name() const noexcept
5457 {
5458 return name_value;
5459 }
5460
5461private:
5462 const char* name_value;
5463};
5464} // namespace detail
5465
5476template<typename E, typename = detail::enable_if_t<is_enum<E>::value>>
5477SBEPP_DEPRECATED constexpr const char* enum_to_string(const E e) noexcept
5478{
5480}
5481
5493template<typename Set, typename Visitor>
5494SBEPP_DEPRECATED constexpr auto
5495 visit_set(const Set s, Visitor&& visitor) noexcept
5496 -> decltype(s(detail::visit_set_tag{}, std::forward<Visitor>(visitor)))
5497{
5498 return s(detail::visit_set_tag{}, std::forward<Visitor>(visitor));
5499}
5500
5501namespace detail
5502{
5503class size_bytes_checked_visitor
5504{
5505public:
5506 constexpr explicit size_bytes_checked_visitor(
5507 const std::size_t size) noexcept
5508 : size{size}
5509 {
5510 }
5511
5512 template<typename T, typename Cursor, typename Tag>
5513 SBEPP_CPP14_CONSTEXPR void on_message(T m, Cursor& c, Tag) noexcept
5514 {
5515 const auto header = sbepp::get_header(m);
5516 const auto header_size = sbepp::size_bytes(header);
5517 if(!validate_and_subtract(header_size))
5518 {
5519 return;
5520 }
5521
5522 if(!validate_and_subtract(*header.blockLength()))
5523 {
5524 return;
5525 }
5526
5527 sbepp::visit_children(m, c, *this);
5528 }
5529
5530 template<typename T, typename Cursor, typename Tag>
5531 SBEPP_CPP14_CONSTEXPR bool on_group(T g, Cursor& c, Tag) noexcept
5532 {
5533 const auto header = sbepp::get_header(g);
5534 const auto header_size = sbepp::size_bytes(header);
5535 if(!validate_and_subtract(header_size))
5536 {
5537 return true;
5538 }
5539
5540 const auto prev_block_length =
5541 set_group_block_length(*header.blockLength());
5542 sbepp::visit_children(g, c, *this);
5543 set_group_block_length(prev_block_length);
5544
5545 return !is_valid();
5546 }
5547
5548 template<typename T, typename Cursor>
5549 SBEPP_CPP14_CONSTEXPR bool on_entry(T e, Cursor& c) noexcept
5550 {
5551 if(!validate_and_subtract(group_block_length))
5552 {
5553 return true;
5554 }
5555
5556 return !sbepp::visit_children(e, c, *this).is_valid();
5557 }
5558
5559 template<typename T, typename Tag>
5560 SBEPP_CPP14_CONSTEXPR bool on_data(T d, Tag) noexcept
5561 {
5562 return !validate_and_subtract(sbepp::size_bytes(d));
5563 }
5564
5565 // ignore them all because we validate `blockLength`
5566 template<typename T, typename Tag>
5567 constexpr bool on_field(T, Tag) const noexcept
5568 {
5569 return {};
5570 }
5571
5572 constexpr bool is_valid() const noexcept
5573 {
5574 return valid;
5575 }
5576
5577 // returns previous value
5578 SBEPP_CPP14_CONSTEXPR std::size_t
5579 set_group_block_length(const std::size_t block_length) noexcept
5580 {
5581 auto prev = group_block_length;
5582 group_block_length = block_length;
5583 return prev;
5584 }
5585
5586 constexpr std::size_t get_size() const noexcept
5587 {
5588 return size;
5589 }
5590
5591private:
5592 std::size_t size;
5593 bool valid{true};
5594 // current group's blockLength, used to validate entry
5595 std::size_t group_block_length{};
5596
5597 SBEPP_CPP14_CONSTEXPR bool
5598 validate_and_subtract(const std::size_t n) noexcept
5599 {
5600 if(size < n)
5601 {
5602 valid = false;
5603 }
5604 else
5605 {
5606 size -= n;
5607 }
5608
5609 return valid;
5610 }
5611};
5612} // namespace detail
5613
5614//! @brief Result type of `size_bytes_checked`
5616{
5618 bool valid;
5620 std::size_t size;
5621};
5622
5633template<typename View>
5634SBEPP_CPP20_CONSTEXPR size_bytes_checked_result
5635 size_bytes_checked(View view, std::size_t size) noexcept
5636{
5637 // `init_cursor` skips header, we need to ensure there's enough space for it
5638 if(!sbepp::addressof(view) || (size < detail::get_header_size(view)))
5639 {
5640 return {};
5641 }
5642
5643 detail::size_bytes_checked_visitor visitor{size};
5644 auto c = sbepp::init_cursor(view);
5645 sbepp::visit(view, c, visitor);
5646 if(visitor.is_valid())
5647 {
5648 return {true, size - visitor.get_size()};
5649 }
5650 return {};
5651}
5652
5661template<typename Tag, typename ViewOrSet>
5662constexpr auto get_by_tag(ViewOrSet viewOrSet) noexcept
5663 -> decltype(viewOrSet(detail::access_by_tag_tag{}, Tag{}))
5664{
5665 return viewOrSet(detail::access_by_tag_tag{}, Tag{});
5666}
5667
5676template<typename Tag, typename View, typename Cursor>
5677constexpr auto get_by_tag(View view, Cursor&& c) noexcept -> decltype(view(
5678 detail::access_by_tag_tag{}, Tag{}, std::forward<Cursor>(c)))
5679{
5680 return view(detail::access_by_tag_tag{}, Tag{}, std::forward<Cursor>(c));
5681}
5682
5692template<typename Tag, typename ViewOrSet, typename Value>
5693constexpr auto set_by_tag(ViewOrSet&& viewOrSet, Value&& value) noexcept
5694 -> decltype(std::forward<ViewOrSet>(viewOrSet)(
5695 detail::access_by_tag_tag{}, Tag{}, std::forward<Value>(value)))
5696{
5697 return std::forward<ViewOrSet>(viewOrSet)(
5698 detail::access_by_tag_tag{}, Tag{}, std::forward<Value>(value));
5699}
5700
5711template<typename Tag, typename View, typename Value, typename Cursor>
5712constexpr auto set_by_tag(View view, Value&& value, Cursor&& c)
5713 -> decltype(view(
5714 detail::access_by_tag_tag{},
5715 Tag{},
5716 std::forward<Value>(value),
5717 std::forward<Cursor>(c)))
5718{
5719 return view(
5720 detail::access_by_tag_tag{},
5721 Tag{},
5722 std::forward<Value>(value),
5723 std::forward<Cursor>(c));
5724}
5725
5726namespace detail
5727{
5728template<template<typename> class Trait, typename T, typename = void_t<>>
5729struct has_traits : std::false_type
5730{
5731};
5732
5733template<template<typename> class Trait, typename T>
5734struct has_traits<Trait, T, void_t<decltype(Trait<T>{})>> : std::true_type
5735{
5736};
5737} // namespace detail
5738
5744template<typename Tag>
5745using is_type_tag = detail::has_traits<type_traits, Tag>;
5746
5752template<typename Tag>
5753using is_enum_tag = detail::has_traits<enum_traits, Tag>;
5754
5760template<typename Tag>
5761using is_enum_value_tag = detail::has_traits<enum_value_traits, Tag>;
5762
5768template<typename Tag>
5769using is_set_tag = detail::has_traits<set_traits, Tag>;
5770
5776template<typename Tag>
5777using is_set_choice_tag = detail::has_traits<set_choice_traits, Tag>;
5778
5784template<typename Tag>
5785using is_composite_tag = detail::has_traits<composite_traits, Tag>;
5786
5792template<typename Tag>
5793using is_field_tag = detail::has_traits<field_traits, Tag>;
5794
5800template<typename Tag>
5801using is_group_tag = detail::has_traits<group_traits, Tag>;
5802
5808template<typename Tag>
5809using is_data_tag = detail::has_traits<data_traits, Tag>;
5810
5816template<typename Tag>
5817using is_message_tag = detail::has_traits<message_traits, Tag>;
5818
5824template<typename Tag>
5825using is_schema_tag = detail::has_traits<schema_traits, Tag>;
5826
5827#if SBEPP_HAS_INLINE_VARS
5829template<typename Tag>
5830inline constexpr auto is_type_tag_v = is_type_tag<Tag>::value;
5831
5833template<typename Tag>
5834inline constexpr auto is_enum_tag_v = is_enum_tag<Tag>::value;
5835
5837template<typename Tag>
5839
5841template<typename Tag>
5842inline constexpr auto is_set_tag_v = is_set_tag<Tag>::value;
5843
5845template<typename Tag>
5847
5849template<typename Tag>
5850inline constexpr auto is_composite_tag_v = is_composite_tag<Tag>::value;
5851
5853template<typename Tag>
5854inline constexpr auto is_field_tag_v = is_field_tag<Tag>::value;
5855
5857template<typename Tag>
5858inline constexpr auto is_group_tag_v = is_group_tag<Tag>::value;
5859
5861template<typename Tag>
5862inline constexpr auto is_data_tag_v = is_data_tag<Tag>::value;
5863
5865template<typename Tag>
5866inline constexpr auto is_message_tag_v = is_message_tag<Tag>::value;
5867
5869template<typename Tag>
5870inline constexpr auto is_schema_tag_v = is_schema_tag<Tag>::value;
5871#endif
5872
5873#if SBEPP_HAS_CONCEPTS
5875template<typename Tag>
5877
5879template<typename Tag>
5881
5883template<typename Tag>
5885
5887template<typename Tag>
5888concept set_tag = is_set_tag_v<Tag>;
5889
5891template<typename Tag>
5893
5895template<typename Tag>
5897
5899template<typename Tag>
5901
5903template<typename Tag>
5905
5907template<typename Tag>
5909
5911template<typename Tag>
5913
5915template<typename Tag>
5917#endif
5918} // namespace sbepp
5919
5920#if SBEPP_HAS_RANGES && SBEPP_HAS_CONCEPTS
5921
5922template<typename Byte, typename Value, std::size_t N, typename Tag>
5923inline constexpr bool std::ranges::enable_borrowed_range<
5925
5926template<typename Byte, typename Value, typename Length, sbepp::endian E>
5927inline constexpr bool std::ranges::enable_borrowed_range<
5929
5930template<sbepp::detail::derived_from_tmp<sbepp::detail::flat_group_base> T>
5931inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5932
5933template<sbepp::detail::derived_from_tmp<sbepp::detail::nested_group_base> T>
5934inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5935#endif
5936
5937#undef SBEPP_CPP17_INLINE_VAR
5938#undef SBEPP_DEPRECATED
5939#undef SBEPP_CPLUSPLUS
5940
5941SBEPP_WARNINGS_ON();
Provides various traits/attributes of a <composite> element.
Definition sbepp.hpp:4306
CompositeType< Byte > value_type
Representation type.
Definition sbepp.hpp:4330
static constexpr offset_t offset() noexcept
Returns type offset. Available only if offset is static, i.e. not available for public composites who...
static constexpr const char * semantic_type() noexcept
Returns semanticType attribute.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
sbepp::type_list< ElementTags... > element_tags
Element tags in schema order.
Definition sbepp.hpp:4334
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in.
static constexpr std::size_t size_bytes() noexcept
Returns size of the composite in bytes.
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr const char * description() noexcept
Returns description attribute.
Represents cursor which is used in cursor-based API. Clients should not use undocumented methods.
Definition sbepp.hpp:795
constexpr Byte * pointer() const noexcept
Returns underlying pointer.
Definition sbepp.hpp:861
constexpr cursor(cursor< Byte2 > other) noexcept
Constructs from another cursor. Enabled only if Byte2* is convertible to Byte*.
Definition sbepp.hpp:824
Byte byte_type
same as Byte
Definition sbepp.hpp:798
cursor()=default
Construct a new cursor object initialized with nullptr
constexpr Byte *& pointer() noexcept
Returns underlying pointer. Might be useful in rare cases to initialize cursor with a particular valu...
Definition sbepp.hpp:851
constexpr cursor & operator=(cursor< Byte2 > other) noexcept
Assigns from another cursor. Enabled only if Byte2* is convertible to Byte
Definition sbepp.hpp:839
Provides various traits/attributes of a <data> element.
Definition sbepp.hpp:4605
static constexpr const char * name() noexcept
Returns name attribute.
DataType value_type
Representation type.
Definition sbepp.hpp:4624
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
LengthTypeTag length_type_tag
length_type tag
Definition sbepp.hpp:4628
LengthType length_type
Length type.
Definition sbepp.hpp:4626
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr std::size_t size_bytes(const length_type::value_type size) noexcept
Returns number of bytes required to represent <data> in memory.
constexpr T operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:2765
constexpr friend bool operator==(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are equal.
Definition sbepp.hpp:2784
constexpr T & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:2759
constexpr bitset_base(T value) noexcept
Constructs from given value.
Definition sbepp.hpp:2754
constexpr friend bool operator!=(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are not equal.
Definition sbepp.hpp:2791
bitset_base()=default
Default constructs underlying value to 0
Base class for all reference semantics types.
Definition sbepp.hpp:726
constexpr byte_range(Byte *ptr, const std::size_t size) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:748
constexpr byte_range(const byte_range< Byte2 > &other) noexcept
Copy constructor. Available if Byte2* is convertible to Byte*
Definition sbepp.hpp:756
byte_range()=default
Initializes to nullptr
constexpr byte_range(Byte *begin, Byte *end) noexcept
Constructs from a pair of pointers.
Definition sbepp.hpp:737
Base class for composites.
Definition sbepp.hpp:1752
Represents reference to dynamic arrays used for <data> elements.
Definition sbepp.hpp:3316
constexpr sbe_size_type sbe_size() const noexcept
Returns SBE size representation.
Definition sbepp.hpp:3402
pointer iterator
Iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3334
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition sbepp.hpp:3336
constexpr iterator insert(iterator pos, std::initializer_list< value_type > ilist) const noexcept
Inserts elements from ilist before pos
Definition sbepp.hpp:3561
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3360
static constexpr size_type max_size() noexcept
Returns max value of SBE length representation.
Definition sbepp.hpp:3420
constexpr iterator erase(iterator first, iterator last) const noexcept
Erases elements in [first; last) range.
Definition sbepp.hpp:3508
constexpr void assign_string(const char *str) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3627
constexpr iterator insert(iterator pos, InputIt first, InputIt last) const
Inserts elements from [first; last) range before pos
Definition sbepp.hpp:3551
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:3591
constexpr reference back() const noexcept
Returns the last element.
Definition sbepp.hpp:3375
constexpr void resize(size_type count, sbepp::default_init_t) const noexcept
Sets size to count, default initializes new elements.
Definition sbepp.hpp:3466
element_type * pointer
Element pointer type.
Definition sbepp.hpp:3332
constexpr void push_back(value_type value) const noexcept
Adds new element to the end.
Definition sbepp.hpp:3480
constexpr iterator insert(iterator pos, const value_type value) const noexcept
Inserts value before pos
Definition sbepp.hpp:3519
constexpr reference operator[](size_type pos) const noexcept
Returns element at pos
Definition sbepp.hpp:3395
constexpr void resize(size_type count) const noexcept
Sets size to count, value initializes new elements.
Definition sbepp.hpp:3434
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:3367
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:3328
constexpr void pop_back() const noexcept
Removes the last element.
Definition sbepp.hpp:3489
Value value_type
Same as Value
Definition sbepp.hpp:3322
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:3608
detail::apply_cv_qualifiers_t< Byte, Value > element_type
Final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:3320
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3342
constexpr void assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3646
constexpr iterator insert(iterator pos, size_type count, const value_type value) const noexcept
Inserts count copies of value before pos
Definition sbepp.hpp:3531
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:3571
constexpr pointer data() const noexcept
Returns pointer to the underlying array.
Definition sbepp.hpp:3388
constexpr iterator erase(iterator pos) const noexcept
Erases element at pos
Definition sbepp.hpp:3497
constexpr void clear() const noexcept
Sets size to 0.
Definition sbepp.hpp:3427
constexpr bool empty() const noexcept
Checks if size() != 0
Definition sbepp.hpp:3414
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3354
constexpr void resize(size_type count, value_type value) const noexcept
Sets size to count, initializes new elements with value
Definition sbepp.hpp:3450
constexpr void assign(InputIt first, InputIt last) const
Replaces the contents of the container with the elements from [first; last) range.
Definition sbepp.hpp:3580
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3348
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:3408
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:3326
Length sbe_size_type
length SBE representation of data's encoding
Definition sbepp.hpp:3324
element_type & reference
Element reference type.
Definition sbepp.hpp:3330
constexpr entry_base(cursor< Byte2 > &c, Byte *end_ptr, BlockLengthType block_length) noexcept
Constructs from cursor.
Definition sbepp.hpp:1831
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:1843
constexpr entry_base(Byte *ptr, const std::size_t size, const BlockLengthType block_length) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:1821
entry_base()=default
Constructs using nullptr
constexpr entry_base(Byte *ptr, Byte *end, BlockLengthType block_length) noexcept
Constructs from two pointers.
Definition sbepp.hpp:1814
Base class for a flat group.
Definition sbepp.hpp:2291
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:2306
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2413
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2337
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2485
constexpr reference front() const noexcept
Returns the first entry.
Definition sbepp.hpp:2397
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:2449
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:2420
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2298
Entry value_type
Entry type.
Definition sbepp.hpp:2294
constexpr reference operator[](size_type pos) const noexcept
Returns group entry at pos
Definition sbepp.hpp:2389
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2343
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2367
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2492
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2433
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2355
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2378
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2349
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2502
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2361
constexpr reference back() const noexcept
Returns the last entry.
Definition sbepp.hpp:2405
typename std::make_signed< size_type >::type difference_type
Signed size_type
Definition sbepp.hpp:2303
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:2467
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:2301
value_type reference
value_type
Definition sbepp.hpp:2296
Base class for messages.
Definition sbepp.hpp:1761
Base class for a nested group.
Definition sbepp.hpp:2525
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2581
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2616
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:2671
Entry value_type
Entry type.
Definition sbepp.hpp:2528
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2599
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2707
value_type reference
value_type
Definition sbepp.hpp:2530
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:2642
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:2535
typename std::make_signed< size_type >::type difference_type
Signed size_type
Definition sbepp.hpp:2537
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2575
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2587
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:2627
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2724
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2635
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2714
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2593
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:2541
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2655
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:2689
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2605
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2532
constexpr friend bool operator<(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is less than rhs
Definition sbepp.hpp:3950
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3863
constexpr friend bool operator!=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3943
constexpr friend bool operator<=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is less than or equal to rhs
Definition sbepp.hpp:3957
constexpr optional_base(nullopt_t) noexcept
Constructs null object.
Definition sbepp.hpp:3852
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:3888
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:3971
T value_type
Underlying type.
Definition sbepp.hpp:3845
constexpr bool in_range() const noexcept
Checks if value is in [Derived::min_value(); Derived::max_value()] range.
Definition sbepp.hpp:3882
constexpr optional_base(value_type val) noexcept
Constructs object from given value.
Definition sbepp.hpp:3858
constexpr bool has_value() const noexcept
Checks if has value.
Definition sbepp.hpp:3898
constexpr friend bool operator>(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3964
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3875
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3869
constexpr friend bool operator==(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3918
constexpr friend std::strong_ordering operator<=>(const optional_base &lhs, const optional_base &rhs) noexcept
Available only if SBEPP_HAS_THREE_WAY_COMPARISON == 1.
constexpr friend bool operator>(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3817
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:3824
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3750
constexpr friend bool operator!=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3796
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3756
constexpr friend bool operator==(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3789
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:3769
constexpr friend bool operator<(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is less than rhs
Definition sbepp.hpp:3803
T value_type
Underlying type.
Definition sbepp.hpp:3738
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3762
constexpr friend bool operator<=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is less than or equal to rhs
Definition sbepp.hpp:3810
friend auto operator<=>(const required_base &, const required_base &)=default
Available only if SBEPP_HAS_THREE_WAY_COMPARISON == 1.
constexpr required_base(value_type val) noexcept
Constructs from given value.
Definition sbepp.hpp:3745
Represents reference to fixed-size array.
Definition sbepp.hpp:2994
pointer iterator
Iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3010
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3094
static constexpr bool empty() noexcept
Checks if size() != 0
Definition sbepp.hpp:3058
detail::apply_cv_qualifiers_t< Byte, Value > element_type
Final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:2998
constexpr reference operator[](size_type pos) const noexcept
Returns element at pos
Definition sbepp.hpp:3026
constexpr std::size_t strlen() const noexcept
Calculates string length from left to right.
Definition sbepp.hpp:3123
constexpr iterator assign_string(const char *str, const eos_null eos_mode=eos_null::all) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3172
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:3033
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3076
static constexpr size_type size() noexcept
Returns N
Definition sbepp.hpp:3064
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:3111
constexpr iterator assign(std::initializer_list< value_type > ilist) const noexcept
Assigns initializer list to first elements.
Definition sbepp.hpp:3278
element_type & reference
Element reference type.
Definition sbepp.hpp:3006
std::reverse_iterator< iterator > reverse_iterator
Reverse iterator type.
Definition sbepp.hpp:3012
constexpr reference back() const noexcept
Returns the last element.
Definition sbepp.hpp:3039
Value value_type
Same as Value
Definition sbepp.hpp:3000
Tag tag
Type tag.
Definition sbepp.hpp:3014
element_type * pointer
Element pointer type.
Definition sbepp.hpp:3008
constexpr std::size_t strlen_r() const noexcept
Calculates string length from right to left.
Definition sbepp.hpp:3148
std::size_t size_type
std::size_t
Definition sbepp.hpp:3002
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3082
constexpr iterator assign_string(R &&r, const eos_null eos_mode=eos_null::all) const
Assigns string represented by a range.
Definition sbepp.hpp:3200
constexpr void fill(const value_type value) const noexcept
Assigns value to all elements.
Definition sbepp.hpp:3237
constexpr iterator assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3220
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3088
constexpr iterator assign(InputIt first, InputIt last) const
Assigns elements from [first; last) range to first elements.
Definition sbepp.hpp:3262
static constexpr size_type max_size() noexcept
Returns size()
Definition sbepp.hpp:3070
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:3004
constexpr pointer data() const noexcept
Returns pointer to the underlying array.
Definition sbepp.hpp:3045
constexpr iterator assign(size_type count, const value_type value) const noexcept
Assigns value to first count elements.
Definition sbepp.hpp:3252
Provides various traits/attributes of an <enum> element.
Definition sbepp.hpp:4168
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4175
static constexpr offset_t offset() noexcept
Returns enum offset. Available only if offset is static, i.e. not available for public enums whose of...
static constexpr const char * description() noexcept
Returns description attribute.
sbepp::type_list< ValueTags... > value_tags
Value tags in schema order.
Definition sbepp.hpp:4189
static constexpr const char * name() noexcept
Returns name attribute.
ScopedEnumType value_type
Representation type.
Definition sbepp.hpp:4187
static constexpr version_t since_version() noexcept
Returns sinceVersion attribute.
Provides various traits/attributes of a <validValue> element.
Definition sbepp.hpp:4207
static constexpr ScopedEnumType value() noexcept
Returns enumerator value.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
static constexpr const char * description() noexcept
Returns description attribute.
Provides various traits/attributes of a <field> element.
Definition sbepp.hpp:4480
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
static constexpr offset_t offset() noexcept
Returns actual offset.
ValueType value_type
Representation type.
Definition sbepp.hpp:4502
TypeTag value_type_tag
value_type's tag. Not available for constants of numeric types
Definition sbepp.hpp:4511
static constexpr field_presence presence() noexcept
Returns the actual presence. Note that it can be different from the one provided in schema,...
Provides various traits/attributes of a <group> element.
Definition sbepp.hpp:4529
static constexpr block_length_t block_length() noexcept
Returns blockLength attribute.
static constexpr std::size_t size_bytes(const NumInGroupType num_in_group,...) noexcept
Returns number of bytes required to represent the group in given configuration.
static constexpr const char * description() noexcept
Returns description attribute.
HeaderType< Byte > dimension_type
Group dimension composite type.
Definition sbepp.hpp:4559
sbepp::type_list< FieldTags... > field_tags
Current-level field tags in schema order.
Definition sbepp.hpp:4583
HeaderTag dimension_type_tag
Dimension composite tag.
Definition sbepp.hpp:4561
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
GroupType< Byte > value_type
Representation type.
Definition sbepp.hpp:4552
static constexpr const char * semantic_type() noexcept
Returns semanticType attribute.
sbepp::type_list< DataTags... > data_tags
Current-level data tags in schema order.
Definition sbepp.hpp:4587
EntryType< Byte > entry_type
Group entry type.
Definition sbepp.hpp:4568
static constexpr const char * name() noexcept
Returns name attribute.
sbepp::type_list< GroupTags... > group_tags
Current-level group tags in schema order.
Definition sbepp.hpp:4585
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
Provides various traits/attributes of a <message> element.
Definition sbepp.hpp:4352
static constexpr std::size_t size_bytes(...) noexcept
Returns number of bytes required to represent the message in given configuration.
sbepp::type_list< GroupTags... > group_tags
Top-level group tags in schema order.
Definition sbepp.hpp:4460
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
sbepp::type_list< DataTags... > data_tags
Top-level data tags in schema order.
Definition sbepp.hpp:4462
static constexpr const char * semantic_type() noexcept
Returns semanticType attribute.
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr block_length_t block_length() noexcept
Returns blockLength attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
MessageType< Byte > value_type
Representation type.
Definition sbepp.hpp:4375
sbepp::type_list< FieldTags... > field_tags
Top-level field tags in schema order.
Definition sbepp.hpp:4458
Provides various traits/attributes of a <messageSchema> element.
Definition sbepp.hpp:4124
static constexpr const char * description() noexcept
Returns description attribute.
HeaderTypeTag header_type_tag
Message header composite tag. Can be used to access its traits.
Definition sbepp.hpp:4146
static constexpr version_t version() noexcept
Returns version attribute.
static constexpr const char * package() noexcept
Returns package attribute.
static constexpr const char * semantic_version() noexcept
Returns semanticVersion attribute.
HeaderComposite< Byte > header_type
Message header composite type.
Definition sbepp.hpp:4144
sbepp::type_list< TypeTags... > type_tags
Public schema type tags, unordered.
Definition sbepp.hpp:4148
static constexpr endian byte_order() noexcept
Returns byteOrder attribute.
sbepp::type_list< MessageTags... > message_tags
Schema message tags in schema order.
Definition sbepp.hpp:4150
Provides various traits/attributes of a <choice> element.
Definition sbepp.hpp:4276
static constexpr choice_index_t index() noexcept
Returns choice bit index.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
Provides various traits/attributes of a <set> element.
Definition sbepp.hpp:4237
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
sbepp::type_list< ChoiceTags... > choice_tags
Choice tags in schema order.
Definition sbepp.hpp:4258
static constexpr offset_t offset() noexcept
Returns type offset. Available only if offset is static, i.e. not available for public sets whose off...
SetType value_type
Representation type.
Definition sbepp.hpp:4256
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4249
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr version_t since_version() noexcept
Returns addedSince attribute.
Provides various traits and attributes of a <type> element.
Definition sbepp.hpp:4043
static constexpr primitive_type min_value() noexcept
Returns minValue. Available only if length() == 1 and presence() != field_presence::constant
static constexpr const char * character_encoding() noexcept
Returns characterEncoding attribute.
ValueType value_type
Representation type.
Definition sbepp.hpp:4049
static constexpr const char * description() noexcept
Returns description attribute.
static constexpr version_t deprecated() noexcept
Returns deprecated attribute. Available only if provided in schema.
PrimitiveType primitive_type
Underlying type.
Definition sbepp.hpp:4046
static constexpr length_t length() noexcept
Returns length attribute.
static constexpr const char * name() noexcept
Returns name attribute.
static constexpr field_presence presence() noexcept
Returns presence.
static constexpr primitive_type max_value() noexcept
Returns maxValue. Available only if length() == 1 and presence() != field_presence::constant
static constexpr const char * semantic_type() noexcept
Returns semanticType attribute.
static constexpr primitive_type null_value() noexcept
Returns nullValue. Available only if length() == 1 and presence() == field_presence::optional
static constexpr offset_t offset() noexcept
Returns type offset. Available only if offset is static, i.e. not available for public types whose of...
static constexpr version_t since_version() noexcept
Returns sinceVersion attribute.
Concept for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5152
Concept for sbepp::is_composite_tag<Tag>::value
Definition sbepp.hpp:5895
Concept for sbepp::is_composite<T>::value
Definition sbepp.hpp:5180
Concept for sbepp::is_data_tag<Tag>::value
Definition sbepp.hpp:5907
Concept for sbepp::is_data<T>::value
Definition sbepp.hpp:5200
Concept for sbepp::is_enum_tag<Tag>::value
Definition sbepp.hpp:5879
Concept for sbepp::is_enum_value_tag<Tag>::value
Definition sbepp.hpp:5883
Concept for sbepp::is_enum<T>::value
Definition sbepp.hpp:5172
Concept for sbepp::is_field_tag<Tag>::value
Definition sbepp.hpp:5899
Concept for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5188
Concept for sbepp::is_group_tag<Tag>::value
Definition sbepp.hpp:5903
Concept for sbepp::is_group<T>::value
Definition sbepp.hpp:5196
Concept for sbepp::is_message_tag<Tag>::value
Definition sbepp.hpp:5911
Concept for sbepp::is_message<T>::value
Definition sbepp.hpp:5184
Concept for sbepp::is_nested_group<T>::value
Definition sbepp.hpp:5192
Concept for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5164
Concept for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5160
Concept for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5156
Concept for sbepp::is_schema_tag<Tag>::value
Definition sbepp.hpp:5915
Concept for sbepp::is_set_choice_tag<Tag>::value
Definition sbepp.hpp:5891
Concept for sbepp::is_set_tag<Tag>::value
Definition sbepp.hpp:5887
Concept for sbepp::is_set<T>::value
Definition sbepp.hpp:5176
Concept for sbepp::is_type_tag<Tag>::value
Definition sbepp.hpp:5875
Concept for sbepp::is_type<T>::value
Definition sbepp.hpp:5168
Contains cursor wrappers which allow more precise control over its position.
Definition sbepp.hpp:1658
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:1740
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:1706
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:1677
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:1720
Namespace for various implementation details. Should not be used directly.
Definition sbepp.hpp:384
The main sbepp namespace.
Definition sbepp.hpp:232
constexpr auto is_composite_v
Shorthand for sbepp::is_composite<T>::value
Definition sbepp.hpp:5126
constexpr auto is_required_type_v
Shorthand for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5102
constexpr auto is_type_v
Shorthand for sbepp::is_type<T>::value
Definition sbepp.hpp:5114
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:2839
detail::is_base_of_tmp< detail::optional_base, T > is_optional_type
Checks if T is a non-array optional type.
Definition sbepp.hpp:5015
constexpr View< Byte > make_view(Byte *ptr, const std::size_t size) noexcept
Constructs view from memory buffer.
Definition sbepp.hpp:4927
typename traits_tag< ValueType >::type traits_tag_t
Shorthand for sbepp::traits_tag<T>::type
Definition sbepp.hpp:4677
constexpr auto is_flat_group_v
Shorthand for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5134
eos_null
Represents number of null bytes that can be added after the end-of-string by detail::static_array_ref...
Definition sbepp.hpp:2907
@ none
Definition sbepp.hpp:2910
@ all
All bytes after the last string character will be set to null.
Definition sbepp.hpp:2916
@ single
Definition sbepp.hpp:2914
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:2858
constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
Returns the header of a message/group.
Definition sbepp.hpp:1619
detail::is_base_of_tmp< detail::required_base, T > is_required_type
Checks if T is a non-array required type.
Definition sbepp.hpp:5011
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:5068
detail::is_base_of_tmp< detail::flat_group_base, T > is_flat_group
Checks if T is a flat group.
Definition sbepp.hpp:5060
detail::has_traits< group_traits, Tag > is_group_tag
Checks if Tag is a group tag.
Definition sbepp.hpp:5800
constexpr auto is_array_type_v
Shorthand for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5098
constexpr nullopt_t nullopt
Helper constant used to initialize optional types with null value.
Definition sbepp.hpp:3725
field_presence
Represents presence trait value type, e.g. type_traits::presence()
Definition sbepp.hpp:313
@ constant
field is constant
Definition sbepp.hpp:319
@ required
field is required
Definition sbepp.hpp:315
@ optional
field is optional
Definition sbepp.hpp:317
constexpr Visitor && visit_children(View view, Cursor &c, Visitor &&visitor={})
Visits view's children using provided cursor.
Definition sbepp.hpp:5369
constexpr auto is_group_tag_v
Shorthand for sbepp::is_group_tag<Tag>::value
Definition sbepp.hpp:5857
constexpr auto is_enum_v
Shorthand for sbepp::is_enum<T>::value
Definition sbepp.hpp:5118
detail::has_traits< schema_traits, Tag > is_schema_tag
Checks if Tag is a schema tag.
Definition sbepp.hpp:5824
detail::has_traits< field_traits, Tag > is_field_tag
Checks if Tag is a field tag.
Definition sbepp.hpp:5792
detail::has_traits< composite_traits, Tag > is_composite_tag
Checks if Tag is a composite tag.
Definition sbepp.hpp:5784
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:2881
constexpr auto fill_message_header(Message m) noexcept -> decltype(m(detail::fill_message_header_tag{}))
Fills message header.
Definition sbepp.hpp:3998
constexpr auto is_non_array_type_v
Shorthand for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5110
constexpr auto is_field_tag_v
Shorthand for sbepp::is_field_tag<Tag>::value
Definition sbepp.hpp:5853
constexpr Visitor && visit(View view, Cursor &c, Visitor &&visitor={})
Visits a view using given cursor.
Definition sbepp.hpp:5229
constexpr auto set_by_tag(ViewOrSet &&viewOrSet, Value &&value) noexcept -> decltype(std::forward< ViewOrSet >(viewOrSet)(detail::access_by_tag_tag{}, Tag{}, std::forward< Value >(value)))
Sets field or set choice value by tag.
Definition sbepp.hpp:5692
constexpr auto is_set_choice_tag_v
Shorthand for sbepp::is_set_choice_tag<Tag>::value
Definition sbepp.hpp:5845
constexpr auto is_message_tag_v
Shorthand for sbepp::is_message_tag<Tag>::value
Definition sbepp.hpp:5865
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:5093
typename byte_type< View >::type byte_type_t
Shortcut for byte_type<T>::type
Definition sbepp.hpp:1651
constexpr auto is_data_tag_v
Shorthand for sbepp::is_data_tag<Tag>::value
Definition sbepp.hpp:5861
detail::is_base_of_tmp< detail::nested_group_base, T > is_nested_group
Checks if T is a nested group.
Definition sbepp.hpp:5064
constexpr const char * enum_to_string(const E e) noexcept
Converts enum to string.
Definition sbepp.hpp:5476
detail::is_base_of_tmp< detail::message_base, T > is_message
Checks if T is a message.
Definition sbepp.hpp:5056
detail::has_traits< set_choice_traits, Tag > is_set_choice_tag
Checks if Tag is a set choice tag.
Definition sbepp.hpp:5776
detail::has_traits< enum_traits, Tag > is_enum_tag
Checks if Tag is an enum tag.
Definition sbepp.hpp:5752
detail::has_traits< set_traits, Tag > is_set_tag
Checks if Tag is a set tag.
Definition sbepp.hpp:5768
constexpr auto is_enum_value_tag_v
Shorthand for sbepp::is_enum_value_tag<Tag>::value
Definition sbepp.hpp:5837
constexpr auto fill_group_header(Group g, Size num_in_group) noexcept -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
Fills group header.
Definition sbepp.hpp:4018
constexpr auto is_composite_tag_v
Shorthand for sbepp::is_composite_tag<Tag>::value
Definition sbepp.hpp:5849
constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
Returns pointer to the underlying data referenced by a view.
Definition sbepp.hpp:1631
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:1592
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:5048
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:5025
constexpr auto is_group_v
Shorthand for sbepp::is_group<T>::value
Definition sbepp.hpp:5142
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:5494
constexpr default_init_t default_init
Helper to pass default_init_t to dynamic_array_ref::resize().
Definition sbepp.hpp:2902
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:5019
std::uint16_t member_id_t
Represents id trait value type, e.g. field_traits::id()
Definition sbepp.hpp:306
constexpr auto get_by_tag(ViewOrSet viewOrSet) noexcept -> decltype(viewOrSet(detail::access_by_tag_tag{}, Tag{}))
Gets field or set choice value by tag.
Definition sbepp.hpp:5661
constexpr auto is_optional_type_v
Shorthand for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5106
detail::has_traits< type_traits, Tag > is_type_tag
Checks if Tag is a type tag.
Definition sbepp.hpp:5744
std::uint64_t length_t
Represents type_traits::length() value type.
Definition sbepp.hpp:290
constexpr auto is_set_tag_v
Shorthand for sbepp::is_set_tag<Tag>::value
Definition sbepp.hpp:5841
detail::has_traits< data_traits, Tag > is_data_tag
Checks if Tag is a data tag.
Definition sbepp.hpp:5808
constexpr size_bytes_checked_result size_bytes_checked(View view, std::size_t size) noexcept
Calculates view size with additional safety checks.
Definition sbepp.hpp:5634
constexpr auto is_message_v
Shorthand for sbepp::is_message<T>::value
Definition sbepp.hpp:5130
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_schema_tag_v
Shorthand for sbepp::is_schema_tag<Tag>::value
Definition sbepp.hpp:5869
constexpr auto is_enum_tag_v
Shorthand for sbepp::is_enum_tag<Tag>::value
Definition sbepp.hpp:5833
constexpr auto is_type_tag_v
Shorthand for sbepp::is_type_tag<Tag>::value
Definition sbepp.hpp:5829
constexpr auto is_set_v
Shorthand for sbepp::is_set<T>::value
Definition sbepp.hpp:5122
detail::is_base_of_tmp< detail::entry_base, T > is_group_entry
Checks if T is a group entry.
Definition sbepp.hpp:5074
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:5138
constexpr View< typename std::add_const< Byte >::type > make_const_view(Byte *ptr, const std::size_t size) noexcept
Constructs read-only view from memory buffer.
Definition sbepp.hpp:4952
constexpr auto is_data_v
Shorthand for sbepp::is_data<T>::value
Definition sbepp.hpp:5146
detail::has_traits< enum_value_traits, Tag > is_enum_value_tag
Checks if Tag is an enum value tag.
Definition sbepp.hpp:5760
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
Definition sbepp.hpp:343
@ little
little-endian
Definition sbepp.hpp:339
@ big
big-endian
Definition sbepp.hpp:341
detail::has_traits< message_traits, Tag > is_message_tag
Checks if Tag is a message tag.
Definition sbepp.hpp:5816
typename detail::is_array_type_impl< T >::type is_array_type
Checks is T is an array type.
Definition sbepp.hpp:5007
detail::is_base_of_tmp< detail::composite_base, T > is_composite
Checks if T is a composite.
Definition sbepp.hpp:5052
#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:1643
typename std::remove_pointer< decltype(sbepp::addressof( std::declval< View >()))>::type type
Holds View byte type.
Definition sbepp.hpp:1645
Tag for dynamic_array_ref::resize(). Used to skip value initialization.
Definition sbepp.hpp:2893
Checks if T is an enumeration.
Definition sbepp.hpp:5033
Tag type used to initialize optional types with null value.
Definition sbepp.hpp:3714
Result type of size_bytes_checked
Definition sbepp.hpp:5615
bool valid
Denotes whether size is valid.
Definition sbepp.hpp:5617
std::size_t size
Calculated size, valid only if valid == true
Definition sbepp.hpp:5619
Maps representation type to its tag.
Definition sbepp.hpp:4669
Tag type
Tag to access ValueType's traits.
Definition sbepp.hpp:4671
An empty structure to represent a sequence of types.
Definition sbepp.hpp:378
Tag for unknown enum values.
Definition sbepp.hpp:4964