sbepp
Loading...
Searching...
No Matches
sbepp.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2023, Oleksandr Koval
3
10#pragma once
11
12#include <array>
13#include <algorithm>
14#include <cstddef>
15#include <cstdint>
16#include <cstring>
17#include <iterator>
18#include <limits>
19#include <type_traits>
20#include <initializer_list>
21
22// Clang generates tons of warnings about code like `return {N};` where `N` is
23// calculated during generation or just a value from schema. Using braced
24// initialization syntax provides additional safety in such cases.
25#ifdef __clang__
26# define SBEPP_WARNINGS_OFF() \
27 _Pragma("clang diagnostic push"); \
28 _Pragma("clang diagnostic ignored \"-Wbraced-scalar-init\"")
29# define SBEPP_WARNINGS_ON() _Pragma("clang diagnostic pop")
30#else
31# define SBEPP_WARNINGS_OFF()
32# define SBEPP_WARNINGS_ON()
33#endif
34
35SBEPP_WARNINGS_OFF();
36
37#ifdef _MSVC_LANG
38# define SBEPP_CPLUSPLUS _MSVC_LANG
39#else
40# define SBEPP_CPLUSPLUS __cplusplus
41#endif
42
43#ifdef __has_include
44# if __has_include(<version>)
45# include <version>
46# endif
47#endif
48
58#if !defined(SBEPP_HAS_THREE_WAY_COMPARISON) \
59 && defined(__cpp_impl_three_way_comparison) \
60 && defined(__cpp_lib_three_way_comparison)
61# if(__cpp_impl_three_way_comparison >= 201907L) \
62 && (__cpp_lib_three_way_comparison >= 201907L)
63# define SBEPP_HAS_THREE_WAY_COMPARISON 1
64# include <compare>
65# endif
66#endif
67#ifndef SBEPP_HAS_THREE_WAY_COMPARISON
68# define SBEPP_HAS_THREE_WAY_COMPARISON 0
69#endif
70
72#if !defined(SBEPP_HAS_CONCEPTS) && defined(__cpp_concepts)
73# if(__cpp_concepts >= 201907L)
74# define SBEPP_HAS_CONCEPTS 1
75# endif
76#endif
77#ifndef SBEPP_HAS_CONCEPTS
78# define SBEPP_HAS_CONCEPTS 0
79#endif
80
82#if !defined(SBEPP_HAS_INLINE_VARS) && defined(__cpp_inline_variables)
83# if(__cpp_inline_variables >= 201606L)
84# define SBEPP_HAS_INLINE_VARS 1
85# define SBEPP_CPP17_INLINE_VAR inline
86# endif
87#endif
88#ifndef SBEPP_CPP17_INLINE_VAR
89# define SBEPP_HAS_INLINE_VARS 0
90# define SBEPP_CPP17_INLINE_VAR
91#endif
92
94#if !defined(SBEPP_HAS_ENDIAN) && defined(__cpp_lib_endian)
95# if(__cpp_lib_endian >= 201907L)
96# define SBEPP_HAS_ENDIAN 1
97# include <bit>
98# endif
99#endif
100#ifndef SBEPP_HAS_ENDIAN
101# define SBEPP_HAS_ENDIAN 0
102#endif
103
105#if !defined(SBEPP_HAS_BITCAST) && defined(__cpp_lib_bit_cast)
106# if(__cpp_lib_bit_cast >= 201806L)
107# define SBEPP_HAS_BITCAST 1
108# include <bit>
109# endif
110#endif
111#ifndef SBEPP_HAS_BITCAST
112# define SBEPP_HAS_BITCAST 0
113#endif
114
116#if !defined(SBEPP_HAS_BYTESWAP) && defined(__cpp_lib_byteswap)
117# if(__cpp_lib_byteswap >= 202110L)
118# define SBEPP_HAS_BYTESWAP 1
119# include <bit>
120# endif
121#endif
122#ifndef SBEPP_HAS_BYTESWAP
123# define SBEPP_HAS_BYTESWAP 0
124#endif
125
127#if !defined(SBEPP_HAS_CONSTEXPR_ALGORITHMS) \
128 && defined(__cpp_lib_constexpr_algorithms)
129# if(__cpp_lib_constexpr_algorithms >= 201806L)
130# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 1
131# endif
132#endif
133#ifndef SBEPP_HAS_CONSTEXPR_ALGORITHMS
134# define SBEPP_HAS_CONSTEXPR_ALGORITHMS 0
135#endif
136
137#ifdef __has_cpp_attribute
138// Clang provides `nodiscard` in C++11 but then warns that it's a C++17 feature
139# if __has_cpp_attribute(nodiscard) \
140 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201703L))
141# define SBEPP_CPP17_NODISCARD [[nodiscard]]
142# endif
143
144# if __has_cpp_attribute(deprecated) \
145 && !(defined(__clang__) && (SBEPP_CPLUSPLUS < 201402L))
146# define SBEPP_DEPRECATED [[deprecated]]
147# endif
148#endif
149
150#ifndef SBEPP_CPP17_NODISCARD
151# define SBEPP_CPP17_NODISCARD
152#endif
153
154#ifndef SBEPP_DEPRECATED
155# if defined(__GNUC__) || defined(__clang__)
156# define SBEPP_DEPRECATED __attribute__((deprecated))
157# elif defined(_MSC_VER)
158# define SBEPP_DEPRECATED __declspec(deprecated)
159# else
160# define SBEPP_DEPRECATED
161# endif
162#endif
163
165#if SBEPP_HAS_BITCAST && SBEPP_HAS_CONSTEXPR_ALGORITHMS
166# define SBEPP_HAS_CONSTEXPR_ACCESSORS 1
167#else
168# define SBEPP_HAS_CONSTEXPR_ACCESSORS 0
169#endif
170
171#if SBEPP_HAS_CONSTEXPR_ACCESSORS
172# include <bit>
173# define SBEPP_CPP20_CONSTEXPR constexpr
174#else
175# define SBEPP_CPP20_CONSTEXPR
176#endif
177
178#ifdef __cpp_constexpr
179# if(__cpp_constexpr >= 201304L)
180# define SBEPP_CPP14_CONSTEXPR constexpr
181# endif
182#else
183# if(SBEPP_CPLUSPLUS >= 201402L)
184# define SBEPP_CPP14_CONSTEXPR constexpr
185# endif
186#endif
187#ifndef SBEPP_CPP14_CONSTEXPR
188# define SBEPP_CPP14_CONSTEXPR
189#endif
190
192#if !defined(SBEPP_HAS_RANGES) && defined(__cpp_lib_ranges)
193# if(__cpp_lib_ranges >= 201911L)
194# define SBEPP_HAS_RANGES 1
195# include <ranges>
196# endif
197#endif
198#ifndef SBEPP_HAS_RANGES
199# define SBEPP_HAS_RANGES 0
200#endif
201
204#if !defined(SBEPP_HAS_IS_CONSTANT_EVALUATED) \
205 && defined(__cpp_lib_is_constant_evaluated) \
206 && (__cpp_lib_is_constant_evaluated >= 201811L)
207# define SBEPP_HAS_IS_CONSTANT_EVALUATED 1
208#endif
209#ifndef SBEPP_HAS_IS_CONSTANT_EVALUATED
210# define SBEPP_HAS_IS_CONSTANT_EVALUATED 0
211#endif
212
214
215#ifdef SBEPP_DOXYGEN
217# define SBEPP_DISABLE_ASSERTS
218
223# define SBEPP_ASSERT_HANDLER
224
229# define SBEPP_ENABLE_ASSERTS_WITH_HANDLER
230
231namespace sbepp
232{
243[[noreturn]] void assertion_failed(
244 char const* expr, char const* function, char const* file, long line);
245} // namespace sbepp
246#endif
247
248#ifdef SBEPP_DISABLE_ASSERTS
249# define SBEPP_SIZE_CHECKS_ENABLED 0
250# define SBEPP_ASSERT(expr) ((void)0)
251#elif defined(SBEPP_ASSERT_HANDLER) \
252 || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
253# if !defined(NDEBUG) || defined(SBEPP_ENABLE_ASSERTS_WITH_HANDLER)
254namespace sbepp
255{
256// must be defined by user
257[[noreturn]] void assertion_failed(
258 char const* expr, char const* function, char const* file, long line);
259} // namespace sbepp
260
261# define SBEPP_SIZE_CHECKS_ENABLED 1
262# define SBEPP_ASSERT(expr) \
263 (static_cast<bool>(expr) \
264 ? ((void)0) \
265 : ::sbepp::assertion_failed( \
266 #expr, __func__, __FILE__, __LINE__))
267# else
268# define SBEPP_SIZE_CHECKS_ENABLED 0
269# define SBEPP_ASSERT(expr) ((void)0)
270# endif
271#else
272# include <cassert>
273# ifdef NDEBUG
274# define SBEPP_SIZE_CHECKS_ENABLED 0
275# else
276# define SBEPP_SIZE_CHECKS_ENABLED 1
277# endif
278# define SBEPP_ASSERT(expr) assert(expr)
279#endif
280
281#define SBEPP_SIZE_CHECK(begin, end, offset, size) \
282 SBEPP_ASSERT( \
283 (begin) \
284 && (((offset) + (size)) <= static_cast<std::size_t>((end) - (begin))))
285
287namespace sbepp
288{
290using length_t = std::uint64_t;
291// for unknown reasons, in the SBE standard `offset` is specified as an unsigned
292// 32-bit integer which makes no sense since `length` has 64 bits
294using offset_t = std::uint64_t;
297using version_t = std::uint64_t;
299using schema_id_t = std::uint32_t;
301using message_id_t = std::uint32_t;
304using block_length_t = std::uint64_t;
306using member_id_t = std::uint16_t;
308using choice_index_t = std::uint8_t;
309
313{
315 required,
317 optional,
320};
321
322#ifdef SBEPP_DOXYGEN
327# define SBEPP_BYTE_ORDER
328#endif
329
335#ifdef SBEPP_DOXYGEN
336enum class endian
337{
339 little,
341 big,
343 native
344};
345#elif SBEPP_HAS_ENDIAN
346using endian = std::endian;
347#else
348// https://en.cppreference.com/w/cpp/types/endian
349enum class endian
350{
351# if defined(_WIN32) || defined(WIN32)
352 little = 0,
353 big = 1,
354 native = little
355# elif defined(__BYTE_ORDER__)
356 little = __ORDER_LITTLE_ENDIAN__,
357 big = __ORDER_BIG_ENDIAN__,
358 native = __BYTE_ORDER__
359# elif defined(SBEPP_BYTE_ORDER)
360 little = 0,
361 big = 1,
363# else
364# error "Byte order cannot be detected.\
365 Define SBEPP_BYTE_ORDER to 'little' or 'big'"
366# endif
367};
368#endif
369
370static_assert(
372 "Mixed-endian is not supported");
373
376namespace detail
377{
378// modern C++ bits
379template<bool B, typename T = void>
380using enable_if_t = typename std::enable_if<B, T>::type;
381
382template<typename T>
383using remove_cv_t = typename std::remove_cv<T>::type;
384
385template<typename T>
386using remove_reference_t = typename std::remove_reference<T>::type;
387
388template<typename ByteFrom, typename ByteTo>
389using enable_if_convertible_t =
390 enable_if_t<std::is_convertible<ByteFrom*, ByteTo*>::value>;
391
392template<typename Byte, typename T = void>
393using enable_if_writable_t = enable_if_t<!std::is_const<Byte>::value, T>;
394
395template<typename...>
396using void_t = void;
397
398template<typename T, typename = enable_if_t<!std::is_floating_point<T>::value>>
399constexpr typename std::make_unsigned<T>::type to_unsigned(T v) noexcept
400{
401 return static_cast<typename std::make_unsigned<T>::type>(v);
402}
403
404inline std::uint64_t to_unsigned(double v) noexcept
405{
406 std::uint64_t res{};
407 std::memcpy(&res, &v, sizeof(res));
408 return res;
409}
410
411inline std::uint32_t to_unsigned(float v) noexcept
412{
413 std::uint32_t res{};
414 std::memcpy(&res, &v, sizeof(res));
415 return res;
416}
417
418template<typename To>
419struct from_unsigned
420{
421 constexpr To
422 operator()(typename std::make_unsigned<To>::type from) const noexcept
423 {
424 return static_cast<To>(from);
425 }
426};
427
428template<>
429struct from_unsigned<double>
430{
431 double operator()(std::uint64_t from) const noexcept
432 {
433 double res{};
434 std::memcpy(&res, &from, sizeof(res));
435 return res;
436 }
437};
438
439template<>
440struct from_unsigned<float>
441{
442 float operator()(std::uint32_t from) const noexcept
443 {
444 float res{};
445 std::memcpy(&res, &from, sizeof(res));
446 return res;
447 }
448};
449
450// intrinsics detection is taken from <boost/endian/detail/intrinsic.hpp>
451#ifndef __has_builtin // Optional of course
452# define __has_builtin(x) 0 // Compatibility with non-clang compilers
453#endif
454
455#if SBEPP_HAS_BYTESWAP
456
457using std::byteswap;
458
459#else
460
461// because `if((E == endian::native) || (sizeof(T) == 1))` is not a constexpr-if
462// this function has to be declared for single byte types even if it will never
463// be used
464template<typename T>
465T byteswap(T) noexcept;
466
467# if defined(_MSC_VER) && (!defined(__clang__) || defined(__c2__))
468
469# include <cstdlib>
470
471inline std::uint64_t byteswap(std::uint64_t v) noexcept
472{
473 return _byteswap_uint64(v);
474}
475
476inline std::uint32_t byteswap(std::uint32_t v) noexcept
477{
478 return _byteswap_ulong(v);
479}
480
481inline std::uint16_t byteswap(std::uint16_t v) noexcept
482{
483 return _byteswap_ushort(v);
484}
485
486# elif( \
487 defined(__clang__) && __has_builtin(__builtin_bswap32) \
488 && __has_builtin(__builtin_bswap64)) \
489 || (defined(__GNUC__) \
490 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
491
492# if(defined(__clang__) && __has_builtin(__builtin_bswap16)) \
493 || (defined(__GNUC__) \
494 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
495
496inline std::uint16_t byteswap(std::uint16_t v) noexcept
497{
498 return __builtin_bswap16(v);
499}
500
501# else
502
503inline std::uint16_t byteswap(std::uint16_t v) noexcept
504{
505 return __builtin_bswap32(v) << 16;
506}
507
508# endif
509
510inline std::uint64_t byteswap(std::uint64_t v) noexcept
511{
512 return __builtin_bswap64(v);
513}
514
515inline std::uint32_t byteswap(std::uint32_t v) noexcept
516{
517 return __builtin_bswap32(v);
518}
519
520# else
521
522constexpr std::uint64_t byteswap(std::uint64_t v) noexcept
523{
524 return ((v & UINT64_C(0x00000000000000FF)) << 56)
525 | ((v & UINT64_C(0x000000000000FF00)) << 40)
526 | ((v & UINT64_C(0x0000000000FF0000)) << 24)
527 | ((v & UINT64_C(0x00000000FF000000)) << 8)
528 | ((v & UINT64_C(0x000000FF00000000)) >> 8)
529 | ((v & UINT64_C(0x0000FF0000000000)) >> 24)
530 | ((v & UINT64_C(0x00FF000000000000)) >> 40)
531 | ((v & UINT64_C(0xFF00000000000000)) >> 56);
532}
533
534constexpr std::uint32_t byteswap(std::uint32_t v) noexcept
535{
536 return ((v & UINT32_C(0x000000FF)) << 24)
537 | ((v & UINT32_C(0x0000FF00)) << 8)
538 | ((v & UINT32_C(0x00FF0000)) >> 8)
539 | ((v & UINT32_C(0xFF000000)) >> 24);
540}
541
542constexpr std::uint16_t byteswap(std::uint16_t v) noexcept
543{
544 return ((v & UINT16_C(0x00FF)) << 8) | ((v & UINT16_C(0xFF00)) >> 8);
545}
546
547# endif
548#endif
549
550template<typename T, endian E, typename Byte>
551SBEPP_CPP20_CONSTEXPR T get_primitive(const Byte* ptr)
552{
553#if SBEPP_HAS_BITCAST
554 std::array<Byte, sizeof(T)> arr;
555 if((E == endian::native) || (sizeof(T) == 1))
556 {
557 std::copy(ptr, ptr + sizeof(T), std::begin(arr));
558 }
559 else
560 {
561 std::reverse_copy(ptr, ptr + sizeof(T), std::begin(arr));
562 }
563 return std::bit_cast<T>(arr);
564#else
565 // old compilers don't optimize `std::copy` approach good enough, that's
566 // why explicit `std::memcpy` call is required
567 T res;
568 std::memcpy(&res, ptr, sizeof(T));
569 if((E == endian::native) || (sizeof(T) == 1))
570 {
571 return res;
572 }
573 else
574 {
575 return from_unsigned<T>{}(byteswap(to_unsigned(res)));
576 }
577#endif
578}
579
580template<endian E, typename T, typename Byte>
581SBEPP_CPP20_CONSTEXPR void set_primitive(Byte* ptr, T value)
582{
583#if SBEPP_HAS_BITCAST
584 auto arr = std::bit_cast<std::array<Byte, sizeof(T)>>(value);
585 if((E == endian::native) || (sizeof(T) == 1))
586 {
587 std::copy(std::begin(arr), std::end(arr), ptr);
588 }
589 else
590 {
591 std::reverse_copy(std::begin(arr), std::end(arr), ptr);
592 }
593#else
594 // old compilers don't optimize `std::copy` approach good enough, that's
595 // why explicit `std::memcpy` call is required
596 if((E != endian::native) && (sizeof(T) != 1))
597 {
598 value = from_unsigned<T>{}(byteswap(to_unsigned(value)));
599 }
600 std::memcpy(ptr, &value, sizeof(T));
601#endif
602}
603
604struct fill_message_header_tag
605{
606 explicit fill_message_header_tag() = default;
607};
608
609struct fill_group_header_tag
610{
611 explicit fill_group_header_tag() = default;
612};
613
614struct size_bytes_tag
615{
616 explicit size_bytes_tag() = default;
617};
618
619struct addressof_tag
620{
621 explicit addressof_tag() = default;
622};
623
624struct end_ptr_tag
625{
626 explicit end_ptr_tag() = default;
627};
628
629struct get_header_tag
630{
631 explicit get_header_tag() = default;
632};
633
634struct get_block_length_tag
635{
636 explicit get_block_length_tag() = default;
637};
638
639struct get_bit_tag
640{
641 explicit get_bit_tag() = default;
642};
643
644struct set_bit_tag
645{
646 explicit set_bit_tag() = default;
647};
648
649struct get_level_tag
650{
651 explicit get_level_tag() = default;
652};
653
654struct visit_tag
655{
656 explicit visit_tag() = default;
657};
658
659struct visit_children_tag
660{
661 explicit visit_children_tag() = default;
662};
663
664struct enum_to_str_tag
665{
666 explicit enum_to_str_tag() = default;
667};
668
669struct visit_set_tag
670{
671 explicit visit_set_tag() = default;
672};
673
674template<typename T, typename U, endian E, typename View>
675SBEPP_CPP20_CONSTEXPR T
676 get_value(const View view, const std::size_t offset) noexcept
677{
678 SBEPP_SIZE_CHECK(
679 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(U));
680 return T{get_primitive<U, E>(view(addressof_tag{}) + offset)};
681}
682
683template<endian E, typename T, typename View>
684SBEPP_CPP20_CONSTEXPR void
685 set_value(const View view, const std::size_t offset, const T value) noexcept
686{
687 SBEPP_SIZE_CHECK(
688 view(addressof_tag{}), view(end_ptr_tag{}), offset, sizeof(T));
689 set_primitive<E>(view(addressof_tag{}) + offset, value);
690}
691
692template<typename Res, typename View>
693SBEPP_CPP20_CONSTEXPR Res
694 get_static_field_view(const View view, const std::size_t offset) noexcept
695{
696 SBEPP_SIZE_CHECK(view(addressof_tag{}), view(end_ptr_tag{}), offset, 0);
697 return {view(addressof_tag{}) + offset, view(end_ptr_tag{})};
698}
699
700template<typename Group, typename View>
701SBEPP_CPP20_CONSTEXPR Group
702 get_first_dynamic_field_view(const View view) noexcept
703{
704 return {
705 view(get_level_tag{}) + view(get_block_length_tag{}),
706 view(end_ptr_tag{})};
707}
708
709template<typename Group, typename View, typename Prev>
710SBEPP_CPP20_CONSTEXPR Group
711 get_dynamic_field_view(const View view, const Prev prev) noexcept
712{
713 return {
714 prev(addressof_tag{}) + prev(size_bytes_tag{}), view(end_ptr_tag{})};
715}
716
719template<typename Byte>
721{
722public:
723 static_assert(sizeof(Byte) == 1, "Byte must represent a single byte");
724
725 template<typename Byte2>
726 friend class byte_range;
727
729 byte_range() = default;
730
732 SBEPP_CPP14_CONSTEXPR byte_range(Byte* begin, Byte* end) noexcept
733 : begin{begin}
734#if SBEPP_SIZE_CHECKS_ENABLED
735 ,
736 end{end}
737#endif
738 {
739 (void)end;
740 }
741
743 constexpr byte_range(Byte* ptr, const std::size_t size) noexcept
744 : byte_range{ptr, ptr + size}
745 {
746 }
747
749 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
750 // NOLINTNEXTLINE: intentionally implicit
751 constexpr byte_range(const byte_range<Byte2>& other) noexcept
752 : begin{other.begin}
753#if SBEPP_SIZE_CHECKS_ENABLED
754 ,
755 end{other.end}
756#endif
757 {
758 }
759
760 constexpr Byte* operator()(addressof_tag) const noexcept
761 {
762 return begin;
763 }
764
765 constexpr Byte* operator()(end_ptr_tag) const noexcept
766 {
767#if SBEPP_SIZE_CHECKS_ENABLED
768 return end;
769#else
770 return nullptr;
771#endif
772 }
773
774private:
775 Byte* begin{};
776#if SBEPP_SIZE_CHECKS_ENABLED
777 Byte* end{};
778#endif
779};
780} // namespace detail
781
788template<typename Byte>
790{
791public:
793 using byte_type = Byte;
794
795 // in accessors we have to use trailing return type because in "skip" mode
796 // they should return `void`. In most cases it's not a problem but
797 // `get_group_view` and `get_data_view` take lambdas which were not allowed
798 // in unevaluated context (e.g. decltype) prior to C++20 so we need this
799 // alias to specify return types for them. First attempt used
800 // pointer-to-member instead of lambda but GCC doesn't support it so I
801 // switched to simpler approach with lambda and trait.
802 template<typename T>
803 using result_type = T;
804
806 cursor() = default;
807
815 template<
816 typename Byte2,
817 typename = detail::enable_if_convertible_t<Byte2, Byte>>
818 // NOLINTNEXTLINE: implicit conversion is intentional
819 constexpr cursor(cursor<Byte2> other) noexcept : ptr{other.ptr}
820 {
821 }
822
831 template<
832 typename Byte2,
833 typename = detail::enable_if_convertible_t<Byte2, Byte>>
834 SBEPP_CPP14_CONSTEXPR cursor& operator=(cursor<Byte2> other) noexcept
835 {
836 ptr = other.ptr;
837 return *this;
838 }
839
846 SBEPP_CPP14_CONSTEXPR Byte*& pointer() noexcept
847 {
848 return ptr;
849 }
850
856 SBEPP_CPP14_CONSTEXPR Byte* pointer() const noexcept
857 {
858 return ptr;
859 }
860
861 template<typename T, typename U, endian E, typename View>
862 SBEPP_CPP20_CONSTEXPR T get_value(
863 const View view,
864 const std::size_t offset,
865 const std::size_t absolute_offset) noexcept
866 {
867 SBEPP_ASSERT(
868 ((view(detail::addressof_tag{}) + absolute_offset)
869 == (ptr + offset))
870 && "Wrong cursor value");
871 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
872 T res{detail::get_primitive<U, E>(ptr + offset)};
873 ptr += offset + sizeof(U);
874 return res;
875 }
876
877 template<endian E, typename T, typename View>
878 SBEPP_CPP20_CONSTEXPR void set_value(
879 const View view,
880 const std::size_t offset,
881 const std::size_t absolute_offset,
882 const T value) noexcept
883 {
884 SBEPP_ASSERT(
885 ((view(detail::addressof_tag{}) + absolute_offset)
886 == (ptr + offset))
887 && "Wrong cursor value");
888 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
889 detail::set_primitive<E>(ptr + offset, value);
890 ptr += offset + sizeof(T);
891 }
892
893 template<typename T, typename U, endian E, typename View>
894 SBEPP_CPP20_CONSTEXPR T get_last_value(
895 const View view,
896 const std::size_t offset,
897 const std::size_t absolute_offset) noexcept
898 {
899 SBEPP_ASSERT(
900 ((view(detail::addressof_tag{}) + absolute_offset)
901 == (ptr + offset))
902 && "Wrong cursor value");
903 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(U));
904 auto res = T{detail::get_primitive<U, E>(ptr + offset)};
905 ptr = view(detail::get_level_tag{})
906 + view(detail::get_block_length_tag{});
907 return res;
908 }
909
910 template<endian E, typename T, typename View>
911 SBEPP_CPP20_CONSTEXPR void set_last_value(
912 const View view,
913 const std::size_t offset,
914 const std::size_t absolute_offset,
915 const T value) noexcept
916 {
917 SBEPP_ASSERT(
918 ((view(detail::addressof_tag{}) + absolute_offset)
919 == (ptr + offset))
920 && "Wrong cursor value");
921 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, sizeof(T));
922 detail::set_primitive<E>(ptr + offset, value);
923 ptr = view(detail::get_level_tag{})
924 + view(detail::get_block_length_tag{});
925 }
926
927 template<typename Res, typename View>
928 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
929 const View view,
930 const std::size_t offset,
931 const std::size_t absolute_offset) noexcept
932 {
933 SBEPP_ASSERT(
934 ((view(detail::addressof_tag{}) + absolute_offset)
935 == (ptr + offset))
936 && "Wrong cursor value");
937 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
938 Res res{ptr + offset, view(detail::end_ptr_tag{})};
939 ptr += offset + res(detail::size_bytes_tag{});
940 return res;
941 }
942
943 template<typename Res, typename View>
944 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
945 const View view,
946 const std::size_t offset,
947 const std::size_t absolute_offset) noexcept
948 {
949 SBEPP_ASSERT(
950 ((view(detail::addressof_tag{}) + absolute_offset)
951 == (ptr + offset))
952 && "Wrong cursor value");
953 SBEPP_SIZE_CHECK(ptr, view(detail::end_ptr_tag{}), offset, 0);
954 Res res{ptr + offset, view(detail::end_ptr_tag{})};
955 ptr = view(detail::get_level_tag{})
956 + view(detail::get_block_length_tag{});
957 return res;
958 }
959
960 template<typename ResView, typename View>
961 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
962 {
963 ptr = view(detail::get_level_tag{})
964 + view(detail::get_block_length_tag{});
965 ResView g{ptr, view(detail::end_ptr_tag{})};
966 ptr += g(detail::get_header_tag{})(detail::size_bytes_tag{});
967
968 return g;
969 }
970
971 template<typename ResView, typename View>
972 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
973 {
974 ptr = view(detail::get_level_tag{})
975 + view(detail::get_block_length_tag{});
976 ResView d{ptr, view(detail::end_ptr_tag{})};
977 ptr += d(detail::size_bytes_tag{});
978
979 return d;
980 }
981
982 template<typename ResView, typename View, typename Getter>
983 SBEPP_CPP20_CONSTEXPR ResView
984 get_group_view(const View view, Getter&& getter) noexcept
985 {
986 SBEPP_ASSERT(
987 (getter()(detail::addressof_tag{}) == ptr) && "Wrong cursor value");
988 ResView res{ptr, view(detail::end_ptr_tag{})};
989 auto header = res(detail::get_header_tag{});
990 ptr += header(detail::size_bytes_tag{});
991 return res;
992 }
993
994 template<typename ResView, typename View, typename Getter>
995 SBEPP_CPP20_CONSTEXPR ResView
996 get_data_view(const View view, Getter&& getter) noexcept
997 {
998 SBEPP_ASSERT(
999 (getter()(detail::addressof_tag{}) == ptr) && "Wrong cursor value");
1000 ResView res{ptr, view(detail::end_ptr_tag{})};
1001 ptr += res(detail::size_bytes_tag{});
1002 return res;
1003 }
1004
1005private:
1006 template<typename T>
1007 friend class cursor;
1008
1009 Byte* ptr{};
1010};
1011
1012namespace detail
1013{
1014template<typename Byte>
1015class init_cursor_wrapper
1016{
1017public:
1018 using byte_type = Byte;
1019
1020 template<typename T>
1021 using result_type = T;
1022
1023 init_cursor_wrapper() = default;
1024
1025 explicit constexpr init_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1026 : cursor{&cursor}
1027 {
1028 }
1029
1030 template<typename T, typename U, endian E, typename View>
1031 SBEPP_CPP20_CONSTEXPR T get_value(
1032 const View view,
1033 const std::size_t /*offset*/,
1034 const std::size_t absolute_offset) noexcept
1035 {
1036 SBEPP_SIZE_CHECK(
1037 view(addressof_tag{}),
1038 view(end_ptr_tag{}),
1039 absolute_offset,
1040 sizeof(U));
1041 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1042 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(U);
1043 return res;
1044 }
1045
1046 template<endian E, typename T, typename View>
1047 SBEPP_CPP20_CONSTEXPR void set_value(
1048 const View view,
1049 const std::size_t /*offset*/,
1050 const std::size_t absolute_offset,
1051 const T value) noexcept
1052 {
1053 SBEPP_SIZE_CHECK(
1054 view(addressof_tag{}),
1055 view(end_ptr_tag{}),
1056 absolute_offset,
1057 sizeof(T));
1058 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1059 cursor->pointer() = view(addressof_tag{}) + absolute_offset + sizeof(T);
1060 }
1061
1062 template<typename T, typename U, endian E, typename View>
1063 SBEPP_CPP20_CONSTEXPR T get_last_value(
1064 const View view,
1065 const std::size_t /*offset*/,
1066 const std::size_t absolute_offset) noexcept
1067 {
1068 SBEPP_SIZE_CHECK(
1069 view(addressof_tag{}),
1070 view(end_ptr_tag{}),
1071 absolute_offset,
1072 sizeof(U));
1073 T res{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1074 cursor->pointer() =
1075 view(get_level_tag{}) + view(get_block_length_tag{});
1076 return res;
1077 }
1078
1079 template<endian E, typename T, typename View>
1080 SBEPP_CPP20_CONSTEXPR void set_last_value(
1081 const View view,
1082 const std::size_t /*offset*/,
1083 const std::size_t absolute_offset,
1084 const T value) noexcept
1085 {
1086 SBEPP_SIZE_CHECK(
1087 view(addressof_tag{}),
1088 view(end_ptr_tag{}),
1089 absolute_offset,
1090 sizeof(T));
1091 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1092 cursor->pointer() =
1093 view(get_level_tag{}) + view(get_block_length_tag{});
1094 }
1095
1096 template<typename Res, typename View>
1097 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1098 const View view,
1099 const std::size_t /*offset*/,
1100 const std::size_t absolute_offset) noexcept
1101 {
1102 SBEPP_SIZE_CHECK(
1103 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1104 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1105 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1106 return res;
1107 }
1108
1109 template<typename Res, typename View>
1110 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1111 const View view,
1112 const std::size_t /*offset*/,
1113 const std::size_t absolute_offset) noexcept
1114 {
1115 SBEPP_SIZE_CHECK(
1116 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1117 Res res{view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1118 cursor->pointer() =
1119 view(get_level_tag{}) + view(get_block_length_tag{});
1120 return res;
1121 }
1122
1123 template<typename ResView, typename View>
1124 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1125 {
1126 return cursor->template get_first_group_view<ResView>(view);
1127 }
1128
1129 template<typename ResView, typename View>
1130 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1131 {
1132 return cursor->template get_first_data_view<ResView>(view);
1133 }
1134
1135 template<typename ResView, typename View, typename Getter>
1136 SBEPP_CPP20_CONSTEXPR ResView
1137 get_group_view(const View /*view*/, Getter&& getter) noexcept
1138 {
1139 auto res = getter();
1140 auto header = res(get_header_tag{});
1141 cursor->pointer() = res(addressof_tag{}) + header(size_bytes_tag{});
1142 return res;
1143 }
1144
1145 template<typename ResView, typename View, typename Getter>
1146 SBEPP_CPP20_CONSTEXPR ResView
1147 get_data_view(const View /*view*/, Getter&& getter) noexcept
1148 {
1149 auto res = getter();
1150 cursor->pointer() = res(addressof_tag{}) + res(size_bytes_tag{});
1151 return res;
1152 }
1153
1154private:
1155 sbepp::cursor<Byte>* cursor{};
1156};
1157
1158template<typename Byte>
1159class init_dont_move_cursor_wrapper
1160{
1161public:
1162 using byte_type = Byte;
1163
1164 template<typename T>
1165 using result_type = T;
1166
1167 init_dont_move_cursor_wrapper() = default;
1168
1169 explicit constexpr init_dont_move_cursor_wrapper(
1170 sbepp::cursor<Byte>& cursor)
1171 : cursor{&cursor}
1172 {
1173 }
1174
1175 template<typename T, typename U, endian E, typename View>
1176 SBEPP_CPP20_CONSTEXPR T get_value(
1177 const View view,
1178 const std::size_t offset,
1179 const std::size_t absolute_offset) noexcept
1180 {
1181 SBEPP_SIZE_CHECK(
1182 view(addressof_tag{}),
1183 view(end_ptr_tag{}),
1184 absolute_offset,
1185 sizeof(U));
1186 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1187 return T{get_primitive<U, E>(view(addressof_tag{}) + absolute_offset)};
1188 }
1189
1190 template<endian E, typename T, typename View>
1191 SBEPP_CPP20_CONSTEXPR void set_value(
1192 const View view,
1193 const std::size_t offset,
1194 const std::size_t absolute_offset,
1195 const T value) noexcept
1196 {
1197 SBEPP_SIZE_CHECK(
1198 view(addressof_tag{}),
1199 view(end_ptr_tag{}),
1200 absolute_offset,
1201 sizeof(T));
1202 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1203 set_primitive<E>(view(addressof_tag{}) + absolute_offset, value);
1204 }
1205
1206 template<typename T, typename U, endian E, typename View>
1207 SBEPP_CPP20_CONSTEXPR T get_last_value(
1208 const View view,
1209 const std::size_t offset,
1210 const std::size_t absolute_offset) noexcept
1211 {
1212 return get_value<T, U, E>(view, offset, absolute_offset);
1213 }
1214
1215 template<endian E, typename T, typename View>
1216 SBEPP_CPP20_CONSTEXPR void set_last_value(
1217 const View view,
1218 const std::size_t offset,
1219 const std::size_t absolute_offset,
1220 const T value) noexcept
1221 {
1222 return set_value<E>(view, offset, absolute_offset, value);
1223 }
1224
1225 template<typename Res, typename View>
1226 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1227 const View view,
1228 const std::size_t offset,
1229 const std::size_t absolute_offset) noexcept
1230 {
1231 SBEPP_SIZE_CHECK(
1232 view(addressof_tag{}), view(end_ptr_tag{}), absolute_offset, 0);
1233 cursor->pointer() = view(addressof_tag{}) + absolute_offset - offset;
1234 return {view(addressof_tag{}) + absolute_offset, view(end_ptr_tag{})};
1235 }
1236
1237 template<typename Res, typename View>
1238 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1239 const View view,
1240 const std::size_t offset,
1241 const std::size_t absolute_offset) noexcept
1242 {
1243 return get_static_field_view<Res>(view, offset, absolute_offset);
1244 }
1245
1246 template<typename ResView, typename View>
1247 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1248 {
1249 cursor->pointer() =
1250 view(get_level_tag{}) + view(get_block_length_tag{});
1251 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1252
1253 return g;
1254 }
1255
1256 template<typename ResView, typename View>
1257 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1258 {
1259 cursor->pointer() =
1260 view(get_level_tag{}) + view(get_block_length_tag{});
1261 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1262
1263 return d;
1264 }
1265
1266 template<typename ResView, typename View, typename Getter>
1267 SBEPP_CPP20_CONSTEXPR ResView
1268 get_group_view(const View /*view*/, Getter&& getter) noexcept
1269 {
1270 auto res = getter();
1271 cursor->pointer() = res(addressof_tag{});
1272 return res;
1273 }
1274
1275 template<typename ResView, typename View, typename Getter>
1276 SBEPP_CPP20_CONSTEXPR ResView
1277 get_data_view(const View /*view*/, Getter&& getter) noexcept
1278 {
1279 auto res = getter();
1280 cursor->pointer() = res(addressof_tag{});
1281 return res;
1282 }
1283
1284private:
1285 sbepp::cursor<Byte>* cursor{};
1286};
1287
1288template<typename Byte>
1289class dont_move_cursor_wrapper
1290{
1291public:
1292 using byte_type = Byte;
1293
1294 template<typename T>
1295 using result_type = T;
1296
1297 dont_move_cursor_wrapper() = default;
1298
1299 explicit constexpr dont_move_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1300 : cursor{&cursor}
1301 {
1302 }
1303
1304 template<typename T, typename U, endian E, typename View>
1305 SBEPP_CPP20_CONSTEXPR T get_value(
1306 const View view,
1307 const std::size_t offset,
1308 const std::size_t absolute_offset) noexcept
1309 {
1310 SBEPP_ASSERT(
1311 ((view(detail::addressof_tag{}) + absolute_offset)
1312 == (cursor->pointer() + offset))
1313 && "Wrong cursor value");
1314 SBEPP_SIZE_CHECK(
1315 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1316 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1317 }
1318
1319 template<endian E, typename T, typename View>
1320 SBEPP_CPP20_CONSTEXPR void set_value(
1321 const View view,
1322 const std::size_t offset,
1323 const std::size_t absolute_offset,
1324 const T value) noexcept
1325 {
1326 SBEPP_ASSERT(
1327 ((view(detail::addressof_tag{}) + absolute_offset)
1328 == (cursor->pointer() + offset))
1329 && "Wrong cursor value");
1330 SBEPP_SIZE_CHECK(
1331 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1332 set_primitive<E>(cursor->pointer() + offset, value);
1333 }
1334
1335 template<typename T, typename U, endian E, typename View>
1336 SBEPP_CPP20_CONSTEXPR T get_last_value(
1337 const View view,
1338 const std::size_t offset,
1339 const std::size_t absolute_offset) noexcept
1340 {
1341 SBEPP_ASSERT(
1342 ((view(detail::addressof_tag{}) + absolute_offset)
1343 == (cursor->pointer() + offset))
1344 && "Wrong cursor value");
1345 SBEPP_SIZE_CHECK(
1346 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1347 return T{get_primitive<U, E>(cursor->pointer() + offset)};
1348 }
1349
1350 template<endian E, typename T, typename View>
1351 SBEPP_CPP20_CONSTEXPR void set_last_value(
1352 const View view,
1353 const std::size_t offset,
1354 const std::size_t absolute_offset,
1355 const T value) noexcept
1356 {
1357 SBEPP_ASSERT(
1358 ((view(detail::addressof_tag{}) + absolute_offset)
1359 == (cursor->pointer() + offset))
1360 && "Wrong cursor value");
1361 SBEPP_SIZE_CHECK(
1362 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(T));
1363 set_primitive<E>(cursor->pointer() + offset, value);
1364 }
1365
1366 template<typename Res, typename View>
1367 SBEPP_CPP20_CONSTEXPR Res get_static_field_view(
1368 const View view,
1369 const std::size_t offset,
1370 const std::size_t absolute_offset) noexcept
1371 {
1372 SBEPP_ASSERT(
1373 ((view(detail::addressof_tag{}) + absolute_offset)
1374 == (cursor->pointer() + offset))
1375 && "Wrong cursor value");
1376 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1377 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1378 }
1379
1380 template<typename Res, typename View>
1381 SBEPP_CPP20_CONSTEXPR Res get_last_static_field_view(
1382 const View view,
1383 const std::size_t offset,
1384 const std::size_t absolute_offset) noexcept
1385 {
1386 SBEPP_ASSERT(
1387 ((view(detail::addressof_tag{}) + absolute_offset)
1388 == (cursor->pointer() + offset))
1389 && "Wrong cursor value");
1390 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1391 return {cursor->pointer() + offset, view(end_ptr_tag{})};
1392 }
1393
1394 template<typename ResView, typename View>
1395 SBEPP_CPP20_CONSTEXPR ResView get_first_group_view(const View view) noexcept
1396 {
1397 cursor->pointer() =
1398 view(get_level_tag{}) + view(get_block_length_tag{});
1399 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1400
1401 return g;
1402 }
1403
1404 template<typename ResView, typename View>
1405 SBEPP_CPP20_CONSTEXPR ResView get_first_data_view(const View view) noexcept
1406 {
1407 cursor->pointer() =
1408 view(get_level_tag{}) + view(get_block_length_tag{});
1409 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1410
1411 return d;
1412 }
1413
1414 template<typename ResView, typename View, typename Getter>
1415 SBEPP_CPP20_CONSTEXPR ResView
1416 get_group_view(const View view, Getter&& getter) noexcept
1417 {
1418 SBEPP_ASSERT(
1419 (getter()(detail::addressof_tag{}) == cursor->pointer())
1420 && "Wrong cursor value");
1421 return {cursor->pointer(), view(end_ptr_tag{})};
1422 }
1423
1424 template<typename ResView, typename View, typename Getter>
1425 SBEPP_CPP20_CONSTEXPR ResView
1426 get_data_view(const View view, Getter&& getter) noexcept
1427 {
1428 SBEPP_ASSERT(
1429 (getter()(detail::addressof_tag{}) == cursor->pointer())
1430 && "Wrong cursor value");
1431 return {cursor->pointer(), view(end_ptr_tag{})};
1432 }
1433
1434private:
1435 sbepp::cursor<Byte>* cursor{};
1436};
1437
1438template<typename Byte>
1439class skip_cursor_wrapper
1440{
1441public:
1442 using byte_type = Byte;
1443
1444 template<typename T>
1445 using result_type = void;
1446
1447 skip_cursor_wrapper() = default;
1448
1449 explicit constexpr skip_cursor_wrapper(sbepp::cursor<Byte>& cursor)
1450 : cursor{&cursor}
1451 {
1452 }
1453
1454 template<typename T, typename U, endian E, typename View>
1455 SBEPP_CPP20_CONSTEXPR void get_value(
1456 const View view,
1457 const std::size_t offset,
1458 const std::size_t absolute_offset) noexcept
1459 {
1460 SBEPP_ASSERT(
1461 ((view(detail::addressof_tag{}) + absolute_offset)
1462 == (cursor->pointer() + offset))
1463 && "Wrong cursor value");
1464 SBEPP_SIZE_CHECK(
1465 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1466 cursor->pointer() += offset + sizeof(U);
1467 }
1468
1469 template<typename T, typename U, endian E, typename View>
1470 SBEPP_CPP20_CONSTEXPR void get_last_value(
1471 const View view,
1472 const std::size_t offset,
1473 const std::size_t absolute_offset) noexcept
1474 {
1475 SBEPP_ASSERT(
1476 ((view(detail::addressof_tag{}) + absolute_offset)
1477 == (cursor->pointer() + offset))
1478 && "Wrong cursor value");
1479 SBEPP_SIZE_CHECK(
1480 cursor->pointer(), view(end_ptr_tag{}), offset, sizeof(U));
1481 cursor->pointer() =
1482 view(get_level_tag{}) + view(get_block_length_tag{});
1483 }
1484
1485 template<typename Res, typename View>
1486 SBEPP_CPP20_CONSTEXPR void get_static_field_view(
1487 const View view,
1488 const std::size_t offset,
1489 const std::size_t absolute_offset) noexcept
1490 {
1491 SBEPP_ASSERT(
1492 ((view(detail::addressof_tag{}) + absolute_offset)
1493 == (cursor->pointer() + offset))
1494 && "Wrong cursor value");
1495 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1496 Res res{cursor->pointer(), view(end_ptr_tag{})};
1497 cursor->pointer() += offset + res(size_bytes_tag{});
1498 }
1499
1500 template<typename Res, typename View>
1501 SBEPP_CPP20_CONSTEXPR void get_last_static_field_view(
1502 const View view,
1503 const std::size_t offset,
1504 const std::size_t absolute_offset) noexcept
1505 {
1506 SBEPP_ASSERT(
1507 ((view(detail::addressof_tag{}) + absolute_offset)
1508 == (cursor->pointer() + offset))
1509 && "Wrong cursor value");
1510 SBEPP_SIZE_CHECK(cursor->pointer(), view(end_ptr_tag{}), offset, 0);
1511 cursor->pointer() =
1512 view(get_level_tag{}) + view(get_block_length_tag{});
1513 }
1514
1515 template<typename ResView, typename View>
1516 SBEPP_CPP20_CONSTEXPR void get_first_group_view(const View view) noexcept
1517 {
1518 cursor->pointer() =
1519 view(get_level_tag{}) + view(get_block_length_tag{});
1520 ResView g{cursor->pointer(), view(end_ptr_tag{})};
1521 cursor->pointer() += g(size_bytes_tag{});
1522 }
1523
1524 template<typename ResView, typename View>
1525 SBEPP_CPP20_CONSTEXPR void get_first_data_view(const View view) noexcept
1526 {
1527 cursor->pointer() =
1528 view(get_level_tag{}) + view(get_block_length_tag{});
1529 ResView d{cursor->pointer(), view(end_ptr_tag{})};
1530 cursor->pointer() += d(size_bytes_tag{});
1531 }
1532
1533 template<typename ResView, typename View, typename Getter>
1534 SBEPP_CPP20_CONSTEXPR void
1535 get_group_view(const View view, Getter&& getter) noexcept
1536 {
1537 SBEPP_ASSERT(
1538 (getter()(detail::addressof_tag{}) == cursor->pointer())
1539 && "Wrong cursor value");
1540 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1541 cursor->pointer() += res(size_bytes_tag{});
1542 }
1543
1544 template<typename ResView, typename View, typename Getter>
1545 SBEPP_CPP20_CONSTEXPR void
1546 get_data_view(const View view, Getter&& getter) noexcept
1547 {
1548 SBEPP_ASSERT(
1549 (getter()(detail::addressof_tag{}) == cursor->pointer())
1550 && "Wrong cursor value");
1551 ResView res{cursor->pointer(), view(end_ptr_tag{})};
1552 cursor->pointer() += res(size_bytes_tag{});
1553 }
1554
1555private:
1556 sbepp::cursor<Byte>* cursor{};
1557};
1558
1559template<typename Cursor, typename T>
1560using cursor_result_type_t =
1561 typename remove_reference_t<Cursor>::template result_type<T>;
1562
1563template<typename Cursor>
1564using cursor_byte_type_t = typename remove_reference_t<Cursor>::byte_type;
1565
1566template<typename MessageByte, typename CursorByte>
1567using enable_if_cursor_compatible_t =
1568 enable_if_convertible_t<MessageByte, CursorByte>;
1569
1570template<typename MessageByte, typename CursorByte>
1571using enable_if_cursor_writeable_t = enable_if_t<
1572 std::is_convertible<MessageByte*, CursorByte*>::value
1573 && !std::is_const<MessageByte>::value && !std::is_const<CursorByte>::value>;
1574} // namespace detail
1575
1586template<typename T>
1587constexpr std::size_t size_bytes(T v) noexcept
1588{
1589 return v(detail::size_bytes_tag{});
1590}
1591
1601template<typename T, typename Byte>
1602constexpr std::size_t size_bytes(T v, cursor<Byte> c) noexcept
1603{
1604 return v(detail::size_bytes_tag{}, c);
1605}
1606
1613template<typename T>
1614constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
1615{
1616 return v(detail::get_header_tag{});
1617}
1618
1625template<typename T>
1626constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
1627{
1628 return v(detail::addressof_tag{});
1629}
1630
1636template<typename View>
1638{
1640 using type = typename std::remove_pointer<decltype(sbepp::addressof(
1641 std::declval<View>()))>::type;
1642};
1643
1645template<typename View>
1647
1652namespace cursor_ops
1653{
1671template<typename Byte>
1672constexpr detail::init_cursor_wrapper<Byte> init(cursor<Byte>& c) noexcept
1673{
1674 return detail::init_cursor_wrapper<Byte>{c};
1675}
1676
1699template<typename Byte>
1700constexpr detail::dont_move_cursor_wrapper<Byte>
1702{
1703 return detail::dont_move_cursor_wrapper<Byte>{c};
1704}
1705
1713template<typename Byte>
1714constexpr detail::init_dont_move_cursor_wrapper<Byte>
1716{
1717 return detail::init_dont_move_cursor_wrapper<Byte>{c};
1718}
1719
1734template<typename Byte>
1735constexpr detail::skip_cursor_wrapper<Byte> skip(cursor<Byte>& c) noexcept
1736{
1737 return detail::skip_cursor_wrapper<Byte>{c};
1738}
1739} // namespace cursor_ops
1740
1741namespace detail
1742{
1743// the only purpose of this class is to implement `is_composite` trait
1745template<typename Byte>
1746class composite_base : public byte_range<Byte>
1747{
1748public:
1749 using byte_range<Byte>::byte_range;
1750 using byte_range<Byte>::operator();
1751};
1752
1754template<typename Byte, typename Header>
1755class message_base : public byte_range<Byte>
1756{
1757public:
1758 using byte_range<Byte>::byte_range;
1759 using byte_range<Byte>::operator();
1760
1761 SBEPP_CPP14_CONSTEXPR Header operator()(get_header_tag) const noexcept
1762 {
1763 Header header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
1764 SBEPP_SIZE_CHECK(
1765 (*this)(addressof_tag{}),
1766 (*this)(end_ptr_tag{}),
1767 0,
1768 sbepp::size_bytes(header));
1769 return header;
1770 }
1771
1772 SBEPP_CPP14_CONSTEXPR Byte* operator()(get_level_tag) const noexcept
1773 {
1774 auto header = (*this)(get_header_tag{});
1775 return header(addressof_tag{}) + header(size_bytes_tag{});
1776 }
1777
1778 constexpr typename std::decay<
1779 decltype(std::declval<Header>().blockLength().value())>::type
1780 operator()(get_block_length_tag) const noexcept
1781 {
1782 return operator()(get_header_tag{}).blockLength().value();
1783 }
1784
1785 template<
1786 typename Byte2,
1787 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
1788 SBEPP_CPP20_CONSTEXPR std::size_t
1789 operator()(size_bytes_tag, cursor<Byte2>& c) const noexcept
1790 {
1791 return c.pointer() - (*this)(addressof_tag{});
1792 }
1793};
1794
1796template<typename Byte, typename BlockLengthType>
1797class entry_base : public byte_range<Byte>
1798{
1799public:
1800 using byte_range<Byte>::operator();
1801
1802 template<typename Byte2, typename BlockLengthType2>
1803 friend class entry_base;
1804
1806 entry_base() = default;
1807
1809 constexpr entry_base(
1810 Byte* ptr, Byte* end, BlockLengthType block_length) noexcept
1811 : byte_range<Byte>{ptr, end}, block_length{block_length}
1812 {
1813 }
1814
1816 constexpr entry_base(
1817 Byte* ptr,
1818 const std::size_t size,
1819 const BlockLengthType block_length) noexcept
1820 : entry_base{ptr, ptr + size, block_length}
1821 {
1822 }
1823
1825 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1826 constexpr entry_base(
1827 cursor<Byte2>& c, Byte* end_ptr, BlockLengthType block_length) noexcept
1828 : entry_base{c.pointer(), end_ptr, block_length}
1829 {
1830 // forwards to the above one for non-empty entries. Empty entries have
1831 // implementation in the derived class which advances cursor up to
1832 // `block_length`.
1833 }
1834
1837 template<typename Byte2, typename = enable_if_convertible_t<Byte2, Byte>>
1838 constexpr entry_base(
1839 const entry_base<Byte2, BlockLengthType>& other) noexcept
1840 : byte_range<Byte>{other}, block_length{other.block_length}
1841 {
1842 }
1843
1844 constexpr BlockLengthType operator()(get_block_length_tag) const noexcept
1845 {
1846 return block_length;
1847 }
1848
1849 constexpr Byte* operator()(get_level_tag) const noexcept
1850 {
1851 return (*this)(addressof_tag{});
1852 }
1853
1854private:
1855 BlockLengthType block_length{};
1856};
1857
1858template<typename Entry>
1859class arrow_proxy
1860{
1861public:
1862 explicit constexpr arrow_proxy(Entry entry) noexcept : entry{entry}
1863 {
1864 }
1865
1866 constexpr const Entry* operator->() const noexcept
1867 {
1868 return &entry;
1869 }
1870
1871private:
1872 Entry entry;
1873};
1874
1875template<
1876 typename Byte,
1877 typename ValueType,
1878 typename IndexType,
1879 typename DifferenceType,
1880 typename BlockLengthType>
1881class forward_iterator
1882{
1883public:
1884 using iterator_category = std::forward_iterator_tag;
1885 using value_type = ValueType;
1886 using reference = value_type;
1887 using difference_type = DifferenceType;
1888 using pointer = arrow_proxy<value_type>;
1889
1890 forward_iterator() = default;
1891
1892 SBEPP_CPP14_CONSTEXPR forward_iterator(
1893 Byte* ptr,
1894 const IndexType index,
1895 const BlockLengthType block_length,
1896 Byte* end) noexcept
1897 : ptr{ptr},
1898 index{index},
1899 block_length{block_length}
1900#if SBEPP_SIZE_CHECKS_ENABLED
1901 ,
1902 end{end}
1903#endif
1904 {
1905 (void)end;
1906 }
1907
1908 constexpr reference operator*() const noexcept
1909 {
1910#if SBEPP_SIZE_CHECKS_ENABLED
1911 return {ptr, end, block_length};
1912#else
1913 return {ptr, nullptr, block_length};
1914#endif
1915 }
1916
1917 constexpr pointer operator->() const noexcept
1918 {
1919 return pointer{operator*()};
1920 }
1921
1922 SBEPP_CPP14_CONSTEXPR forward_iterator& operator++() noexcept
1923 {
1924 SBEPP_SIZE_CHECK(ptr, end, 0, sbepp::size_bytes(operator*()));
1925 ptr += sbepp::size_bytes(operator*());
1926 index++;
1927 return *this;
1928 }
1929
1930 SBEPP_CPP14_CONSTEXPR forward_iterator operator++(int) noexcept
1931 {
1932 auto old = *this;
1933 operator++();
1934 return old;
1935 }
1936
1937 friend constexpr bool operator==(
1938 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1939 {
1940 return lhs.index == rhs.index;
1941 }
1942
1943 friend constexpr bool operator!=(
1944 const forward_iterator& lhs, const forward_iterator& rhs) noexcept
1945 {
1946 return lhs.index != rhs.index;
1947 }
1948
1949private:
1950 Byte* ptr{};
1951 IndexType index{};
1952 BlockLengthType block_length{};
1953#if SBEPP_SIZE_CHECKS_ENABLED
1954 Byte* end{};
1955#endif
1956};
1957
1958template<
1959 typename Byte,
1960 typename ValueType,
1961 typename BlockLengthType,
1962 typename DifferenceType,
1963 typename IndexType>
1964class random_access_iterator
1965{
1966public:
1967 using iterator_category = std::random_access_iterator_tag;
1968 using value_type = ValueType;
1969 using reference = value_type;
1970 using difference_type = DifferenceType;
1971 using pointer = arrow_proxy<value_type>;
1972
1973 random_access_iterator() = default;
1974
1975 SBEPP_CPP14_CONSTEXPR random_access_iterator(
1976 Byte* ptr,
1977 const BlockLengthType block_length,
1978 const IndexType index,
1979 Byte* end) noexcept
1980 : ptr{ptr},
1981 block_length{block_length},
1982 index{index}
1983#if SBEPP_SIZE_CHECKS_ENABLED
1984 ,
1985 end{end}
1986#endif
1987 {
1988 (void)end;
1989 }
1990
1991 constexpr reference operator*() const noexcept
1992 {
1993#if SBEPP_SIZE_CHECKS_ENABLED
1994 return {ptr, end, block_length};
1995#else
1996 return {ptr, nullptr, block_length};
1997#endif
1998 }
1999
2000 constexpr pointer operator->() const noexcept
2001 {
2002 return pointer{operator*()};
2003 }
2004
2005 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator++() noexcept
2006 {
2007 SBEPP_SIZE_CHECK(ptr, end, 0, block_length);
2008 ptr += block_length;
2009 index++;
2010 return *this;
2011 }
2012
2013 SBEPP_CPP14_CONSTEXPR random_access_iterator operator++(int) noexcept
2014 {
2015 auto old = *this;
2016 operator++();
2017 return old;
2018 }
2019
2020 SBEPP_CPP14_CONSTEXPR random_access_iterator& operator--() noexcept
2021 {
2022 ptr -= block_length;
2023 index--;
2024 return *this;
2025 }
2026
2027 SBEPP_CPP14_CONSTEXPR random_access_iterator operator--(int) noexcept
2028 {
2029 auto old = *this;
2030 operator--();
2031 return old;
2032 }
2033
2034 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2035 operator+=(difference_type n) noexcept
2036 {
2037 ptr += n * block_length;
2038 index += n;
2039 return *this;
2040 }
2041
2042 SBEPP_CPP14_CONSTEXPR random_access_iterator
2043 operator+(difference_type n) const noexcept
2044 {
2045 auto tmp = *this;
2046 return tmp += n;
2047 }
2048
2049 friend constexpr random_access_iterator
2050 operator+(difference_type n, const random_access_iterator& it) noexcept
2051 {
2052 return it + n;
2053 }
2054
2055 SBEPP_CPP14_CONSTEXPR random_access_iterator&
2056 operator-=(difference_type n) noexcept
2057 {
2058 return *this += -n;
2059 }
2060
2061 SBEPP_CPP14_CONSTEXPR random_access_iterator
2062 operator-(difference_type n) const noexcept
2063 {
2064 auto tmp = *this;
2065 return tmp -= n;
2066 }
2067
2068 constexpr difference_type
2069 operator-(const random_access_iterator& rhs) const noexcept
2070 {
2071 return index - rhs.index;
2072 }
2073
2074 constexpr reference operator[](difference_type n) const noexcept
2075 {
2076 return *(*this + n);
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
2114 friend constexpr bool operator>=(
2115 const random_access_iterator& lhs,
2116 const random_access_iterator& rhs) noexcept
2117 {
2118 return lhs.index >= rhs.index;
2119 }
2120
2121private:
2122 Byte* ptr{};
2123 BlockLengthType block_length{};
2124 // iterator should be index-based instead of just pointer-based to support
2125 // groups with empty entries, i.e. when `block_length == 0`
2126 IndexType index{};
2127#if SBEPP_SIZE_CHECKS_ENABLED
2128 Byte* end{};
2129#endif
2130};
2131
2132template<
2133 typename ValueType,
2134 typename IndexType,
2135 typename CursorType,
2136 typename BlockLengthType,
2137 typename Byte>
2138class input_iterator
2139{
2140public:
2141 using iterator_category = std::input_iterator_tag;
2142 using value_type = ValueType;
2143 using reference = value_type;
2144 using difference_type = typename std::make_signed<IndexType>::type;
2145 using pointer = arrow_proxy<value_type>;
2146
2147 input_iterator() = default;
2148
2149 SBEPP_CPP14_CONSTEXPR input_iterator(
2150 const IndexType index,
2151 CursorType* cursor,
2152 BlockLengthType block_length,
2153 Byte* end) noexcept
2154 : index{index},
2155 cursor{cursor},
2156 block_length{block_length}
2157#if SBEPP_SIZE_CHECKS_ENABLED
2158 ,
2159 end{end}
2160#endif
2161 {
2162 (void)end;
2163 }
2164
2165 constexpr reference operator*() const noexcept
2166 {
2167#if SBEPP_SIZE_CHECKS_ENABLED
2168 return {*cursor, end, block_length};
2169#else
2170 return {*cursor, nullptr, block_length};
2171#endif
2172 }
2173
2174 constexpr pointer operator->() const noexcept
2175 {
2176 return pointer{operator*()};
2177 }
2178
2179 SBEPP_CPP14_CONSTEXPR input_iterator& operator++() noexcept
2180 {
2181 index++;
2182 return *this;
2183 }
2184
2185 SBEPP_CPP14_CONSTEXPR input_iterator operator++(int) noexcept
2186 {
2187 auto old = *this;
2188 operator++();
2189 return old;
2190 }
2191
2192 friend constexpr bool operator==(
2193 const input_iterator& lhs, const input_iterator& rhs) noexcept
2194 {
2195 return lhs.index == rhs.index;
2196 }
2197
2198 friend constexpr bool operator!=(
2199 const input_iterator& lhs, const input_iterator& rhs) noexcept
2200 {
2201 return lhs.index != rhs.index;
2202 }
2203
2204private:
2205 IndexType index{};
2206 CursorType* cursor{};
2207 BlockLengthType block_length{};
2208#if SBEPP_SIZE_CHECKS_ENABLED
2209 Byte* end{};
2210#endif
2211};
2212
2213template<
2214 typename ValueType,
2215 typename IndexType,
2216 typename CursorType,
2217 typename BlockLengthType,
2218 typename Byte>
2219class cursor_range
2220{
2221public:
2222 SBEPP_CPP14_CONSTEXPR cursor_range(
2223 CursorType& cursor,
2224 BlockLengthType block_length,
2225 Byte* end,
2226 IndexType start_pos,
2227 IndexType length) noexcept
2228 : cursor{&cursor},
2229 block_length{block_length},
2230 start_pos{start_pos},
2231#if SBEPP_SIZE_CHECKS_ENABLED
2232 end_ptr{end},
2233#endif
2234 length{length}
2235 {
2236 (void)end;
2237 }
2238
2239 using iterator =
2240 input_iterator<ValueType, IndexType, CursorType, BlockLengthType, Byte>;
2241
2242 constexpr iterator begin() const noexcept
2243 {
2244#if SBEPP_SIZE_CHECKS_ENABLED
2245 return {start_pos, cursor, block_length, end_ptr};
2246#else
2247 return {start_pos, cursor, block_length, nullptr};
2248#endif
2249 }
2250
2251 constexpr iterator end() const noexcept
2252 {
2253#if SBEPP_SIZE_CHECKS_ENABLED
2254 return {
2255 static_cast<IndexType>(start_pos + size()),
2256 cursor,
2257 block_length,
2258 end_ptr};
2259#else
2260 return {
2261 static_cast<IndexType>(start_pos + size()),
2262 cursor,
2263 block_length,
2264 nullptr};
2265#endif
2266 }
2267
2268 constexpr IndexType size() const noexcept
2269 {
2270 return length;
2271 }
2272
2273private:
2274 CursorType* cursor{};
2275 BlockLengthType block_length{};
2276 IndexType start_pos{};
2277#if SBEPP_SIZE_CHECKS_ENABLED
2278 Byte* end_ptr{};
2279#endif
2280 IndexType length{};
2281};
2282
2284template<typename Byte, typename Entry, typename Dimension>
2285class flat_group_base : public byte_range<Byte>
2286{
2287public:
2289 using value_type = Entry;
2293 using sbe_size_type = typename std::decay<
2294 decltype(std::declval<Dimension>().numInGroup())>::type;
2296 using size_type = typename sbe_size_type::value_type;
2298 using difference_type = typename std::make_signed<size_type>::type;
2301 using iterator = random_access_iterator<
2302 Byte,
2303 Entry,
2304 typename std::decay<
2305 decltype(std::declval<Dimension>().blockLength().value())>::type,
2307 size_type>;
2308
2309 using byte_range<Byte>::byte_range;
2310 using byte_range<Byte>::operator();
2311
2312 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2313 {
2314 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2315 SBEPP_SIZE_CHECK(
2316 (*this)(addressof_tag{}),
2317 (*this)(end_ptr_tag{}),
2318 0,
2319 sbepp::size_bytes(header));
2320 return header;
2321 }
2322
2323 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2324 {
2325 auto dimension = (*this)(get_header_tag{});
2326 return sbepp::size_bytes(dimension)
2327 + dimension.numInGroup().value()
2328 * dimension.blockLength().value();
2329 }
2330
2332 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2333 {
2334 return (*this)(get_header_tag{}).numInGroup();
2335 }
2336
2338 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2339 {
2340 return sbe_size().value();
2341 }
2342
2344 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2345 {
2346 (*this)(get_header_tag{}).numInGroup(count);
2347 }
2348
2350 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2351 {
2352 return !size();
2353 }
2354
2356 constexpr static size_type max_size() noexcept
2357 {
2358 return sbe_size_type::max_value();
2359 }
2360
2362 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2363 {
2364 auto dimension = (*this)(get_header_tag{});
2365 return iterator{
2366 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2367 dimension.blockLength().value(),
2368 0,
2369 (*this)(end_ptr_tag{})};
2370 }
2371
2373 constexpr iterator end() const noexcept
2374 {
2375 return iterator{
2376 (*this)(addressof_tag{}) + (*this)(size_bytes_tag{}),
2377 (*this)(get_header_tag{}).blockLength().value(),
2378 size(),
2379 (*this)(end_ptr_tag{})};
2380 }
2381
2384 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
2385 {
2386 SBEPP_ASSERT(pos < size());
2387 return *(begin() + pos);
2388 }
2389
2392 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2393 {
2394 SBEPP_ASSERT(!empty());
2395 return *begin();
2396 }
2397
2400 SBEPP_CPP14_CONSTEXPR reference back() const noexcept
2401 {
2402 SBEPP_ASSERT(!empty());
2403 return *(--end());
2404 }
2405
2408 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2409 {
2410 resize(0);
2411 }
2412
2414 template<typename Byte2>
2415 using cursor_range_t = detail::cursor_range<
2416 value_type,
2417 size_type,
2419 typename std::decay<
2420 decltype(std::declval<Dimension>().blockLength().value())>::type,
2421 Byte>;
2422
2424 template<
2425 typename Byte2,
2426 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2427 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2428 cursor_range(cursor<Byte2>& c) const noexcept
2429 {
2430 return {
2431 c,
2432 (*this)(get_header_tag{}).blockLength().value(),
2433 (*this)(end_ptr_tag{}),
2434 0,
2435 size()};
2436 }
2437
2440 template<
2441 typename Byte2,
2442 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2443 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2444 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2445 {
2446 SBEPP_ASSERT(pos < size());
2447
2448 return {
2449 c,
2450 (*this)(get_header_tag{}).blockLength().value(),
2451 (*this)(end_ptr_tag{}),
2452 pos,
2453 static_cast<size_type>(size() - pos)};
2454 }
2455
2459 template<
2460 typename Byte2,
2461 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2463 cursor<Byte2>& c,
2464 const size_type pos,
2465 const size_type count) const noexcept
2466 {
2467 SBEPP_ASSERT(pos < size());
2468 SBEPP_ASSERT(count <= (size() - pos));
2469
2470 return {
2471 c,
2472 (*this)(get_header_tag{}).blockLength().value(),
2473 (*this)(end_ptr_tag{}),
2474 pos,
2475 count};
2476 }
2477
2479 template<typename Byte2>
2480 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2481
2483 template<
2484 typename Byte2,
2485 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2486 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2487 cursor_begin(cursor<Byte2>& c) const noexcept
2488 {
2489 return cursor_range(c).begin();
2490 }
2491
2493 template<
2494 typename Byte2,
2495 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2496 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2497 cursor_end(cursor<Byte2>& c) const noexcept
2498 {
2499 return cursor_range(c).end();
2500 }
2501
2502 template<typename Visitor, typename Cursor>
2503 SBEPP_CPP14_CONSTEXPR bool
2504 operator()(visit_children_tag, Visitor& v, Cursor& c)
2505 {
2506 for(const auto entry : this->cursor_range(c))
2507 {
2508 if(v.template on_entry(entry, c))
2509 {
2510 return true;
2511 }
2512 }
2513 return false;
2514 }
2515};
2516
2518template<typename Byte, typename Entry, typename Dimension>
2519class nested_group_base : public byte_range<Byte>
2520{
2521public:
2523 using value_type = Entry;
2527 using sbe_size_type = typename std::decay<
2528 decltype(std::declval<Dimension>().numInGroup())>::type;
2530 using size_type = typename sbe_size_type::value_type;
2532 using difference_type = typename std::make_signed<size_type>::type;
2533
2536 using iterator = forward_iterator<
2537 Byte,
2538 Entry,
2539 size_type,
2541 typename std::decay<
2542 decltype(std::declval<Dimension>().blockLength().value())>::type>;
2543
2544 using byte_range<Byte>::byte_range;
2545 using byte_range<Byte>::operator();
2546
2547 SBEPP_CPP14_CONSTEXPR Dimension operator()(get_header_tag) const noexcept
2548 {
2549 Dimension header{(*this)(addressof_tag{}), (*this)(end_ptr_tag{})};
2550 SBEPP_SIZE_CHECK(
2551 (*this)(addressof_tag{}),
2552 (*this)(end_ptr_tag{}),
2553 0,
2554 sbepp::size_bytes(header));
2555 return header;
2556 }
2557
2558 SBEPP_CPP20_CONSTEXPR std::size_t operator()(size_bytes_tag) const noexcept
2559 {
2560 std::size_t size{sbepp::size_bytes((*this)(get_header_tag{}))};
2561 for(const auto entry : *this)
2562 {
2563 size += sbepp::size_bytes(entry);
2564 }
2565
2566 return size;
2567 }
2568
2570 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
2571 {
2572 return (*this)(get_header_tag{}).numInGroup();
2573 }
2574
2576 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
2577 {
2578 return sbe_size().value();
2579 }
2580
2582 SBEPP_CPP20_CONSTEXPR void resize(const size_type count) const noexcept
2583 {
2584 (*this)(get_header_tag{}).numInGroup(count);
2585 }
2586
2588 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
2589 {
2590 return !size();
2591 }
2592
2594 constexpr static size_type max_size() noexcept
2595 {
2596 return sbe_size_type::max_value();
2597 }
2598
2600 SBEPP_CPP14_CONSTEXPR iterator begin() const noexcept
2601 {
2602 auto dimension = (*this)(get_header_tag{});
2603 return iterator{
2604 (*this)(addressof_tag{}) + sbepp::size_bytes(dimension),
2605 0,
2606 dimension.blockLength().value(),
2607 (*this)(end_ptr_tag{})};
2608 }
2609
2611 constexpr iterator end() const noexcept
2612 {
2613 return iterator{
2614 nullptr,
2615 (*this)(get_header_tag{}).numInGroup().value(),
2616 (*this)(get_header_tag{}).blockLength().value(),
2617 (*this)(end_ptr_tag{})};
2618 }
2619
2622 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
2623 {
2624 SBEPP_ASSERT(!empty());
2625 return *begin();
2626 }
2627
2630 SBEPP_CPP14_CONSTEXPR void clear() const noexcept
2631 {
2632 resize(0);
2633 }
2634
2636 template<typename Byte2>
2637 using cursor_range_t = detail::cursor_range<
2638 value_type,
2639 size_type,
2641 typename std::decay<
2642 decltype(std::declval<Dimension>().blockLength().value())>::type,
2643 Byte>;
2644
2646 template<
2647 typename Byte2,
2648 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2649 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2650 cursor_range(cursor<Byte2>& c) const noexcept
2651 {
2652 return {
2653 c,
2654 (*this)(get_header_tag{}).blockLength().value(),
2655 (*this)(end_ptr_tag{}),
2656 0,
2657 size()};
2658 }
2659
2662 template<
2663 typename Byte2,
2664 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2665 SBEPP_CPP20_CONSTEXPR cursor_range_t<Byte2>
2666 cursor_subrange(cursor<Byte2>& c, const size_type pos) const noexcept
2667 {
2668 SBEPP_ASSERT(pos < size());
2669
2670 return {
2671 c,
2672 (*this)(get_header_tag{}).blockLength().value(),
2673 (*this)(end_ptr_tag{}),
2674 pos,
2675 static_cast<size_type>(size() - pos)};
2676 }
2677
2681 template<
2682 typename Byte2,
2683 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2685 cursor<Byte2>& c,
2686 const size_type pos,
2687 const size_type count) const noexcept
2688 {
2689 SBEPP_ASSERT(pos < size());
2690 SBEPP_ASSERT(count <= (size() - pos));
2691
2692 return {
2693 c,
2694 (*this)(get_header_tag{}).blockLength().value(),
2695 (*this)(end_ptr_tag{}),
2696 pos,
2697 count};
2698 }
2699
2701 template<typename Byte2>
2702 using cursor_iterator = typename cursor_range_t<Byte2>::iterator;
2703
2705 template<
2706 typename Byte2,
2707 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2708 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2709 cursor_begin(cursor<Byte2>& c) const noexcept
2710 {
2711 return cursor_range(c).begin();
2712 }
2713
2715 template<
2716 typename Byte2,
2717 typename = enable_if_cursor_compatible_t<Byte, Byte2>>
2718 SBEPP_CPP20_CONSTEXPR cursor_iterator<Byte2>
2719 cursor_end(cursor<Byte2>& c) const noexcept
2720 {
2721 return cursor_range(c).end();
2722 }
2723
2724 template<typename Visitor, typename Cursor>
2725 SBEPP_CPP14_CONSTEXPR bool
2726 operator()(visit_children_tag, Visitor& v, Cursor& c)
2727 {
2728 for(const auto entry : this->cursor_range(c))
2729 {
2730 if(v.template on_entry(entry, c))
2731 {
2732 return true;
2733 }
2734 }
2735 return false;
2736 }
2737};
2738
2741template<typename T>
2743{
2744public:
2746 bitset_base() = default;
2747
2749 explicit constexpr bitset_base(T value) noexcept : bits{value}
2750 {
2751 }
2752
2754 SBEPP_CPP14_CONSTEXPR T& operator*() noexcept
2755 {
2756 return bits;
2757 }
2758
2760 constexpr T operator*() const noexcept
2761 {
2762 return bits;
2763 }
2764
2765 constexpr bool
2766 operator()(get_bit_tag, const choice_index_t n) const noexcept
2767 {
2768 return bits & (1 << n);
2769 }
2770
2771 SBEPP_CPP14_CONSTEXPR void
2772 operator()(set_bit_tag, const choice_index_t n, const bool b) noexcept
2773 {
2774 bits = ((bits & ~(1 << n)) | (b << n));
2775 }
2776
2778 constexpr friend bool
2779 operator==(const bitset_base& lhs, const bitset_base& rhs) noexcept
2780 {
2781 return *lhs == *rhs;
2782 }
2783
2785 constexpr friend bool
2786 operator!=(const bitset_base& lhs, const bitset_base& rhs) noexcept
2787 {
2788 return *lhs != *rhs;
2789 }
2790
2791private:
2792 T bits{};
2793};
2794
2795template<typename View, typename = void_t<>>
2796struct has_get_header : std::false_type
2797{
2798};
2799
2800template<typename View>
2801struct has_get_header<
2802 View,
2803 void_t<decltype(sbepp::get_header(std::declval<View>()))>> : std::true_type
2804{
2805};
2806
2807template<
2808 typename View,
2809 typename = detail::enable_if_t<detail::has_get_header<View>::value>>
2810constexpr std::size_t get_header_size(View view) noexcept
2811{
2813}
2814
2815template<
2816 typename View,
2817 typename = detail::enable_if_t<!detail::has_get_header<View>::value>,
2818 typename = int>
2819constexpr std::size_t get_header_size(View) noexcept
2820{
2821 return 0;
2822}
2823} // namespace detail
2824
2832template<typename Enum>
2833constexpr typename std::underlying_type<Enum>::type
2834 to_underlying(Enum e) noexcept
2835{
2836 return static_cast<typename std::underlying_type<Enum>::type>(e);
2837}
2838
2852template<typename View>
2853SBEPP_CPP14_CONSTEXPR cursor<byte_type_t<View>> init_cursor(View view) noexcept
2854{
2856 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2857 return c;
2858}
2859
2874template<typename View>
2875SBEPP_CPP14_CONSTEXPR cursor<typename std::add_const<byte_type_t<View>>::type>
2876 init_const_cursor(View view) noexcept
2877{
2879 c.pointer() = sbepp::addressof(view) + detail::get_header_size(view);
2880 return c;
2881}
2882
2888{
2889 explicit default_init_t() = default;
2890};
2891
2897SBEPP_CPP17_INLINE_VAR constexpr default_init_t default_init{};
2898
2901enum class eos_null
2902{
2905 none,
2909 single,
2911 all
2912};
2913
2914namespace detail
2915{
2916template<typename From, typename To>
2917struct copy_cv_qualifiers
2918{
2919 using copy_const_t = typename std::
2920 conditional<std::is_const<From>::value, const To, To>::type;
2921
2922 using type = typename std::conditional<
2923 std::is_volatile<From>::value,
2924 volatile copy_const_t,
2925 copy_const_t>::type;
2926};
2927
2928template<typename From, typename To>
2929using apply_cv_qualifiers_t = typename copy_cv_qualifiers<From, To>::type;
2930
2931#if SBEPP_HAS_RANGES
2932template<typename R>
2933using is_range = std::bool_constant<std::ranges::range<R>>;
2934#else
2935template<typename R, typename = void_t<>>
2936struct is_range : std::false_type
2937{
2938};
2939
2940template<typename R>
2941struct is_range<
2942 R,
2943 void_t<
2944 decltype(std::begin(std::declval<R>())),
2945 decltype(std::end(std::declval<R>()))>> : std::true_type
2946{
2947};
2948#endif
2949
2950constexpr bool is_constant_evaluated() noexcept
2951{
2952 // it's possible to use `__builtin_is_constant_evaluated` with lower C++
2953 // versions but I see no reason for this since it's only used for
2954 // `assign_string` and other accessors are not be `constexpr` until C++20
2955#if SBEPP_HAS_IS_CONSTANT_EVALUATED
2956 return std::is_constant_evaluated();
2957#else
2958 return false;
2959#endif
2960}
2961
2962inline SBEPP_CPP20_CONSTEXPR std::size_t string_length(const char* str) noexcept
2963{
2964 if(is_constant_evaluated())
2965 {
2966 std::size_t length{};
2967 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2968 for(; *str != '\0'; str++, length++)
2969 {
2970 }
2971
2972 return length;
2973 }
2974 else
2975 {
2976 return std::strlen(str);
2977 }
2978}
2979
2987template<typename Byte, typename Value, std::size_t N, typename Tag>
2989{
2990public:
2993 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
2995 using value_type = Value;
2997 using size_type = std::size_t;
2999 using difference_type = std::ptrdiff_t;
3007 using reverse_iterator = std::reverse_iterator<iterator>;
3009 using tag = Tag;
3010
3011 using detail::byte_range<Byte>::byte_range;
3012 using detail::byte_range<Byte>::operator();
3013
3014 constexpr std::size_t operator()(detail::size_bytes_tag) const noexcept
3015 {
3016 return size();
3017 }
3018
3021 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3022 {
3023 SBEPP_ASSERT(pos < size());
3024 return data()[pos];
3025 }
3026
3028 constexpr reference front() const noexcept
3029 {
3030 return *data();
3031 }
3032
3034 constexpr reference back() const noexcept
3035 {
3036 return data()[size() - 1];
3037 }
3038
3040 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3041 {
3042 // it would be nice to use `reinterpret_cast` here but it's not allowed
3043 // in constexpr context
3044 SBEPP_SIZE_CHECK(
3045 (*this)(detail::addressof_tag{}),
3046 (*this)(detail::end_ptr_tag{}),
3047 0,
3048 N);
3049 return (pointer)(*this)(detail::addressof_tag{}); // NOLINT
3050 }
3051
3053 SBEPP_CPP17_NODISCARD static constexpr bool empty() noexcept
3054 {
3055 return !size();
3056 }
3057
3059 static constexpr size_type size() noexcept
3060 {
3061 return N;
3062 }
3063
3065 static constexpr size_type max_size() noexcept
3066 {
3067 return size();
3068 }
3069
3071 constexpr iterator begin() const noexcept
3072 {
3073 return data();
3074 }
3075
3077 constexpr iterator end() const noexcept
3078 {
3079 return data() + size();
3080 }
3081
3083 constexpr reverse_iterator rbegin() const noexcept
3084 {
3085 return reverse_iterator{end()};
3086 }
3087
3089 constexpr reverse_iterator rend() const noexcept
3090 {
3091 return reverse_iterator{begin()};
3092 }
3093
3106 raw() const noexcept
3107 {
3109 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3110 }
3111
3118 SBEPP_CPP20_CONSTEXPR std::size_t strlen() const noexcept
3119 {
3120 if(is_constant_evaluated())
3121 {
3122 return string_length(data());
3123 }
3124 else
3125 {
3126 const auto first_null = static_cast<const value_type*>(
3127 std::memchr(data(), '\0', size()));
3128 if(first_null)
3129 {
3130 return first_null - data();
3131 }
3132
3133 return size();
3134 }
3135 }
3136
3143 SBEPP_CPP20_CONSTEXPR std::size_t strlen_r() const noexcept
3144 {
3145 const auto last_non_null = std::find_if(
3146 rbegin(),
3147 rend(),
3148 [](const value_type value)
3149 {
3150 return value != '\0';
3151 });
3152 return size() - (last_non_null - rbegin());
3153 }
3154
3166 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3167 SBEPP_CPP20_CONSTEXPR iterator assign_string(
3168 const char* str, const eos_null eos_mode = eos_null::all) const noexcept
3169 {
3170 SBEPP_ASSERT(str != nullptr);
3171 const auto length = string_length(str);
3172 SBEPP_ASSERT(length <= size());
3173 const auto eos_pos = std::copy_n(str, length, begin());
3174 pad(eos_mode, eos_pos);
3175 return eos_pos;
3176 }
3177
3190 template<
3191 typename R,
3192 typename =
3193 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3194 SBEPP_CPP20_CONSTEXPR iterator
3195 assign_string(R&& r, const eos_null eos_mode = eos_null::all) const
3196 {
3197 auto eos_pos = assign_range(std::forward<R>(r));
3198 pad(eos_mode, eos_pos);
3199 return eos_pos;
3200 }
3201
3211 template<
3212 typename R,
3213 typename =
3214 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3215 SBEPP_CPP20_CONSTEXPR iterator assign_range(R&& r) const
3216 {
3217#if SBEPP_HAS_RANGES
3218 auto res = std::ranges::copy(std::forward<R>(r), begin()).out;
3219#else
3220 auto res = std::copy(std::begin(r), std::end(r), begin());
3221#endif
3222 SBEPP_ASSERT(res <= end());
3223 return res;
3224 }
3225
3231 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3232 SBEPP_CPP20_CONSTEXPR void fill(const value_type value) const noexcept
3233 {
3234 std::fill_n(begin(), size(), value);
3235 }
3236
3245 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3246 SBEPP_CPP20_CONSTEXPR iterator
3247 assign(size_type count, const value_type value) const noexcept
3248 {
3249 SBEPP_ASSERT(count <= size());
3250 return std::fill_n(begin(), count, value);
3251 }
3252
3256 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3257 SBEPP_CPP20_CONSTEXPR iterator assign(InputIt first, InputIt last) const
3258 {
3259 const auto last_out = std::copy(first, last, begin());
3260 SBEPP_ASSERT(static_cast<size_type>(last_out - begin()) <= size());
3261 return last_out;
3262 }
3263
3271 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3272 SBEPP_CPP20_CONSTEXPR iterator
3273 assign(std::initializer_list<value_type> ilist) const noexcept
3274 {
3275 SBEPP_ASSERT(ilist.size() <= size());
3276 return assign(std::begin(ilist), std::end(ilist));
3277 }
3278
3279private:
3280 SBEPP_CPP20_CONSTEXPR void
3281 pad(const eos_null mode, iterator eos_pos) const noexcept
3282 {
3283 if(mode == eos_null::all)
3284 {
3285 std::fill(eos_pos, end(), '\0');
3286 }
3287 else if(mode == eos_null::single)
3288 {
3289 if(eos_pos != end())
3290 {
3291 *eos_pos = '\0';
3292 }
3293 }
3294 else
3295 {
3296 SBEPP_ASSERT(mode == eos_null::none);
3297 return;
3298 }
3299 }
3300};
3301
3309template<typename Byte, typename Value, typename Length, endian E>
3311{
3312public:
3313 static_assert(
3314 std::is_unsigned<typename Length::value_type>::value,
3315 "Length must be unsigned");
3316
3319 using element_type = detail::apply_cv_qualifiers_t<Byte, Value>;
3321 using value_type = Value;
3323 using sbe_size_type = Length;
3325 using size_type = typename sbe_size_type::value_type;
3327 using difference_type = std::ptrdiff_t;
3335 using reverse_iterator = std::reverse_iterator<iterator>;
3336
3337 using detail::byte_range<Byte>::byte_range;
3338 using detail::byte_range<Byte>::operator();
3339
3341 constexpr iterator begin() const noexcept
3342 {
3343 return data_checked();
3344 }
3345
3347 SBEPP_CPP20_CONSTEXPR iterator end() const noexcept
3348 {
3349 return begin() + size();
3350 }
3351
3353 SBEPP_CPP20_CONSTEXPR reverse_iterator rbegin() const noexcept
3354 {
3355 return reverse_iterator{end()};
3356 }
3357
3359 constexpr reverse_iterator rend() const noexcept
3360 {
3361 return reverse_iterator{begin()};
3362 }
3363
3366 SBEPP_CPP14_CONSTEXPR reference front() const noexcept
3367 {
3368 SBEPP_ASSERT(!empty());
3369 return *data();
3370 }
3371
3374 SBEPP_CPP20_CONSTEXPR reference back() const noexcept
3375 {
3376 SBEPP_ASSERT(!empty());
3377 return *(data() + size() - 1);
3378 }
3379
3387 SBEPP_CPP14_CONSTEXPR pointer data() const noexcept
3388 {
3389 return data_checked();
3390 }
3391
3394 SBEPP_CPP14_CONSTEXPR reference operator[](size_type pos) const noexcept
3395 {
3396 SBEPP_ASSERT(pos < size());
3397 return *(data() + pos);
3398 }
3399
3401 SBEPP_CPP20_CONSTEXPR sbe_size_type sbe_size() const noexcept
3402 {
3403 return detail::get_value<size_type, size_type, E>(*this, 0);
3404 }
3405
3407 SBEPP_CPP20_CONSTEXPR size_type size() const noexcept
3408 {
3409 return sbe_size().value();
3410 }
3411
3413 SBEPP_CPP17_NODISCARD SBEPP_CPP20_CONSTEXPR bool empty() const noexcept
3414 {
3415 return !size();
3416 }
3417
3419 constexpr static size_type max_size() noexcept
3420 {
3421 return sbe_size_type::max_value();
3422 }
3423
3425 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3426 SBEPP_CPP20_CONSTEXPR void clear() const noexcept
3427 {
3428 resize(0, default_init);
3429 }
3430
3432 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3433 SBEPP_CPP20_CONSTEXPR void resize(size_type count) const noexcept
3434 {
3435 const auto old_size = size();
3436 resize(count, default_init);
3437 if(count > old_size)
3438 {
3439 for(auto i = old_size; i != count; i++)
3440 {
3441 operator[](i) = {};
3442 }
3443 }
3444 }
3445
3447 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3448 SBEPP_CPP20_CONSTEXPR void
3449 resize(size_type count, value_type value) const noexcept
3450 {
3451 const auto old_size = size();
3452 resize(count, default_init);
3453 if(count > old_size)
3454 {
3455 for(auto i = old_size; i != count; i++)
3456 {
3457 operator[](i) = value;
3458 }
3459 }
3460 }
3461
3463 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3464 SBEPP_CPP20_CONSTEXPR void
3466 {
3467 // can't use `detail::set_value()` here because its size check checks
3468 // only `sizeof(T)`, here we need `sizeof(size_type) + count`
3469 SBEPP_SIZE_CHECK(
3470 (*this)(addressof_tag{}),
3471 (*this)(end_ptr_tag{}),
3472 0,
3473 sizeof(size_type) + count);
3474 set_primitive<E>((*this)(addressof_tag{}), count);
3475 }
3476
3478 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3479 SBEPP_CPP20_CONSTEXPR void push_back(value_type value) const noexcept
3480 {
3481 const auto current_size = size();
3482 resize(current_size + 1, default_init);
3483 (*this)[current_size] = value;
3484 }
3485
3487 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3488 SBEPP_CPP20_CONSTEXPR void pop_back() const noexcept
3489 {
3490 SBEPP_ASSERT(!empty());
3491 resize(size() - 1, default_init);
3492 }
3493
3495 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3496 SBEPP_CPP20_CONSTEXPR iterator erase(iterator pos) const noexcept
3497 {
3498 SBEPP_ASSERT(pos >= begin() && pos < end());
3499 std::copy(pos + 1, end(), pos);
3500 resize(size() - 1, default_init);
3501 return pos;
3502 }
3503
3505 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3506 SBEPP_CPP20_CONSTEXPR iterator
3507 erase(iterator first, iterator last) const noexcept
3508 {
3509 SBEPP_ASSERT(first >= begin() && last < end());
3510 std::copy(last, end(), first);
3511 resize(size() - (last - first), default_init);
3512 return first;
3513 }
3514
3516 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3517 SBEPP_CPP20_CONSTEXPR iterator
3518 insert(iterator pos, const value_type value) const noexcept
3519 {
3520 SBEPP_ASSERT(pos >= begin() && pos <= end());
3521 const auto old_end = end();
3522 resize(size() + 1, default_init);
3523 std::copy_backward(pos, old_end, end());
3524 *pos = value;
3525 return pos;
3526 }
3527
3529 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3530 SBEPP_CPP20_CONSTEXPR iterator insert(
3531 iterator pos, size_type count, const value_type value) const noexcept
3532 {
3533 SBEPP_ASSERT(pos >= begin() && pos <= end());
3534 const auto old_end = end();
3535 resize(size() + count, default_init);
3536 std::copy_backward(pos, old_end, end());
3537 std::fill_n(pos, count, value);
3538 return pos;
3539 }
3540
3542 template<
3543 typename InputIt,
3544 typename = detail::enable_if_t<
3545 !std::is_const<Byte>::value
3546 && std::is_convertible<
3547 typename std::iterator_traits<InputIt>::iterator_category,
3548 std::input_iterator_tag>::value>>
3549 SBEPP_CPP14_CONSTEXPR iterator
3550 insert(iterator pos, InputIt first, InputIt last) const
3551 {
3552 SBEPP_ASSERT(pos >= begin() && pos <= end());
3553 using category_t =
3554 typename std::iterator_traits<InputIt>::iterator_category;
3555 return insert_impl(pos, first, last, category_t{});
3556 }
3557
3559 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3560 constexpr iterator insert(
3561 iterator pos, std::initializer_list<value_type> ilist) const noexcept
3562 {
3563 return insert(pos, std::begin(ilist), std::end(ilist));
3564 }
3565
3568 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3569 SBEPP_CPP20_CONSTEXPR void
3570 assign(size_type count, const value_type value) const noexcept
3571 {
3572 resize(count, default_init);
3573 std::fill_n(begin(), count, value);
3574 }
3575
3578 template<typename InputIt, typename = enable_if_writable_t<Byte, InputIt>>
3579 SBEPP_CPP20_CONSTEXPR void assign(InputIt first, InputIt last) const
3580 {
3581 auto begin = data_unchecked();
3582 const auto new_end = std::copy(first, last, begin);
3583 resize(new_end - begin, default_init);
3584 }
3585
3588 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3589 SBEPP_CPP20_CONSTEXPR void
3590 assign(std::initializer_list<value_type> ilist) const noexcept
3591 {
3592 SBEPP_SIZE_CHECK(
3593 (*this)(detail::addressof_tag{}),
3594 (*this)(detail::end_ptr_tag{}),
3595 0,
3596 sizeof(size_type) + ilist.size());
3597 assign(std::begin(ilist), std::end(ilist));
3598 }
3599
3607 raw() const noexcept
3608 {
3610 (*this)(detail::addressof_tag{}), (*this)(detail::end_ptr_tag{})};
3611 }
3612
3613 SBEPP_CPP20_CONSTEXPR std::size_t
3614 operator()(detail::size_bytes_tag) const noexcept
3615 {
3616 return sizeof(size_type) + size();
3617 }
3618
3625 template<typename T = void, typename = enable_if_writable_t<Byte, T>>
3626 SBEPP_CPP20_CONSTEXPR void assign_string(const char* str) const noexcept
3627 {
3628 SBEPP_ASSERT(str != nullptr);
3629 const auto length = string_length(str);
3630 resize(length, default_init);
3631 std::copy_n(str, length, begin());
3632 }
3633
3641 template<
3642 typename R,
3643 typename =
3644 enable_if_t<!std::is_const<Byte>::value && is_range<R>::value>>
3645 SBEPP_CPP20_CONSTEXPR void assign_range(R&& r) const
3646 {
3647 const auto begin = data_unchecked();
3648#if SBEPP_HAS_RANGES
3649 const auto new_end = std::ranges::copy(std::forward<R>(r), begin).out;
3650#else
3651 const auto new_end = std::copy(std::begin(r), std::end(r), begin);
3652#endif
3653 resize(new_end - begin, default_init);
3654 }
3655
3656private:
3657 SBEPP_CPP14_CONSTEXPR pointer data_checked() const noexcept
3658 {
3659 SBEPP_SIZE_CHECK(
3660 (*this)(detail::addressof_tag{}),
3661 (*this)(detail::end_ptr_tag{}),
3662 0,
3663 sizeof(size_type) + size());
3664 return data_unchecked();
3665 }
3666
3667 SBEPP_CPP14_CONSTEXPR pointer data_unchecked() const noexcept
3668 {
3669 SBEPP_SIZE_CHECK(
3670 (*this)(detail::addressof_tag{}),
3671 (*this)(detail::end_ptr_tag{}),
3672 0,
3673 sizeof(size_type));
3674 // cast is conditionally required here when `Byte` is different type
3675 // from `Value`. `reinterpret_cast` is not allowed in constexpr context
3676 // even when it's an identity cast. On the other hand, C-style cast
3677 // is allowed in constexpr context when it renders to an identity cast
3678 // which effectively makes this and other functions conditionally
3679 // `constexpr` when `Byte` is equal to `Value`.
3680 // NOLINTNEXTLINE: see above
3681 return (pointer)((*this)(detail::addressof_tag{}) + sizeof(size_type));
3682 }
3683
3684 template<typename It>
3685 SBEPP_CPP14_CONSTEXPR iterator insert_impl(
3686 iterator pos, It first, It last, std::input_iterator_tag) const
3687 {
3688 auto out = pos;
3689 for(; first != last; ++first, ++out)
3690 {
3691 insert(out, *first);
3692 }
3693
3694 return pos;
3695 }
3696
3697 template<typename It>
3698 SBEPP_CPP20_CONSTEXPR iterator insert_impl(
3699 iterator pos, It first, It last, std::forward_iterator_tag) const
3700 {
3701 const auto in_size = std::distance(first, last);
3702 auto old_end = end();
3703 resize(size() + in_size, default_init);
3704 std::copy_backward(pos, old_end, end());
3705 std::copy(first, last, pos);
3706 return pos;
3707 }
3708};
3709} // namespace detail
3710
3713{
3714 explicit constexpr nullopt_t(int)
3715 {
3716 }
3717};
3718
3724SBEPP_CPP17_INLINE_VAR constexpr nullopt_t nullopt{0};
3725
3726namespace detail
3727{
3728// see `optional_base` note about explicit `alignas`
3732template<typename T, typename Derived>
3733class alignas(T) required_base
3734{
3735public:
3737 using value_type = T;
3738
3740 required_base() = default;
3741
3743 // NOLINTNEXTLINE: it should be implicit
3744 constexpr required_base(value_type val) noexcept : val{val}
3745 {
3746 }
3747
3749 constexpr value_type value() const noexcept
3750 {
3751 return **this;
3752 }
3753
3755 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3756 {
3757 return val;
3758 }
3759
3761 constexpr value_type operator*() const noexcept
3762 {
3763 return val;
3764 }
3765
3768 constexpr bool in_range() const noexcept
3769 {
3770 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3771 }
3772
3776#ifdef SBEPP_DOXYGEN
3778 friend auto
3779 operator<=>(const required_base&, const required_base&) = default;
3780#endif
3781
3782#if SBEPP_HAS_THREE_WAY_COMPARISON
3783 friend auto
3784 operator<=>(const required_base&, const required_base&) = default;
3785#else
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
3822 constexpr friend bool
3823 operator>=(const required_base& lhs, const required_base& rhs) noexcept
3824 {
3825 return *lhs >= *rhs;
3826 }
3827#endif
3829
3830private:
3831 value_type val{};
3832};
3833
3834// old compilers might generate wrong alignment for classes which contain
3835// `double` member. To overcome this, explicit alignment is provided.
3839template<typename T, typename Derived>
3840class alignas(T) optional_base
3841{
3842public:
3844 using value_type = T;
3845
3847 optional_base() = default;
3848
3850 // NOLINTNEXTLINE: it's intentionally implicit
3851 constexpr optional_base(nullopt_t) noexcept : optional_base{}
3852 {
3853 }
3854
3856 // NOLINTNEXTLINE: it's intentionally implicit
3857 constexpr optional_base(value_type val) noexcept : val{val}
3858 {
3859 }
3860
3862 constexpr value_type value() const noexcept
3863 {
3864 return **this;
3865 }
3866
3868 SBEPP_CPP14_CONSTEXPR value_type& operator*() noexcept
3869 {
3870 return val;
3871 }
3872
3874 constexpr value_type operator*() const noexcept
3875 {
3876 return val;
3877 }
3878
3881 constexpr bool in_range() const noexcept
3882 {
3883 return (Derived::min_value() <= val) && (val <= Derived::max_value());
3884 }
3885
3887 SBEPP_CPP14_CONSTEXPR value_type value_or(T default_value) const noexcept
3888 {
3889 if(*this)
3890 {
3891 return value();
3892 }
3893 return default_value;
3894 }
3895
3897 constexpr bool has_value() const noexcept
3898 {
3899 return (val != Derived::null_value());
3900 }
3901
3903 constexpr explicit operator bool() const noexcept
3904 {
3905 return has_value();
3906 }
3907
3914
3916 constexpr friend bool
3917 operator==(const optional_base& lhs, const optional_base& rhs) noexcept
3918 {
3919 return *lhs == *rhs;
3920 }
3921
3922#ifdef SBEPP_DOXYGEN
3924 constexpr friend std::strong_ordering operator<=>(
3925 const optional_base& lhs, const optional_base& rhs) noexcept;
3926#endif
3927
3928#if SBEPP_HAS_THREE_WAY_COMPARISON
3929 constexpr friend std::strong_ordering
3930 operator<=>(const optional_base& lhs, const optional_base& rhs) noexcept
3931 {
3932 if(lhs && rhs)
3933 {
3934 return *lhs <=> *rhs;
3935 }
3936 return lhs.has_value() <=> rhs.has_value();
3937 }
3938#else
3939
3941 constexpr friend bool
3942 operator!=(const optional_base& lhs, const optional_base& rhs) noexcept
3943 {
3944 return *lhs != *rhs;
3945 }
3946
3948 constexpr friend bool
3949 operator<(const optional_base& lhs, const optional_base& rhs) noexcept
3950 {
3951 return rhs && (!lhs || (*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 lhs && (!rhs || (*lhs > *rhs));
3966 }
3967
3969 constexpr friend bool
3970 operator>=(const optional_base& lhs, const optional_base& rhs) noexcept
3971 {
3972 return !rhs || (lhs && (*lhs >= *rhs));
3973 }
3974#endif
3976
3977private:
3978 value_type val{Derived::null_value()};
3979};
3980} // namespace detail
3981
3996template<typename Message>
3997constexpr auto fill_message_header(Message m) noexcept
3998 -> decltype(m(detail::fill_message_header_tag{}))
3999{
4000 return m(detail::fill_message_header_tag{});
4001}
4002
4016template<typename Group, typename Size>
4017constexpr auto fill_group_header(Group g, Size num_in_group) noexcept
4018 -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
4019{
4020 return g(detail::fill_group_header_tag{}, num_in_group);
4021}
4022
4036template<typename T>
4037class type_traits;
4038
4039#ifdef SBEPP_DOXYGEN
4040template<typename T>
4042{
4043public:
4045 using primitive_type = PrimitiveType;
4046
4048 using value_type = ValueType;
4049
4055 template<typename Byte>
4056 using value_type = ArrayType<Byte>;
4057
4059 static constexpr const char* name() noexcept;
4060
4062 static constexpr const char* description() noexcept;
4063
4065 static constexpr field_presence presence() noexcept;
4066
4071 static constexpr primitive_type min_value() noexcept;
4072
4077 static constexpr primitive_type max_value() noexcept;
4078
4083 static constexpr primitive_type null_value() noexcept;
4084
4086 static constexpr length_t length() noexcept;
4087
4092 static constexpr offset_t offset() noexcept;
4093
4095 static constexpr const char* semantic_type() noexcept;
4096
4098 static constexpr version_t since_version() noexcept;
4099
4102 static constexpr version_t deprecated() noexcept;
4103
4105 static constexpr const char* character_encoding() noexcept;
4106};
4107#endif
4108
4117template<typename T>
4118class schema_traits;
4119
4120#ifdef SBEPP_DOXYGEN
4121template<typename T>
4123{
4124public:
4126 static constexpr const char* package() noexcept;
4128 static constexpr schema_id_t id() noexcept;
4130 static constexpr version_t version() noexcept;
4132 static constexpr const char* semantic_version() noexcept;
4134 static constexpr endian byte_order() noexcept;
4136 static constexpr const char* description() noexcept;
4142 template<typename Byte>
4143 using header_type = HeaderComposite<Byte>;
4145 using header_type_tag = HeaderTypeTag;
4146};
4147#endif
4148
4157template<typename T>
4158class enum_traits;
4159
4160#ifdef SBEPP_DOXYGEN
4161template<typename T>
4163{
4164public:
4166 static constexpr const char* name() noexcept;
4168 static constexpr const char* description() noexcept;
4170 using encoding_type = EncodingType;
4175 static constexpr offset_t offset() noexcept;
4177 static constexpr version_t since_version() noexcept;
4180 static constexpr version_t deprecated() noexcept;
4182 using value_type = ScopedEnumType;
4183};
4184#endif
4185
4194template<typename T>
4195class enum_value_traits;
4196
4197#ifdef SBEPP_DOXYGEN
4198template<typename T>
4200{
4201public:
4203 static constexpr const char* name() noexcept;
4205 static constexpr const char* description() noexcept;
4207 static constexpr version_t since_version() noexcept;
4210 static constexpr version_t deprecated() noexcept;
4212 static constexpr ScopedEnumType value() noexcept;
4213};
4214#endif
4215
4224template<typename T>
4225class set_traits;
4226
4227#ifdef SBEPP_DOXYGEN
4228template<typename T>
4230{
4231public:
4233 static constexpr const char* name() noexcept;
4235 static constexpr const char* description() noexcept;
4237 static constexpr version_t since_version() noexcept;
4240 static constexpr version_t deprecated() noexcept;
4242 using encoding_type = EncodingType;
4247 static constexpr offset_t offset() noexcept;
4249 using value_type = SetType;
4250};
4251#endif
4252
4261template<typename T>
4262class set_choice_traits;
4263
4264#ifdef SBEPP_DOXYGEN
4265template<typename T>
4267{
4268public:
4270 static constexpr const char* name() noexcept;
4272 static constexpr const char* description() noexcept;
4274 static constexpr version_t since_version() noexcept;
4277 static constexpr version_t deprecated() noexcept;
4279 static constexpr choice_index_t index() noexcept;
4280};
4281#endif
4282
4291template<typename T>
4292class composite_traits;
4293
4294#ifdef SBEPP_DOXYGEN
4295template<typename T>
4297{
4298public:
4300 static constexpr const char* name() noexcept;
4302 static constexpr const char* description() noexcept;
4307 static constexpr offset_t offset() noexcept;
4309 static constexpr const char* semantic_type() noexcept;
4311 static constexpr version_t since_version() noexcept;
4313 // !schema
4314 static constexpr version_t deprecated() noexcept;
4320 template<typename Byte>
4321 using value_type = CompositeType<Byte>;
4323 static constexpr std::size_t size_bytes() noexcept;
4324};
4325#endif
4326
4335template<typename T>
4336class message_traits;
4337
4338#ifdef SBEPP_DOXYGEN
4339template<typename T>
4341{
4342public:
4344 static constexpr const char* name() noexcept;
4346 static constexpr const char* description() noexcept;
4348 static constexpr message_id_t id() noexcept;
4350 static constexpr block_length_t block_length() noexcept;
4352 static constexpr const char* semantic_type() noexcept;
4354 static constexpr version_t since_version() noexcept;
4357 static constexpr version_t deprecated() noexcept;
4363 template<typename Byte>
4364 using value_type = MessageType<Byte>;
4366 using schema_tag = SchemaTag;
4367
4445 static constexpr std::size_t size_bytes(...) noexcept;
4446};
4447#endif
4448
4457template<typename T>
4458class field_traits;
4459
4460#ifdef SBEPP_DOXYGEN
4461template<typename T>
4463{
4464public:
4466 static constexpr const char* name() noexcept;
4468 static constexpr member_id_t id() noexcept;
4470 static constexpr const char* description() noexcept;
4476 static constexpr field_presence presence() noexcept;
4478 static constexpr offset_t offset() noexcept;
4480 static constexpr version_t since_version() noexcept;
4483 static constexpr version_t deprecated() noexcept;
4485 using value_type = ValueType;
4491 template<typename Byte>
4492 using value_type = Type<Byte>;
4494 using value_type_tag = TypeTag;
4495};
4496#endif
4497
4506template<typename T>
4507class group_traits;
4508
4509#ifdef SBEPP_DOXYGEN
4510template<typename T>
4512{
4513public:
4515 static constexpr const char* name() noexcept;
4517 static constexpr const char* description() noexcept;
4519 static constexpr member_id_t id() noexcept;
4521 static constexpr block_length_t block_length() noexcept;
4523 static constexpr const char* semantic_type() noexcept;
4525 static constexpr version_t since_version() noexcept;
4528 static constexpr version_t deprecated() noexcept;
4534 template<typename Byte>
4535 using value_type = GroupType<Byte>;
4541 template<typename Byte>
4542 using dimension_type = HeaderType<Byte>;
4544 using dimension_type_tag = HeaderTag;
4550 template<typename Byte>
4551 using entry_type = EntryType<Byte>;
4563 static constexpr std::size_t
4564 size_bytes(const NumInGroupType num_in_group, ...) noexcept;
4565};
4566#endif
4567
4576template<typename T>
4577class data_traits;
4578
4579#ifdef SBEPP_DOXYGEN
4580template<typename T>
4582{
4583public:
4585 static constexpr const char* name() noexcept;
4587 static constexpr member_id_t id() noexcept;
4589 static constexpr const char* description() noexcept;
4591 static constexpr version_t since_version() noexcept;
4594 static constexpr version_t deprecated() noexcept;
4600 template<typename Byte>
4601 using value_type = DataType;
4603 using length_type = LengthType;
4605 using length_type_tag = LengthTypeTag;
4612 static constexpr std::size_t
4613 size_bytes(const length_type::value_type size) noexcept;
4614};
4615#endif
4640template<typename ValueType>
4641struct traits_tag;
4642
4643#ifdef SBEPP_DOXYGEN
4644template<typename ValueType>
4646{
4648 using type = Tag;
4649};
4650#endif
4651
4653template<typename ValueType>
4655
4656template<typename Byte, typename Value, std::size_t N, typename Tag>
4657struct traits_tag<detail::static_array_ref<Byte, Value, N, Tag>>
4658{
4659 using type = Tag;
4660};
4661
4662// NOLINTNEXTLINE: macro is required here
4663#define SBEPP_BUILT_IN_IMPL(NAME, TYPE, MIN, MAX, NULL) \
4664 \
4665 \
4666 class NAME##_t : public detail::required_base<TYPE, NAME##_t> \
4667 { \
4668 public: \
4669 using detail::required_base<TYPE, NAME##_t>::required_base; \
4670 \
4671 \
4672 static constexpr value_type min_value() noexcept \
4673 { \
4674 return {MIN}; \
4675 } \
4676 \
4677 \
4678 static constexpr value_type max_value() noexcept \
4679 { \
4680 return {MAX}; \
4681 } \
4682 }; \
4683 \
4684
4685 \
4686 class NAME##_opt_t : public detail::optional_base<TYPE, NAME##_opt_t> \
4687 { \
4688 public: \
4689 using detail::optional_base<TYPE, NAME##_opt_t>::optional_base; \
4690 \
4691 \
4692 static constexpr value_type min_value() noexcept \
4693 { \
4694 return {MIN}; \
4695 } \
4696 \
4697 \
4698 static constexpr value_type max_value() noexcept \
4699 { \
4700 return {MAX}; \
4701 } \
4702 \
4703 \
4704 static constexpr value_type null_value() noexcept \
4705 { \
4706 return {NULL}; \
4707 } \
4708 }; \
4709 \
4710 template<> \
4711 class type_traits<NAME##_t> \
4712 { \
4713 public: \
4714 static constexpr const char* name() noexcept \
4715 { \
4716 return #NAME; \
4717 } \
4718 \
4719 static constexpr const char* description() noexcept \
4720 { \
4721 return ""; \
4722 } \
4723 \
4724 static constexpr field_presence presence() noexcept \
4725 { \
4726 return field_presence::required; \
4727 } \
4728 \
4729 static constexpr TYPE min_value() noexcept \
4730 { \
4731 return NAME##_t::min_value(); \
4732 } \
4733 \
4734 static constexpr TYPE max_value() noexcept \
4735 { \
4736 return NAME##_t::max_value(); \
4737 } \
4738 \
4739 static constexpr length_t length() noexcept \
4740 { \
4741 return 1; \
4742 } \
4743 \
4744 static constexpr const char* semantic_type() noexcept \
4745 { \
4746 return ""; \
4747 } \
4748 \
4749 static constexpr version_t since_version() noexcept \
4750 { \
4751 return 0; \
4752 } \
4753 \
4754 using value_type = NAME##_t; \
4755 using primitive_type = value_type::value_type; \
4756 }; \
4757 \
4758 template<> \
4759 struct traits_tag<NAME##_t> \
4760 { \
4761 using type = NAME##_t; \
4762 }; \
4763 \
4764 template<> \
4765 class type_traits<NAME##_opt_t> \
4766 { \
4767 public: \
4768 static constexpr const char* name() noexcept \
4769 { \
4770 return #NAME; \
4771 } \
4772 \
4773 static constexpr const char* description() noexcept \
4774 { \
4775 return ""; \
4776 } \
4777 \
4778 static constexpr field_presence presence() noexcept \
4779 { \
4780 return field_presence::optional; \
4781 } \
4782 \
4783 static constexpr TYPE min_value() noexcept \
4784 { \
4785 return NAME##_opt_t::min_value(); \
4786 } \
4787 \
4788 static constexpr TYPE max_value() noexcept \
4789 { \
4790 return NAME##_opt_t::max_value(); \
4791 } \
4792 \
4793 static constexpr TYPE null_value() noexcept \
4794 { \
4795 return NAME##_opt_t::null_value(); \
4796 } \
4797 \
4798 static constexpr length_t length() noexcept \
4799 { \
4800 return 1; \
4801 } \
4802 \
4803 static constexpr const char* semantic_type() noexcept \
4804 { \
4805 return ""; \
4806 } \
4807 \
4808 static constexpr version_t since_version() noexcept \
4809 { \
4810 return 0; \
4811 } \
4812 \
4813 using value_type = NAME##_opt_t; \
4814 using primitive_type = value_type::value_type; \
4815 }; \
4816 \
4817 template<> \
4818 struct traits_tag<NAME##_opt_t> \
4819 { \
4820 using type = NAME##_opt_t; \
4821 }
4823SBEPP_BUILT_IN_IMPL(char, char, 0x20, 0x7E, 0);
4824SBEPP_BUILT_IN_IMPL(
4825 int8,
4826 std::int8_t,
4827 std::numeric_limits<std::int8_t>::min() + 1,
4828 std::numeric_limits<std::int8_t>::max(),
4829 std::numeric_limits<std::int8_t>::min());
4830SBEPP_BUILT_IN_IMPL(
4831 uint8,
4832 std::uint8_t,
4833 std::numeric_limits<std::uint8_t>::min(),
4834 std::numeric_limits<std::uint8_t>::max() - 1,
4835 std::numeric_limits<std::uint8_t>::max());
4836SBEPP_BUILT_IN_IMPL(
4837 int16,
4838 std::int16_t,
4839 std::numeric_limits<std::int16_t>::min() + 1,
4840 std::numeric_limits<std::int16_t>::max(),
4841 std::numeric_limits<std::int16_t>::min());
4842SBEPP_BUILT_IN_IMPL(
4843 uint16,
4844 std::uint16_t,
4845 std::numeric_limits<std::uint16_t>::min(),
4846 std::numeric_limits<std::uint16_t>::max() - 1,
4847 std::numeric_limits<std::uint16_t>::max());
4848SBEPP_BUILT_IN_IMPL(
4849 int32,
4850 std::int32_t,
4851 std::numeric_limits<std::int32_t>::min() + 1,
4852 std::numeric_limits<std::int32_t>::max(),
4853 std::numeric_limits<std::int32_t>::min());
4854SBEPP_BUILT_IN_IMPL(
4855 uint32,
4856 std::uint32_t,
4857 std::numeric_limits<std::uint32_t>::min(),
4858 std::numeric_limits<std::uint32_t>::max() - 1,
4859 std::numeric_limits<std::uint32_t>::max());
4860SBEPP_BUILT_IN_IMPL(
4861 int64,
4862 std::int64_t,
4863 std::numeric_limits<std::int64_t>::min() + 1,
4864 std::numeric_limits<std::int64_t>::max(),
4865 std::numeric_limits<std::int64_t>::min());
4866SBEPP_BUILT_IN_IMPL(
4867 uint64,
4868 std::uint64_t,
4869 std::numeric_limits<std::uint64_t>::min(),
4870 std::numeric_limits<std::uint64_t>::max() - 1,
4871 std::numeric_limits<std::uint64_t>::max());
4872SBEPP_BUILT_IN_IMPL(
4873 float,
4874 float,
4875 std::numeric_limits<float>::min(),
4876 std::numeric_limits<float>::max(),
4877 std::numeric_limits<float>::quiet_NaN());
4878SBEPP_BUILT_IN_IMPL(
4879 double,
4880 double,
4881 std::numeric_limits<double>::min(),
4882 std::numeric_limits<double>::max(),
4883 std::numeric_limits<double>::quiet_NaN());
4884
4885#undef SBEPP_BUILT_IN_IMPL
4886
4904template<template<typename> class View, typename Byte>
4905constexpr View<Byte> make_view(Byte* ptr, const std::size_t size) noexcept
4906{
4907 return {ptr, size};
4908}
4909
4928template<template<typename> class View, typename Byte>
4929constexpr View<typename std::add_const<Byte>::type>
4930 make_const_view(Byte* ptr, const std::size_t size) noexcept
4931{
4932 return {ptr, size};
4933}
4934
4941struct unknown_enum_value_tag
4942{
4943};
4944
4945namespace detail
4946{
4947// taken from https://stackoverflow.com/a/34672753
4948template<template<typename...> class Base, typename Derived>
4949struct is_base_of_tmp_impl
4950{
4951 static constexpr std::false_type test(...);
4952
4953 template<typename... Ts>
4954 static constexpr std::true_type test(Base<Ts...>*);
4955
4956 using type = decltype(test(std::declval<Derived*>()));
4957};
4958
4959template<template<typename...> class Base, typename Derived>
4960using is_base_of_tmp = typename is_base_of_tmp_impl<Base, Derived>::type;
4961
4962#if SBEPP_HAS_CONCEPTS
4963template<typename Derived, template<typename...> class Base>
4964concept derived_from_tmp = is_base_of_tmp<Base, Derived>::value;
4965#endif
4966} // namespace detail
4967
4968namespace detail
4969{
4970template<typename Derived>
4971struct is_array_type_impl
4972{
4973 static constexpr std::false_type test(...);
4974
4975 template<typename T1, typename T2, std::size_t N, typename T3>
4976 static constexpr std::true_type
4977 test(detail::static_array_ref<T1, T2, N, T3>*);
4978
4979 using type = decltype(test(std::declval<Derived*>()));
4980};
4981} // namespace detail
4982
4984template<typename T>
4985using is_array_type = typename detail::is_array_type_impl<T>::type;
4986
4988template<typename T>
4989using is_required_type = detail::is_base_of_tmp<detail::required_base, T>;
4990
4992template<typename T>
4993using is_optional_type = detail::is_base_of_tmp<detail::optional_base, T>;
4994
4996template<typename T>
4997using is_non_array_type = std::integral_constant<
4998 bool,
5000
5002template<typename T>
5003using is_type = std::integral_constant<
5004 bool,
5007
5009template<typename T, typename = void>
5010struct is_enum : std::false_type
5011{
5012};
5013
5014template<typename T>
5015struct is_enum<
5016 T,
5017 detail::void_t<decltype(tag_invoke(
5018 std::declval<detail::visit_tag>(),
5019 std::declval<T>(),
5020 std::declval<int&>()))>> : std::true_type
5021{
5022};
5023
5025template<typename T>
5026using is_set = detail::is_base_of_tmp<detail::bitset_base, T>;
5027
5029template<typename T>
5030using is_composite = detail::is_base_of_tmp<detail::composite_base, T>;
5031
5033template<typename T>
5034using is_message = detail::is_base_of_tmp<detail::message_base, T>;
5035
5037template<typename T>
5038using is_flat_group = detail::is_base_of_tmp<detail::flat_group_base, T>;
5039
5041template<typename T>
5042using is_nested_group = detail::is_base_of_tmp<detail::nested_group_base, T>;
5043
5045template<typename T>
5046using is_group = std::integral_constant<
5047 bool,
5049
5051template<typename T>
5052using is_group_entry = detail::is_base_of_tmp<detail::entry_base, T>;
5053
5054namespace detail
5055{
5056template<typename Derived>
5057struct is_data_impl
5058{
5059 static constexpr std::false_type test(...);
5060
5061 template<typename T1, typename T2, typename T3, endian E>
5062 static constexpr std::true_type
5064
5065 using type = decltype(test(std::declval<Derived*>()));
5066};
5067} // namespace detail
5068
5070template<typename T>
5071using is_data = typename detail::is_data_impl<T>::type;
5072
5073#if SBEPP_HAS_INLINE_VARS
5075template<typename T>
5076inline constexpr auto is_array_type_v = is_array_type<T>::value;
5077
5079template<typename T>
5080inline constexpr auto is_required_type_v = is_required_type<T>::value;
5081
5083template<typename T>
5084inline constexpr auto is_optional_type_v = is_optional_type<T>::value;
5085
5087template<typename T>
5088inline constexpr auto is_non_array_type_v = is_non_array_type<T>::value;
5089
5091template<typename T>
5092inline constexpr auto is_type_v = is_type<T>::value;
5093
5095template<typename T>
5096inline constexpr auto is_enum_v = is_enum<T>::value;
5097
5099template<typename T>
5100inline constexpr auto is_set_v = is_set<T>::value;
5101
5103template<typename T>
5104inline constexpr auto is_composite_v = is_composite<T>::value;
5105
5107template<typename T>
5108inline constexpr auto is_message_v = is_message<T>::value;
5109
5111template<typename T>
5112inline constexpr auto is_flat_group_v = is_flat_group<T>::value;
5113
5115template<typename T>
5116inline constexpr auto is_nested_group_v = is_nested_group<T>::value;
5117
5119template<typename T>
5120inline constexpr auto is_group_v = is_group<T>::value;
5121
5123template<typename T>
5124inline constexpr auto is_data_v = is_data<T>::value;
5125#endif
5126
5127#if SBEPP_HAS_CONCEPTS
5129template<typename T>
5130concept array_type = is_array_type_v<T>;
5131
5133template<typename T>
5134concept required_type = is_required_type_v<T>;
5135
5137template<typename T>
5138concept optional_type = is_optional_type_v<T>;
5139
5141template<typename T>
5142concept non_array_type = is_non_array_type_v<T>;
5143
5145template<typename T>
5146concept type = is_type_v<T>;
5147
5149template<typename T>
5150concept enumeration = is_enum_v<T>;
5151
5153template<typename T>
5154concept set = is_set_v<T>;
5155
5157template<typename T>
5158concept composite = is_composite_v<T>;
5159
5161template<typename T>
5162concept message = is_message_v<T>;
5163
5165template<typename T>
5166concept flat_group = is_flat_group_v<T>;
5167
5169template<typename T>
5170concept nested_group = is_nested_group_v<T>;
5171
5173template<typename T>
5174concept group = is_group_v<T>;
5175
5177template<typename T>
5178concept data = is_data_v<T>;
5179#endif
5180
5181namespace detail
5182{
5183template<typename T>
5184using is_visitable_view = std::integral_constant<
5185 bool,
5186 is_message<T>::value || is_group<T>::value || is_group_entry<T>::value
5187 || is_composite<T>::value>;
5188}
5189
5201template<
5202 typename Visitor,
5203 typename View,
5204 typename Cursor,
5205 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5206SBEPP_CPP14_CONSTEXPR Visitor&&
5207 visit(View view, Cursor& c, Visitor&& visitor = {})
5208{
5209 view(detail::visit_tag{}, visitor, c);
5210 return std::forward<Visitor>(visitor);
5211}
5212
5223template<
5224 typename Visitor,
5225 typename View,
5226 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5227SBEPP_CPP14_CONSTEXPR Visitor&& visit(View view, Visitor&& visitor = {})
5228{
5229 auto c = sbepp::init_cursor(view);
5230 return sbepp::visit(view, c, std::forward<Visitor>(visitor));
5231}
5232
5233#ifndef SBEPP_DOXYGEN
5234template<typename Visitor, typename Set>
5235SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_set<Set>::value, Visitor&&>
5236 visit(Set s, Visitor&& visitor = {})
5237{
5238 s(detail::visit_tag{}, visitor);
5239 return std::forward<Visitor>(visitor);
5240}
5241
5242template<typename Visitor, typename Enum>
5243SBEPP_CPP14_CONSTEXPR detail::enable_if_t<is_enum<Enum>::value, Visitor&&>
5244 visit(Enum e, Visitor&& visitor = {})
5245{
5246 tag_invoke(detail::visit_tag{}, e, visitor);
5247 return std::forward<Visitor>(visitor);
5248}
5249
5250#else
5251
5268template<typename Visitor, typename Set>
5269SBEPP_CPP14_CONSTEXPR Visitor&& visit(Set s, Visitor&& visitor = {});
5270
5287template<typename Visitor, typename Enum>
5288SBEPP_CPP14_CONSTEXPR Visitor&& visit(Enum e, Visitor&& visitor = {});
5289#endif
5290
5303template<
5304 typename Visitor,
5305 typename View,
5306 typename Cursor,
5307 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5308SBEPP_CPP14_CONSTEXPR Visitor&&
5309 visit_children(View view, Cursor& c, Visitor&& visitor = {})
5310{
5311 view(detail::visit_children_tag{}, visitor, c);
5312 return std::forward<Visitor>(visitor);
5313}
5314
5325template<
5326 typename Visitor,
5327 typename View,
5328 typename = detail::enable_if_t<detail::is_visitable_view<View>::value>>
5329SBEPP_CPP14_CONSTEXPR Visitor&&
5330 visit_children(View view, Visitor&& visitor = {})
5331{
5332 auto c = sbepp::init_cursor(view);
5333 return sbepp::visit_children(view, c, std::forward<Visitor>(visitor));
5334}
5335
5336namespace detail
5337{
5338class enum_to_string_visitor
5339{
5340public:
5341 template<typename Enum, typename Tag>
5342 SBEPP_CPP14_CONSTEXPR void on_enum_value(Enum /*e*/, Tag) noexcept
5343 {
5345 }
5346
5347 template<typename Enum>
5348 SBEPP_CPP14_CONSTEXPR void
5349 on_enum_value(Enum /*e*/, sbepp::unknown_enum_value_tag) noexcept
5350 {
5351 name_value = nullptr;
5352 }
5353
5354 constexpr const char* name() const noexcept
5355 {
5356 return name_value;
5357 }
5358
5359private:
5360 const char* name_value;
5361};
5362} // namespace detail
5363
5374template<typename E, typename = detail::enable_if_t<is_enum<E>::value>>
5375SBEPP_DEPRECATED constexpr const char* enum_to_string(const E e) noexcept
5376{
5377 return visit<detail::enum_to_string_visitor>(e).name();
5378}
5379
5391template<typename Set, typename Visitor>
5392SBEPP_DEPRECATED constexpr auto
5393 visit_set(const Set s, Visitor&& visitor) noexcept
5394 -> decltype(s(detail::visit_set_tag{}, std::forward<Visitor>(visitor)))
5395{
5396 return s(detail::visit_set_tag{}, std::forward<Visitor>(visitor));
5397}
5398
5399namespace detail
5400{
5401class size_bytes_checked_visitor
5402{
5403public:
5404 constexpr explicit size_bytes_checked_visitor(
5405 const std::size_t size) noexcept
5406 : size{size}
5407 {
5408 }
5409
5410 template<typename T, typename Cursor, typename Tag>
5411 SBEPP_CPP14_CONSTEXPR void on_message(T m, Cursor& c, Tag) noexcept
5412 {
5413 const auto header = sbepp::get_header(m);
5414 const auto header_size = sbepp::size_bytes(header);
5415 if(!validate_and_subtract(header_size))
5416 {
5417 return;
5418 }
5419
5420 if(!validate_and_subtract(*header.blockLength()))
5421 {
5422 return;
5423 }
5424
5425 sbepp::visit_children(m, c, *this);
5426 }
5427
5428 template<typename T, typename Cursor, typename Tag>
5429 SBEPP_CPP14_CONSTEXPR bool on_group(T g, Cursor& c, Tag) noexcept
5430 {
5431 const auto header = sbepp::get_header(g);
5432 const auto header_size = sbepp::size_bytes(header);
5433 if(!validate_and_subtract(header_size))
5434 {
5435 return true;
5436 }
5437
5438 const auto prev_block_length =
5439 set_group_block_length(*header.blockLength());
5440 sbepp::visit_children(g, c, *this);
5441 set_group_block_length(prev_block_length);
5442
5443 return !is_valid();
5444 }
5445
5446 template<typename T, typename Cursor>
5447 SBEPP_CPP14_CONSTEXPR bool on_entry(T e, Cursor& c) noexcept
5448 {
5449 if(!validate_and_subtract(group_block_length))
5450 {
5451 return true;
5452 }
5453
5454 return !sbepp::visit_children(e, c, *this).is_valid();
5455 }
5456
5457 template<typename T, typename Tag>
5458 SBEPP_CPP14_CONSTEXPR bool on_data(T d, Tag) noexcept
5459 {
5460 return !validate_and_subtract(sbepp::size_bytes(d));
5461 }
5462
5463 // ignore them all because we validate `blockLength`
5464 template<typename T, typename Tag>
5465 constexpr bool on_field(T, Tag) const noexcept
5466 {
5467 return {};
5468 }
5469
5470 constexpr bool is_valid() const noexcept
5471 {
5472 return valid;
5473 }
5474
5475 // returns previous value
5476 SBEPP_CPP14_CONSTEXPR std::size_t
5477 set_group_block_length(const std::size_t block_length) noexcept
5478 {
5479 auto prev = group_block_length;
5480 group_block_length = block_length;
5481 return prev;
5482 }
5483
5484 constexpr std::size_t get_size() const noexcept
5485 {
5486 return size;
5487 }
5488
5489private:
5490 std::size_t size;
5491 bool valid{true};
5492 // current group's blockLength, used to validate entry
5493 std::size_t group_block_length{};
5494
5495 SBEPP_CPP14_CONSTEXPR bool
5496 validate_and_subtract(const std::size_t n) noexcept
5497 {
5498 if(size < n)
5499 {
5500 valid = false;
5501 }
5502 else
5503 {
5504 size -= n;
5505 }
5506
5507 return valid;
5508 }
5509};
5510} // namespace detail
5511
5513struct size_bytes_checked_result
5514{
5516 bool valid;
5518 std::size_t size;
5519};
5520
5521// can be used with message/group
5532template<typename View>
5533SBEPP_CPP20_CONSTEXPR size_bytes_checked_result
5534 size_bytes_checked(View view, std::size_t size) noexcept
5535{
5536 // `init_cursor` skips header, we need to ensure there's enough space for it
5537 if(!sbepp::addressof(view) || (size < detail::get_header_size(view)))
5538 {
5539 return {};
5540 }
5541
5542 detail::size_bytes_checked_visitor visitor{size};
5543 auto c = sbepp::init_cursor(view);
5544 sbepp::visit(view, c, visitor);
5545 if(visitor.is_valid())
5546 {
5547 return {true, size - visitor.get_size()};
5548 }
5549 return {};
5550}
5551} // namespace sbepp
5552
5553#if SBEPP_HAS_RANGES && SBEPP_HAS_CONCEPTS
5554
5555template<typename Byte, typename Value, std::size_t N, typename Tag>
5556inline constexpr bool std::ranges::enable_borrowed_range<
5558
5559template<typename Byte, typename Value, typename Length, sbepp::endian E>
5560inline constexpr bool std::ranges::enable_borrowed_range<
5562
5563template<sbepp::detail::derived_from_tmp<sbepp::detail::flat_group_base> T>
5564inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5565
5566template<sbepp::detail::derived_from_tmp<sbepp::detail::nested_group_base> T>
5567inline constexpr bool std::ranges::enable_borrowed_range<T> = true;
5568#endif
5569
5570#undef SBEPP_CPP17_INLINE_VAR
5571#undef SBEPP_DEPRECATED
5572#undef SBEPP_CPLUSPLUS
5573
5574SBEPP_WARNINGS_ON();
Provides various traits/attributes of a <composite> element.
Definition sbepp.hpp:4297
CompositeType< Byte > value_type
Representation type.
Definition sbepp.hpp:4321
static constexpr const char * name() noexcept
Returns name attribute.
Represents cursor which is used in cursor-based API. Clients should not use undocumented methods.
Definition sbepp.hpp:790
constexpr Byte * pointer() const noexcept
access underlying pointer
Definition sbepp.hpp:856
constexpr cursor(cursor< Byte2 > other) noexcept
Construct from another cursor. Enabled only if Byte2* is convertible to Byte*.
Definition sbepp.hpp:819
Byte byte_type
same as Byte
Definition sbepp.hpp:793
cursor()=default
Construct a new cursor object initialized with nullptr
constexpr Byte *& pointer() noexcept
access underlying pointer. Might be useful in rare cases to initialize cursor with a particular value...
Definition sbepp.hpp:846
constexpr cursor & operator=(cursor< Byte2 > other) noexcept
Assign from another cursor. Enabled only if Byte2* is convertible to Byte
Definition sbepp.hpp:834
Provides various traits/attributes of a <data> element.
Definition sbepp.hpp:4582
static constexpr const char * name() noexcept
Returns name attribute.
DataType value_type
Representation type.
Definition sbepp.hpp:4601
LengthTypeTag length_type_tag
length_type tag
Definition sbepp.hpp:4605
LengthType length_type
Length type.
Definition sbepp.hpp:4603
Base class for bitsets.
Definition sbepp.hpp:2743
constexpr T operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:2760
constexpr friend bool operator==(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are equal.
Definition sbepp.hpp:2779
constexpr T & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:2754
constexpr bitset_base(T value) noexcept
Constructs from given value.
Definition sbepp.hpp:2749
constexpr friend bool operator!=(const bitset_base &lhs, const bitset_base &rhs) noexcept
Tests if underlying values are not equal.
Definition sbepp.hpp:2786
bitset_base()=default
Default constructs underlying value to 0
Base class for all reference semantics types.
Definition sbepp.hpp:721
constexpr byte_range(Byte *ptr, const std::size_t size) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:743
constexpr byte_range(const byte_range< Byte2 > &other) noexcept
Copy constructor. Available if Byte2* is convertible to Byte*
Definition sbepp.hpp:751
byte_range()=default
Initializes to nullptr
constexpr byte_range(Byte *begin, Byte *end) noexcept
Constructs from a pair of pointers.
Definition sbepp.hpp:732
Base class for composites.
Definition sbepp.hpp:1747
Represents reference to dynamic arrays used for <data> elements.
Definition sbepp.hpp:3311
constexpr sbe_size_type sbe_size() const noexcept
Returns SBE size representation.
Definition sbepp.hpp:3401
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3333
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:3335
constexpr iterator insert(iterator pos, std::initializer_list< value_type > ilist) const noexcept
Inserts elements from ilist before pos
Definition sbepp.hpp:3560
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3359
static constexpr size_type max_size() noexcept
Returns max value of SBE length representation.
Definition sbepp.hpp:3419
constexpr iterator erase(iterator first, iterator last) const noexcept
Erases elements in [first; last) range.
Definition sbepp.hpp:3507
constexpr void assign_string(const char *str) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3626
constexpr iterator insert(iterator pos, InputIt first, InputIt last) const
Inserts elements from [first; last) range before pos
Definition sbepp.hpp:3550
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:3590
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:3374
constexpr void resize(size_type count, sbepp::default_init_t) const noexcept
Sets size to count, default initializes new elements.
Definition sbepp.hpp:3465
element_type * pointer
element pointer type
Definition sbepp.hpp:3331
constexpr void push_back(value_type value) const noexcept
Adds new element to the end.
Definition sbepp.hpp:3479
constexpr iterator insert(iterator pos, const value_type value) const noexcept
Inserts value before pos
Definition sbepp.hpp:3518
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:3394
constexpr void resize(size_type count) const noexcept
Sets size to count, value initializes new elements.
Definition sbepp.hpp:3433
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:3366
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:3327
constexpr void pop_back() const noexcept
Removes the last element.
Definition sbepp.hpp:3488
Value value_type
same as Value
Definition sbepp.hpp:3321
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:3607
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:3319
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3341
constexpr void assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3645
constexpr iterator insert(iterator pos, size_type count, const value_type value) const noexcept
Inserts count copies of value before pos
Definition sbepp.hpp:3530
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:3570
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:3387
constexpr iterator erase(iterator pos) const noexcept
Erases element at pos
Definition sbepp.hpp:3496
constexpr void clear() const noexcept
Sets size to 0.
Definition sbepp.hpp:3426
constexpr bool empty() const noexcept
Checks if size() != 0
Definition sbepp.hpp:3413
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3353
constexpr void resize(size_type count, value_type value) const noexcept
Sets size to count, initializes new elements with value
Definition sbepp.hpp:3449
constexpr void assign(InputIt first, InputIt last) const
Replaces the contents of the container with the elements from [first; last) range.
Definition sbepp.hpp:3579
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3347
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:3407
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:3325
Length sbe_size_type
length SBE representation of data's encoding
Definition sbepp.hpp:3323
element_type & reference
element reference type
Definition sbepp.hpp:3329
Base class for group entries.
Definition sbepp.hpp:1798
constexpr entry_base(cursor< Byte2 > &c, Byte *end_ptr, BlockLengthType block_length) noexcept
Constructs from cursor.
Definition sbepp.hpp:1826
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:1838
constexpr entry_base(Byte *ptr, const std::size_t size, const BlockLengthType block_length) noexcept
Constructs from pointer and size.
Definition sbepp.hpp:1816
entry_base()=default
Constructs using nullptr
constexpr entry_base(Byte *ptr, Byte *end, BlockLengthType block_length) noexcept
Constructs from two pointers.
Definition sbepp.hpp:1809
Base class for a flat group.
Definition sbepp.hpp:2286
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:2301
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2408
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2332
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2480
constexpr reference front() const noexcept
Returns the first entry.
Definition sbepp.hpp:2392
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:2444
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:2415
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2293
Entry value_type
Entry type.
Definition sbepp.hpp:2289
constexpr reference operator[](size_type pos) const noexcept
Access group entry at pos
Definition sbepp.hpp:2384
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2338
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2362
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2487
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2428
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2350
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2373
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2344
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2497
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2356
constexpr reference back() const noexcept
Returns the last entry.
Definition sbepp.hpp:2400
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2298
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:2462
typename sbe_size_type::value_type size_type
Raw size type.
Definition sbepp.hpp:2296
value_type reference
value_type
Definition sbepp.hpp:2291
Base class for messages.
Definition sbepp.hpp:1756
Base class for a nested group.
Definition sbepp.hpp:2520
constexpr size_type size() const noexcept
Returns raw size.
Definition sbepp.hpp:2576
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:2611
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:2666
Entry value_type
entry type
Definition sbepp.hpp:2523
static constexpr size_type max_size() noexcept
Returns numInGroup's maxValue
Definition sbepp.hpp:2594
typename cursor_range_t< Byte2 >::iterator cursor_iterator
cursor_range_t::iterator. Satisfies std::input_iterator
Definition sbepp.hpp:2702
value_type reference
value_type
Definition sbepp.hpp:2525
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:2637
typename sbe_size_type::value_type size_type
raw size type
Definition sbepp.hpp:2530
typename std::make_signed< size_type >::type difference_type
signed size_type
Definition sbepp.hpp:2532
constexpr sbe_size_type sbe_size() const noexcept
Returns header's numInGroup
Definition sbepp.hpp:2570
constexpr void resize(const size_type count) const noexcept
Sets numInGroup to count
Definition sbepp.hpp:2582
constexpr reference front() const noexcept
Returns the first element.
Definition sbepp.hpp:2622
constexpr cursor_iterator< Byte2 > cursor_end(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the end.
Definition sbepp.hpp:2719
constexpr void clear() const noexcept
Resizes to 0
Definition sbepp.hpp:2630
constexpr cursor_iterator< Byte2 > cursor_begin(cursor< Byte2 > &c) const noexcept
Returns cursor iterator to the beginning.
Definition sbepp.hpp:2709
constexpr bool empty() const noexcept
Checks if size() == 0
Definition sbepp.hpp:2588
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:2536
constexpr cursor_range_t< Byte2 > cursor_range(cursor< Byte2 > &c) const noexcept
Returns cursor range to all group entries.
Definition sbepp.hpp:2650
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:2684
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:2600
typename std::decay< decltype(std::declval< Dimension >().numInGroup())>::type sbe_size_type
numInGroup value type
Definition sbepp.hpp:2527
Base class for optional types.
Definition sbepp.hpp:3841
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3862
constexpr friend bool operator!=(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3942
constexpr optional_base(nullopt_t) noexcept
Constructs null object.
Definition sbepp.hpp:3851
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:3887
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:3970
T value_type
Underlying type.
Definition sbepp.hpp:3844
constexpr bool in_range() const noexcept
Checks if value is in [Derived::min_value(); Derived::max_value()] range.
Definition sbepp.hpp:3881
constexpr optional_base(value_type val) noexcept
Constructs object from given value.
Definition sbepp.hpp:3857
constexpr bool has_value() const noexcept
Checks if has value.
Definition sbepp.hpp:3897
constexpr friend bool operator>(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3963
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3874
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3868
constexpr friend bool operator==(const optional_base &lhs, const optional_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3917
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:3734
constexpr friend bool operator>(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is greater than rhs
Definition sbepp.hpp:3816
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:3823
constexpr value_type value() const noexcept
Returns underlying value.
Definition sbepp.hpp:3749
constexpr friend bool operator!=(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is not equal to rhs
Definition sbepp.hpp:3795
constexpr value_type & operator*() noexcept
Returns reference to underlying value.
Definition sbepp.hpp:3755
constexpr friend bool operator==(const required_base &lhs, const required_base &rhs) noexcept
Tests if lhs is equal to rhs
Definition sbepp.hpp:3788
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:3768
T value_type
Underlying type.
Definition sbepp.hpp:3737
constexpr value_type operator*() const noexcept
Returns underlying value.
Definition sbepp.hpp:3761
constexpr required_base(value_type val) noexcept
Constructs from given value.
Definition sbepp.hpp:3744
Represents reference to fixed-size array.
Definition sbepp.hpp:2989
pointer iterator
iterator type. Satisfies std::random_access_iterator
Definition sbepp.hpp:3005
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator to the end.
Definition sbepp.hpp:3089
static constexpr bool empty() noexcept
Checks if size() != 0
Definition sbepp.hpp:3053
detail::apply_cv_qualifiers_t< Byte, Value > element_type
final element type. value_type with the same cv-qualifiers as Byte
Definition sbepp.hpp:2993
constexpr reference operator[](size_type pos) const noexcept
Access element at pos
Definition sbepp.hpp:3021
constexpr std::size_t strlen() const noexcept
Calculates string length from left to right.
Definition sbepp.hpp:3118
constexpr iterator assign_string(const char *str, const eos_null eos_mode=eos_null::all) const noexcept
Assigns null-terminated string.
Definition sbepp.hpp:3167
constexpr reference front() const noexcept
Access the first element.
Definition sbepp.hpp:3028
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition sbepp.hpp:3071
static constexpr size_type size() noexcept
Returns N
Definition sbepp.hpp:3059
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:3106
constexpr iterator assign(std::initializer_list< value_type > ilist) const noexcept
Assigns initializer list to first elements.
Definition sbepp.hpp:3273
element_type & reference
element reference type
Definition sbepp.hpp:3001
std::reverse_iterator< iterator > reverse_iterator
reverse iterator type
Definition sbepp.hpp:3007
constexpr reference back() const noexcept
Access the last element.
Definition sbepp.hpp:3034
Value value_type
same as Value
Definition sbepp.hpp:2995
Tag tag
type tag
Definition sbepp.hpp:3009
element_type * pointer
element pointer type
Definition sbepp.hpp:3003
constexpr std::size_t strlen_r() const noexcept
Calculates string length from right to left.
Definition sbepp.hpp:3143
std::size_t size_type
std::size_t
Definition sbepp.hpp:2997
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition sbepp.hpp:3077
constexpr iterator assign_string(R &&r, const eos_null eos_mode=eos_null::all) const
Assigns string represented by a range.
Definition sbepp.hpp:3195
constexpr void fill(const value_type value) const noexcept
Assigns value to all elements.
Definition sbepp.hpp:3232
constexpr iterator assign_range(R &&r) const
Assigns range.
Definition sbepp.hpp:3215
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator to the beginning.
Definition sbepp.hpp:3083
constexpr iterator assign(InputIt first, InputIt last) const
Assigns elements from [first; last) range to first elements.
Definition sbepp.hpp:3257
static constexpr size_type max_size() noexcept
Returns size()
Definition sbepp.hpp:3065
std::ptrdiff_t difference_type
std::ptrdiff_t
Definition sbepp.hpp:2999
constexpr pointer data() const noexcept
Direct access to the underlying array.
Definition sbepp.hpp:3040
constexpr iterator assign(size_type count, const value_type value) const noexcept
Assigns value to first count elements.
Definition sbepp.hpp:3247
Provides various traits/attributes of an <enum> element.
Definition sbepp.hpp:4163
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4170
static constexpr const char * name() noexcept
Returns name attribute.
ScopedEnumType value_type
Representation type.
Definition sbepp.hpp:4182
Provides various traits/attributes of a <validValue> element.
Definition sbepp.hpp:4200
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <field> element.
Definition sbepp.hpp:4463
static constexpr const char * name() noexcept
Returns name attribute.
ValueType value_type
Representation type.
Definition sbepp.hpp:4485
TypeTag value_type_tag
value_type's tag. Not available for constants of numeric types
Definition sbepp.hpp:4494
Provides various traits/attributes of a <group> element.
Definition sbepp.hpp:4512
HeaderType< Byte > dimension_type
Group dimension composite type.
Definition sbepp.hpp:4542
HeaderTag dimension_type_tag
Dimension composite tag.
Definition sbepp.hpp:4544
GroupType< Byte > value_type
Representation type.
Definition sbepp.hpp:4535
EntryType< Byte > entry_type
Group entry type.
Definition sbepp.hpp:4551
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <message> element.
Definition sbepp.hpp:4341
static constexpr const char * name() noexcept
Returns name attribute.
SchemaTag schema_tag
Schema tag.
Definition sbepp.hpp:4366
MessageType< Byte > value_type
Representation type.
Definition sbepp.hpp:4364
Provides various traits/attributes of a <messageSchema> element.
Definition sbepp.hpp:4123
HeaderTypeTag header_type_tag
Message header composite tag. Can be used to access its traits.
Definition sbepp.hpp:4145
static constexpr const char * package() noexcept
Returns package attribute.
HeaderComposite< Byte > header_type
Message header composite type.
Definition sbepp.hpp:4143
Provides various traits/attributes of a <choice> element.
Definition sbepp.hpp:4267
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits/attributes of a <set> element.
Definition sbepp.hpp:4230
SetType value_type
Representation type.
Definition sbepp.hpp:4249
EncodingType encoding_type
Underlying type.
Definition sbepp.hpp:4242
static constexpr const char * name() noexcept
Returns name attribute.
Provides various traits and attributes of a <type> element.
Definition sbepp.hpp:4042
ValueType value_type
Representation type.
Definition sbepp.hpp:4048
PrimitiveType primitive_type
Underlying type.
Definition sbepp.hpp:4045
static constexpr const char * name() noexcept
Returns name attribute.
Concept for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5129
Concept for sbepp::is_composite<T>::value
Definition sbepp.hpp:5157
Concept for sbepp::is_data<T>::value
Definition sbepp.hpp:5177
Concept for sbepp::is_enum<T>::value
Definition sbepp.hpp:5149
Concept for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5165
Concept for sbepp::is_group<T>::value
Definition sbepp.hpp:5173
Concept for sbepp::is_message<T>::value
Definition sbepp.hpp:5161
Concept for sbepp::is_nested_group<T>::value
Definition sbepp.hpp:5169
Concept for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5141
Concept for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5137
Concept for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5133
Concept for sbepp::is_set<T>::value
Definition sbepp.hpp:5153
Concept for sbepp::is_type<T>::value
Definition sbepp.hpp:5145
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:1735
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:1701
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:1672
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:1715
The main sbepp namespace.
Definition sbepp.hpp:232
constexpr auto is_composite_v
Shorthand for sbepp::is_composite<T>::value
Definition sbepp.hpp:5103
constexpr auto is_required_type_v
Shorthand for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5079
constexpr auto is_type_v
Shorthand for sbepp::is_type<T>::value
Definition sbepp.hpp:5091
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:2834
detail::is_base_of_tmp< detail::optional_base, T > is_optional_type
Checks if T is a non-array optional type.
Definition sbepp.hpp:4992
constexpr View< Byte > make_view(Byte *ptr, const std::size_t size) noexcept
Construct view from memory buffer.
Definition sbepp.hpp:4904
typename traits_tag< ValueType >::type traits_tag_t
Shorthand for sbepp::traits_tag<T>::type
Definition sbepp.hpp:4654
constexpr auto is_flat_group_v
Shorthand for sbepp::is_flat_group<T>::value
Definition sbepp.hpp:5111
eos_null
Represents number of null bytes that can be added after the end-of-string by detail::static_array_ref...
Definition sbepp.hpp:2902
@ 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:2853
constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
Returns the header of a message/group.
Definition sbepp.hpp:1614
detail::is_base_of_tmp< detail::required_base, T > is_required_type
Checks if T is a non-array required type.
Definition sbepp.hpp:4988
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:5045
detail::is_base_of_tmp< detail::flat_group_base, T > is_flat_group
Checks if T is a flat group.
Definition sbepp.hpp:5037
constexpr auto is_array_type_v
Shorthand for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5075
constexpr nullopt_t nullopt
Helper constant used to initialize optional types with null value.
Definition sbepp.hpp:3724
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:5308
constexpr auto is_enum_v
Shorthand for sbepp::is_enum<T>::value
Definition sbepp.hpp:5095
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:2876
constexpr auto fill_message_header(Message m) noexcept -> decltype(m(detail::fill_message_header_tag{}))
Fill message header.
Definition sbepp.hpp:3997
constexpr auto is_non_array_type_v
Shorthand for sbepp::is_non_array_type<T>::value
Definition sbepp.hpp:5087
constexpr Visitor && visit(View view, Cursor &c, Visitor &&visitor={})
Visit a view using given cursor.
Definition sbepp.hpp:5206
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:5070
typename byte_type< View >::type byte_type_t
Shortcut for byte_type<T>::type
Definition sbepp.hpp:1646
detail::is_base_of_tmp< detail::nested_group_base, T > is_nested_group
Checks if T is a nested group.
Definition sbepp.hpp:5041
constexpr const char * enum_to_string(const E e) noexcept
Converts enum to string.
Definition sbepp.hpp:5374
detail::is_base_of_tmp< detail::message_base, T > is_message
Checks if T is a message.
Definition sbepp.hpp:5033
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:4017
constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
Returns pointer to the underlying data referenced by a view.
Definition sbepp.hpp:1626
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:1587
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:5025
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:5002
constexpr auto is_group_v
Shorthand for sbepp::is_group<T>::value
Definition sbepp.hpp:5119
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:5392
constexpr default_init_t default_init
helper to pass default_init_t to dynamic_array_ref::resize().
Definition sbepp.hpp:2897
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:4996
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:5083
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:5533
constexpr auto is_message_v
Shorthand for sbepp::is_message<T>::value
Definition sbepp.hpp:5107
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:5099
detail::is_base_of_tmp< detail::entry_base, T > is_group_entry
Checks if T is a group entry.
Definition sbepp.hpp:5051
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:5115
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:4929
constexpr auto is_data_v
Shorthand for sbepp::is_data<T>::value
Definition sbepp.hpp:5123
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:4984
detail::is_base_of_tmp< detail::composite_base, T > is_composite
Checks if T is a composite.
Definition sbepp.hpp:5029
#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:1638
typename std::remove_pointer< decltype(sbepp::addressof( std::declval< View >()))>::type type
holds View's byte type
Definition sbepp.hpp:1640
tag for dynamic_array_ref::resize(). Used to skip value initialization.
Definition sbepp.hpp:2888
Checks if T is an enumeration.
Definition sbepp.hpp:5010
Tag type used to initialize optional types with null value.
Definition sbepp.hpp:3713
Result type of size_bytes_checked
Definition sbepp.hpp:5513
Maps representation type to its tag.
Definition sbepp.hpp:4646
Tag type
Tag to access ValueType's traits.
Definition sbepp.hpp:4648
Tag for unknown enum values.
Definition sbepp.hpp:4941