sbepp
Loading...
Searching...
No Matches
sbepp.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2023, Oleksandr Koval
3
10#pragma once
11
12#include <array>
13#include <algorithm>
14#include <cstddef>
15#include <cstdint>
16#include <cstring>
17#include <iterator>
18#include <limits>
19#include <type_traits>
20#include <initializer_list>
21
22// Clang generates tons of warnings about code like `return {N};` where `N` is
23// calculated during generation or just a value from schema. Using braced
24// initialization syntax provides additional safety in such cases.
25#ifdef __clang__
26# define SBEPP_WARNINGS_OFF() \
27 _Pragma("clang diagnostic push"); \
28 _Pragma("clang diagnostic ignored \"-Wbraced-scalar-init\"")
29# define SBEPP_WARNINGS_ON() _Pragma("clang diagnostic pop")
30#else
31# define SBEPP_WARNINGS_OFF()
32# define SBEPP_WARNINGS_ON()
33#endif
34
35SBEPP_WARNINGS_OFF();
36
37#ifdef _MSVC_LANG
38# define SBEPP_CPLUSPLUS _MSVC_LANG
39#else
40# define SBEPP_CPLUSPLUS __cplusplus
41#endif
42
43#ifdef __has_include
44# if __has_include(<version>)
45# include <version>
46# endif
47#endif
48
58#if !defined(SBEPP_HAS_THREE_WAY_COMPARISON) \
59 && defined(__cpp_impl_three_way_comparison) \
60 && defined(__cpp_lib_three_way_comparison)
61# if(__cpp_impl_three_way_comparison >= 201907L) \
62 && (__cpp_lib_three_way_comparison >= 201907L)
63# define SBEPP_HAS_THREE_WAY_COMPARISON 1
64# include <compare>
65# endif
66#endif
67#ifndef SBEPP_HAS_THREE_WAY_COMPARISON
68# define SBEPP_HAS_THREE_WAY_COMPARISON 0
69#endif
70
72#if !defined(SBEPP_HAS_CONCEPTS) && defined(__cpp_concepts)
73# if(__cpp_concepts >= 201907L)
74# define SBEPP_HAS_CONCEPTS 1
75# endif
76#endif
77#ifndef SBEPP_HAS_CONCEPTS
78# define SBEPP_HAS_CONCEPTS 0
79#endif
80
82#if !defined(SBEPP_HAS_INLINE_VARS) && defined(__cpp_inline_variables)
83# if(__cpp_inline_variables >= 201606L)
84# define SBEPP_HAS_INLINE_VARS 1
85# define SBEPP_CPP17_INLINE_VAR inline
86# endif
87#endif
88#ifndef SBEPP_CPP17_INLINE_VAR
89# define SBEPP_HAS_INLINE_VARS 0
90# define SBEPP_CPP17_INLINE_VAR
91#endif
92
94#if !defined(SBEPP_HAS_ENDIAN) && defined(__cpp_lib_endian)
95# if(__cpp_lib_endian >= 201907L)
96# define SBEPP_HAS_ENDIAN 1
97# include <bit>
98# endif
99#endif
100#ifndef SBEPP_HAS_ENDIAN
101# define SBEPP_HAS_ENDIAN 0
102#endif
103
105#if !defined(SBEPP_HAS_BITCAST) && defined(__cpp_lib_bit_cast)
106# if(__cpp_lib_bit_cast >= 201806L)
107# define SBEPP_HAS_BITCAST 1
108# include <bit>
109# endif
110#endif
111#ifndef SBEPP_HAS_BITCAST
112# define SBEPP_HAS_BITCAST 0
113#endif
114
116#if !defined(SBEPP_HAS_BYTESWAP) && defined(__cpp_lib_byteswap)
117# if(__cpp_lib_byteswap >= 202110L)
118# define SBEPP_HAS_BYTESWAP 1
119# include <bit>
120# endif
121#endif
122#ifndef SBEPP_HAS_BYTESWAP
123# define SBEPP_HAS_BYTESWAP 0
124#endif
125
127#if !defined(SBEPP_HAS_CONSTEXPR_ALGORITHMS) \
128 && defined(__cpp_lib_constexpr_algorithms)
129# if(__cpp_lib_constexpr_algorithms >= 201806L)
130# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 1
131# endif
132#endif
133#ifndef SBEPP_HAS_CONSTEXPR_ALGORITHMS
134# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 0
135#endif
136
137#ifdef __has_cpp_attribute
138// Clang provides `nodiscard` in C++11 but then warns that it's a C++17 feature
139# if __has_cpp_attribute(nodiscard) \
140 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201703L))
141# define SBEPP_CPP17_NODISCARD [[nodiscard]]
142# endif
143
144# if __has_cpp_attribute(deprecated) \
145 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201402L))
146# define SBEPP_DEPRECATED [[deprecated]]
147# endif
148#endif
149
150#ifndef SBEPP_CPP17_NODISCARD
151# define SBEPP_CPP17_NODISCARD
152#endif
153
154#ifndef SBEPP_DEPRECATED
155# if defined(__GNUC__) || defined(__clang__)
156# define SBEPP_DEPRECATED __attribute__((deprecated))
157# elif defined(_MSC_VER)
158# define SBEPP_DEPRECATED __declspec(deprecated)
159# else
160# define SBEPP_DEPRECATED
161# endif
162#endif
163
165#if SBEPP_HAS_BITCAST && SBEPP_HAS_CONSTEXPR_ALGORITHMS
166# define SBEPP_HAS_CONSTEXPR_ACCESSORS 1
167#else
168# define SBEPP_HAS_CONSTEXPR_ACCESSORS 0
169#endif
170
171#if SBEPP_HAS_CONSTEXPR_ACCESSORS
172# include <bit>
173# define SBEPP_CPP20_CONSTEXPR constexpr
174#else
175# define SBEPP_CPP20_CONSTEXPR
176#endif
177
178#ifdef __cpp_constexpr
179# if(__cpp_constexpr >= 201304L)
180# define SBEPP_CPP14_CONSTEXPR constexpr
181# endif
182#else
183# if(SBEPP_CPLUSPLUS >= 201402L)
184# define SBEPP_CPP14_CONSTEXPR constexpr
185# endif
186#endif
187#ifndef SBEPP_CPP14_CONSTEXPR
188# define SBEPP_CPP14_CONSTEXPR
189#endif
190
192#if !defined(SBEPP_HAS_RANGES) && defined(__cpp_lib_ranges)
193# if(__cpp_lib_ranges >= 201911L)
194# define SBEPP_HAS_RANGES 1
195# include <ranges>
196# endif
197#endif
198#ifndef SBEPP_HAS_RANGES
199# define SBEPP_HAS_RANGES 0
200#endif
201
204#if !defined(SBEPP_HAS_IS_CONSTANT_EVALUATED) \
205 && defined(__cpp_lib_is_constant_evaluated) \
206 && (__cpp_lib_is_constant_evaluated >= 201811L)
207# define SBEPP_HAS_IS_CONSTANT_EVALUATED 1
208#endif
209#ifndef SBEPP_HAS_IS_CONSTANT_EVALUATED
210# define SBEPP_HAS_IS_CONSTANT_EVALUATED 0
211#endif
212
214
215#ifdef SBEPP_DOXYGEN
217# define SBEPP_DISABLE_ASSERTS
218
223# define SBEPP_ASSERT_HANDLER
224
229# define SBEPP_ENABLE_ASSERTS_WITH_HANDLER
230
231namespace sbepp
232{
243[[noreturn]] void assertion_failed(
244 char const* expr, char const* function, char const* file, long line);
245} // namespace sbepp
246#endif
247
248#ifdef SBEPP_DISABLE_ASSERTS
249# define SBEPP_SIZE_CHECKS_ENABLED 0
250# define SBEPP_ASSERT(expr) ((void)0)
251#elif defined(SBEPP_ASSERT_HANDLER) \
252 || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
253# if !defined(NDEBUG) || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
254namespace sbepp
255{
256// must be defined by user
257[[noreturn]] void assertion_failed(
258 char const* expr, char const* function, char const* file, long line);
259} // namespace sbepp
260
261# define SBEPP_SIZE_CHECKS_ENABLED 1
262# define SBEPP_ASSERT(expr) \
263 (static_cast<bool>(expr) \
264 ? ((void)0) \
265 : ::sbepp::assertion_failed( \
266 #expr, __func__, __FILE__, __LINE__))
267# else
268# define SBEPP_SIZE_CHECKS_ENABLED 0
269# define SBEPP_ASSERT(expr) ((void)0)
270# endif
271#else
272# include <cassert>
273# ifdef NDEBUG
274# define SBEPP_SIZE_CHECKS_ENABLED 0
275# else
276# define SBEPP_SIZE_CHECKS_ENABLED 1
277# endif
278# define SBEPP_ASSERT(expr) assert(expr)
279#endif
280
281#define SBEPP_SIZE_CHECK(begin, end, offset, size) \
282 SBEPP_ASSERT( \
283 (begin) \
284 && (((offset) + (size)) <= static_cast<std::size_t>((end) - (begin))))
285
287namespace sbepp
288{
290using length_t = std::uint64_t;
291// for unknown reasons, in the SBE standard `offset` is specified as an unsigned
292// 32-bit integer which makes no sense since `length` has 64 bits
294using offset_t = std::uint64_t;
297using version_t = std::uint64_t;
299using schema_id_t = std::uint32_t;
301using message_id_t = std::uint32_t;
304using block_length_t = std::uint64_t;
306using member_id_t = std::uint16_t;
308using choice_index_t = std::uint8_t;
309
313{
315 required,
317 optional,
320};
321
322#ifdef SBEPP_DOXYGEN
327# define SBEPP_BYTE_ORDER
328#endif
329
335#ifdef SBEPP_DOXYGEN
336enum class endian
337{
339 little,
341 big,
343 native
344};
345#elif SBEPP_HAS_ENDIAN
346using endian = std::endian;
347#else
348// https://en.cppreference.com/w/cpp/types/endian
349enum class endian
350{
351# if defined(_WIN32) || defined(WIN32)
352 little = 0,
353 big = 1,
354 native = little
355# elif defined(__BYTE_ORDER__)
356 little = __ORDER_LITTLE_ENDIAN__,
357 big = __ORDER_BIG_ENDIAN__,
358 native = __BYTE_ORDER__
359# elif defined(SBEPP_BYTE_ORDER)
360 little = 0,
361 big = 1,
363# else
364# error "Byte order cannot be detected.\
365 Define SBEPP_BYTE_ORDER to 'little' or 'big'"
366# endif
367};
368#endif
369
370static_assert(
372 "Mixed-endian is not supported");
373
376namespace detail
377{
378// modern C++ bits
379template<bool B, typename T = void>
380using enable_if_t = typename std::enable_if<B, T>::type;
381
382template<typename T>
383using remove_cv_t = typename std::remove_cv<T>::type;
384
385template<typename T>
386using remove_reference_t = typename std::remove_reference<T>::type;
387
388template<typename ByteFrom, typename ByteTo>
389using enable_if_convertible_t =
390 enable_if_t<std::is_convertible<ByteFrom*, ByteTo*>::value>;
391
392template<typename Byte, typename T = void>
393using enable_if_writable_t = enable_if_t<!std::is_const<Byte>::value, T>;
394
395template<typename...>
396using void_t = void;
397
398#if !SBEPP_HAS_BYTESWAP
399
400// intrinsics detection is taken from <boost/endian/detail/intrinsic.hpp>
401# ifndef __has_builtin // Optional of course
402# define __has_builtin(x) 0 // Compatibility with non-clang compilers
403# endif
404
405# if defined(_MSC_VER) && (!defined(__clang__) || defined(__c2__))
406
407# include <cstdlib>
408
409inline std::uint64_t byteswap(std::uint64_t v) noexcept
410{
411 return _byteswap_uint64(v);
412}
413
414inline std::uint32_t byteswap(std::uint32_t v) noexcept
415{
416 return _byteswap_ulong(v);
417}
418
419inline std::uint16_t byteswap(std::uint16_t v) noexcept
420{
421 return _byteswap_ushort(v);
422}
423
424# elif( \
425 defined(__clang__) && __has_builtin(__builtin_bswap32) \
426 && __has_builtin(__builtin_bswap64)) \
427 || (defined(__GNUC__) \
428 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
429
430# if(defined(__clang__) && __has_builtin(__builtin_bswap16)) \
431 || (defined(__GNUC__) \
432 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
433
434inline std::uint16_t byteswap(std::uint16_t v) noexcept
435{
436 return __builtin_bswap16(v);
437}
438
439# else
440
441inline std::uint16_t byteswap(std::uint16_t v) noexcept
442{
443 return __builtin_bswap32(v) << 16;
444}
445
446# endif
447
448inline std::uint64_t byteswap(std::uint64_t v) noexcept
449{
450 return __builtin_bswap64(v);
451}
452
453inline std::uint32_t byteswap(std::uint32_t v) noexcept
454{
455 return __builtin_bswap32(v);
456}
457
458# else
459
460constexpr std::uint64_t byteswap(std::uint64_t v) noexcept
461{
462 return ((v & UINT64_C(0x00000000000000FF)) << 56)
463 | ((v & UINT64_C(0x000000000000FF00)) << 40)
464 | ((v & UINT64_C(0x0000000000FF0000)) << 24)
465 | ((v & UINT64_C(0x00000000FF000000)) << 8)
466 | ((v & UINT64_C(0x000000FF00000000)) >> 8)
467 | ((v & UINT64_C(0x0000FF0000000000)) >> 24)
468 | ((v & UINT64_C(0x00FF000000000000)) >> 40)
469 | ((v & UINT64_C(0xFF00000000000000)) >> 56);
470}
471
472constexpr std::uint32_t byteswap(std::uint32_t v) noexcept
473{
474 return ((v & UINT32_C(0x000000FF)) << 24)
475 | ((v & UINT32_C(0x0000FF00)) << 8)
476 | ((v & UINT32_C(0x00FF0000)) >> 8)
477 | ((v & UINT32_C(0xFF000000)) >> 24);
478}
479
480constexpr std::uint16_t byteswap(std::uint16_t v) noexcept
481{
482 return ((v & UINT16_C(0x00FF)) << 8) | ((v & UINT16_C(0xFF00)) >> 8);
483}
484
485# endif
486#endif
487
488template<typename T>
489struct fp_underlying_type;
490
491template<typename T>
492using fp_underlying_type_t = typename fp_underlying_type<T>::type;
493
494template<>
495struct fp_underlying_type<float>
496{
497 using type = std::uint32_t;
498};
499
500template<>
501struct fp_underlying_type<double>
502{
503 using type = std::uint64_t;
504};
505
506// usually, I don't like putting `enable_if` into return type but these
507// overloads are not public and it looks better than adding `typename = void` to
508// template headers
509template<typename T>
510constexpr enable_if_t<sizeof(T) == 1, T> byteswap(T value) noexcept
511{
512 return value;
513}
514
515template<typename T>
516SBEPP_CPP20_CONSTEXPR
517 enable_if_t<!std::is_floating_point<T>::value && (sizeof(T) != 1), T>
518 byteswap(T value) noexcept
519{
520#if SBEPP_HAS_BYTESWAP
521 // casts are required because this overload is selected for enums which are
522 // not integral and can't be passed to `std::byteswap` as is
523 return static_cast<T>(std::byteswap(
524 static_cast<typename std::make_unsigned<T>::type>(value)));
525#else
526 return static_cast<T>(
527 byteswap(static_cast<typename std::make_unsigned<T>::type>(value)));
528#endif
529}
530
531template<typename T>
532enable_if_t<std::is_floating_point<T>::value, T> byteswap(T value) noexcept
533{
534 fp_underlying_type_t<T> underlying{};
535 std::memcpy(&underlying, &value, sizeof(underlying));
536 underlying = byteswap(underlying);
537
538 std::memcpy(&value, &underlying, sizeof(underlying));
539
540 return value;
541}
542
543template<typename T, endian E, typename Byte>
544SBEPP_CPP20_CONSTEXPR T get_primitive(const Byte* ptr)
545{
546#if SBEPP_HAS_BITCAST
547 std::array<Byte, sizeof(T)> arr;
548 if(E == endian::native)
549 {
550 std::copy(ptr, ptr + sizeof(T), std::begin(arr));
551 }
552 else
553 {
554 std::reverse_copy(ptr, ptr + sizeof(T), std::begin(arr));
555 }
556 return std::bit_cast<T>(arr);
557#else
558 // old compilers don't optimize `std::copy` approach good enough, that's
559 // why explicit `std::memcpy` call is required
560 T res;
561 std::memcpy(&res, ptr, sizeof(T));
562 if(E == endian::native)
563 {
564 return res;
565 }
566 else
567 {
568 return byteswap(res);
569 }
570#endif
571}
572
573template<endian E, typename T, typename Byte>
574SBEPP_CPP20_CONSTEXPR void set_primitive(Byte* ptr, T value)
575{
576#if SBEPP_HAS_BITCAST
577 auto arr = std::bit_cast<std::array<Byte, sizeof(T)>>(value);
578 if(E == endian::native)
579 {
580 std::copy(std::begin(arr), std::end(arr), ptr);
581 }
582 else
583 {
584 std::reverse_copy(std::begin(arr), std::end(arr), ptr);
585 }
586#else
587 // old compilers don't optimize `std::copy` approach good enough, that's
588 // why explicit `std::memcpy` call is required
589 if(E != endian::native)
590 {
591 value = byteswap(value);
592 }
593 std::memcpy(ptr, &value, sizeof(T));
594#endif
595}
596
597struct fill_message_header_tag
598{
599 explicit fill_message_header_tag() = default;
600};
601
602struct fill_group_header_tag
603{
604 explicit fill_group_header_tag() = default;
605};
606
607struct size_bytes_tag
608{
609 explicit size_bytes_tag() = default;
610};
611
612struct addressof_tag
613{
614 explicit addressof_tag() = default;
615};
616
617struct end_ptr_tag
618{
619 explicit end_ptr_tag() = default;
620};
621
622struct get_header_tag
623{
624 explicit get_header_tag() = default;
625};
626
627struct get_block_length_tag
628{
629 explicit get_block_length_tag() = default;
630};
631
632struct get_bit_tag
633{
634 explicit get_bit_tag() = default;
635};
636
637struct set_bit_tag
638{
639 explicit set_bit_tag() = default;
640};
641
642struct get_level_tag
643{
644 explicit get_level_tag() = default;
645};
646
647struct visit_tag
648{
649 explicit visit_tag() = default;
650};
651
652struct visit_children_tag
653{
654 explicit visit_children_tag() = default;
655};
656
657struct enum_to_str_tag
658{
659 explicit enum_to_str_tag() = default;
660};
661
662struct visit_set_tag
663{
664 explicit visit_set_tag() = default;
665};
666
667template<typename T, typename U, endian E, typename View>
668SBEPP_CPP20_CONSTEXPR T
669 get_value(const View view, const std::size_t offset) noexcept
670{
671 SBEPP_SIZE_CHECK(
672 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(U));
673 return T{get_primitive<U, E>(view(addressof_tag{}) + offset)};
674}
675
676template<endian E, typename T, typename View>
677SBEPP_CPP20_CONSTEXPR void
678 set_value(const View view, const std::size_t offset, const T value) noexcept
679{
680 SBEPP_SIZE_CHECK(
681 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(T));
682 set_primitive<E>(view(addressof_tag{}) + offset, value);
683}
684
685template<typename Res, typename View>
686SBEPP_CPP20_CONSTEXPR Res
687 get_static_field_view(const View view, const std::size_t offset) noexcept
688{
689 SBEPP_SIZE_CHECK(view(addressof_tag{}), view(end_ptr_tag{}), offset, 0);
690 return {view(addressof_tag{}) + offset, view(end_ptr_tag{})};
691}
692
693template<typename Group, typename View>
694SBEPP_CPP20_CONSTEXPR Group
695 get_first_dynamic_field_view(const View view) noexcept
696{
697 return {
698 view(get_level_tag{}) + view(get_block_length_tag{}),
699 view(end_ptr_tag{})};
700}
701
702template<typename Group, typename View, typename Prev>
703SBEPP_CPP20_CONSTEXPR Group
704 get_dynamic_field_view(const View view, const Prev prev) noexcept
705{
706 return {
707 prev(addressof_tag{}) + prev(size_bytes_tag{}), view(end_ptr_tag{})};
708}
709
712template<typename Byte>
714{
715public:
716 static_assert(sizeof(Byte) == 1, "Byte must represent a single byte");
717
718 template<typename Byte2>
719 friend class byte_range;
720
722 byte_range() = default;
723
725 SBEPP_CPP14_CONSTEXPR byte_range(Byte* begin, Byte* end) noexcept
726 : begin{begin}
727#if SBEPP_SIZE_CHECKS_ENABLED
728 ,
729 end{end}
730#endif
731 {
732 (void)end;
733 }
734
736 constexpr byte_range(Byte* ptr, const std::size_t size) noexcept
737 : byte_range{ptr, ptr + size}
738 {
739 }
740
742 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
743 // NOLINTNEXTLINE: intentionally implicit
744 constexpr byte_range(const byte_range<Byte2>& other) noexcept
745 : begin{other.begin}
746#if SBEPP_SIZE_CHECKS_ENABLED
747 ,
748 end{other.end}
749#endif
750 {
751 }
752
753 constexpr Byte* operator()(addressof_tag) const noexcept
754 {
755 return begin;
756 }
757
758 constexpr Byte* operator()(end_ptr_tag) const noexcept
759 {
760#if SBEPP_SIZE_CHECKS_ENABLED
761 return end;
762#else
763 return nullptr;
764#endif
765 }
766
767private:
768 Byte* begin{};
769#if SBEPP_SIZE_CHECKS_ENABLED
770 Byte* end{};
771#endif
772};
773} // namespace detail
774
781template<typename Byte>
783{
784public:
786 using byte_type = Byte;
787
788 // in accessors we have to use trailing return type because in "skip" mode
789 // they should return `void`. In most cases it's not a problem but
790 // `get_group_view` and `get_data_view` take lambdas which were not allowed
791 // in unevaluated context (e.g. decltype) prior to C++20 so we need this
792 // alias to specify return types for them. First attempt used
793 // pointer-to-member instead of lambda but GCC doesn't support it so I
794 // switched to simpler approach with lambda and trait.
795 template<typename T>
796 using result_type = T;
797
799 cursor() = default;
800
808 template<
809 typename Byte2,
810 typename = detail::enable_if_convertible_t<Byte2, Byte>>
811 // NOLINTNEXTLINE: implicit conversion is intentional
812 constexpr cursor(cursor<Byte2> other) noexcept : ptr{other.ptr}
813 {
814 }
815
824 template<
825 typename Byte2,
826 typename = detail::enable_if_convertible_t<Byte2, Byte>>
827 SBEPP_CPP14_CONSTEXPR cursor& operator=(cursor<Byte2> other) noexcept
828 {
829 ptr = other.ptr;
830 return *this;
831 }
832
839 SBEPP_CPP14_CONSTEXPR Byte*& pointer() noexcept
840 {
841 return ptr;
842 }
843
849 SBEPP_CPP14_CONSTEXPR Byte* pointer() const noexcept
850 {
851 return ptr;
852 }
853
854 template<typename T, typename U, endian E, typename View>
855 SBEPP_CPP20_CONSTEXPR T get_value(
856 const View view,
857 const std::size_t offset,
858 const std::size_t absolute_offset) noexcept
859 {
860 SBEPP_ASSERT(
861 ((view(detail::addressof_tag{}) + absolute_offset)
862 == (ptr + offset))
863 && "Wrong cursor value");
864 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
865 T res{detail::get_primitive<U, E>(ptr + offset)};
866 ptr += offset + sizeof(U);
867 return res;
868 }
869
870 template<endian E, typename T, typename View>
871 SBEPP_CPP20_CONSTEXPR void set_value(
872 const View view,
873 const std::size_t offset,
874 const std::size_t absolute_offset,
875 const T value) noexcept
876 {
877 SBEPP_ASSERT(
878 ((view(detail::addressof_tag{}) + absolute_offset)
879 == (ptr + offset))
880 && "Wrong cursor value");
881 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
882 detail::set_primitive<E>(ptr + offset, value);
883 ptr += offset + sizeof(T);
884 }
885
886 template<typename T, typename U, endian E, typename View>
887 SBEPP_CPP20_CONSTEXPR T get_last_value(
888 const View view,
889 const std::size_t offset,
890 const std::size_t absolute_offset) noexcept
891 {
892 SBEPP_ASSERT(
893 ((view(detail::addressof_tag{}) + absolute_offset)
894 == (ptr + offset))
895 && "Wrong cursor value");
896 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
897 auto res = T{detail::get_primitive<U, E>(ptr + offset)};
898 ptr = view(detail::get_level_tag{})
899 + view(detail::get_block_length_tag{});
900 return res;
901 }
902
903 template<endian E, typename T, typename View>
904 SBEPP_CPP20_CONSTEXPR void set_last_value(
905 const View view,
906 const std::size_t offset,
907 const std::size_t absolute_offset,
908 const T value) noexcept
909 {
910 SBEPP_ASSERT(
911 ((view(detail::addressof_tag{}) + absolute_offset)
912 == (ptr + offset))
913 && "Wrong cursor value");
914 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
915 detail::set_primitive<E>(ptr + offset, value);
916 ptr = view(detail::get_level_tag{})
917 + view(detail::get_block_length_tag{});
918 }
919
920 template<typename Res, typename View>
921 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
922 const View view,
923 const std::size_t offset,
924 const std::size_t absolute_offset) noexcept
925 {
926 SBEPP_ASSERT(
927 ((view(detail::addressof_tag{}) + absolute_offset)
928 == (ptr + offset))
929 && "Wrong cursor value");
930 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
931 Res res{ptr + offset, view(detail::end_ptr_tag{})};
932 ptr += offset + res(detail::size_bytes_tag{});
933 return res;
934 }
935
936 template<typename Res, typename View>
937 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
938 const View view,
939 const std::size_t offset,
940 const std::size_t absolute_offset) noexcept
941 {
942 SBEPP_ASSERT(
943 ((view(detail::addressof_tag{}) + absolute_offset)
944 == (ptr + offset))
945 && "Wrong cursor value");
946 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
947 Res res{ptr + offset, view(detail::end_ptr_tag{})};
948 ptr = view(detail::get_level_tag{})
949 + view(detail::get_block_length_tag{});
950 return res;
951 }
952
953 template<typename ResView, typename View>
954 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
955 {
956 ptr = view(detail::get_level_tag{})
957 + view(detail::get_block_length_tag{});
958 ResView g{ptr, view(detail::end_ptr_tag{})};
959 ptr += g(detail::get_header_tag{})(detail::size_bytes_tag{});
960
961 return g;
962 }
963
964 template<typename ResView, typename View>
965 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
966 {
967 ptr = view(detail::get_level_tag{})
968 + view(detail::get_block_length_tag{});
969 ResView d{ptr, view(detail::end_ptr_tag{})};
970 ptr += d(detail::size_bytes_tag{});
971
972 return d;
973 }
974
975 template<typename ResView, typename View, typename Getter>
976 SBEPP_CPP20_CONSTEXPR ResView
977 get_group_view(const View view, Getter&& getter) noexcept
978 {
979 SBEPP_ASSERT(
980 (getter()(detail::addressof_tag{}) == ptr) && "Wrong cursor value");
981 ResView res{ptr, view(detail::end_ptr_tag{})};
982 auto header = res(detail::get_header_tag{});
983 ptr += header(detail::size_bytes_tag{});
984 return res;
985 }
986
987 template<typename ResView, typename View, typename Getter>
988 SBEPP_CPP20_CONSTEXPR ResView
989 get_data_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 ptr += res(detail::size_bytes_tag{});
995 return res;
996 }
997
998private:
999 template<typename T>
1000 friend class cursor;
1001
1002 Byte* ptr{};
1003};
1004
1005namespace detail
1006{
1007template<typename Byte>
1008class init_cursor_wrapper
1009{
1010public:
1011 using byte_type = Byte;
1012
1013 template<typename T>
1014 using result_type = T;
1015
1016 init_cursor_wrapper() = default;
1017
1018 explicit constexpr init_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1019 : cursor{&cursor}
1020 {
1021 }
1022
1023 template<typename T, typename U, endian E, typename View>
1024 SBEPP_CPP20_CONSTEXPR T get_value(
1025 const View view,
1026 const std::size_t /*offset*/,
1027 const std::size_t absolute_offset) noexcept
1028 {
1029 SBEPP_SIZE_CHECK(
1030 view(addressof_tag{}),
1031 view(end_ptr_tag{}),
1032 absolute_offset,
1033 sizeof(U));
1034 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1035 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(U);
1036 return res;
1037 }
1038
1039 template<endian E, typename T, typename View>
1040 SBEPP_CPP20_CONSTEXPR void set_value(
1041 const View view,
1042 const std::size_t /*offset*/,
1043 const std::size_t absolute_offset,
1044 const T value) noexcept
1045 {
1046 SBEPP_SIZE_CHECK(
1047 view(addressof_tag{}),
1048 view(end_ptr_tag{}),
1049 absolute_offset,
1050 sizeof(T));
1051 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1052 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(T);
1053 }
1054
1055 template<typename T, typename U, endian E, typename View>
1056 SBEPP_CPP20_CONSTEXPR T get_last_value(
1057 const View view,
1058 const std::size_t /*offset*/,
1059 const std::size_t absolute_offset) noexcept
1060 {
1061 SBEPP_SIZE_CHECK(
1062 view(addressof_tag{}),
1063 view(end_ptr_tag{}),
1064 absolute_offset,
1065 sizeof(U));
1066 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1067 cursor->pointer() =
1068 view(get_level_tag{}) + view(get_block_length_tag{});
1069 return res;
1070 }
1071
1072 template<endian E, typename T, typename View>
1073 SBEPP_CPP20_CONSTEXPR void set_last_value(
1074 const View view,
1075 const std::size_t /*offset*/,
1076 const std::size_t absolute_offset,
1077 const T value) noexcept
1078 {
1079 SBEPP_SIZE_CHECK(
1080 view(addressof_tag{}),
1081 view(end_ptr_tag{}),
1082 absolute_offset,
1083 sizeof(T));
1084 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1085 cursor->pointer() =
1086 view(get_level_tag{}) + view(get_block_length_tag{});
1087 }
1088
1089 template<typename Res, typename View>
1090 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1091 const View view,
1092 const std::size_t /*offset*/,
1093 const std::size_t absolute_offset) noexcept
1094 {
1095 SBEPP_SIZE_CHECK(
1096 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1097 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1098 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1099 return res;
1100 }
1101
1102 template<typename Res, typename View>
1103 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1104 const View view,
1105 const std::size_t /*offset*/,
1106 const std::size_t absolute_offset) noexcept
1107 {
1108 SBEPP_SIZE_CHECK(
1109 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1110 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1111 cursor->pointer() =
1112 view(get_level_tag{}) + view(get_block_length_tag{});
1113 return res;
1114 }
1115
1116 template<typename ResView, typename View>
1117 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1118 {
1119 return cursor->template get_first_group_view<ResView>(view);
1120 }
1121
1122 template<typename ResView, typename View>
1123 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1124 {
1125 return cursor->template get_first_data_view<ResView>(view);
1126 }
1127
1128 template<typename ResView, typename View, typename Getter>
1129 SBEPP_CPP20_CONSTEXPR ResView
1130 get_group_view(const View /*view*/, Getter&& getter) noexcept
1131 {
1132 auto res = getter();
1133 auto header = res(get_header_tag{});
1134 cursor->pointer() = res(addressof_tag{}) + header(size_bytes_tag{});
1135 return res;
1136 }
1137
1138 template<typename ResView, typename View, typename Getter>
1139 SBEPP_CPP20_CONSTEXPR ResView
1140 get_data_view(const View /*view*/, Getter&& getter) noexcept
1141 {
1142 auto res = getter();
1143 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1144 return res;
1145 }
1146
1147private:
1148 sbepp::cursor<Byte>* cursor{};
1149};
1150
1151template<typename Byte>
1152class init_dont_move_cursor_wrapper
1153{
1154public:
1155 using byte_type = Byte;
1156
1157 template<typename T>
1158 using result_type = T;
1159
1160 init_dont_move_cursor_wrapper() = default;
1161
1162 explicit constexpr init_dont_move_cursor_wrapper(
1163 sbepp::cursor<Byte>& cursor)
1164 : cursor{&cursor}
1165 {
1166 }
1167
1168 template<typename T, typename U, endian E, typename View>
1169 SBEPP_CPP20_CONSTEXPR T get_value(
1170 const View view,
1171 const std::size_t offset,
1172 const std::size_t absolute_offset) noexcept
1173 {
1174 SBEPP_SIZE_CHECK(
1175 view(addressof_tag{}),
1176 view(end_ptr_tag{}),
1177 absolute_offset,
1178 sizeof(U));
1179 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1180 return T{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1181 }
1182
1183 template<endian E, typename T, typename View>
1184 SBEPP_CPP20_CONSTEXPR void set_value(
1185 const View view,
1186 const std::size_t offset,
1187 const std::size_t absolute_offset,
1188 const T value) noexcept
1189 {
1190 SBEPP_SIZE_CHECK(
1191 view(addressof_tag{}),
1192 view(end_ptr_tag{}),
1193 absolute_offset,
1194 sizeof(T));
1195 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1196 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1197 }
1198
1199 template<typename T, typename U, endian E, typename View>
1200 SBEPP_CPP20_CONSTEXPR T get_last_value(
1201 const View view,
1202 const std::size_t offset,
1203 const std::size_t absolute_offset) noexcept
1204 {
1205 return get_value<T, U, E>(view, offset, absolute_offset);
1206 }
1207
1208 template<endian E, typename T, typename View>
1209 SBEPP_CPP20_CONSTEXPR void set_last_value(
1210 const View view,
1211 const std::size_t offset,
1212 const std::size_t absolute_offset,
1213 const T value) noexcept
1214 {
1215 return set_value<E>(view, offset, absolute_offset, value);
1216 }
1217
1218 template<typename Res, typename View>
1219 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1220 const View view,
1221 const std::size_t offset,
1222 const std::size_t absolute_offset) noexcept
1223 {
1224 SBEPP_SIZE_CHECK(
1225 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1226 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1227 return {view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1228 }
1229
1230 template<typename Res, typename View>
1231 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1232 const View view,
1233 const std::size_t offset,
1234 const std::size_t absolute_offset) noexcept
1235 {
1236 return get_static_field_view<Res>(view, offset, absolute_offset);
1237 }
1238
1239 template<typename ResView, typename View>
1240 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1241 {
1242 cursor->pointer() =
1243 view(get_level_tag{}) + view(get_block_length_tag{});
1244 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1245
1246 return g;
1247 }
1248
1249 template<typename ResView, typename View>
1250 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1251 {
1252 cursor->pointer() =
1253 view(get_level_tag{}) + view(get_block_length_tag{});
1254 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1255
1256 return d;
1257 }
1258
1259 template<typename ResView, typename View, typename Getter>
1260 SBEPP_CPP20_CONSTEXPR ResView
1261 get_group_view(const View /*view*/, Getter&& getter) noexcept
1262 {
1263 auto res = getter();
1264 cursor->pointer() = res(addressof_tag{});
1265 return res;
1266 }
1267
1268 template<typename ResView, typename View, typename Getter>
1269 SBEPP_CPP20_CONSTEXPR ResView
1270 get_data_view(const View /*view*/, Getter&& getter) noexcept
1271 {
1272 auto res = getter();
1273 cursor->pointer() = res(addressof_tag{});
1274 return res;
1275 }
1276
1277private:
1278 sbepp::cursor<Byte>* cursor{};
1279};
1280
1281template<typename Byte>
1282class dont_move_cursor_wrapper
1283{
1284public:
1285 using byte_type = Byte;
1286
1287 template<typename T>
1288 using result_type = T;
1289
1290 dont_move_cursor_wrapper() = default;
1291
1292 explicit constexpr dont_move_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1293 : cursor{&cursor}
1294 {
1295 }
1296
1297 template<typename T, typename U, endian E, typename View>
1298 SBEPP_CPP20_CONSTEXPR T get_value(
1299 const View view,
1300 const std::size_t offset,
1301 const std::size_t absolute_offset) noexcept
1302 {
1303 SBEPP_ASSERT(
1304 ((view(detail::addressof_tag{}) + absolute_offset)
1305 == (cursor->pointer() + offset))
1306 && "Wrong cursor value");
1307 SBEPP_SIZE_CHECK(
1308 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1309 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1310 }
1311
1312 template<endian E, typename T, typename View>
1313 SBEPP_CPP20_CONSTEXPR void set_value(
1314 const View view,
1315 const std::size_t offset,
1316 const std::size_t absolute_offset,
1317 const T value) noexcept
1318 {
1319 SBEPP_ASSERT(
1320 ((view(detail::addressof_tag{}) + absolute_offset)
1321 == (cursor->pointer() + offset))
1322 && "Wrong cursor value");
1323 SBEPP_SIZE_CHECK(
1324 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1325 set_primitive<E>(cursor->pointer() + offset, value);
1326 }
1327
1328 template<typename T, typename U, endian E, typename View>
1329 SBEPP_CPP20_CONSTEXPR T get_last_value(
1330 const View view,
1331 const std::size_t offset,
1332 const std::size_t absolute_offset) noexcept
1333 {
1334 SBEPP_ASSERT(
1335 ((view(detail::addressof_tag{}) + absolute_offset)
1336 == (cursor->pointer() + offset))
1337 && "Wrong cursor value");
1338 SBEPP_SIZE_CHECK(
1339 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1340 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1341 }
1342
1343 template<endian E, typename T, typename View>
1344 SBEPP_CPP20_CONSTEXPR void set_last_value(
1345 const View view,
1346 const std::size_t offset,
1347 const std::size_t absolute_offset,
1348 const T value) noexcept
1349 {
1350 SBEPP_ASSERT(
1351 ((view(detail::addressof_tag{}) + absolute_offset)
1352 == (cursor->pointer() + offset))
1353 && "Wrong cursor value");
1354 SBEPP_SIZE_CHECK(
1355 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1356 set_primitive<E>(cursor->pointer() + offset, value);
1357 }
1358
1359 template<typename Res, typename View>
1360 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1361 const View view,
1362 const std::size_t offset,
1363 const std::size_t absolute_offset) noexcept
1364 {
1365 SBEPP_ASSERT(
1366 ((view(detail::addressof_tag{}) + absolute_offset)
1367 == (cursor->pointer() + offset))
1368 && "Wrong cursor value");
1369 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1370 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1371 }
1372
1373 template<typename Res, typename View>
1374 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1375 const View view,
1376 const std::size_t offset,
1377 const std::size_t absolute_offset) noexcept
1378 {
1379 SBEPP_ASSERT(
1380 ((view(detail::addressof_tag{}) + absolute_offset)
1381 == (cursor->pointer() + offset))
1382 && "Wrong cursor value");
1383 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1384 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1385 }
1386
1387 template<typename ResView, typename View>
1388 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1389 {
1390 cursor->pointer() =
1391 view(get_level_tag{}) + view(get_block_length_tag{});
1392 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1393
1394 return g;
1395 }
1396
1397 template<typename ResView, typename View>
1398 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1399 {
1400 cursor->pointer() =
1401 view(get_level_tag{}) + view(get_block_length_tag{});
1402 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1403
1404 return d;
1405 }
1406
1407 template<typename ResView, typename View, typename Getter>
1408 SBEPP_CPP20_CONSTEXPR ResView
1409 get_group_view(const View view, Getter&& getter) noexcept
1410 {
1411 SBEPP_ASSERT(
1412 (getter()(detail::addressof_tag{}) == cursor->pointer())
1413 && "Wrong cursor value");
1414 return {cursor->pointer(), view(end_ptr_tag{})};
1415 }
1416
1417 template<typename ResView, typename View, typename Getter>
1418 SBEPP_CPP20_CONSTEXPR ResView
1419 get_data_view(const View view, Getter&& getter) noexcept
1420 {
1421 SBEPP_ASSERT(
1422 (getter()(detail::addressof_tag{}) == cursor->pointer())
1423 && "Wrong cursor value");
1424 return {cursor->pointer(), view(end_ptr_tag{})};
1425 }
1426
1427private:
1428 sbepp::cursor<Byte>* cursor{};
1429};
1430
1431template<typename Byte>
1432class skip_cursor_wrapper
1433{
1434public:
1435 using byte_type = Byte;
1436
1437 template<typename T>
1438 using result_type = void;
1439
1440 skip_cursor_wrapper() = default;
1441
1442 explicit constexpr skip_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1443 : cursor{&cursor}
1444 {
1445 }
1446
1447 template<typename T, typename U, endian E, typename View>
1448 SBEPP_CPP20_CONSTEXPR void get_value(
1449 const View view,
1450 const std::size_t offset,
1451 const std::size_t absolute_offset) noexcept
1452 {
1453 SBEPP_ASSERT(
1454 ((view(detail::addressof_tag{}) + absolute_offset)
1455 == (cursor->pointer() + offset))
1456 && "Wrong cursor value");
1457 SBEPP_SIZE_CHECK(
1458 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1459 cursor->pointer() += offset + sizeof(U);
1460 }
1461
1462 template<typename T, typename U, endian E, typename View>
1463 SBEPP_CPP20_CONSTEXPR void get_last_value(
1464 const View view,
1465 const std::size_t offset,
1466 const std::size_t absolute_offset) noexcept
1467 {
1468 SBEPP_ASSERT(
1469 ((view(detail::addressof_tag{}) + absolute_offset)
1470 == (cursor->pointer() + offset))
1471 && "Wrong cursor value");
1472 SBEPP_SIZE_CHECK(
1473 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1474 cursor->pointer() =
1475 view(get_level_tag{}) + view(get_block_length_tag{});
1476 }
1477
1478 template<typename Res, typename View>
1479 SBEPP_CPP20_CONSTEXPR void get_static_field_view(
1480 const View view,
1481 const std::size_t offset,
1482 const std::size_t absolute_offset) noexcept
1483 {
1484 SBEPP_ASSERT(
1485 ((view(detail::addressof_tag{}) + absolute_offset)
1486 == (cursor->pointer() + offset))
1487 && "Wrong cursor value");
1488 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1489 Res res{cursor->pointer(), view(end_ptr_tag{})};
1490 cursor->pointer() += offset + res(size_bytes_tag{});
1491 }
1492
1493 template<typename Res, typename View>
1494 SBEPP_CPP20_CONSTEXPR void get_last_static_field_view(
1495 const View view,
1496 const std::size_t offset,
1497 const std::size_t absolute_offset) noexcept
1498 {
1499 SBEPP_ASSERT(
1500 ((view(detail::addressof_tag{}) + absolute_offset)
1501 == (cursor->pointer() + offset))
1502 && "Wrong cursor value");
1503 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1504 cursor->pointer() =
1505 view(get_level_tag{}) + view(get_block_length_tag{});
1506 }
1507
1508 template<typename ResView, typename View>
1509 SBEPP_CPP20_CONSTEXPR void get_first_group_view(const View view) noexcept
1510 {
1511 cursor->pointer() =
1512 view(get_level_tag{}) + view(get_block_length_tag{});
1513 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1514 cursor->pointer() += g(size_bytes_tag{});
1515 }
1516
1517 template<typename ResView, typename View>
1518 SBEPP_CPP20_CONSTEXPR void get_first_data_view(const View view) noexcept
1519 {
1520 cursor->pointer() =
1521 view(get_level_tag{}) + view(get_block_length_tag{});
1522 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1523 cursor->pointer() += d(size_bytes_tag{});
1524 }
1525
1526 template<typename ResView, typename View, typename Getter>
1527 SBEPP_CPP20_CONSTEXPR void
1528 get_group_view(const View view, Getter&& getter) noexcept
1529 {
1530 SBEPP_ASSERT(
1531 (getter()(detail::addressof_tag{}) == cursor->pointer())
1532 && "Wrong cursor value");
1533 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1534 cursor->pointer() += res(size_bytes_tag{});
1535 }
1536
1537 template<typename ResView, typename View, typename Getter>
1538 SBEPP_CPP20_CONSTEXPR void
1539 get_data_view(const View view, Getter&& getter) noexcept
1540 {
1541 SBEPP_ASSERT(
1542 (getter()(detail::addressof_tag{}) == cursor->pointer())
1543 && "Wrong cursor value");
1544 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1545 cursor->pointer() += res(size_bytes_tag{});
1546 }
1547
1548private:
1549 sbepp::cursor<Byte>* cursor{};
1550};
1551
1552template<typename Cursor, typename T>
1553using cursor_result_type_t =
1554 typename remove_reference_t<Cursor>::template result_type<T>;
1555
1556template<typename Cursor>
1557using cursor_byte_type_t = typename remove_reference_t<Cursor>::byte_type;
1558
1559template<typename MessageByte, typename CursorByte>
1560using enable_if_cursor_compatible_t =
1561 enable_if_convertible_t<MessageByte, CursorByte>;
1562
1563template<typename MessageByte, typename CursorByte>
1564using enable_if_cursor_writeable_t = enable_if_t<
1565 std::is_convertible<MessageByte*, CursorByte*>::value
1566 && !std::is_const<MessageByte>::value && !std::is_const<CursorByte>::value>;
1567} // namespace detail
1568
1579template<typename T>
1580constexpr std::size_t size_bytes(T v) noexcept
1581{
1582 return v(detail::size_bytes_tag{});
1583}
1584
1594template<typename T, typename Byte>
1595constexpr std::size_t size_bytes(T v, cursor<Byte> c) noexcept
1596{
1597 return v(detail::size_bytes_tag{}, c);
1598}
1599
1606template<typename T>
1607constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
1608{
1609 return v(detail::get_header_tag{});
1610}
1611
1618template<typename T>
1619constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
1620{
1621 return v(detail::addressof_tag{});
1622}
1623
1629template<typename View>
1631{
1633 using type = typename std::remove_pointer<decltype(sbepp::addressof(
1634 std::declval<View>()))>::type;
1635};
1636
1638template<typename View>
1640
1645namespace cursor_ops
1646{
1664template<typename Byte>
1665constexpr detail::init_cursor_wrapper<Byte> init(cursor<Byte>& c) noexcept
1666{
1667 return detail::init_cursor_wrapper<Byte>{c};
1668}
1669
1692template<typename Byte>
1693constexpr detail::dont_move_cursor_wrapper<Byte>
1695{
1696 return detail::dont_move_cursor_wrapper<Byte>{c};
1697}
1698
1706template<typename Byte>
1707constexpr detail::init_dont_move_cursor_wrapper<Byte>
1709{
1710 return detail::init_dont_move_cursor_wrapper<Byte>{c};
1711}
1712
1727template<typename Byte>
1728constexpr detail::skip_cursor_wrapper<Byte> skip(cursor<Byte>& c) noexcept
1729{
1730 return detail::skip_cursor_wrapper<Byte>{c};
1731}
1732} // namespace cursor_ops
1733
1734namespace detail
1735{
1736// the only purpose of this class is to implement `is_composite` trait
1738template<typename Byte>
1739class composite_base : public byte_range<Byte>
1740{
1741public:
1742 using byte_range<Byte>::byte_range;
1743 using byte_range<Byte>::operator();
1744};
1745
1747template<typename Byte, typename Header>
1748class message_base : public byte_range<Byte>
1749{
1750public:
1751 using byte_range<Byte>::byte_range;
1752 using byte_range<Byte>::operator();
1753
1754 SBEPP_CPP14_CONSTEXPR Header operator()(get_header_tag) const noexcept
1755 {
1756 Header header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
1757 SBEPP_SIZE_CHECK(
1758 (*this)(addressof_tag{}),
1759 (*this)(end_ptr_tag{}),
1760 0,
1761 sbepp::size_bytes(header));
1762 return header;
1763 }
1764
1765 SBEPP_CPP14_CONSTEXPR Byte* operator()(get_level_tag) const noexcept
1766 {
1767 auto header = (*this)(get_header_tag{});
1768 return header(addressof_tag{}) + header(size_bytes_tag{});
1769 }
1770
1771 constexpr typename std::decay<
1772 decltype(std::declval<Header>().blockLength().value())>::type
1773 operator()(get_block_length_tag) const noexcept
1774 {
1775 return operator()(get_header_tag{}).blockLength().value();
1776 }
1777
1778 template<
1779 typename Byte2,
1780 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
1781 SBEPP_CPP20_CONSTEXPR std::size_t
1782 operator()(size_bytes_tag, cursor<Byte2>& c) const noexcept
1783 {
1784 return c.pointer() - (*this)(addressof_tag{});
1785 }
1786};
1787
1789template<typename Byte, typename BlockLengthType>
1790class entry_base : public byte_range<Byte>
1791{
1792public:
1793 using byte_range<Byte>::operator();
1794
1795 template<typename Byte2, typename BlockLengthType2>
1796 friend class entry_base;
1797
1799 entry_base() = default;
1800
1802 constexpr entry_base(
1803 Byte* ptr, Byte* end, BlockLengthType block_length) noexcept
1804 : byte_range<Byte>{ptr, end}, block_length{block_length}
1805 {
1806 }
1807
1809 constexpr entry_base(
1810 Byte* ptr,
1811 const std::size_t size,
1812 const BlockLengthType block_length) noexcept
1813 : entry_base{ptr, ptr + size, block_length}
1814 {
1815 }
1816
1818 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1819 constexpr entry_base(
1820 cursor<Byte2>& c, Byte* end_ptr, BlockLengthType block_length) noexcept
1821 : entry_base{c.pointer(), end_ptr, block_length}
1822 {
1823 // forwards to the above one for non-empty entries. Empty entries have
1824 // implementation in the derived class which advances cursor up to
1825 // `block_length`.
1826 }
1827
1830 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1831 constexpr entry_base(
1832 const entry_base<Byte2, BlockLengthType>& other) noexcept
1833 : byte_range<Byte>{other}, block_length{other.block_length}
1834 {
1835 }
1836
1837 constexpr BlockLengthType operator()(get_block_length_tag) const noexcept
1838 {
1839 return block_length;
1840 }
1841
1842 constexpr Byte* operator()(get_level_tag) const noexcept
1843 {
1844 return (*this)(addressof_tag{});
1845 }
1846
1847private:
1848 BlockLengthType block_length{};
1849};
1850
1851template<typename Entry>
1852class arrow_proxy
1853{
1854public:
1855 explicit constexpr arrow_proxy(Entry entry) noexcept : entry{entry}
1856 {
1857 }
1858
1859 constexpr const Entry* operator->() const noexcept
1860 {
1861 return &entry;
1862 }
1863
1864private:
1865 Entry entry;
1866};
1867
1868template<
1869 typename Byte,
1870 typename ValueType,
1871 typename IndexType,
1872 typename DifferenceType,
1873 typename BlockLengthType>
1874class forward_iterator
1875{
1876public:
1877 using iterator_category = std::forward_iterator_tag;
1878 using value_type = ValueType;
1879 using reference = value_type;
1880 using difference_type = DifferenceType;
1881 using pointer = arrow_proxy<value_type>;
1882
1883 forward_iterator() = default;
1884
1885 SBEPP_CPP14_CONSTEXPR forward_iterator(
1886 Byte* ptr,
1887 const IndexType index,
1888 const BlockLengthType block_length,
1889 Byte* end) noexcept
1890 : ptr{ptr},
1891 index{index},
1892 block_length{block_length}
1893#if SBEPP_SIZE_CHECKS_ENABLED
1894 ,
1895 end{end}
1896#endif
1897 {
1898 (void)end;
1899 }
1900
1901 constexpr reference operator*() const noexcept
1902 {
1903#if SBEPP_SIZE_CHECKS_ENABLED
1904 return {ptr, end, block_length};
1905#else
1906 return {ptr, nullptr, block_length};
1907#endif
1908 }
1909
1910 constexpr pointer operator->() const noexcept
1911 {
1912 return pointer{operator*()};
1913 }
1914
1915 SBEPP_CPP14_CONSTEXPR forward_iterator& operator++() noexcept
1916 {
1917 SBEPP_SIZE_CHECK(ptr, end, 0, sbepp::size_bytes(operator*()));
1918 ptr += sbepp::size_bytes(operator*());
1919 index++;
1920 return *this;
1921 }
1922
1923 SBEPP_CPP14_CONSTEXPR forward_iterator operator++(int) noexcept
1924 {
1925 auto old = *this;
1926 operator++();
1927 return old;
1928 }
1929
1930 friend constexpr bool operator==(
1931 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1932 {
1933 return lhs.index == rhs.index;
1934 }
1935
1936 friend constexpr bool operator!=(
1937 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1938 {
1939 return lhs.index != rhs.index;
1940 }
1941
1942private:
1943 Byte* ptr{};
1944 IndexType index{};
1945 BlockLengthType block_length{};
1946#if SBEPP_SIZE_CHECKS_ENABLED
1947 Byte* end{};
1948#endif
1949};
1950
1951template<
1952 typename Byte,
1953 typename ValueType,
1954 typename BlockLengthType,
1955 typename DifferenceType,
1956 typename IndexType>
1957class random_access_iterator
1958{
1959public:
1960 using iterator_category = std::random_access_iterator_tag;
1961 using value_type = ValueType;
1962 using reference = value_type;
1963 using difference_type = DifferenceType;
1964 using pointer = arrow_proxy<value_type>;
1965
1966 random_access_iterator() = default;
1967
1968 SBEPP_CPP14_CONSTEXPR random_access_iterator(
1969 Byte* ptr,
1970 const BlockLengthType block_length,
1971 const IndexType index,
1972 Byte* end) noexcept
1973 : ptr{ptr},
1974 block_length{block_length},
1975 index{index}
1976#if SBEPP_SIZE_CHECKS_ENABLED
1977 ,
1978 end{end}
1979#endif
1980 {
1981 (void)end;
1982 }
1983
1984 constexpr reference operator*() const noexcept
1985 {
1986#if SBEPP_SIZE_CHECKS_ENABLED
1987 return {ptr, end, block_length};
1988#else
1989 return {ptr, nullptr, block_length};
1990#endif
1991 }
1992
1993 constexpr pointer operator->() const noexcept
1994 {
1995 return pointer{operator*()};
1996 }
1997
1998 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator++() noexcept
1999 {
2000 SBEPP_SIZE_CHECK(ptr, end, 0, block_length);
2001 ptr += block_length;
2002 index++;
2003 return *this;
2004 }
2005
2006 SBEPP_CPP14_CONSTEXPR random_access_iterator operator++(int) noexcept
2007 {
2008 auto old = *this;
2009 operator++();
2010 return old;
2011 }
2012
2013 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator--() noexcept
2014 {
2015 ptr -= block_length;
2016 index--;
2017 return *this;
2018 }
2019
2020 SBEPP_CPP14_CONSTEXPR random_access_iterator operator--(int) noexcept
2021 {
2022 auto old = *this;
2023 operator--();
2024 return old;
2025 }
2026
2027 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2028 operator+=(difference_type n) noexcept
2029 {
2030 ptr += n * block_length;
2031 index += n;
2032 return *this;
2033 }
2034
2035 SBEPP_CPP14_CONSTEXPR random_access_iterator
2036 operator+(difference_type n) const noexcept
2037 {
2038 auto tmp = *this;
2039 return tmp += n;
2040 }
2041
2042 friend constexpr random_access_iterator
2043 operator+(difference_type n, const random_access_iterator& it) noexcept
2044 {
2045 return it + n;
2046 }
2047
2048 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2049 operator-=(difference_type n) noexcept
2050 {
2051 return *this += -n;
2052 }
2053
2054 SBEPP_CPP14_CONSTEXPR random_access_iterator
2055 operator-(difference_type n) const noexcept
2056 {
2057 auto tmp = *this;
2058 return tmp -= n;
2059 }
2060
2061 constexpr difference_type
2062 operator-(const random_access_iterator& rhs) const noexcept
2063 {
2064 return index - rhs.index;
2065 }
2066
2067 constexpr reference operator[](difference_type n) const noexcept
2068 {
2069 return *(*this + n);
2070 }
2071
2072 friend constexpr bool operator==(
2073 const random_access_iterator& lhs,
2074 const random_access_iterator& rhs) noexcept
2075 {
2076 return lhs.index == rhs.index;
2077 }
2078
2079 friend constexpr bool operator!=(
2080 const random_access_iterator& lhs,
2081 const random_access_iterator& rhs) noexcept
2082 {
2083 return lhs.index != rhs.index;
2084 }
2085
2086 friend constexpr bool operator<(
2087 const random_access_iterator& lhs,
2088 const random_access_iterator& rhs) noexcept
2089 {
2090 return lhs.index < rhs.index;
2091 }
2092
2093 friend constexpr bool operator<=(
2094 const random_access_iterator& lhs,
2095 const random_access_iterator& rhs) noexcept
2096 {
2097 return lhs.index <= rhs.index;
2098 }
2099
2100 friend constexpr bool operator>(
2101 const random_access_iterator& lhs,
2102 const random_access_iterator& rhs) noexcept
2103 {
2104 return lhs.index > rhs.index;
2105 }
2106
2107 friend constexpr bool operator>=(
2108 const random_access_iterator& lhs,
2109 const random_access_iterator& rhs) noexcept
2110 {
2111 return lhs.index >= rhs.index;
2112 }
2113
2114private:
2115 Byte* ptr{};
2116 BlockLengthType block_length{};
2117 // iterator should be index-based instead of just pointer-based to support
2118 // groups with empty entries, i.e. when `block_length == 0`
2119 IndexType index{};
2120#if SBEPP_SIZE_CHECKS_ENABLED
2121 Byte* end{};
2122#endif
2123};
2124
2125template<
2126 typename ValueType,
2127 typename IndexType,
2128 typename CursorType,
2129 typename BlockLengthType,
2130 typename Byte>
2131class input_iterator
2132{
2133public:
2134 using iterator_category = std::input_iterator_tag;
2135 using value_type = ValueType;
2136 using reference = value_type;
2137 using difference_type = typename std::make_signed<IndexType>::type;
2138 using pointer = arrow_proxy<value_type>;
2139
2140 input_iterator() = default;
2141
2142 SBEPP_CPP14_CONSTEXPR input_iterator(
2143 const IndexType index,
2144 CursorType* cursor,
2145 BlockLengthType block_length,
2146 Byte* end) noexcept
2147 : index{index},
2148 cursor{cursor},
2149 block_length{block_length}
2150#if SBEPP_SIZE_CHECKS_ENABLED
2151 ,
2152 end{end}
2153#endif
2154 {
2155 (void)end;
2156 }
2157
2158 constexpr reference operator*() const noexcept
2159 {
2160#if SBEPP_SIZE_CHECKS_ENABLED
2161 return {*cursor, end, block_length};
2162#else
2163 return {*cursor, nullptr, block_length};
2164#endif
2165 }
2166
2167 constexpr pointer operator->() const noexcept
2168 {
2169 return pointer{operator*()};
2170 }
2171
2172 SBEPP_CPP14_CONSTEXPR input_iterator& operator++() noexcept
2173 {
2174 index++;
2175 return *this;
2176 }
2177
2178 SBEPP_CPP14_CONSTEXPR input_iterator operator++(int) noexcept
2179 {
2180 auto old = *this;
2181 operator++();
2182 return old;
2183 }
2184
2185 friend constexpr bool operator==(
2186 const input_iterator& lhs, const input_iterator& rhs) noexcept
2187 {
2188 return lhs.index == rhs.index;
2189 }
2190
2191 friend constexpr bool operator!=(
2192 const input_iterator& lhs, const input_iterator& rhs) noexcept
2193 {
2194 return lhs.index != rhs.index;
2195 }
2196
2197private:
2198 IndexType index{};
2199 CursorType* cursor{};
2200 BlockLengthType block_length{};
2201#if SBEPP_SIZE_CHECKS_ENABLED
2202 Byte* end{};
2203#endif
2204};
2205
2206template<
2207 typename ValueType,
2208 typename IndexType,
2209 typename CursorType,
2210 typename BlockLengthType,
2211 typename Byte>
2212class cursor_range
2213{
2214public:
2215 SBEPP_CPP14_CONSTEXPR cursor_range(
2216 CursorType& cursor,
2217 BlockLengthType block_length,
2218 Byte* end,
2219 IndexType start_pos,
2220 IndexType length) noexcept
2221 : cursor{&cursor},
2222 block_length{block_length},
2223 start_pos{start_pos},
2224#if SBEPP_SIZE_CHECKS_ENABLED
2225 end_ptr{end},
2226#endif
2227 length{length}
2228 {
2229 (void)end;
2230 }
2231
2232 using iterator =
2233 input_iterator<ValueType, IndexType, CursorType, BlockLengthType, Byte>;
2234
2235 constexpr iterator begin() const noexcept
2236 {
2237#if SBEPP_SIZE_CHECKS_ENABLED
2238 return {start_pos, cursor, block_length, end_ptr};
2239#else
2240 return {start_pos, cursor, block_length, nullptr};
2241#endif
2242 }
2243
2244 constexpr iterator end() const noexcept
2245 {
2246#if SBEPP_SIZE_CHECKS_ENABLED
2247 return {
2248 static_cast<IndexType>(start_pos + size()),
2249 cursor,
2250 block_length,
2251 end_ptr};
2252#else
2253 return {
2254 static_cast<IndexType>(start_pos + size()),
2255 cursor,
2256 block_length,
2257 nullptr};
2258#endif
2259 }
2260
2261 constexpr IndexType size() const noexcept
2262 {
2263 return length;
2264 }
2265
2266private:
2267 CursorType* cursor{};
2268 BlockLengthType block_length{};
2269 IndexType start_pos{};
2270#if SBEPP_SIZE_CHECKS_ENABLED
2271 Byte* end_ptr{};
2272#endif
2273 IndexType length{};
2274};
2275
2277template<typename Byte, typename Entry, typename Dimension>
2278class flat_group_base : public byte_range<Byte>
2279{
2280public:
2282 using value_type = Entry;
2286 using sbe_size_type = typename std::decay<
2287 decltype(std::declval<Dimension>().numInGroup())>::type;
2289 using size_type = typename sbe_size_type::value_type;
2291 using difference_type = typename std::make_signed<size_type>::type;
2294 using iterator = random_access_iterator<
2295 Byte,
2296 Entry,
2297 typename std::decay<
2298 decltype(std::declval<Dimension>().blockLength().value())>::type,
2300 size_type>;
2301
2302 using byte_range<Byte>::byte_range;
2303 using byte_range<Byte>::operator();
2304
2305 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2306 {
2307 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2308 SBEPP_SIZE_CHECK(
2309 (*this)(addressof_tag{}),
2310 (*this)(end_ptr_tag{}),
2311 0,
2312 sbepp::size_bytes(header));
2313 return header;
2314 }
2315
2316 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2317 {
2318 auto dimension = (*this)(get_header_tag{});
2319 return sbepp::size_bytes(dimension)
2320 + dimension.numInGroup().value()
2321 * dimension.blockLength().value();
2322 }
2323
2325 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2326 {
2327 return (*this)(get_header_tag{}).numInGroup();
2328 }
2329
2331 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2332 {
2333 return sbe_size().value();
2334 }
2335
2337 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2338 {
2339 (*this)(get_header_tag{}).numInGroup(count);
2340 }
2341
2343 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2344 {
2345 return !size();
2346 }
2347
2349 constexpr static size_type max_size() noexcept
2350 {
2351 return sbe_size_type::max_value();
2352 }
2353
2355 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2356 {
2357 auto dimension = (*this)(get_header_tag{});
2358 return iterator{
2359 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2360 dimension.blockLength().value(),
2361 0,
2362 (*this)(end_ptr_tag{})};
2363 }
2364
2366 constexpr iterator end() const noexcept
2367 {
2368 return iterator{
2369 (*this)(addressof_tag{}) + (*this)(size_bytes_tag{}),
2370 (*this)(get_header_tag{}).blockLength().value(),
2371 size(),
2372 (*this)(end_ptr_tag{})};
2373 }
2374
2377 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
2378 {
2379 SBEPP_ASSERT(pos < size());
2380 return *(begin() + pos);
2381 }
2382
2385 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2386 {
2387 SBEPP_ASSERT(!empty());
2388 return *begin();
2389 }
2390
2393 SBEPP_CPP14_CONSTEXPR reference back() const noexcept
2394 {
2395 SBEPP_ASSERT(!empty());
2396 return *(--end());
2397 }
2398
2401 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2402 {
2403 resize(0);
2404 }
2405
2407 template<typename Byte2>
2408 using cursor_range_t = detail::cursor_range<
2409 value_type,
2410 size_type,
2412 typename std::decay<
2413 decltype(std::declval<Dimension>().blockLength().value())>::type,
2414 Byte>;
2415
2417 template<
2418 typename Byte2,
2419 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2420 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2421 cursor_range(cursor<Byte2>& c) const noexcept
2422 {
2423 return {
2424 c,
2425 (*this)(get_header_tag{}).blockLength().value(),
2426 (*this)(end_ptr_tag{}),
2427 0,
2428 size()};
2429 }
2430
2433 template<
2434 typename Byte2,
2435 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2436 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2437 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2438 {
2439 SBEPP_ASSERT(pos < size());
2440
2441 return {
2442 c,
2443 (*this)(get_header_tag{}).blockLength().value(),
2444 (*this)(end_ptr_tag{}),
2445 pos,
2446 static_cast<size_type>(size() - pos)};
2447 }
2448
2452 template<
2453 typename Byte2,
2454 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2456 cursor<Byte2>& c,
2457 const size_type pos,
2458 const size_type count) const noexcept
2459 {
2460 SBEPP_ASSERT(pos < size());
2461 SBEPP_ASSERT(count <= (size() - pos));
2462
2463 return {
2464 c,
2465 (*this)(get_header_tag{}).blockLength().value(),
2466 (*this)(end_ptr_tag{}),
2467 pos,
2468 count};
2469 }
2470
2472 template<typename Byte2>
2473 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2474
2476 template<
2477 typename Byte2,
2478 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2479 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2480 cursor_begin(cursor<Byte2>& c) const noexcept
2481 {
2482 return cursor_range(c).begin();
2483 }
2484
2486 template<
2487 typename Byte2,
2488 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2489 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2490 cursor_end(cursor<Byte2>& c) const noexcept
2491 {
2492 return cursor_range(c).end();
2493 }
2494
2495 template<typename Visitor, typename Cursor>
2496 SBEPP_CPP14_CONSTEXPR bool
2497 operator()(visit_children_tag, Visitor& v, Cursor& c)
2498 {
2499 for(const auto entry : this->cursor_range(c))
2500 {
2501 if(v.on_entry(entry, c))
2502 {
2503 return true;
2504 }
2505 }
2506 return false;
2507 }
2508};
2509
2511template<typename Byte, typename Entry, typename Dimension>
2512class nested_group_base : public byte_range<Byte>
2513{
2514public:
2516 using value_type = Entry;
2520 using sbe_size_type = typename std::decay<
2521 decltype(std::declval<Dimension>().numInGroup())>::type;
2523 using size_type = typename sbe_size_type::value_type;
2525 using difference_type = typename std::make_signed<size_type>::type;
2526
2529 using iterator = forward_iterator<
2530 Byte,
2531 Entry,
2532 size_type,
2534 typename std::decay<
2535 decltype(std::declval<Dimension>().blockLength().value())>::type>;
2536
2537 using byte_range<Byte>::byte_range;
2538 using byte_range<Byte>::operator();
2539
2540 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2541 {
2542 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2543 SBEPP_SIZE_CHECK(
2544 (*this)(addressof_tag{}),
2545 (*this)(end_ptr_tag{}),
2546 0,
2547 sbepp::size_bytes(header));
2548 return header;
2549 }
2550
2551 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2552 {
2553 std::size_t size{sbepp::size_bytes((*this)(get_header_tag{}))};
2554 for(const auto entry : *this)
2555 {
2556 size += sbepp::size_bytes(entry);
2557 }
2558
2559 return size;
2560 }
2561
2563 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2564 {
2565 return (*this)(get_header_tag{}).numInGroup();
2566 }
2567
2569 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2570 {
2571 return sbe_size().value();
2572 }
2573
2575 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2576 {
2577 (*this)(get_header_tag{}).numInGroup(count);
2578 }
2579
2581 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2582 {
2583 return !size();
2584 }
2585
2587 constexpr static size_type max_size() noexcept
2588 {
2589 return sbe_size_type::max_value();
2590 }
2591
2593 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2594 {
2595 auto dimension = (*this)(get_header_tag{});
2596 return iterator{
2597 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2598 0,
2599 dimension.blockLength().value(),
2600 (*this)(end_ptr_tag{})};
2601 }
2602
2604 constexpr iterator end() const noexcept
2605 {
2606 return iterator{
2607 nullptr,
2608 (*this)(get_header_tag{}).numInGroup().value(),
2609 (*this)(get_header_tag{}).blockLength().value(),
2610 (*this)(end_ptr_tag{})};
2611 }
2612
2615 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2616 {
2617 SBEPP_ASSERT(!empty());
2618 return *begin();
2619 }
2620
2623 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2624 {
2625 resize(0);
2626 }
2627
2629 template<typename Byte2>
2630 using cursor_range_t = detail::cursor_range<
2631 value_type,
2632 size_type,
2634 typename std::decay<
2635 decltype(std::declval<Dimension>().blockLength().value())>::type,
2636 Byte>;
2637
2639 template<
2640 typename Byte2,
2641 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2642 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2643 cursor_range(cursor<Byte2>& c) const noexcept
2644 {
2645 return {
2646 c,
2647 (*this)(get_header_tag{}).blockLength().value(),
2648 (*this)(end_ptr_tag{}),
2649 0,
2650 size()};
2651 }
2652
2655 template<
2656 typename Byte2,
2657 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2658 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2659 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2660 {
2661 SBEPP_ASSERT(pos < size());
2662
2663 return {
2664 c,
2665 (*this)(get_header_tag{}).blockLength().value(),
2666 (*this)(end_ptr_tag{}),
2667 pos,
2668 static_cast<size_type>(size() - pos)};
2669 }
2670
2674 template<
2675 typename Byte2,
2676 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2678 cursor<Byte2>& c,
2679 const size_type pos,
2680 const size_type count) const noexcept
2681 {
2682 SBEPP_ASSERT(pos < size());
2683 SBEPP_ASSERT(count <= (size() - pos));
2684
2685 return {
2686 c,
2687 (*this)(get_header_tag{}).blockLength().value(),
2688 (*this)(end_ptr_tag{}),
2689 pos,
2690 count};
2691 }
2692
2694 template<typename Byte2>
2695 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2696
2698 template<
2699 typename Byte2,
2700 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2701 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2702 cursor_begin(cursor<Byte2>& c) const noexcept
2703 {
2704 return cursor_range(c).begin();
2705 }
2706
2708 template<
2709 typename Byte2,
2710 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2711 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2712 cursor_end(cursor<Byte2>& c) const noexcept
2713 {
2714 return cursor_range(c).end();
2715 }
2716
2717 template<typename Visitor, typename Cursor>
2718 SBEPP_CPP14_CONSTEXPR bool
2719 operator()(visit_children_tag, Visitor& v, Cursor& c)
2720 {
2721 for(const auto entry : this->cursor_range(c))
2722 {
2723 if(v.on_entry(entry, c))
2724 {
2725 return true;
2726 }
2727 }
2728 return false;
2729 }
2730};
2731
2734template<typename T>
2736{
2737public:
2739 bitset_base() = default;
2740
2742 explicit constexpr bitset_base(T value) noexcept : bits{value}
2743 {
2744 }
2745
2747 SBEPP_CPP14_CONSTEXPR T& operator*() noexcept
2748 {
2749 return bits;
2750 }
2751
2753 constexpr T operator*() const noexcept
2754 {
2755 return bits;
2756 }
2757
2758 constexpr bool
2759 operator()(get_bit_tag, const choice_index_t n) const noexcept
2760 {
2761 return bits & (1 << n);
2762 }
2763
2764 SBEPP_CPP14_CONSTEXPR void
2765 operator()(set_bit_tag, const choice_index_t n, const bool b) noexcept
2766 {
2767 bits = ((bits & ~(1 << n)) | (b << n));
2768 }
2769
2771 constexpr friend bool
2772 operator==(const bitset_base& lhs, const bitset_base& rhs) noexcept
2773 {
2774 return *lhs == *rhs;
2775 }
2776
2778 constexpr friend bool
2779 operator!=(const bitset_base& lhs, const bitset_base& rhs) noexcept
2780 {
2781 return *lhs != *rhs;
2782 }
2783
2784private:
2785 T bits{};
2786};
2787
2788template<typename View, typename = void_t<>>
2789struct has_get_header : std::false_type
2790{
2791};
2792
2793template<typename View>
2794struct has_get_header<
2795 View,
2796 void_t<decltype(sbepp::get_header(std::declval<View>()))>> : std::true_type
2797{
2798};
2799
2800template<
2801 typename View,
2802 typename = detail::enable_if_t<detail::has_get_header<View>::value>>
2803constexpr std::size_t get_header_size(View view) noexcept
2804{
2806}
2807
2808template<
2809 typename View,
2810 typename = detail::enable_if_t<!detail::has_get_header<View>::value>,
2811 typename = int>
2812constexpr std::size_t get_header_size(View) noexcept
2813{
2814 return 0;
2815}
2816} // namespace detail
2817
2825template<typename Enum>
2826constexpr typename std::underlying_type<Enum>::type
2827 to_underlying(Enum e) noexcept
2828{
2829 return static_cast<typename std::underlying_type<Enum>::type>(e);
2830}
2831
2845template<typename View>
2846SBEPP_CPP14_CONSTEXPR cursor<byte_type_t<View>> init_cursor(View view) noexcept
2847{
2849 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2850 return c;
2851}
2852
2867template<typename View>
2868SBEPP_CPP14_CONSTEXPR cursor<typename std::add_const<byte_type_t<View>>::type>
2869 init_const_cursor(View view) noexcept
2870{
2872 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2873 return c;
2874}
2875
2881{
2882 explicit default_init_t() = default;
2883};
2884
2890SBEPP_CPP17_INLINE_VAR constexpr default_init_t default_init{};
2891
2894enum class eos_null
2895{
2898 none,
2902 single,
2904 all
2905};
2906
2907namespace detail
2908{
2909template<typename From, typename To>
2910struct copy_cv_qualifiers
2911{
2912 using copy_const_t = typename std::
2913 conditional<std::is_const<From>::value, const To, To>::type;
2914
2915 using type = typename std::conditional<
2916 std::is_volatile<From>::value,
2917 volatile copy_const_t,
2918 copy_const_t>::type;
2919};
2920
2921template<typename From, typename To>
2922using apply_cv_qualifiers_t = typename copy_cv_qualifiers<From, To>::type;
2923
2924#if SBEPP_HAS_RANGES
2925template<typename R>
2926using is_range = std::bool_constant<std::ranges::range<R>>;
2927#else
2928template<typename R, typename = void_t<>>
2929struct is_range : std::false_type
2930{
2931};
2932
2933template<typename R>
2934struct is_range<
2935 R,
2936 void_t<
2937 decltype(std::begin(std::declval<R>())),
2938 decltype(std::end(std::declval<R>()))>> : std::true_type
2939{
2940};
2941#endif
2942
2943constexpr bool is_constant_evaluated() noexcept
2944{
2945 // it's possible to use `__builtin_is_constant_evaluated` with lower C++
2946 // versions but I see no reason for this since it's only used for
2947 // `assign_string` and other accessors are not be `constexpr` until C++20
2948#if SBEPP_HAS_IS_CONSTANT_EVALUATED
2949 return std::is_constant_evaluated();
2950#else
2951 return false;
2952#endif
2953}
2954
2955inline SBEPP_CPP20_CONSTEXPR std::size_t string_length(const char* str) noexcept
2956{
2957 if(is_constant_evaluated())
2958 {
2959 std::size_t length{};
2960 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2961 for(; *str != '\0'; str++, length++)
2962 {
2963 }
2964
2965 return length;
2966 }
2967 else
2968 {
2969 return std::strlen(str);
2970 }
2971}
2972
2980template<typename Byte, typename Value, std::size_t N, typename Tag>
2982{
2983public:
2986 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
2988 using value_type = Value;
2990 using size_type = std::size_t;
2992 using difference_type = std::ptrdiff_t;
3000 using reverse_iterator = std::reverse_iterator<iterator>;
3002 using tag = Tag;
3003
3004 using detail::byte_range<Byte>::byte_range;
3005 using detail::byte_range<Byte>::operator();
3006
3007 constexpr std::size_t operator()(detail::size_bytes_tag) const noexcept
3008 {
3009 return size();
3010 }
3011
3014 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3015 {
3016 SBEPP_ASSERT(pos < size());
3017 return data()[pos];
3018 }
3019
3021 constexpr reference front() const noexcept
3022 {
3023 return *data();
3024 }
3025
3027 constexpr reference back() const noexcept
3028 {
3029 return data()[size() - 1];
3030 }
3031
3033 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3034 {
3035 // it would be nice to use `reinterpret_cast` here but it's not allowed
3036 // in constexpr context
3037 SBEPP_SIZE_CHECK(
3038 (*this)(detail::addressof_tag{}),
3039 (*this)(detail::end_ptr_tag{}),
3040 0,
3041 N);
3042 return (pointer)(*this)(detail::addressof_tag{}); // NOLINT
3043 }
3044
3046 SBEPP_CPP17_NODISCARD static constexpr bool empty() noexcept
3047 {
3048 return !size();
3049 }
3050
3052 static constexpr size_type size() noexcept
3053 {
3054 return N;
3055 }
3056
3058 static constexpr size_type max_size() noexcept
3059 {
3060 return size();
3061 }
3062
3064 constexpr iterator begin() const noexcept
3065 {
3066 return data();
3067 }
3068
3070 constexpr iterator end() const noexcept
3071 {
3072 return data() + size();
3073 }
3074
3076 constexpr reverse_iterator rbegin() const noexcept
3077 {
3078 return reverse_iterator{end()};
3079 }
3080
3082 constexpr reverse_iterator rend() const noexcept
3083 {
3084 return reverse_iterator{begin()};
3085 }
3086
3099 raw() const noexcept
3100 {
3102 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3103 }
3104
3111 SBEPP_CPP20_CONSTEXPR std::size_t strlen() const noexcept
3112 {
3113 if(is_constant_evaluated())
3114 {
3115 return string_length(data());
3116 }
3117 else
3118 {
3119 const auto first_null = static_cast<const value_type*>(
3120 std::memchr(data(), '\0', size()));
3121 if(first_null)
3122 {
3123 return first_null - data();
3124 }
3125
3126 return size();
3127 }
3128 }
3129
3136 SBEPP_CPP20_CONSTEXPR std::size_t strlen_r() const noexcept
3137 {
3138 const auto last_non_null = std::find_if(
3139 rbegin(),
3140 rend(),
3141 [](const value_type value)
3142 {
3143 return value != '\0';
3144 });
3145 return size() - (last_non_null - rbegin());
3146 }
3147
3159 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3160 SBEPP_CPP20_CONSTEXPR iterator assign_string(
3161 const char* str, const eos_null eos_mode = eos_null::all) const noexcept
3162 {
3163 SBEPP_ASSERT(str != nullptr);
3164 const auto length = string_length(str);
3165 SBEPP_ASSERT(length <= size());
3166 const auto eos_pos = std::copy_n(str, length, begin());
3167 pad(eos_mode, eos_pos);
3168 return eos_pos;
3169 }
3170
3183 template<
3184 typename R,
3185 typename =
3186 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3187 SBEPP_CPP20_CONSTEXPR iterator
3188 assign_string(R&& r, const eos_null eos_mode = eos_null::all) const
3189 {
3190 auto eos_pos = assign_range(std::forward<R>(r));
3191 pad(eos_mode, eos_pos);
3192 return eos_pos;
3193 }
3194
3204 template<
3205 typename R,
3206 typename =
3207 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3208 SBEPP_CPP20_CONSTEXPR iterator assign_range(R&& r) const
3209 {
3210#if SBEPP_HAS_RANGES
3211 auto res = std::ranges::copy(std::forward<R>(r), begin()).out;
3212#else
3213 auto res = std::copy(std::begin(r), std::end(r), begin());
3214#endif
3215 SBEPP_ASSERT(res <= end());
3216 return res;
3217 }
3218
3224 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3225 SBEPP_CPP20_CONSTEXPR void fill(const value_type value) const noexcept
3226 {
3227 std::fill_n(begin(), size(), value);
3228 }
3229
3238 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3239 SBEPP_CPP20_CONSTEXPR iterator
3240 assign(size_type count, const value_type value) const noexcept
3241 {
3242 SBEPP_ASSERT(count <= size());
3243 return std::fill_n(begin(), count, value);
3244 }
3245
3249 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3250 SBEPP_CPP20_CONSTEXPR iterator assign(InputIt first, InputIt last) const
3251 {
3252 const auto last_out = std::copy(first, last, begin());
3253 SBEPP_ASSERT(static_cast<size_type>(last_out - begin()) <= size());
3254 return last_out;
3255 }
3256
3264 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3265 SBEPP_CPP20_CONSTEXPR iterator
3266 assign(std::initializer_list<value_type> ilist) const noexcept
3267 {
3268 SBEPP_ASSERT(ilist.size() <= size());
3269 return assign(std::begin(ilist), std::end(ilist));
3270 }
3271
3272private:
3273 SBEPP_CPP20_CONSTEXPR void
3274 pad(const eos_null mode, iterator eos_pos) const noexcept
3275 {
3276 if(mode == eos_null::all)
3277 {
3278 std::fill(eos_pos, end(), '\0');
3279 }
3280 else if(mode == eos_null::single)
3281 {
3282 if(eos_pos != end())
3283 {
3284 *eos_pos = '\0';
3285 }
3286 }
3287 else
3288 {
3289 SBEPP_ASSERT(mode == eos_null::none);
3290 return;
3291 }
3292 }
3293};
3294
3302template<typename Byte, typename Value, typename Length, endian E>
3304{
3305public:
3306 static_assert(
3307 std::is_unsigned<typename Length::value_type>::value,
3308 "Length must be unsigned");
3309
3312 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
3314 using value_type = Value;
3316 using sbe_size_type = Length;
3318 using size_type = typename sbe_size_type::value_type;
3320 using difference_type = std::ptrdiff_t;
3328 using reverse_iterator = std::reverse_iterator<iterator>;
3329
3330 using detail::byte_range<Byte>::byte_range;
3331 using detail::byte_range<Byte>::operator();
3332
3334 constexpr iterator begin() const noexcept
3335 {
3336 return data_checked();
3337 }
3338
3340 SBEPP_CPP20_CONSTEXPR iterator end() const noexcept
3341 {
3342 return begin() + size();
3343 }
3344
3346 SBEPP_CPP20_CONSTEXPR reverse_iterator rbegin() const noexcept
3347 {
3348 return reverse_iterator{end()};
3349 }
3350
3352 constexpr reverse_iterator rend() const noexcept
3353 {
3354 return reverse_iterator{begin()};
3355 }
3356
3359 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
3360 {
3361 SBEPP_ASSERT(!empty());
3362 return *data();
3363 }
3364
3367 SBEPP_CPP20_CONSTEXPR reference back() const noexcept
3368 {
3369 SBEPP_ASSERT(!empty());
3370 return *(data() + size() - 1);
3371 }
3372
3380 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3381 {
3382 return data_checked();
3383 }
3384
3387 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3388 {
3389 SBEPP_ASSERT(pos < size());
3390 return *(data() + pos);
3391 }
3392
3394 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
3395 {
3396 return detail::get_value<size_type, size_type, E>(*this, 0);
3397 }
3398
3400 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
3401 {
3402 return sbe_size().value();
3403 }
3404
3406 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
3407 {
3408 return !size();
3409 }
3410
3412 constexpr static size_type max_size() noexcept
3413 {
3414 return sbe_size_type::max_value();
3415 }
3416
3418 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3419 SBEPP_CPP20_CONSTEXPR void clear() const noexcept
3420 {
3421 resize(0, default_init);
3422 }
3423
3425 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3426 SBEPP_CPP20_CONSTEXPR void resize(size_type count) const noexcept
3427 {
3428 const auto old_size = size();
3429 resize(count, default_init);
3430 if(count > old_size)
3431 {
3432 for(auto i = old_size; i != count; i++)
3433 {
3434 operator[](i) = {};
3435 }
3436 }
3437 }
3438
3440 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3441 SBEPP_CPP20_CONSTEXPR void
3442 resize(size_type count, value_type value) const noexcept
3443 {
3444 const auto old_size = size();
3445 resize(count, default_init);
3446 if(count > old_size)
3447 {
3448 for(auto i = old_size; i != count; i++)
3449 {
3450 operator[](i) = value;
3451 }
3452 }
3453 }
3454
3456 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3457 SBEPP_CPP20_CONSTEXPR void
3459 {
3460 // can't use `detail::set_value()` here because its size check checks
3461 // only `sizeof(T)`, here we need `sizeof(size_type) + count`
3462 SBEPP_SIZE_CHECK(
3463 (*this)(addressof_tag{}),
3464 (*this)(end_ptr_tag{}),
3465 0,
3466 sizeof(size_type) + count);
3467 set_primitive<E>((*this)(addressof_tag{}), count);
3468 }
3469
3471 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3472 SBEPP_CPP20_CONSTEXPR void push_back(value_type value) const noexcept
3473 {
3474 const auto current_size = size();
3475 resize(current_size + 1, default_init);
3476 (*this)[current_size] = value;
3477 }
3478
3480 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3481 SBEPP_CPP20_CONSTEXPR void pop_back() const noexcept
3482 {
3483 SBEPP_ASSERT(!empty());
3484 resize(size() - 1, default_init);
3485 }
3486
3488 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3489 SBEPP_CPP20_CONSTEXPR iterator erase(iterator pos) const noexcept
3490 {
3491 SBEPP_ASSERT(pos >= begin() && pos < end());
3492 std::copy(pos + 1, end(), pos);
3493 resize(size() - 1, default_init);
3494 return pos;
3495 }
3496
3498 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3499 SBEPP_CPP20_CONSTEXPR iterator
3500 erase(iterator first, iterator last) const noexcept
3501 {
3502 SBEPP_ASSERT(first >= begin() && last < end());
3503 std::copy(last, end(), first);
3504 resize(size() - (last - first), default_init);
3505 return first;
3506 }
3507
3509 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3510 SBEPP_CPP20_CONSTEXPR iterator
3511 insert(iterator pos, const value_type value) const noexcept
3512 {
3513 SBEPP_ASSERT(pos >= begin() && pos <= end());
3514 const auto old_end = end();
3515 resize(size() + 1, default_init);
3516 std::copy_backward(pos, old_end, end());
3517 *pos = value;
3518 return pos;
3519 }
3520
3522 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3523 SBEPP_CPP20_CONSTEXPR iterator insert(
3524 iterator pos, size_type count, const value_type value) const noexcept
3525 {
3526 SBEPP_ASSERT(pos >= begin() && pos <= end());
3527 const auto old_end = end();
3528 resize(size() + count, default_init);
3529 std::copy_backward(pos, old_end, end());
3530 std::fill_n(pos, count, value);
3531 return pos;
3532 }
3533
3535 template<
3536 typename InputIt,
3537 typename = detail::enable_if_t<
3538 !std::is_const<Byte>::value
3539 && std::is_convertible<
3540 typename std::iterator_traits<InputIt>::iterator_category,
3541 std::input_iterator_tag>::value>>
3542 SBEPP_CPP14_CONSTEXPR iterator
3543 insert(iterator pos, InputIt first, InputIt last) const
3544 {
3545 SBEPP_ASSERT(pos >= begin() && pos <= end());
3546 using category_t =
3547 typename std::iterator_traits<InputIt>::iterator_category;
3548 return insert_impl(pos, first, last, category_t{});
3549 }
3550
3552 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3553 constexpr iterator insert(
3554 iterator pos, std::initializer_list<value_type> ilist) const noexcept
3555 {
3556 return insert(pos, std::begin(ilist), std::end(ilist));
3557 }
3558
3561 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3562 SBEPP_CPP20_CONSTEXPR void
3563 assign(size_type count, const value_type value) const noexcept
3564 {
3565 resize(count, default_init);
3566 std::fill_n(begin(), count, value);
3567 }
3568
3571 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3572 SBEPP_CPP20_CONSTEXPR void assign(InputIt first, InputIt last) const
3573 {
3574 auto begin = data_unchecked();
3575 const auto new_end = std::copy(first, last, begin);
3576 resize(new_end - begin, default_init);
3577 }
3578
3581 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3582 SBEPP_CPP20_CONSTEXPR void
3583 assign(std::initializer_list<value_type> ilist) const noexcept
3584 {
3585 SBEPP_SIZE_CHECK(
3586 (*this)(detail::addressof_tag{}),
3587 (*this)(detail::end_ptr_tag{}),
3588 0,
3589 sizeof(size_type) + ilist.size());
3590 assign(std::begin(ilist), std::end(ilist));
3591 }
3592
3600 raw() const noexcept
3601 {
3603 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3604 }
3605
3606 SBEPP_CPP20_CONSTEXPR std::size_t
3607 operator()(detail::size_bytes_tag) const noexcept
3608 {
3609 return sizeof(size_type) + size();
3610 }
3611
3618 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3619 SBEPP_CPP20_CONSTEXPR void assign_string(const char* str) const noexcept
3620 {
3621 SBEPP_ASSERT(str != nullptr);
3622 const auto length = string_length(str);
3623 resize(length, default_init);
3624 std::copy_n(str, length, begin());
3625 }
3626
3634 template<
3635 typename R,
3636 typename =
3637 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3638 SBEPP_CPP20_CONSTEXPR void assign_range(R&& r) const
3639 {
3640 const auto begin = data_unchecked();
3641#if SBEPP_HAS_RANGES
3642 const auto new_end = std::ranges::copy(std::forward<R>(r), begin).out;
3643#else
3644 const auto new_end = std::copy(std::begin(r), std::end(r), begin);
3645#endif
3646 resize(new_end - begin, default_init);
3647 }
3648
3649private:
3650 SBEPP_CPP14_CONSTEXPR pointer data_checked() const noexcept
3651 {
3652 SBEPP_SIZE_CHECK(
3653 (*this)(detail::addressof_tag{}),
3654 (*this)(detail::end_ptr_tag{}),
3655 0,
3656 sizeof(size_type) + size());
3657 return data_unchecked();
3658 }
3659
3660 SBEPP_CPP14_CONSTEXPR pointer data_unchecked() const noexcept
3661 {
3662 SBEPP_SIZE_CHECK(
3663 (*this)(detail::addressof_tag{}),
3664 (*this)(detail::end_ptr_tag{}),
3665 0,
3666 sizeof(size_type));
3667 // cast is conditionally required here when `Byte` is different type
3668 // from `Value`. `reinterpret_cast` is not allowed in constexpr context
3669 // even when it's an identity cast. On the other hand, C-style cast
3670 // is allowed in constexpr context when it renders to an identity cast
3671 // which effectively makes this and other functions conditionally
3672 // `constexpr` when `Byte` is equal to `Value`.
3673 // NOLINTNEXTLINE: see above
3674 return (pointer)((*this)(detail::addressof_tag{}) + sizeof(size_type));
3675 }
3676
3677 template<typename It>
3678 SBEPP_CPP14_CONSTEXPR iterator insert_impl(
3679 iterator pos, It first, It last, std::input_iterator_tag) const
3680 {
3681 auto out = pos;
3682 for(; first != last; ++first, ++out)
3683 {
3684 insert(out, *first);
3685 }
3686
3687 return pos;
3688 }
3689
3690 template<typename It>
3691 SBEPP_CPP20_CONSTEXPR iterator insert_impl(
3692 iterator pos, It first, It last, std::forward_iterator_tag) const
3693 {
3694 const auto in_size = std::distance(first, last);
3695 auto old_end = end();
3696 resize(size() + in_size, default_init);
3697 std::copy_backward(pos, old_end, end());
3698 std::copy(first, last, pos);
3699 return pos;
3700 }
3701};
3702} // namespace detail
3703
3706{
3707 explicit constexpr nullopt_t(int)
3708 {
3709 }
3710};
3711
3717SBEPP_CPP17_INLINE_VAR constexpr nullopt_t nullopt{0};
3718
3719namespace detail
3720{
3721// see `optional_base` note about explicit `alignas`
3725template<typename T, typename Derived>
3726class alignas(T) required_base
3727{
3728public:
3730 using value_type = T;
3731
3733 required_base() = default;
3734
3736 // NOLINTNEXTLINE: it should be implicit
3737 constexpr required_base(value_type val) noexcept : val{val}
3738 {
3739 }
3740
3742 constexpr value_type value() const noexcept
3743 {
3744 return **this;
3745 }
3746
3748 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3749 {
3750 return val;
3751 }
3752
3754 constexpr value_type operator*() const noexcept
3755 {
3756 return val;
3757 }
3758
3761 constexpr bool in_range() const noexcept
3762 {
3763 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3764 }
3765
3769#ifdef SBEPP_DOXYGEN
3771 friend auto
3772 operator<=>(const required_base&, const required_base&) = default;
3773#endif
3774
3775#if SBEPP_HAS_THREE_WAY_COMPARISON
3776 friend auto
3777 operator<=>(const required_base&, const required_base&) = default;
3778#else
3780 constexpr friend bool
3781 operator==(const required_base& lhs, const required_base& rhs) noexcept
3782 {
3783 return *lhs == *rhs;
3784 }
3785
3787 constexpr friend bool
3788 operator!=(const required_base& lhs, const required_base& rhs) noexcept
3789 {
3790 return *lhs != *rhs;
3791 }
3792
3794 constexpr friend bool
3795 operator<(const required_base& lhs, const required_base& rhs) noexcept
3796 {
3797 return *lhs < *rhs;
3798 }
3799
3801 constexpr friend bool
3802 operator<=(const required_base& lhs, const required_base& rhs) noexcept
3803 {
3804 return *lhs <= *rhs;
3805 }
3806
3808 constexpr friend bool
3809 operator>(const required_base& lhs, const required_base& rhs) noexcept
3810 {
3811 return *lhs > *rhs;
3812 }
3813
3815 constexpr friend bool
3816 operator>=(const required_base& lhs, const required_base& rhs) noexcept
3817 {
3818 return *lhs >= *rhs;
3819 }
3820#endif
3822
3823private:
3824 value_type val{};
3825};
3826
3827// old compilers might generate wrong alignment for classes which contain
3828// `double` member. To overcome this, explicit alignment is provided.
3832template<typename T, typename Derived>
3833class alignas(T) optional_base
3834{
3835public:
3837 using value_type = T;
3838
3840 optional_base() = default;
3841
3843 // NOLINTNEXTLINE: it's intentionally implicit
3844 constexpr optional_base(nullopt_t) noexcept : optional_base{}
3845 {
3846 }
3847
3849 // NOLINTNEXTLINE: it's intentionally implicit
3850 constexpr optional_base(value_type val) noexcept : val{val}
3851 {
3852 }
3853
3855 constexpr value_type value() const noexcept
3856 {
3857 return **this;
3858 }
3859
3861 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3862 {
3863 return val;
3864 }
3865
3867 constexpr value_type operator*() const noexcept
3868 {
3869 return val;
3870 }
3871
3874 constexpr bool in_range() const noexcept
3875 {
3876 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3877 }
3878
3880 SBEPP_CPP14_CONSTEXPR value_type value_or(T default_value) const noexcept
3881 {
3882 if(*this)
3883 {
3884 return value();
3885 }
3886 return default_value;
3887 }
3888
3890 constexpr bool has_value() const noexcept
3891 {
3892 return (val != Derived::null_value());
3893 }
3894
3896 constexpr explicit operator bool() const noexcept
3897 {
3898 return has_value();
3899 }
3900
3907
3909 constexpr friend bool
3910 operator==(const optional_base& lhs, const optional_base& rhs) noexcept
3911 {
3912 return *lhs == *rhs;
3913 }
3914
3915#ifdef SBEPP_DOXYGEN
3917 constexpr friend std::strong_ordering operator<=>(
3918 const optional_base& lhs, const optional_base& rhs) noexcept;
3919#endif
3920
3921#if SBEPP_HAS_THREE_WAY_COMPARISON
3922 constexpr friend std::strong_ordering
3923 operator<=>(const optional_base& lhs, const optional_base& rhs) noexcept
3924 {
3925 if(lhs && rhs)
3926 {
3927 return *lhs <=> *rhs;
3928 }
3929 return lhs.has_value() <=> rhs.has_value();
3930 }
3931#else
3932
3934 constexpr friend bool
3935 operator!=(const optional_base& lhs, const optional_base& rhs) noexcept
3936 {
3937 return *lhs != *rhs;
3938 }
3939
3941 constexpr friend bool
3942 operator<(const optional_base& lhs, const optional_base& rhs) noexcept
3943 {
3944 return rhs && (!lhs || (*lhs < *rhs));
3945 }
3946
3948 constexpr friend bool
3949 operator<=(const optional_base& lhs, const optional_base& rhs) noexcept
3950 {
3951 return !lhs || (rhs && (*lhs <= *rhs));
3952 }
3953
3955 constexpr friend bool
3956 operator>(const optional_base& lhs, const optional_base& rhs) noexcept
3957 {
3958 return lhs && (!rhs || (*lhs > *rhs));
3959 }
3960
3962 constexpr friend bool
3963 operator>=(const optional_base& lhs, const optional_base& rhs) noexcept
3964 {
3965 return !rhs || (lhs && (*lhs >= *rhs));
3966 }
3967#endif
3969
3970private:
3971 value_type val{Derived::null_value()};
3972};
3973} // namespace detail
3974
3989template<typename Message>
3990constexpr auto fill_message_header(Message m) noexcept
3991 -> decltype(m(detail::fill_message_header_tag{}))
3992{
3993 return m(detail::fill_message_header_tag{});
3994}
3995
4009template<typename Group, typename Size>
4010constexpr auto fill_group_header(Group g, Size num_in_group) noexcept
4011 -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
4012{
4013 return g(detail::fill_group_header_tag{}, num_in_group);
4014}
4015
4029template<typename T>
4030class type_traits;
4031
4032#ifdef SBEPP_DOXYGEN
4033template<typename T>
4035{
4036public:
4038 using primitive_type = PrimitiveType;
4039
4041 using value_type = ValueType;
4042
4048 template<typename Byte>
4049 using value_type = ArrayType<Byte>;
4050
4052 static constexpr const char* name() noexcept;
4053
4055 static constexpr const char* description() noexcept;
4056
4058 static constexpr field_presence presence() noexcept;
4059
4064 static constexpr primitive_type min_value() noexcept;
4065
4070 static constexpr primitive_type max_value() noexcept;
4071
4076 static constexpr primitive_type null_value() noexcept;
4077
4079 static constexpr length_t length() noexcept;
4080
4085 static constexpr offset_t offset() noexcept;
4086
4088 static constexpr const char* semantic_type() noexcept;
4089
4091 static constexpr version_t since_version() noexcept;
4092
4095 static constexpr version_t deprecated() noexcept;
4096
4098 static constexpr const char* character_encoding() noexcept;
4099};
4100#endif
4101
4110template<typename T>
4111class schema_traits;
4112
4113#ifdef SBEPP_DOXYGEN
4114template<typename T>
4116{
4117public:
4119 static constexpr const char* package() noexcept;
4121 static constexpr schema_id_t id() noexcept;
4123 static constexpr version_t version() noexcept;
4125 static constexpr const char* semantic_version() noexcept;
4127 static constexpr endian byte_order() noexcept;
4129 static constexpr const char* description() noexcept;
4135 template<typename Byte>
4136 using header_type = HeaderComposite<Byte>;
4138 using header_type_tag = HeaderTypeTag;
4139};
4140#endif
4141
4150template<typename T>
4151class enum_traits;
4152
4153#ifdef SBEPP_DOXYGEN
4154template<typename T>
4156{
4157public:
4159 static constexpr const char* name() noexcept;
4161 static constexpr const char* description() noexcept;
4163 using encoding_type = EncodingType;
4168 static constexpr offset_t offset() noexcept;
4170 static constexpr version_t since_version() noexcept;
4173 static constexpr version_t deprecated() noexcept;
4175 using value_type = ScopedEnumType;
4176};
4177#endif
4178
4187template<typename T>
4188class enum_value_traits;
4189
4190#ifdef SBEPP_DOXYGEN
4191template<typename T>
4193{
4194public:
4196 static constexpr const char* name() noexcept;
4198 static constexpr const char* description() noexcept;
4200 static constexpr version_t since_version() noexcept;
4203 static constexpr version_t deprecated() noexcept;
4205 static constexpr ScopedEnumType value() noexcept;
4206};
4207#endif
4208
4217template<typename T>
4218class set_traits;
4219
4220#ifdef SBEPP_DOXYGEN
4221template<typename T>
4223{
4224public:
4226 static constexpr const char* name() noexcept;
4228 static constexpr const char* description() noexcept;
4230 static constexpr version_t since_version() noexcept;
4233 static constexpr version_t deprecated() noexcept;
4235 using encoding_type = EncodingType;
4240 static constexpr offset_t offset() noexcept;
4242 using value_type = SetType;
4243};
4244#endif
4245
4254template<typename T>
4255class set_choice_traits;
4256
4257#ifdef SBEPP_DOXYGEN
4258template<typename T>
4260{
4261public:
4263 static constexpr const char* name() noexcept;
4265 static constexpr const char* description() noexcept;
4267 static constexpr version_t since_version() noexcept;
4270 static constexpr version_t deprecated() noexcept;
4272 static constexpr choice_index_t index() noexcept;
4273};
4274#endif
4275
4284template<typename T>
4285class composite_traits;
4286
4287#ifdef SBEPP_DOXYGEN
4288template<typename T>
4290{
4291public:
4293 static constexpr const char* name() noexcept;
4295 static constexpr const char* description() noexcept;
4300 static constexpr offset_t offset() noexcept;
4302 static constexpr const char* semantic_type() noexcept;
4304 static constexpr version_t since_version() noexcept;
4306 // !schema
4307 static constexpr version_t deprecated() noexcept;
4313 template<typename Byte>
4314 using value_type = CompositeType<Byte>;
4316 static constexpr std::size_t size_bytes() noexcept;
4317};
4318#endif
4319
4328template<typename T>
4329class message_traits;
4330
4331#ifdef SBEPP_DOXYGEN
4332template<typename T>
4334{
4335public:
4337 static constexpr const char* name() noexcept;
4339 static constexpr const char* description() noexcept;
4341 static constexpr message_id_t id() noexcept;
4343 static constexpr block_length_t block_length() noexcept;
4345 static constexpr const char* semantic_type() noexcept;
4347 static constexpr version_t since_version() noexcept;
4350 static constexpr version_t deprecated() noexcept;
4356 template<typename Byte>
4357 using value_type = MessageType<Byte>;
4359 using schema_tag = SchemaTag;
4360
4438 static constexpr std::size_t size_bytes(...) noexcept;
4439};
4440#endif
4441
4450template<typename T>
4451class field_traits;
4452
4453#ifdef SBEPP_DOXYGEN
4454template<typename T>
4456{
4457public:
4459 static constexpr const char* name() noexcept;
4461 static constexpr member_id_t id() noexcept;
4463 static constexpr const char* description() noexcept;
4469 static constexpr field_presence presence() noexcept;
4471 static constexpr offset_t offset() noexcept;
4473 static constexpr version_t since_version() noexcept;
4476 static constexpr version_t deprecated() noexcept;
4478 using value_type = ValueType;
4484 template<typename Byte>
4485 using value_type = Type<Byte>;
4487 using value_type_tag = TypeTag;
4488};
4489#endif
4490
4499template<typename T>
4500class group_traits;
4501
4502#ifdef SBEPP_DOXYGEN
4503template<typename T>
4505{
4506public:
4508 static constexpr const char* name() noexcept;
4510 static constexpr const char* description() noexcept;
4512 static constexpr member_id_t id() noexcept;
4514 static constexpr block_length_t block_length() noexcept;
4516 static constexpr const char* semantic_type() noexcept;
4518 static constexpr version_t since_version() noexcept;
4521 static constexpr version_t deprecated() noexcept;
4527 template<typename Byte>
4528 using value_type = GroupType<Byte>;
4534 template<typename Byte>
4535 using dimension_type = HeaderType<Byte>;
4537 using dimension_type_tag = HeaderTag;
4543 template<typename Byte>
4544 using entry_type = EntryType<Byte>;
4556 static constexpr std::size_t
4557 size_bytes(const NumInGroupType num_in_group, ...) noexcept;
4558};
4559#endif
4560
4569template<typename T>
4570class data_traits;
4571
4572#ifdef SBEPP_DOXYGEN
4573template<typename T>
4575{
4576public:
4578 static constexpr const char* name() noexcept;
4580 static constexpr member_id_t id() noexcept;
4582 static constexpr const char* description() noexcept;
4584 static constexpr version_t since_version() noexcept;
4587 static constexpr version_t deprecated() noexcept;
4593 template<typename Byte>
4594 using value_type = DataType;
4596 using length_type = LengthType;
4598 using length_type_tag = LengthTypeTag;
4605 static constexpr std::size_t
4606 size_bytes(const length_type::value_type size) noexcept;
4607};
4608#endif
4633template<typename ValueType>
4634struct traits_tag;
4635
4636#ifdef SBEPP_DOXYGEN
4637template<typename ValueType>
4639{
4641 using type = Tag;
4642};
4643#endif
4644
4646template<typename ValueType>
4648
4649template<typename Byte, typename Value, std::size_t N, typename Tag>
4650struct traits_tag<detail::static_array_ref<Byte, Value, N, Tag>>
4651{
4652 using type = Tag;
4653};
4654
4655// NOLINTNEXTLINE: macro is required here
4656#define SBEPP_BUILT_IN_IMPL(NAME, TYPE, MIN, MAX, NULL) \
4657 \
4658 \
4659 class NAME##_t : public detail::required_base<TYPE, NAME##_t> \
4660 { \
4661 public: \
4662 using detail::required_base<TYPE, NAME##_t>::required_base; \
4663 \
4664 \
4665 static constexpr value_type min_value() noexcept \
4666 { \
4667 return {MIN}; \
4668 } \
4669 \
4670 \
4671 static constexpr value_type max_value() noexcept \
4672 { \
4673 return {MAX}; \
4674 } \
4675 }; \
4676 \
4677
4678 \
4679 class NAME##_opt_t : public detail::optional_base<TYPE, NAME##_opt_t> \
4680 { \
4681 public: \
4682 using detail::optional_base<TYPE, NAME##_opt_t>::optional_base; \
4683 \
4684 \
4685 static constexpr value_type min_value() noexcept \
4686 { \
4687 return {MIN}; \
4688 } \
4689 \
4690 \
4691 static constexpr value_type max_value() noexcept \
4692 { \
4693 return {MAX}; \
4694 } \
4695 \
4696 \
4697 static constexpr value_type null_value() noexcept \
4698 { \
4699 return {NULL}; \
4700 } \
4701 }; \
4702 \
4703 template<> \
4704 class type_traits<NAME##_t> \
4705 { \
4706 public: \
4707 static constexpr const char* name() noexcept \
4708 { \
4709 return #NAME; \
4710 } \
4711 \
4712 static constexpr const char* description() noexcept \
4713 { \
4714 return ""; \
4715 } \
4716 \
4717 static constexpr field_presence presence() noexcept \
4718 { \
4719 return field_presence::required; \
4720 } \
4721 \
4722 static constexpr TYPE min_value() noexcept \
4723 { \
4724 return NAME##_t::min_value(); \
4725 } \
4726 \
4727 static constexpr TYPE max_value() noexcept \
4728 { \
4729 return NAME##_t::max_value(); \
4730 } \
4731 \
4732 static constexpr length_t length() noexcept \
4733 { \
4734 return 1; \
4735 } \
4736 \
4737 static constexpr const char* semantic_type() noexcept \
4738 { \
4739 return ""; \
4740 } \
4741 \
4742 static constexpr version_t since_version() noexcept \
4743 { \
4744 return 0; \
4745 } \
4746 \
4747 using value_type = NAME##_t; \
4748 using primitive_type = value_type::value_type; \
4749 }; \
4750 \
4751 template<> \
4752 struct traits_tag<NAME##_t> \
4753 { \
4754 using type = NAME##_t; \
4755 }; \
4756 \
4757 template<> \
4758 class type_traits<NAME##_opt_t> \
4759 { \
4760 public: \
4761 static constexpr const char* name() noexcept \
4762 { \
4763 return #NAME; \
4764 } \
4765 \
4766 static constexpr const char* description() noexcept \
4767 { \
4768 return ""; \
4769 } \
4770 \
4771 static constexpr field_presence presence() noexcept \
4772 { \
4773 return field_presence::optional; \
4774 } \
4775 \
4776 static constexpr TYPE min_value() noexcept \
4777 { \
4778 return NAME##_opt_t::min_value(); \
4779 } \
4780 \
4781 static constexpr TYPE max_value() noexcept \
4782 { \
4783 return NAME##_opt_t::max_value(); \
4784 } \
4785 \
4786 static constexpr TYPE null_value() noexcept \
4787 { \
4788 return NAME##_opt_t::null_value(); \
4789 } \
4790 \
4791 static constexpr length_t length() noexcept \
4792 { \
4793 return 1; \
4794 } \
4795 \
4796 static constexpr const char* semantic_type() noexcept \
4797 { \
4798 return ""; \
4799 } \
4800 \
4801 static constexpr version_t since_version() noexcept \
4802 { \
4803 return 0; \
4804 } \
4805 \
4806 using value_type = NAME##_opt_t; \
4807 using primitive_type = value_type::value_type; \
4808 }; \
4809 \
4810 template<> \
4811 struct traits_tag<NAME##_opt_t> \
4812 { \
4813 using type = NAME##_opt_t; \
4814 }
4816SBEPP_BUILT_IN_IMPL(char, char, 0x20, 0x7E, 0);
4817SBEPP_BUILT_IN_IMPL(
4818 int8,
4819 std::int8_t,
4820 std::numeric_limits<std::int8_t>::min() + 1,
4821 std::numeric_limits<std::int8_t>::max(),
4822 std::numeric_limits<std::int8_t>::min());
4823SBEPP_BUILT_IN_IMPL(
4824 uint8,
4825 std::uint8_t,
4826 std::numeric_limits<std::uint8_t>::min(),
4827 std::numeric_limits<std::uint8_t>::max() - 1,
4828 std::numeric_limits<std::uint8_t>::max());
4829SBEPP_BUILT_IN_IMPL(
4830 int16,
4831 std::int16_t,
4832 std::numeric_limits<std::int16_t>::min() + 1,
4833 std::numeric_limits<std::int16_t>::max(),
4834 std::numeric_limits<std::int16_t>::min());
4835SBEPP_BUILT_IN_IMPL(
4836 uint16,
4837 std::uint16_t,
4838 std::numeric_limits<std::uint16_t>::min(),
4839 std::numeric_limits<std::uint16_t>::max() - 1,
4840 std::numeric_limits<std::uint16_t>::max());
4841SBEPP_BUILT_IN_IMPL(
4842 int32,
4843 std::int32_t,
4844 std::numeric_limits<std::int32_t>::min() + 1,
4845 std::numeric_limits<std::int32_t>::max(),
4846 std::numeric_limits<std::int32_t>::min());
4847SBEPP_BUILT_IN_IMPL(
4848 uint32,
4849 std::uint32_t,
4850 std::numeric_limits<std::uint32_t>::min(),
4851 std::numeric_limits<std::uint32_t>::max() - 1,
4852 std::numeric_limits<std::uint32_t>::max());
4853SBEPP_BUILT_IN_IMPL(
4854 int64,
4855 std::int64_t,
4856 std::numeric_limits<std::int64_t>::min() + 1,
4857 std::numeric_limits<std::int64_t>::max(),
4858 std::numeric_limits<std::int64_t>::min());
4859SBEPP_BUILT_IN_IMPL(
4860 uint64,
4861 std::uint64_t,
4862 std::numeric_limits<std::uint64_t>::min(),
4863 std::numeric_limits<std::uint64_t>::max() - 1,
4864 std::numeric_limits<std::uint64_t>::max());
4865SBEPP_BUILT_IN_IMPL(
4866 float,
4867 float,
4868 std::numeric_limits<float>::min(),
4869 std::numeric_limits<float>::max(),
4870 std::numeric_limits<float>::quiet_NaN());
4871SBEPP_BUILT_IN_IMPL(
4872 double,
4873 double,
4874 std::numeric_limits<double>::min(),
4875 std::numeric_limits<double>::max(),
4876 std::numeric_limits<double>::quiet_NaN());
4877
4878#undef SBEPP_BUILT_IN_IMPL
4879
4897template<template<typename> class View, typename Byte>
4898constexpr View<Byte> make_view(Byte* ptr, const std::size_t size) noexcept
4899{
4900 return {ptr, size};
4901}
4902
4921template<template<typename> class View, typename Byte>
4922constexpr View<typename std::add_const<Byte>::type>
4923 make_const_view(Byte* ptr, const std::size_t size) noexcept
4924{
4925 return {ptr, size};
4926}
4927
4934struct unknown_enum_value_tag
4935{
4936};
4937
4938namespace detail
4939{
4940// taken from https://stackoverflow.com/a/34672753
4941template<template<typename...> class Base, typename Derived>
4942struct is_base_of_tmp_impl
4943{
4944 static constexpr std::false_type test(...);
4945
4946 template<typename... Ts>
4947 static constexpr std::true_type test(Base<Ts...>*);
4948
4949 using type = decltype(test(std::declval<Derived*>()));
4950};
4951
4952template<template<typename...> class Base, typename Derived>
4953using is_base_of_tmp = typename is_base_of_tmp_impl<Base, Derived>::type;
4954
4955#if SBEPP_HAS_CONCEPTS
4956template<typename Derived, template<typename...> class Base>
4957concept derived_from_tmp = is_base_of_tmp<Base, Derived>::value;
4958#endif
4959} // namespace detail
4960
4961namespace detail
4962{
4963template<typename Derived>
4964struct is_array_type_impl
4965{
4966 static constexpr std::false_type test(...);
4967
4968 template<typename T1, typename T2, std::size_t N, typename T3>
4969 static constexpr std::true_type
4970 test(detail::static_array_ref<T1, T2, N, T3>*);
4971
4972 using type = decltype(test(std::declval<Derived*>()));
4973};
4974} // namespace detail
4975
4977template<typename T>
4978using is_array_type = typename detail::is_array_type_impl<T>::type;
4979
4981template<typename T>
4982using is_required_type = detail::is_base_of_tmp<detail::required_base, T>;
4983
4985template<typename T>
4986using is_optional_type = detail::is_base_of_tmp<detail::optional_base, T>;
4987
4989template<typename T>
4990using is_non_array_type = std::integral_constant<
4991 bool,
4993
4995template<typename T>
4996using is_type = std::integral_constant<
4997 bool,
5000
5002template<typename T, typename = void>
5003struct is_enum : std::false_type
5004{
5005};
5006
5007template<typename T>
5008struct is_enum<
5009 T,
5010 detail::void_t<decltype(tag_invoke(
5011 std::declval<detail::visit_tag>(),
5012 std::declval<T>(),
5013 std::declval<int&>()))>> : std::true_type
5014{
5015};
5016
5018template<typename T>
5019using is_set = detail::is_base_of_tmp<detail::bitset_base, T>;
5020
5022template<typename T>
5023using is_composite = detail::is_base_of_tmp<detail::composite_base, T>;
5024
5026template<typename T>
5027using is_message = detail::is_base_of_tmp<detail::message_base, T>;
5028
5030template<typename T>
5031using is_flat_group = detail::is_base_of_tmp<detail::flat_group_base, T>;
5032
5034template<typename T>
5035using is_nested_group = detail::is_base_of_tmp<detail::nested_group_base, T>;
5036
5038template<typename T>
5039using is_group = std::integral_constant<
5040 bool,
5042
5044template<typename T>
5045using is_group_entry = detail::is_base_of_tmp<detail::entry_base, T>;
5046
5047namespace detail
5048{
5049template<typename Derived>
5050struct is_data_impl
5051{
5052 static constexpr std::false_type test(...);
5053
5054 template<typename T1, typename T2, typename T3, endian E>
5055 static constexpr std::true_type
5057
5058 using type = decltype(test(std::declval<Derived*>()));
5059};
5060} // namespace detail
5061
5063template<typename T>
5064using is_data = typename detail::is_data_impl<T>::type;
5065
5066#if SBEPP_HAS_INLINE_VARS
5068template<typename T>
5069inline constexpr auto is_array_type_v = is_array_type<T>::value;
5070
5072template<typename T>
5073inline constexpr auto is_required_type_v = is_required_type<T>::value;
5074
5076template<typename T>
5077inline constexpr auto is_optional_type_v = is_optional_type<T>::value;
5078
5080template<typename T>
5081inline constexpr auto is_non_array_type_v = is_non_array_type<T>::value;
5082
5084template<typename T>
5085inline constexpr auto is_type_v = is_type<T>::value;
5086
5088template<typename T>
5089inline constexpr auto is_enum_v = is_enum<T>::value;
5090
5092template<typename T>
5093inline constexpr auto is_set_v = is_set<T>::value;
5094
5096template<typename T>
5097inline constexpr auto is_composite_v = is_composite<T>::value;
5098
5100template<typename T>
5101inline constexpr auto is_message_v = is_message<T>::value;
5102
5104template<typename T>
5105inline constexpr auto is_flat_group_v = is_flat_group<T>::value;
5106
5108template<typename T>
5109inline constexpr auto is_nested_group_v = is_nested_group<T>::value;
5110
5112template<typename T>
5113inline constexpr auto is_group_v = is_group<T>::value;
5114
5116template<typename T>
5117inline constexpr auto is_data_v = is_data<T>::value;
5118#endif
5119
5120#if SBEPP_HAS_CONCEPTS
5122template<typename T>
5123concept array_type = is_array_type_v<T>;
5124
5126template<typename T>
5127concept required_type = is_required_type_v<T>;
5128
5130template<typename T>
5131concept optional_type = is_optional_type_v<T>;
5132
5134template<typename T>
5135concept non_array_type = is_non_array_type_v<T>;
5136
5138template<typename T>
5139concept type = is_type_v<T>;
5140
5142template<typename T>
5143concept enumeration = is_enum_v<T>;
5144
5146template<typename T>
5147concept set = is_set_v<T>;
5148
5150template<typename T>
5151concept composite = is_composite_v<T>;
5152
5154template<typename T>
5155concept message = is_message_v<T>;
5156
5158template<typename T>
5159concept flat_group = is_flat_group_v<T>;
5160
5162template<typename T>
5163concept nested_group = is_nested_group_v<T>;
5164
5166template<typename T>
5167concept group = is_group_v<T>;
5168
5170template<typename T>
5171concept data = is_data_v<T>;
5172#endif
5173
5174namespace detail
5175{
5176template<typename T>
5177using is_visitable_view = std::integral_constant<
5178 bool,
5179 is_message<T>::value || is_group<T>::value || is_group_entry<T>::value
5180 || is_composite<T>::value>;
5181}
5182
5194template<
5195 typename Visitor,
5196 typename View,
5197 typename Cursor,
5198 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5199SBEPP_CPP14_CONSTEXPR Visitor&&
5200 visit(View view, Cursor& c, Visitor&& visitor = {})
5201{
5202 view(detail::visit_tag{}, visitor, c);
5203 return std::forward<Visitor>(visitor);
5204}
5205
5216template<
5217 typename Visitor,
5218 typename View,
5219 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5220SBEPP_CPP14_CONSTEXPR Visitor&& visit(View view, Visitor&& visitor = {})
5221{
5222 auto c = sbepp::init_cursor(view);
5223 return sbepp::visit(view, c, std::forward<Visitor>(visitor));
5224}
5225
5226#ifndef SBEPP_DOXYGEN
5227template<typename Visitor, typename Set>
5228SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_set<Set>::value, Visitor&&>
5229 visit(Set s, Visitor&& visitor = {})
5230{
5231 s(detail::visit_tag{}, visitor);
5232 return std::forward<Visitor>(visitor);
5233}
5234
5235template<typename Visitor, typename Enum>
5236SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_enum<Enum>::value, Visitor&&>
5237 visit(Enum e, Visitor&& visitor = {})
5238{
5239 tag_invoke(detail::visit_tag{}, e, visitor);
5240 return std::forward<Visitor>(visitor);
5241}
5242
5243#else
5244
5261template<typename Visitor, typename Set>
5262SBEPP_CPP14_CONSTEXPR Visitor&& visit(Set s, Visitor&& visitor = {});
5263
5280template<typename Visitor, typename Enum>
5281SBEPP_CPP14_CONSTEXPR Visitor&& visit(Enum e, Visitor&& visitor = {});
5282#endif
5283
5296template<
5297 typename Visitor,
5298 typename View,
5299 typename Cursor,
5300 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5301SBEPP_CPP14_CONSTEXPR Visitor&&
5302 visit_children(View view, Cursor& c, Visitor&& visitor = {})
5303{
5304 view(detail::visit_children_tag{}, visitor, c);
5305 return std::forward<Visitor>(visitor);
5306}
5307
5318template<
5319 typename Visitor,
5320 typename View,
5321 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5322SBEPP_CPP14_CONSTEXPR Visitor&&
5323 visit_children(View view, Visitor&& visitor = {})
5324{
5325 auto c = sbepp::init_cursor(view);
5326 return sbepp::visit_children(view, c, std::forward<Visitor>(visitor));
5327}
5328
5329namespace detail
5330{
5331class enum_to_string_visitor
5332{
5333public:
5334 template<typename Enum, typename Tag>
5335 SBEPP_CPP14_CONSTEXPR void on_enum_value(Enum /*e*/, Tag) noexcept
5336 {
5338 }
5339
5340 template<typename Enum>
5341 SBEPP_CPP14_CONSTEXPR void
5342 on_enum_value(Enum /*e*/, sbepp::unknown_enum_value_tag) noexcept
5343 {
5344 name_value = nullptr;
5345 }
5346
5347 constexpr const char* name() const noexcept
5348 {
5349 return name_value;
5350 }
5351
5352private:
5353 const char* name_value;
5354};
5355} // namespace detail
5356
5367template<typename E, typename = detail::enable_if_t<is_enum<E>::value>>
5368SBEPP_DEPRECATED constexpr const char* enum_to_string(const E e) noexcept
5369{
5370 return visit<detail::enum_to_string_visitor>(e).name();
5371}
5372
5384template<typename Set, typename Visitor>
5385SBEPP_DEPRECATED constexpr auto
5386 visit_set(const Set s, Visitor&& visitor) noexcept
5387 -> decltype(s(detail::visit_set_tag{}, std::forward<Visitor>(visitor)))
5388{
5389 return s(detail::visit_set_tag{}, std::forward<Visitor>(visitor));
5390}
5391
5392namespace detail
5393{
5394class size_bytes_checked_visitor
5395{
5396public:
5397 constexpr explicit size_bytes_checked_visitor(
5398 const std::size_t size) noexcept
5399 : size{size}
5400 {
5401 }
5402
5403 template<typename T, typename Cursor, typename Tag>
5404 SBEPP_CPP14_CONSTEXPR void on_message(T m, Cursor& c, Tag) noexcept
5405 {
5406 const auto header = sbepp::get_header(m);
5407 const auto header_size = sbepp::size_bytes(header);
5408 if(!validate_and_subtract(header_size))
5409 {
5410 return;
5411 }
5412
5413 if(!validate_and_subtract(*header.blockLength()))
5414 {
5415 return;
5416 }
5417
5418 sbepp::visit_children(m, c, *this);
5419 }
5420
5421 template<typename T, typename Cursor, typename Tag>
5422 SBEPP_CPP14_CONSTEXPR bool on_group(T g, Cursor& c, Tag) noexcept
5423 {
5424 const auto header = sbepp::get_header(g);
5425 const auto header_size = sbepp::size_bytes(header);
5426 if(!validate_and_subtract(header_size))
5427 {
5428 return true;
5429 }
5430
5431 const auto prev_block_length =
5432 set_group_block_length(*header.blockLength());
5433 sbepp::visit_children(g, c, *this);
5434 set_group_block_length(prev_block_length);
5435
5436 return !is_valid();
5437 }
5438
5439 template<typename T, typename Cursor>
5440 SBEPP_CPP14_CONSTEXPR bool on_entry(T e, Cursor& c) noexcept
5441 {
5442 if(!validate_and_subtract(group_block_length))
5443 {
5444 return true;
5445 }
5446
5447 return !sbepp::visit_children(e, c, *this).is_valid();
5448 }
5449
5450 template<typename T, typename Tag>
5451 SBEPP_CPP14_CONSTEXPR bool on_data(T d, Tag) noexcept
5452 {
5453 return !validate_and_subtract(sbepp::size_bytes(d));
5454 }
5455
5456 // ignore them all because we validate `blockLength`
5457 template<typename T, typename Tag>
5458 constexpr bool on_field(T, Tag) const noexcept
5459 {
5460 return {};
5461 }
5462
5463 constexpr bool is_valid() const noexcept
5464 {
5465 return valid;
5466 }
5467
5468 // returns previous value
5469 SBEPP_CPP14_CONSTEXPR std::size_t
5470 set_group_block_length(const std::size_t block_length) noexcept
5471 {
5472 auto prev = group_block_length;
5473 group_block_length = block_length;
5474 return prev;
5475 }
5476
5477 constexpr std::size_t get_size() const noexcept
5478 {
5479 return size;
5480 }
5481
5482private:
5483 std::size_t size;
5484 bool valid{true};
5485 // current group's blockLength, used to validate entry
5486 std::size_t group_block_length{};
5487
5488 SBEPP_CPP14_CONSTEXPR bool
5489 validate_and_subtract(const std::size_t n) noexcept
5490 {
5491 if(size < n)
5492 {
5493 valid = false;
5494 }
5495 else
5496 {
5497 size -= n;
5498 }
5499
5500 return valid;
5501 }
5502};
5503} // namespace detail
5504
5506struct size_bytes_checked_result
5507{
5509 bool valid;
5511 std::size_t size;
5512};
5513
5514// can be used with message/group
5525template<typename View>
5526SBEPP_CPP20_CONSTEXPR size_bytes_checked_result
5527 size_bytes_checked(View view, std::size_t size) noexcept
5528{
5529 // `init_cursor` skips header, we need to ensure there's enough space for it
5530 if(!sbepp::addressof(view) || (size < detail::get_header_size(view)))
5531 {
5532 return {};
5533 }
5534
5535 detail::size_bytes_checked_visitor visitor{size};
5536 auto c = sbepp::init_cursor(view);
5537 sbepp::visit(view, c, visitor);
5538 if(visitor.is_valid())
5539 {
5540 return {true, size - visitor.get_size()};
5541 }
5542 return {};
5543}
5544} // namespace sbepp
5545
5546#if SBEPP_HAS_RANGES && SBEPP_HAS_CONCEPTS
5547
5548template<typename Byte, typename Value, std::size_t N, typename Tag>
5549inline constexpr bool std::ranges::enable_borrowed_range<
5551
5552template<typename Byte, typename Value, typename Length, sbepp::endian E>
5553inline constexpr bool std::ranges::enable_borrowed_range<
5555
5556template<sbepp::detail::derived_from_tmp<sbepp::detail::flat_group_base> T>
5557inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5558
5559template<sbepp::detail::derived_from_tmp<sbepp::detail::nested_group_base> T>
5560inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5561#endif
5562
5563#undef SBEPP_CPP17_INLINE_VAR
5564#undef SBEPP_DEPRECATED
5565#undef SBEPP_CPLUSPLUS
5566
5567SBEPP_WARNINGS_ON();
Provides various traits/attributes of a <composite> element.
Definition sbepp.hpp:4290
CompositeType< Byte > value_type
Representation type.
Definition sbepp.hpp:4314
static constexpr const char * name() noexcept
Returns name attribute.
Represents cursor which is used in cursor-based API. Clients should not use undocumented methods.
Definition sbepp.hpp:783
constexpr Byte * pointer() const noexcept
access underlying pointer
Definition sbepp.hpp:849
constexpr cursor(cursor< Byte2 > other) noexcept
Construct from another cursor. Enabled only if Byte2* is convertible to Byte*.
Definition sbepp.hpp:812
Byte byte_type
same as Byte
Definition sbepp.hpp:786
cursor()=default
Construct a new cursor object initialized with nullptr
constexpr Byte *& pointer() noexcept
access underlying pointer. Might be useful in rare cases to initialize cursor with a particular value...
Definition sbepp.hpp:839
constexpr cursor & operator=(cursor< Byte2 > other) noexcept
Assign from another cursor. Enabled only if Byte2* is convertible to Byte
Definition sbepp.hpp:827
Provides various traits/attributes of a <data> element.
Definition sbepp.hpp:4575
static constexpr const char * name() noexcept
Returns name attribute.
DataType value_type
Representation type.
Definition sbepp.hpp:4594
LengthTypeTag length_type_tag
length_type tag
Definition sbepp.hpp:4598
LengthType length_type
Length type.
Definition sbepp.hpp:4596
Base class for bitsets.
Definition sbepp.hpp:2736
constexpr T operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:2753
constexpr friend bool operator==(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are equal.
Definition sbepp.hpp:2772
constexpr T & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:2747
constexpr bitset_base(T value) noexcept
Constructs from given value.
Definition sbepp.hpp:2742
constexpr friend bool operator!=(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are not equal.
Definition sbepp.hpp:2779
bitset_base()=default
Default constructs underlying value to 0
Base class for all reference semantics types.
Definition sbepp.hpp:714
constexpr byte_range(Byte *ptr, const std::size_t size) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:736
constexpr byte_range(const byte_range< Byte2 > &other) noexcept
Copy constructor. Available if Byte2* is convertible to Byte*
Definition sbepp.hpp:744
byte_range()=default
Initializes to nullptr
constexpr byte_range(Byte *begin, Byte *end) noexcept
Constructs from a pair of pointers.
Definition sbepp.hpp:725
Base class for composites.
Definition sbepp.hpp:1740
Represents reference to dynamic arrays used for <data> elements.
Definition sbepp.hpp:3304
constexpr sbe_size_type sbe_size() const noexcept
Returns SBE size representation.
Definition sbepp.hpp:3394
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3326
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:3328
constexpr iterator insert(iterator pos, std::initializer_list< value_type > ilist) const noexcept
Inserts elements from ilist before pos
Definition sbepp.hpp:3553
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3352
static constexpr size_type max_size() noexcept
Returns max value of SBE length representation.
Definition sbepp.hpp:3412
constexpr iterator erase(iterator first, iterator last) const noexcept
Erases elements in [first; last) range.
Definition sbepp.hpp:3500
constexpr void assign_string(const char *str) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3619
constexpr iterator insert(iterator pos, InputIt first, InputIt last) const
Inserts elements from [first; last) range before pos
Definition sbepp.hpp:3543
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:3583
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:3367
constexpr void resize(size_type count, sbepp::default_init_t) const noexcept
Sets size to count, default initializes new elements.
Definition sbepp.hpp:3458
element_type * pointer
element pointer type
Definition sbepp.hpp:3324
constexpr void push_back(value_type value) const noexcept
Adds new element to the end.
Definition sbepp.hpp:3472
constexpr iterator insert(iterator pos, const value_type value) const noexcept
Inserts value before pos
Definition sbepp.hpp:3511
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:3387
constexpr void resize(size_type count) const noexcept
Sets size to count, value initializes new elements.
Definition sbepp.hpp:3426
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:3359
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:3320
constexpr void pop_back() const noexcept
Removes the last element.
Definition sbepp.hpp:3481
Value value_type
same as Value
Definition sbepp.hpp:3314
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:3600
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:3312
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3334
constexpr void assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3638
constexpr iterator insert(iterator pos, size_type count, const value_type value) const noexcept
Inserts count copies of value before pos
Definition sbepp.hpp:3523
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:3563
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:3380
constexpr iterator erase(iterator pos) const noexcept
Erases element at pos
Definition sbepp.hpp:3489
constexpr void clear() const noexcept
Sets size to 0.
Definition sbepp.hpp:3419
constexpr bool empty() const noexcept
Checks if size() != 0
Definition sbepp.hpp:3406
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3346
constexpr void resize(size_type count, value_type value) const noexcept
Sets size to count, initializes new elements with value
Definition sbepp.hpp:3442
constexpr void assign(InputIt first, InputIt last) const
Replaces the contents of the container with the elements from [first; last) range.
Definition sbepp.hpp:3572
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3340
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:3400
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:3318
Length sbe_size_type
length SBE representation of data's encoding
Definition sbepp.hpp:3316
element_type & reference
element reference type
Definition sbepp.hpp:3322
Base class for group entries.
Definition sbepp.hpp:1791
constexpr entry_base(cursor< Byte2 > &c, Byte *end_ptr, BlockLengthType block_length) noexcept
Constructs from cursor.
Definition sbepp.hpp:1819
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:1831
constexpr entry_base(Byte *ptr, const std::size_t size, const BlockLengthType block_length) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:1809
entry_base()=default
Constructs using nullptr
constexpr entry_base(Byte *ptr, Byte *end, BlockLengthType block_length) noexcept
Constructs from two pointers.
Definition sbepp.hpp:1802
Base class for a flat group.
Definition sbepp.hpp:2279
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:2294
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2401
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2325
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2473
constexpr reference front() const noexcept
Returns the first entry.
Definition sbepp.hpp:2385
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:2437
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:2408
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2286
Entry value_type
Entry type.
Definition sbepp.hpp:2282
constexpr reference operator[](size_type pos) const noexcept
Access group entry at pos
Definition sbepp.hpp:2377
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2331
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2355
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2480
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2421
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2343
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2366
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2337
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2490
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2349
constexpr reference back() const noexcept
Returns the last entry.
Definition sbepp.hpp:2393
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2291
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:2455
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:2289
value_type reference
value_type
Definition sbepp.hpp:2284
Base class for messages.
Definition sbepp.hpp:1749
Base class for a nested group.
Definition sbepp.hpp:2513
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2569
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2604
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:2659
Entry value_type
entry type
Definition sbepp.hpp:2516
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2587
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2695
value_type reference
value_type
Definition sbepp.hpp:2518
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:2630
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:2523
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2525
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2563
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2575
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:2615
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2712
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2623
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2702
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2581
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:2529
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2643
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:2677
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2593
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2520
Base class for optional types.
Definition sbepp.hpp:3834
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3855
constexpr friend bool operator!=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3935
constexpr optional_base(nullopt_t) noexcept
Constructs null object.
Definition sbepp.hpp:3844
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:3880
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:3963
T value_type
Underlying type.
Definition sbepp.hpp:3837
constexpr bool in_range() const noexcept
Checks if value is in [Derived::min_value(); Derived::max_value()] range.
Definition sbepp.hpp:3874
constexpr optional_base(value_type val) noexcept
Constructs object from given value.
Definition sbepp.hpp:3850
constexpr bool has_value() const noexcept
Checks if has value.
Definition sbepp.hpp:3890
constexpr friend bool operator>(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3956
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3867
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3861
constexpr friend bool operator==(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3910
constexpr friend std::strong_ordering operator<=>(const optional_base &lhs, const optional_base &rhs) noexcept
Available only if SBEPP_HAS_THREE_WAY_COMPARISON == 1.
Base class for required types.
Definition sbepp.hpp:3727
constexpr friend bool operator>(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3809
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:3816
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3742
constexpr friend bool operator!=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3788
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3748
constexpr friend bool operator==(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3781
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:3761
T value_type
Underlying type.
Definition sbepp.hpp:3730
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3754
constexpr required_base(value_type val) noexcept
Constructs from given value.
Definition sbepp.hpp:3737
Represents reference to fixed-size array.
Definition sbepp.hpp:2982
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:2998
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3082
static constexpr bool empty() noexcept
Checks if size() != 0
Definition sbepp.hpp:3046
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:2986
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:3014
constexpr std::size_t strlen() const noexcept
Calculates string length from left to right.
Definition sbepp.hpp:3111
constexpr iterator assign_string(const char *str, const eos_null eos_mode=eos_null::all) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3160
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:3021
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3064
static constexpr size_type size() noexcept
Returns N
Definition sbepp.hpp:3052
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:3099
constexpr iterator assign(std::initializer_list< value_type > ilist) const noexcept
Assigns initializer list to first elements.
Definition sbepp.hpp:3266
element_type & reference
element reference type
Definition sbepp.hpp:2994
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:3000
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:3027
Value value_type
same as Value
Definition sbepp.hpp:2988
Tag tag
type tag
Definition sbepp.hpp:3002
element_type * pointer
element pointer type
Definition sbepp.hpp:2996
constexpr std::size_t strlen_r() const noexcept
Calculates string length from right to left.
Definition sbepp.hpp:3136
std::size_t size_type
std::size_t
Definition sbepp.hpp:2990
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3070
constexpr iterator assign_string(R &&r, const eos_null eos_mode=eos_null::all) const
Assigns string represented by a range.
Definition sbepp.hpp:3188
constexpr void fill(const value_type value) const noexcept
Assigns value to all elements.
Definition sbepp.hpp:3225
constexpr iterator assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3208
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3076
constexpr iterator assign(InputIt first, InputIt last) const
Assigns elements from [first; last) range to first elements.
Definition sbepp.hpp:3250
static constexpr size_type max_size() noexcept
Returns size()
Definition sbepp.hpp:3058
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:2992
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:3033
constexpr iterator assign(size_type count, const value_type value) const noexcept
Assigns value to first count elements.
Definition sbepp.hpp:3240
Provides various traits/attributes of an <enum> element.
Definition sbepp.hpp:4156
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4163
static constexpr const char * name() noexcept
Returns name attribute.
ScopedEnumType value_type
Representation type.
Definition sbepp.hpp:4175
Provides various traits/attributes of a <validValue> element.
Definition sbepp.hpp:4193
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <field> element.
Definition sbepp.hpp:4456
static constexpr const char * name() noexcept
Returns name attribute.
ValueType value_type
Representation type.
Definition sbepp.hpp:4478
TypeTag value_type_tag
value_type's tag. Not available for constants of numeric types
Definition sbepp.hpp:4487
Provides various traits/attributes of a <group> element.
Definition sbepp.hpp:4505
HeaderType< Byte > dimension_type
Group dimension composite type.
Definition sbepp.hpp:4535
HeaderTag dimension_type_tag
Dimension composite tag.
Definition sbepp.hpp:4537
GroupType< Byte > value_type
Representation type.
Definition sbepp.hpp:4528
EntryType< Byte > entry_type
Group entry type.
Definition sbepp.hpp:4544
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <message> element.
Definition sbepp.hpp:4334
static constexpr const char * name() noexcept
Returns name attribute.
SchemaTag schema_tag
Schema tag.
Definition sbepp.hpp:4359
MessageType< Byte > value_type
Representation type.
Definition sbepp.hpp:4357
Provides various traits/attributes of a <messageSchema> element.
Definition sbepp.hpp:4116
HeaderTypeTag header_type_tag
Message header composite tag. Can be used to access its traits.
Definition sbepp.hpp:4138
static constexpr const char * package() noexcept
Returns package attribute.
HeaderComposite< Byte > header_type
Message header composite type.
Definition sbepp.hpp:4136
Provides various traits/attributes of a <choice> element.
Definition sbepp.hpp:4260
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <set> element.
Definition sbepp.hpp:4223
SetType value_type
Representation type.
Definition sbepp.hpp:4242
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4235
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits and attributes of a <type> element.
Definition sbepp.hpp:4035
ValueType value_type
Representation type.
Definition sbepp.hpp:4041
PrimitiveType primitive_type
Underlying type.
Definition sbepp.hpp:4038
static constexpr const char * name() noexcept
Returns name attribute.
Concept for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5122
Concept for sbepp::is_composite<T>::value
Definition sbepp.hpp:5150
Concept for sbepp::is_data<T>::value
Definition sbepp.hpp:5170
Concept for sbepp::is_enum<T>::value
Definition sbepp.hpp:5142
Concept for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5158
Concept for sbepp::is_group<T>::value
Definition sbepp.hpp:5166
Concept for sbepp::is_message<T>::value
Definition sbepp.hpp:5154
Concept for sbepp::is_nested_group<T>::value
Definition sbepp.hpp:5162
Concept for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5134
Concept for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5130
Concept for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5126
Concept for sbepp::is_set<T>::value
Definition sbepp.hpp:5146
Concept for sbepp::is_type<T>::value
Definition sbepp.hpp:5138
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:1728
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:1694
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:1665
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:1708
The main sbepp namespace.
Definition sbepp.hpp:232
constexpr auto is_composite_v
Shorthand for sbepp::is_composite<T>::value
Definition sbepp.hpp:5096
constexpr auto is_required_type_v
Shorthand for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5072
constexpr auto is_type_v
Shorthand for sbepp::is_type<T>::value
Definition sbepp.hpp:5084
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:2827
detail::is_base_of_tmp< detail::optional_base, T > is_optional_type
Checks if T is a non-array optional type.
Definition sbepp.hpp:4985
constexpr View< Byte > make_view(Byte *ptr, const std::size_t size) noexcept
Construct view from memory buffer.
Definition sbepp.hpp:4897
typename traits_tag< ValueType >::type traits_tag_t
Shorthand for sbepp::traits_tag<T>::type
Definition sbepp.hpp:4647
constexpr auto is_flat_group_v
Shorthand for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5104
eos_null
Represents number of null bytes that can be added after the end-of-string by detail::static_array_ref...
Definition sbepp.hpp:2895
@ all
All bytes after the last string character will be set to null.
constexpr cursor< byte_type_t< View > > init_cursor(View view) noexcept
Initializes cursor from a message/group view with the same byte type.
Definition sbepp.hpp:2846
constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
Returns the header of a message/group.
Definition sbepp.hpp:1607
detail::is_base_of_tmp< detail::required_base, T > is_required_type
Checks if T is a non-array required type.
Definition sbepp.hpp:4981
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:5038
detail::is_base_of_tmp< detail::flat_group_base, T > is_flat_group
Checks if T is a flat group.
Definition sbepp.hpp:5030
constexpr auto is_array_type_v
Shorthand for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5068
constexpr nullopt_t nullopt
Helper constant used to initialize optional types with null value.
Definition sbepp.hpp:3717
field_presence
Represents presence trait value type, e.g. type_traits::presence()
Definition sbepp.hpp:313
@ constant
field is constant
@ required
field is required
@ optional
field is optional
constexpr Visitor && visit_children(View view, Cursor &c, Visitor &&visitor={})
Visit view's children using provided cursor.
Definition sbepp.hpp:5301
constexpr auto is_enum_v
Shorthand for sbepp::is_enum<T>::value
Definition sbepp.hpp:5088
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:2869
constexpr auto fill_message_header(Message m) noexcept -> decltype(m(detail::fill_message_header_tag{}))
Fill message header.
Definition sbepp.hpp:3990
constexpr auto is_non_array_type_v
Shorthand for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5080
constexpr Visitor && visit(View view, Cursor &c, Visitor &&visitor={})
Visit a view using given cursor.
Definition sbepp.hpp:5199
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:5063
typename byte_type< View >::type byte_type_t
Shortcut for byte_type<T>::type
Definition sbepp.hpp:1639
detail::is_base_of_tmp< detail::nested_group_base, T > is_nested_group
Checks if T is a nested group.
Definition sbepp.hpp:5034
constexpr const char * enum_to_string(const E e) noexcept
Converts enum to string.
Definition sbepp.hpp:5367
detail::is_base_of_tmp< detail::message_base, T > is_message
Checks if T is a message.
Definition sbepp.hpp:5026
constexpr auto fill_group_header(Group g, Size num_in_group) noexcept -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
Fill group header.
Definition sbepp.hpp:4010
constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
Returns pointer to the underlying data referenced by a view.
Definition sbepp.hpp:1619
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:1580
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:5018
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:4995
constexpr auto is_group_v
Shorthand for sbepp::is_group<T>::value
Definition sbepp.hpp:5112
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:5385
constexpr default_init_t default_init
helper to pass default_init_t to dynamic_array_ref::resize().
Definition sbepp.hpp:2890
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:4989
std::uint16_t member_id_t
Represents id trait value type, e.g. field_traits::id()
Definition sbepp.hpp:306
constexpr auto is_optional_type_v
Shorthand for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5076
std::uint64_t length_t
Represents type_traits::length() value type.
Definition sbepp.hpp:290
constexpr size_bytes_checked_result size_bytes_checked(View view, std::size_t size) noexcept
Calculate view size with additional safety checks.
Definition sbepp.hpp:5526
constexpr auto is_message_v
Shorthand for sbepp::is_message<T>::value
Definition sbepp.hpp:5100
std::uint64_t block_length_t
Represents block_length trait value type, e.g. message_traits::block_length()
Definition sbepp.hpp:304
constexpr auto is_set_v
Shorthand for sbepp::is_set<T>::value
Definition sbepp.hpp:5092
detail::is_base_of_tmp< detail::entry_base, T > is_group_entry
Checks if T is a group entry.
Definition sbepp.hpp:5044
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:5108
constexpr View< typename std::add_const< Byte >::type > make_const_view(Byte *ptr, const std::size_t size) noexcept
Construct read-only view from memory buffer.
Definition sbepp.hpp:4922
constexpr auto is_data_v
Shorthand for sbepp::is_data<T>::value
Definition sbepp.hpp:5116
endian
Represents schema_traits::byte_order() value type. When SBEPP_HAS_ENDIAN is 1, it's just an alias to ...
Definition sbepp.hpp:337
@ native
current platform endianness
@ little
little-endian
@ big
big-endian
typename detail::is_array_type_impl< T >::type is_array_type
Checks is T is an array type.
Definition sbepp.hpp:4977
detail::is_base_of_tmp< detail::composite_base, T > is_composite
Checks if T is a composite.
Definition sbepp.hpp:5022
#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:1631
typename std::remove_pointer< decltype(sbepp::addressof( std::declval< View >()))>::type type
holds View's byte type
Definition sbepp.hpp:1633
tag for dynamic_array_ref::resize(). Used to skip value initialization.
Definition sbepp.hpp:2881
Checks if T is an enumeration.
Definition sbepp.hpp:5003
Tag type used to initialize optional types with null value.
Definition sbepp.hpp:3706
Result type of size_bytes_checked
Definition sbepp.hpp:5506
Maps representation type to its tag.
Definition sbepp.hpp:4639
Tag type
Tag to access ValueType's traits.
Definition sbepp.hpp:4641
Tag for unknown enum values.
Definition sbepp.hpp:4934