OnixS C++ CME MDP Premium Market Data Handler 5.10.2
Users' manual and API documentation
Loading...
Searching...
No Matches
SbeMessage.h
Go to the documentation of this file.
1// Copyright Onix Solutions Limited [OnixS]. All rights reserved.
2//
3// This software owned by Onix Solutions Limited [OnixS] and is
4// protected by copyright law and international copyright treaties.
5//
6// Access to and use of the software is governed by the terms of the applicable
7// OnixS Software Services Agreement (the Agreement) and Customer end user license
8// agreements granting a non-assignable, non-transferable and non-exclusive license
9// to use the software for it's own data processing purposes under the terms defined
10// in the Agreement.
11//
12// Except as otherwise granted within the terms of the Agreement, copying or
13// reproduction of any part of this source code or associated reference material
14// to any other location for further reproduction or redistribution, and any
15// amendments to this copyright notice, are expressly prohibited.
16//
17// Any reproduction or redistribution for sale or hiring of the Software not in
18// accordance with the terms of the Agreement is a violation of copyright law.
19//
20
21#pragma once
22
23#include <OnixS/CME/MDH/ABI.h>
34
35#include <cassert>
36#include <limits>
37#include <stdexcept>
38
40
42typedef MessageHeader::TemplateId MessageTemplateId;
43
45template <typename Message>
46inline void checkBinaryLength(const Message&, MessageSize length, MessageSize minimalRequiredLength)
47{
48 if ONIXS_CMEMDH_UNLIKELY (length < minimalRequiredLength)
49 {
50 throwBinaryBlockIsTooSmall(length, minimalRequiredLength, Message::className());
51 }
52}
53
55{
56protected:
57 ~BinaryBlockBase() = default;
58};
59
65template <class Container, class BlockLength>
67{
70 const Container& container() const noexcept
71 {
72 return *static_cast<const Container*>(this);
73 }
74
75protected:
77 BinaryBlock() = default;
78
79 ~BinaryBlock() = default;
80
82 template <class Value>
84 Value ordinary(BlockLength offset) const noexcept
85 {
86 assert(
87 container().blockLength() >= (offset + size<Value>())
88 && "The requested field exceeds provided block boundaries."
89 );
90
91 const void* const location = advanceByBytes(container().block(), offset);
92 return getValue<Value>(location);
93 }
94
96 template <class Value>
98 Value ordinary(BlockLength offset, SchemaVersion since) const
99 {
100 if ONIXS_CMEMDH_UNLIKELY (since > container().version())
101 throwDisallowedField();
102
103 return ordinary<Value>(offset);
104 }
105
110 template <class Value, class NullValue>
112 bool ordinary(Value& value, BlockLength offset, NullValue null) const noexcept
113 {
114 value = ordinary<Value>(offset);
115
116 return (null != value);
117 }
118
123 template <class Value, class NullValue>
125 bool ordinary(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
126 {
127 return (since <= container().version() && ordinary(value, offset, null));
128 }
129
131 template <class Enumeration>
133 typename Enumeration::Enum enumeration(BlockLength offset) const noexcept
134 {
135 typedef typename Enumeration::Base Base;
136 typedef typename Enumeration::Enum Enum;
137
138 return static_cast<Enum>(ordinary<Base>(offset));
139 }
140
142 template <class Enumeration, class NullValue>
144 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null) const noexcept
145 {
146 typedef typename Enumeration::Base Base;
147 typedef typename Enumeration::Enum Enum;
148
149 value = static_cast<Enum>(ordinary<Base>(offset));
150 return null != value;
151 }
152
154 template <class Enumeration, class NullValue>
156 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
157 {
158 return (since <= container().version() && enumeration<Enumeration>(value, offset, null));
159 }
160
162 template <class Value>
164 Decimal decimal(BlockLength offset) const
165 {
166 return Decimal(ordinary<Value>(offset));
167 }
168
173 template <class NullValue>
175 bool decimal(Decimal& value, BlockLength offset, NullValue null) const noexcept
176 {
177 typedef typename NullValue::Value Value;
178 const Value optional = ordinary<Value>(offset);
179 value = optional;
180
181 return null != optional;
182 }
183
188 template <class Value, class NullValue>
190 bool decimal(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
191 {
192 return (since <= container().version() && decimal(value, offset, null));
193 }
194
196 template <BlockLength Length>
198 StrRef fixedStr(BlockLength offset) const noexcept
199 {
200 assert(
201 container().blockLength() >= (offset + Length) && "The requested field exceeds provided block boundaries."
202 );
203
204 const Char* const text = reinterpret_cast<const Char*>(advanceByBytes(container().block(), offset));
205 return StrRef(text, strnlen(text, Length));
206 }
207
212 template <BlockLength Length>
214 bool fixedStr(StrRef& value, BlockLength offset) const noexcept
215 {
216 value = fixedStr<Length>(offset);
217 return !value.empty();
218 }
219
224 template <BlockLength Length>
226 bool fixedStr(StrRef& value, BlockLength offset, SchemaVersion since) const noexcept
227 {
228 return (since <= container().version() && fixedStr<Length>(value, offset));
229 }
230};
231
236template <class Container, class BlockLength>
237class SbeFields : public BinaryBlock<Container, BlockLength>
238{
239public:
242 Container& container() noexcept
243 {
244 return *static_cast<Container*>(this);
245 }
246
249 void zeroPaddingBytes(BlockLength offset) noexcept
250 {
251 const BlockLength encodedBlockLength = container().blockLength();
252
253 assert(encodedBlockLength >= offset);
254
255 const size_t paddingLength = encodedBlockLength - offset;
256 std::memset(advanceByBytes(container().block(), offset), 0, paddingLength);
257 }
258
260 template <class FieldValue>
262 void setOrdinary(BlockLength offset, FieldValue value) noexcept
263 {
264 assert(
265 container().blockLength() >= (offset + size<FieldValue>())
266 && "The requested field exceeds provided block boundaries."
267 );
268
269 void* const fieldPos = advanceByBytes(container().block(), offset);
270 setValue(fieldPos, value);
271 }
272
274 template <class FieldValue>
276 void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
277 {
278 if ONIXS_CMEMDH_UNLIKELY (since > container().version())
279 {
280 throwDisallowedField();
281 }
282
283 setOrdinary(offset, value);
284 }
285
287 template <class Enumeration>
289 void setEnumeration(BlockLength offset, typename Enumeration::Enum value) noexcept
290 {
291 typedef typename Enumeration::Base Base;
292 setOrdinary<Base>(offset, static_cast<Base>(value));
293 }
294
296 template <class Enumeration>
298 void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
299 {
300 typedef typename Enumeration::Base Base;
301 setOrdinary(offset, static_cast<Base>(value), since);
302 }
303
305 template <BlockLength Size>
307 void setFixedStr(BlockLength offset, StrRef value) noexcept
308 {
309 assert(
310 container().blockLength() >= (offset + Size) && "The requested field exceeds provided block boundaries."
311 );
312 assert(value.size() <= Size && "The string is truncated.");
313
314 void* const fieldPos = advanceByBytes(container().block(), offset);
315 const size_t sizeToCopy = (std::min)(Size, static_cast<BlockLength>(value.size()));
316
317 if (sizeToCopy > 0)
318 std::memcpy(fieldPos, value.data(), sizeToCopy);
319
320 std::memset(advanceByBytes(fieldPos, sizeToCopy), 0, Size - sizeToCopy);
321 }
322
324 template <BlockLength Size>
326 void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
327 {
328 if ONIXS_CMEMDH_UNLIKELY (since > container().version())
329 {
330 throwDisallowedField();
331 }
332
333 setFixedStr<Size>(offset, value);
334 }
335
336protected:
338 SbeFields() = default;
339
340 ~SbeFields() = default;
341};
342
344template <class BodySizeType>
345class SbeGroupEntry : public SbeFields<SbeGroupEntry<BodySizeType>, BodySizeType>
346{
347public:
349 typedef BodySizeType BlockLength;
350
353 : encoded_(nullptr)
354 , size_(0)
355 , version_(0)
356 {
357 }
358
362 : encoded_(encoded)
363 , size_(size)
364 , version_(version)
365 {
366 assert(encoded);
367 }
368
371 bool valid() const noexcept
372 {
373 return (encoded_ != nullptr);
374 }
375
378 const void* encoded() const noexcept
379 {
380 assert(valid());
381
382 return encoded_;
383 }
384
387 void* encoded() noexcept
388 {
389 assert(valid());
390
391 return encoded_;
392 }
393
396 const void* block() const noexcept
397 {
398 assert(valid());
399
400 return encoded_;
401 }
402
405 void* block() noexcept
406 {
407 assert(valid());
408
409 return encoded_;
410 }
411
414 BlockLength blockLength() const noexcept
415 {
416 return size_;
417 }
418
421 SchemaVersion version() const noexcept
422 {
423 return version_;
424 }
425
426private:
427 void* encoded_;
428 BodySizeType size_;
429 SchemaVersion version_;
430};
431
433template <class EntryType, class BlockLength, class NumInGroup, class Length>
435{
436public:
438 typedef Length EncodedLength;
439
442
444 typedef NumInGroup Size;
445
448 {
449 public:
452
453 typedef Entry* pointer;
454 typedef Entry& reference;
455
456 typedef ptrdiff_t difference_type;
457
458 typedef std::random_access_iterator_tag iterator_category;
459
461 Iterator() noexcept
462 : entry_(nullptr)
463 , size_(0)
464 , version_(0)
465 {
466 }
467
470 Iterator(void* entry, EncodedLength size, SchemaVersion version) noexcept
471 : entry_(entry)
472 , size_(size)
473 , version_(version)
474 {
475 assert(valid());
476 }
477
479 bool valid() const noexcept
480 {
481 return (entry_ != nullptr);
482 }
483
486 Entry get() const
487 {
488 assert(valid());
489
490 return Entry(entry_, size_, version_);
491 }
492
495 {
496 return get();
497 }
498
500 bool operator==(const Iterator& other) const noexcept
501 {
502 return entry_ == other.entry_;
503 }
504
506 bool operator!=(const Iterator& other) const noexcept
507 {
508 return entry_ != other.entry_;
509 }
510
512 bool operator<(const Iterator& other) const noexcept
513 {
514 return entry_ < other.entry_;
515 }
516
518 bool operator>(const Iterator& other) const noexcept
519 {
520 return entry_ > other.entry_;
521 }
522
525 {
526 assert(valid());
527
528 entry_ = advanceByBytes(entry_, size_);
529
530 return *this;
531 }
532
535 {
536 assert(valid());
537
538 entry_ = advanceBackByBytes(entry_, size_);
539
540 return *this;
541 }
542
546 {
547 assert(valid());
548
549 return Iterator(advanceByBytes(entry_, distance * size_), size_, version_);
550 }
551
555 {
556 assert(valid());
557
558 return Iterator(advanceBackByBytes(entry_, distance * size_), size_, version_);
559 }
560
561 private:
562 void* entry_;
563 EncodedLength size_;
564 SchemaVersion version_;
565 };
566
569 : encoded_(nullptr)
570 , blockLength_(0)
571 , size_(0)
572 , version_(0)
573 {
574 }
575
577 SbeGroupEntries(void* encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) noexcept
578 : encoded_(encoded)
579 , blockLength_(blockLength)
580 , size_(groupSize)
581 , version_(version)
582 {
583 assert(encoded_);
584 assert(blockLength > 0);
585 assert(version != 0);
586 }
587
589 bool valid() const noexcept
590 {
591 return (nullptr != encoded_);
592 }
593
595 bool empty() const noexcept
596 {
597 return (0 == size_);
598 }
599
601 Size size() const noexcept
602 {
603 return size_;
604 }
605
607 Iterator begin() const
608 {
609 return Iterator(encoded(), blockLength_, version_);
610 }
611
613 Iterator end() const
614 {
615 return Iterator(advanceByBytes(encoded(), encodedLength()), blockLength_, version_);
616 }
617
621 Entry operator[](Size index) const
622 {
623 assert(index < size_);
624 assert(encoded_);
625
626 return Entry(advanceByBytes(encoded_, static_cast<ptrdiff_t>(index) * blockLength_), blockLength_, version_);
627 }
628
630 void* encoded() const noexcept
631 {
632 return encoded_;
633 }
634
637 {
638 return (static_cast<EncodedLength>(blockLength_) * static_cast<EncodedLength>(size_));
639 }
640
642 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength>
644 : encoded_(other.encoded_)
645 , blockLength_(other.blockLength_)
646 , size_(other.size_)
647 , version_(other.version_)
648 {
649 // Dimension types may vary for the different instantiations of the template.
650 // Therefore, truncation of the dimensions must be avoided.
651
652 assert(blockLength_ == other.blockLength_);
653 assert(size_ == other.size_);
654 }
655
656 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength>
658 ) noexcept
659 {
660 encoded_ = other.encoded_;
661
662 blockLength_ = other.blockLength_;
663
664 assert(blockLength_ == other.blockLength_);
665
666 size_ = other.size_;
667
668 assert(size_ == other.size_);
669
670 version_ = other.version_;
671
672 return *this;
673 }
674
675private:
676 // Allows coping and cloning for different instantiations.
677 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength>
678 friend class SbeGroupEntries;
679
680 void* encoded_;
681 BlockLength blockLength_;
682 NumInGroup size_;
683 SchemaVersion version_;
684};
685
687template <class EntryType, class DimensionType, class GroupSizeType>
689{
690public:
692 typedef DimensionType Dimension;
693
695 typedef GroupSizeType BinarySize;
696
698 enum
699 {
701 };
702
704 typedef typename DimensionType::BlockLength EntrySize;
705
709
711 typedef typename Entries::Iterator Iterator;
712
714 typedef typename Entries::Entry Entry;
715
717 typedef typename Entries::Size Size;
718
720 SbeGroup() noexcept
721 : header_(nullptr)
722 , entries_(nullptr)
723 , version_(0)
724 {
725 }
726
730 : header_(static_cast<Dimension*>(data))
731 , entries_(advanceByBytes(data, Dimension::Size))
732 , version_(version)
733 {
734 ONIXS_CMEMDH_ASSERT(size >= Dimension::Size);
735 assert(header_);
736 assert(entries_);
737
738 assert(valid());
739 }
740
742 bool valid() const noexcept
743 {
744 return (entries_ != nullptr);
745 }
746
748 bool empty() const noexcept
749 {
750 assert(valid());
751
752 return 0 == size();
753 }
754
757 Size size() const noexcept
758 {
759 assert(valid());
760 assert(header_);
761
762 const Dimension* const group = static_cast<const Dimension*>(header_);
763
764 return group->numInGroup();
765 }
766
769 Iterator begin() const noexcept
770 {
771 assert(valid());
772
773 return Iterator(entries_, numericCast<EntrySize>(entrySize()), version_);
774 }
775
778 Iterator end() const noexcept
779 {
780 assert(valid());
781
782 return Iterator(advanceByBytes(binary(), binarySize()), numericCast<EntrySize>(entrySize()), version_);
783 }
784
789 Entry operator[](Size index) const
790 {
791 assert(valid());
792 assert(index < size());
793
794 return Entry(advanceByBytes(entries_, static_cast<ptrdiff_t>(index) * entrySize()), entrySize(), version_);
795 }
796
799 Entries entries() const noexcept
800 {
801 assert(valid());
802 assert(header_);
803
804 return Entries(entries_, header_->blockLength(), header_->numInGroup(), version_);
805 }
806
808 const void* encoded() const noexcept
809 {
810 return header_;
811 }
812
814 const void* tail() const noexcept
815 {
816 return advanceByBytes(toByteBlock(encoded()), binarySize());
817 }
818
821 void* binary() const noexcept
822 {
823 return header_;
824 }
825
828 BinarySize binarySize() const noexcept
829 {
830 return Dimension::Size + (static_cast<BinarySize>(entrySize()) * static_cast<BinarySize>(size()));
831 }
832
835 EntrySize entrySize() const noexcept
836 {
837 assert(valid());
838 assert(header_);
839
840 Dimension* const group = static_cast<Dimension*>(header_);
841 return group->blockLength();
842 }
843
844private:
846 void init(EntrySize entrySize) noexcept
847 {
848 assert(valid());
849 assert(header_);
850
851 Dimension* const group = static_cast<Dimension*>(header_);
852 group->setBlockLength(entrySize);
853 group->setNumInGroup(0);
854 }
855
857 Size allocate(Size entryCount, const void* messageTail, const void* blockEnd)
858 {
859 assert(valid());
860 assert(blockEnd);
861 assert(messageTail);
862
863 Dimension* const group = static_cast<Dimension*>(header_);
864
865 const EntrySize entrySize = group->blockLength();
866
867 if ONIXS_CMEMDH_UNLIKELY (entrySize < EntryType::blockLength(version_))
868 {
869 throwBadBinaryBlock();
870 }
871
872 const Size oldEntryCount = group->numInGroup();
873
874 if (oldEntryCount == entryCount)
875 return entryCount;
876
877 const ptrdiff_t memShift = (entryCount - oldEntryCount) * static_cast<ptrdiff_t>(entrySize);
878
879 const void* const newMessageTail = advanceByBytes(messageTail, memShift);
880
881 if ONIXS_CMEMDH_UNLIKELY (byteDistance(blockEnd, newMessageTail) < 0)
882 {
883 throwNotEnoughSpace();
884 }
885
886 const void* const oldEndOfGroup = advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * oldEntryCount);
887
888 void* const newEndGroup = advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * entryCount);
889
890 std::memmove(newEndGroup, oldEndOfGroup, byteDistance(messageTail, oldEndOfGroup));
891
892 group->setNumInGroup(entryCount);
893
894 return oldEntryCount;
895 }
896
899 void setup(Size entryCount, const void* messageTail, const void* blockEnd)
900 {
901 assert(valid());
902 assert(blockEnd);
903 assert(messageTail);
904
905 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
906
907 for (Size index = oldEntryCount; index < entryCount; ++index)
908 zeroPaddingBytes((*this)[index].resetVariableFields());
909 }
910
913 void construct(Size entryCount, const void* messageTail, const void* blockEnd)
914 {
915 assert(valid());
916 assert(blockEnd);
917 assert(messageTail);
918
919 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
920
921 for (Size index = oldEntryCount; index < entryCount; ++index)
922 zeroPaddingBytes((*this)[index].reset());
923 }
924
926 static void zeroPaddingBytes(Entry& entry)
927 {
928 assert(entry.valid());
929 entry.zeroPaddingBytes(EntryType::minimalBlockLength(entry.version()));
930 }
931
932private:
933 Dimension* header_;
934 void* entries_;
935 SchemaVersion version_;
936
937 friend class SbeMessage;
938};
939
941template <class BinarySize>
943{
944public:
947 SbeVariableLengthFieldList(void* binary, BinarySize size, SchemaVersion version) noexcept
948 : binary_(binary)
949 , size_(size)
950 , version_(version)
951 {
952 }
953
955 bool empty() const noexcept
956 {
957 return (0 == size_);
958 }
959
961 template <class BinaryVariableLengthFieldType>
962 BinaryVariableLengthFieldType& head() const noexcept
963 {
964 return *static_cast<BinaryVariableLengthFieldType*>(binary_);
965 }
966
968 template <class BinaryVariableLengthFieldType>
970 {
971 assert(!empty());
972
973 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
974
975 assert(headSize <= size_);
976
977 return SbeVariableLengthFieldList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
978 }
979
983 template <class BinaryVariableLengthFieldType>
985 {
986 if ONIXS_CMEMDH_UNLIKELY (empty() || (size_ < BinaryVariableLengthFieldType::Size))
987 {
988 throwBadBinaryBlock();
989 }
990
991 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
992
993 if ONIXS_CMEMDH_UNLIKELY (headSize > size_)
994 {
995 throwBadBinaryBlock();
996 }
997
998 return SbeVariableLengthFieldList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
999 }
1000
1001private:
1002 void* binary_;
1003 BinarySize size_;
1004 SchemaVersion version_;
1005};
1006
1008template <class BinarySize>
1010{
1011public:
1014 SbeGroupList(void* binary, BinarySize size, SchemaVersion version) noexcept
1015 : binary_(binary)
1016 , size_(size)
1017 , version_(version)
1018 {
1019 }
1020
1023 bool empty() const noexcept
1024 {
1025 return (0 == size_);
1026 }
1027
1029 template <class Group>
1031 ONIXS_CMEMDH_HOTPATH Group head() const noexcept
1032 {
1033 assert(!empty());
1034
1035 return Group(binary_, size_, version_);
1036 }
1037
1039 template <class Group>
1041 {
1042 assert(!empty());
1043
1044 const BinarySize headSize = head<Group>().binarySize();
1045
1046 assert(headSize <= size_);
1047
1048 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1049 }
1050
1052 template <class Group>
1054 {
1055 assert(!empty());
1056
1057 const BinarySize headSize = head<Group>().binarySize();
1058
1059 assert(headSize <= size_);
1060
1061 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1062 }
1063
1067 template <class Group>
1069 {
1070 const BinarySize headSize = checkHead<Group>();
1071
1072 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1073 }
1074
1078 template <class Group>
1080 {
1081 const BinarySize headSize = checkHead<Group>();
1082
1083 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1084 }
1085
1086private:
1087 template <class Group>
1088 BinarySize checkHead() const
1089 {
1090 if ONIXS_CMEMDH_UNLIKELY (size_ < Group::Dimension::Size)
1091 {
1092 throwBadBinaryBlock();
1093 }
1094
1095 const Group group = head<Group>();
1096
1097 const BinarySize headSize = group.binarySize();
1098
1099 if ONIXS_CMEMDH_UNLIKELY (headSize > size_)
1100 {
1101 throwBadBinaryBlock();
1102 }
1103
1104 if (!group.empty())
1105 {
1106 const BinarySize entrySize = group.entrySize();
1107 const BinarySize expectedEntrySize = Group::Entry::minimalBlockLength(version_);
1108
1109 if ONIXS_CMEMDH_UNLIKELY (entrySize < expectedEntrySize)
1110 {
1111 throwBadBinaryBlock();
1112 }
1113 }
1114
1115 return headSize;
1116 }
1117
1118 void* binary_;
1119 BinarySize size_;
1120 SchemaVersion version_;
1121};
1122
1124template <typename Traits>
1126{
1127 if ONIXS_CMEMDH_UNLIKELY (version < Traits::MinimalVersion)
1128 {
1129 throwBadMessageVersion(version, Traits::MinimalVersion);
1130 }
1131}
1132
1134template <typename Traits>
1136{
1137 checkVersion<Traits>(version);
1138
1139 if ONIXS_CMEMDH_UNLIKELY (version < since)
1140 {
1141 throwBadMessageVersion(version, since);
1142 }
1143}
1144
1146template <typename Traits>
1148{
1149 if ONIXS_CMEMDH_UNLIKELY (id != Traits::Id)
1150 {
1151 throwBadSchemaId(Traits::Id, id);
1152 }
1153}
1154
1156template <typename Traits>
1158{
1160 checkVersion<Traits>(version);
1161}
1162
1164class SbeMessage : public SbeFields<Messaging::SbeMessage, MessageSize>
1165{
1166public:
1169 struct NoInit{};
1170 struct NoCheck{};
1171
1174
1177
1179 SbeMessage() noexcept
1180 : header_(nullptr)
1181 , size_(0)
1182 {
1183 }
1184
1188 : header_(static_cast<MessageHeader*>(data))
1189 , size_(size)
1190 {
1191 assert(data);
1192 assert(size <= MaxMessageSize);
1193
1194 if ONIXS_CMEMDH_UNLIKELY (size < MessageHeader::Size)
1195 {
1196 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1197 }
1198
1199 this->version(version);
1200 }
1201
1204 SbeMessage(void* data, MessageSize size)
1205 : header_(static_cast<MessageHeader*>(data))
1206 , size_(size)
1207 {
1208 assert(data);
1209 assert(size <= MaxMessageSize);
1210
1211 if ONIXS_CMEMDH_UNLIKELY (size < MessageHeader::Size)
1212 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1213
1214 // Now it is safe to read header_.
1215 if ONIXS_CMEMDH_UNLIKELY (size < (MessageHeader::Size + header_->blockLength()))
1216 {
1217 throwBinaryBlockIsTooSmall(size, MessageHeader::Size + header_->blockLength());
1218 }
1219 }
1220
1225 SbeMessage(void* data, MessageSize size, NoCheck) noexcept
1226 : header_(static_cast<MessageHeader*>(data))
1227 , size_(size)
1228 {
1229 assert(data);
1230 assert(size <= MaxMessageSize);
1231
1232 assert(size >= MessageHeader::Size);
1233 assert(size >= MessageHeader::Size + header_->blockLength());
1234 }
1235
1237 void clear() noexcept
1238 {
1239 *this = SbeMessage();
1240 assert(!valid());
1241 }
1242
1245 bool valid() const noexcept
1246 {
1247 return (nullptr != header_);
1248 }
1249
1253 {
1254 assert(valid());
1255
1256 return header_->templateId();
1257 }
1258
1261 SchemaVersion version() const noexcept
1262 {
1263 assert(valid());
1264
1265 return header_->version();
1266 }
1267
1270 SchemaId schemaId() const noexcept
1271 {
1272 assert(valid());
1273
1274 return header_->schemaId();
1275 }
1276
1279 const void* binary() const noexcept
1280 {
1281 assert(valid());
1282
1283 return header_;
1284 }
1285
1288 void* binary() noexcept
1289 {
1290 assert(valid());
1291
1292 return header_;
1293 }
1294
1295 // \return the end of the memory block.
1297 const void* blockEnd() noexcept
1298 {
1299 assert(valid());
1300
1301 return advanceByBytes(header_, size_);
1302 }
1303
1304 // \return the end of the memory block.
1306 const void* blockEnd() const noexcept
1307 {
1308 assert(valid());
1309
1310 return advanceByBytes(header_, size_);
1311 }
1312
1315 MessageSize bufferSize() const noexcept
1316 {
1317 return size_;
1318 }
1319
1322 void* body() noexcept
1323 {
1324 assert(valid());
1325
1326 return advanceByBytes(header_, MessageHeader::Size);
1327 }
1328
1331 BlockLength blockLength() const noexcept
1332 {
1333 assert(valid());
1334
1335 return header_->blockLength();
1336 }
1337
1340 const void* block() const noexcept
1341 {
1342 assert(valid());
1343
1344 return advanceByBytes(header_, MessageHeader::Size);
1345 }
1346
1349 void* block() noexcept
1350 {
1351 assert(valid());
1352
1353 return advanceByBytes(header_, MessageHeader::Size);
1354 }
1355
1356protected:
1359
1363 {
1364 assert(valid());
1365
1366 header_->setVersion(version);
1367
1368 return *this;
1369 }
1370
1374 {
1375 assert(header_);
1376
1377 void* list = advanceByBytes<void>(body(), blockLength());
1378
1379 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1380
1381 return GroupList(list, listSize, header_->version());
1382 }
1383
1386 GroupList groups() const noexcept
1387 {
1388 assert(header_);
1389
1390 const void* list = advanceByBytes(block(), blockLength());
1391
1392 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1393
1394 return GroupList(const_cast<void*>(list), listSize, header_->version());
1395 }
1396
1398 template <typename Group>
1399 ONIXS_CMEMDH_HOTPATH void initGroup(Group& group, typename Group::EntrySize entrySize) noexcept
1400 {
1401 assert(group.valid());
1402 group.init(entrySize);
1403 }
1404
1406 template <typename Group>
1407 ONIXS_CMEMDH_HOTPATH void setupGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1408 {
1409 assert(messageTail);
1410 assert(group.valid());
1411 group.setup(entryCount, messageTail, blockEnd());
1412 }
1413
1415 template <typename Group>
1416 ONIXS_CMEMDH_HOTPATH void constructGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1417 {
1418 assert(messageTail);
1419 assert(group.valid());
1420 group.construct(entryCount, messageTail, blockEnd());
1421 }
1422
1425
1429 {
1430 assert(header_);
1431
1432 void* list = advanceByBytes<void>(body(), blockLength());
1433
1434 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1435
1436 return VariableLengthFieldList(list, listSize, header_->version());
1437 }
1438
1442 {
1443 assert(header_);
1444
1445 const void* list = advanceByBytes(block(), blockLength());
1446
1447 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1448
1449 return VariableLengthFieldList(const_cast<void*>(list), listSize, header_->version());
1450 }
1451
1453 void init(
1455 MessageHeader::BlockLength minimalBlockLength,
1457 SchemaId id
1458 ) noexcept
1459 {
1460 assert(header_);
1461 assert(blockLength >= minimalBlockLength);
1462
1463 header_->setTemplateId(value);
1464 header_->setBlockLength(blockLength);
1465 header_->setSchemaId(id);
1466
1467 zeroPaddingBytes(minimalBlockLength);
1468 }
1469
1471 MessageSize calculateBinarySize(const void* tail) const noexcept
1472 {
1473 assert(tail);
1474
1475 const ptrdiff_t distance = byteDistance(tail, binary());
1476
1477 assert(distance > 0);
1478
1479 assert(distance <= (std::numeric_limits<MessageSize>::max)());
1480
1481 const MessageSize size = static_cast<MessageSize>(distance);
1482
1483 assert(size <= size_);
1484
1485 return size;
1486 }
1487
1489 template <class Group, class Callable, class Owner>
1490 void resetGroup(Callable callable, Owner& owner) noexcept
1491 {
1492 const typename Group::EntrySize entrySize = Group::Entry::blockLength(version());
1493
1494 Group grp = callable(owner);
1495
1496 initGroup(grp, entrySize);
1497 }
1498
1500 template <class Callable, class Owner>
1501 void setVariableLengthFieldToNull(Callable callable, SchemaVersion since, Owner& owner) noexcept
1502 {
1503 if ONIXS_CMEMDH_UNLIKELY (since > version())
1504 {
1505 return;
1506 }
1507
1508 setVariableLengthFieldToNull(callable, owner);
1509 }
1510
1512 template <class Group, class Callable, class Owner>
1513 void resetGroup(Callable callable, SchemaVersion since, Owner& owner)
1514 {
1515 if ONIXS_CMEMDH_UNLIKELY (since > version())
1516 {
1517 return;
1518 }
1519
1520 resetGroup<Group>(callable, owner);
1521 }
1522
1524 template <class Group, class Callable, class Owner>
1525 Group getGroup(Callable callable, Owner& owner) const noexcept
1526 {
1527 static_assert(noexcept(callable(owner)), "");
1528 return callable(owner);
1529 }
1530
1532 template <class Group, class Callable, class Owner>
1533 Group getGroup(Callable callable, SchemaVersion since, Owner& owner) const noexcept
1534 {
1535 if ONIXS_CMEMDH_UNLIKELY (since > version())
1536 {
1537 return Group();
1538 }
1539
1540 return getGroup<Group>(callable, owner);
1541 }
1542
1545 template <class Group, class Callable, class Owner>
1546 Group constructGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1547 {
1548 if ONIXS_CMEMDH_UNLIKELY (since > version())
1549 {
1550 return Group();
1551 }
1552
1553 return constructGroup<Group>(callable, length, owner);
1554 }
1555
1558 template <class Group, class Callable, class Owner>
1559 Group constructGroup(Callable callable, typename Group::Size length, Owner& owner)
1560 {
1561 Group group = callable(owner);
1562
1563 constructGroup(group, length, owner.tail());
1564
1565 return group;
1566 }
1567
1569 template <class Group, class Callable, class Owner>
1570 Group setupGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1571 {
1572 if ONIXS_CMEMDH_UNLIKELY (since > version())
1573 {
1574 return Group();
1575 }
1576
1577 return setupGroup<Group>(callable, length, owner);
1578 }
1579
1581 template <class Group, class Callable, class Owner>
1582 Group setupGroup(Callable callable, typename Group::Size length, Owner& owner)
1583 {
1584 Group group = callable(owner);
1585
1586 setupGroup(group, length, owner.tail());
1587
1588 return group;
1589 }
1590
1594 static constexpr MessageSize getMaxMessageSize() noexcept
1595 {
1596 return MaxMessageSize;
1597 }
1598
1599private:
1600 MessageHeader* header_;
1601 MessageSize size_;
1602};
1603
1605template <class Message>
1609 const void* data, MessageSize size,
1610 typename std::enable_if<std::is_same<typename std::remove_cv<Message>::type, SbeMessage>::value>::type* = nullptr)
1611{
1612 return SbeMessage(toMutable(data), size);
1613}
1614
1616template <class Message>
1620 const void* data, MessageSize size,
1621 typename std::enable_if<std::is_base_of<SbeMessage, typename std::remove_cv<Message>::type>::value && !std::is_same<typename std::remove_cv<Message>::type, SbeMessage>::value>::type* = nullptr)
1622{
1623 return Message(toMutable(data), size, Messaging::SbeMessage::NoInit{});
1624}
1625
1627template <class Message>
1631 const void* data, MessageSize size, SbeMessage::NoCheck noCheck,
1632 typename std::enable_if<std::is_same<typename std::remove_cv<Message>::type, SbeMessage>::value>::type* = nullptr) noexcept
1633{
1634 return SbeMessage(toMutable(data), size, noCheck);
1635}
1636
1638template <class Message>
1642 const void* data, MessageSize size, SbeMessage::NoCheck noCheck,
1643 typename std::enable_if<std::is_base_of<SbeMessage, typename std::remove_cv<Message>::type>::value && !std::is_same<typename std::remove_cv<Message>::type, SbeMessage>::value>::type* = nullptr) noexcept
1644{
1645 return Message(toMutable(data), size, Messaging::SbeMessage::NoInit{}, noCheck);
1646}
1647
#define ONIXS_CMEMDH_MESSAGING_NAMESPACE_BEGIN
Definition Bootstrap.h:57
#define ONIXS_CMEMDH_MESSAGING_NAMESPACE_END
Definition Bootstrap.h:58
#define ONIXS_CMEMDH_LTWT_EXPORTED
Definition Bootstrap.h:47
#define ONIXS_CMEMDH_FORCEINLINE
Definition Compiler.h:161
#define ONIXS_CMEMDH_NODISCARD
Definition Compiler.h:150
#define ONIXS_CMEMDH_HOTPATH
Definition Compiler.h:152
#define ONIXS_CMEMDH_UNUSED
Definition Compiler.h:162
bool fixedStr(StrRef &value, BlockLength offset) const noexcept
Definition SbeMessage.h:214
Value ordinary(BlockLength offset) const noexcept
Definition SbeMessage.h:84
bool decimal(Decimal &value, BlockLength offset, NullValue null) const noexcept
Definition SbeMessage.h:175
Value ordinary(BlockLength offset, SchemaVersion since) const
Definition SbeMessage.h:98
bool fixedStr(StrRef &value, BlockLength offset, SchemaVersion since) const noexcept
Definition SbeMessage.h:226
bool ordinary(Value &value, BlockLength offset, NullValue null) const noexcept
Definition SbeMessage.h:112
bool decimal(Value &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Definition SbeMessage.h:190
Enumeration::Enum enumeration(BlockLength offset) const noexcept
Definition SbeMessage.h:133
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:144
BinaryBlock()=default
Initializes a blank instance.
bool ordinary(Value &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Definition SbeMessage.h:125
StrRef fixedStr(BlockLength offset) const noexcept
Provides access to a string field value.
Definition SbeMessage.h:198
Decimal decimal(BlockLength offset) const
Definition SbeMessage.h:164
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:156
NumInGroup numInGroup() const noexcept
Definition Composites.h:184
BlockLength blockLength() const noexcept
Definition Composites.h:171
Template ID and length of message root.
Definition Composites.h:308
UInt16 BlockLength
Type alias for the BlockLength.
Definition Composites.h:314
UInt16 TemplateId
Type alias for the TemplateId.
Definition Composites.h:317
SbeFields()=default
Initializes a blank instance.
Container & container() noexcept
Definition SbeMessage.h:242
void zeroPaddingBytes(BlockLength offset) noexcept
If specified, the extra space is padded at the end of each entry and should be set to zeroes by encod...
Definition SbeMessage.h:249
void setFixedStr(BlockLength offset, StrRef value) noexcept
Sets the field value.
Definition SbeMessage.h:307
void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:276
void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:298
void setEnumeration(BlockLength offset, typename Enumeration::Enum value) noexcept
Sets the field value.
Definition SbeMessage.h:289
void setOrdinary(BlockLength offset, FieldValue value) noexcept
Sets the field value.
Definition SbeMessage.h:262
void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:326
Iterator operator+(difference_type distance) const
Advances by given number of entries.
Definition SbeMessage.h:545
bool operator==(const Iterator &other) const noexcept
Compares iterators.
Definition SbeMessage.h:500
std::random_access_iterator_tag iterator_category
Definition SbeMessage.h:458
Iterator operator-(difference_type distance) const
Advances back by given number of entries.
Definition SbeMessage.h:554
Iterator() noexcept
Initializes the instance that refers to nothing.
Definition SbeMessage.h:461
bool operator<(const Iterator &other) const noexcept
Established the order between two iterators.
Definition SbeMessage.h:512
bool operator!=(const Iterator &other) const noexcept
Compares iterators.
Definition SbeMessage.h:506
Iterator & operator++()
Advances the next repeating group entry.
Definition SbeMessage.h:524
bool operator>(const Iterator &other) const noexcept
Established the order between two iterators.
Definition SbeMessage.h:518
Iterator & operator--()
Advances to the previous repeating group entry.
Definition SbeMessage.h:534
Iterator(void *entry, EncodedLength size, SchemaVersion version) noexcept
Initializes the instance to the given repeating group.
Definition SbeMessage.h:470
Operations over SBE-encoded repeating group entries.
Definition SbeMessage.h:435
SbeGroupEntries() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:568
SbeGroupEntries(void *encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) noexcept
Initializes the instance referencing to data.
Definition SbeMessage.h:577
EntryType Entry
The type of the repeating group entry.
Definition SbeMessage.h:441
Iterator end() const
Returns the iterator pointing to the entry behind the end of the group.
Definition SbeMessage.h:613
SbeGroupEntries(const SbeGroupEntries< OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength > &other) noexcept
Copy constructor.
Definition SbeMessage.h:643
Length EncodedLength
The length of the binary data occupied by the group entries.
Definition SbeMessage.h:438
NumInGroup Size
Number of entries in the collection.
Definition SbeMessage.h:444
SbeGroupEntries & operator=(const SbeGroupEntries< OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength > &other) noexcept
Definition SbeMessage.h:657
SbeGroupEntry()
Initializes a blank instance.
Definition SbeMessage.h:352
const void * block() const noexcept
Definition SbeMessage.h:396
SbeGroupEntry(void *encoded, BlockLength size, SchemaVersion version)
Initializes the instance from the memory block of the encoded message.
Definition SbeMessage.h:361
BlockLength blockLength() const noexcept
Definition SbeMessage.h:414
BodySizeType BlockLength
Type to present the length of binary data of the repeating group entry.
Definition SbeMessage.h:349
SbeVariableLengthFieldList< BinarySize > checkVariableLengthFields() const
Checks the variable length fields list consistency.
SbeGroupList tail() const noexcept
SbeGroupList checkTail() const
Checks the list consistency.
SbeVariableLengthFieldList< BinarySize > variableLengthFields() const noexcept
SbeGroupList(void *binary, BinarySize size, SchemaVersion version) noexcept
Initializes the list over the memory block.
const void * tail() const noexcept
Definition SbeMessage.h:814
SbeGroup() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:720
Entries::Size Size
Number of entries in the group.
Definition SbeMessage.h:717
GroupSizeType BinarySize
Length of group data.
Definition SbeMessage.h:695
DimensionType::BlockLength EntrySize
Length of group entry data.
Definition SbeMessage.h:704
SbeGroup(void *data, BinarySize size, SchemaVersion version) noexcept
Initializes an instance referencing to a valid group of a given message.
Definition SbeMessage.h:729
Entries::Iterator Iterator
The iterator type for group entries.
Definition SbeMessage.h:711
Entries::Entry Entry
Group entry type.
Definition SbeMessage.h:714
Entries entries() const noexcept
Definition SbeMessage.h:799
Entry operator[](Size index) const
Definition SbeMessage.h:789
Iterator end() const noexcept
Definition SbeMessage.h:778
const void * encoded() const noexcept
Definition SbeMessage.h:808
SbeGroupEntries< EntryType, typename Dimension::BlockLength, typename Dimension::NumInGroup, GroupSizeType > Entries
Binary group blocks.
Definition SbeMessage.h:708
DimensionType Dimension
Repeating group dimension type.
Definition SbeMessage.h:692
Iterator begin() const noexcept
Definition SbeMessage.h:769
void clear() noexcept
Blank the instance.
const void * binary() const noexcept
MessageTemplateId templateId() const noexcept
SchemaId schemaId() const noexcept
Group setupGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner &owner)
Setups the repeating group with the given number of entries.
GroupList groups() const noexcept
Group setupGroup(Callable callable, typename Group::Size length, Owner &owner)
Setups the repeating group with the given number of entries.
const void * blockEnd() const noexcept
SbeMessage(void *data, MessageSize size)
Initializes the instance over the given memory block.
SbeVariableLengthFieldList< MessageSize > VariableLengthFieldList
Binary group list instantiation.
SbeMessage & version(SchemaVersion version) noexcept
Sets the SBE Schema version.
Group getGroup(Callable callable, Owner &owner) const noexcept
Group getGroup(Callable callable, SchemaVersion since, Owner &owner) const noexcept
MessageSize EncodedLength
Length of the message binary data.
const void * block() const noexcept
SbeMessage(void *data, MessageSize size, NoCheck) noexcept
Initializes the instance over the given memory block.
void initGroup(Group &group, typename Group::EntrySize entrySize) noexcept
Resets the group to the initial state.
void setupGroup(Group &group, typename Group::Size entryCount, const void *messageTail)
Initializes the group header.
VariableLengthFieldList variableLengthFields() const noexcept
SchemaVersion version() const noexcept
SbeGroupList< MessageSize > GroupList
Binary group list instantiation.
SbeMessage(void *data, MessageSize size, SchemaVersion version)
Initializes the instance over the given memory block.
MessageSize bufferSize() const noexcept
static constexpr MessageSize getMaxMessageSize() noexcept
Maximal message size.
Group constructGroup(Callable callable, typename Group::Size length, Owner &owner)
Group constructGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner &owner)
void setVariableLengthFieldToNull(Callable callable, SchemaVersion since, Owner &owner) noexcept
Sets the variable length field to null.
BlockLength blockLength() const noexcept
void resetGroup(Callable callable, SchemaVersion since, Owner &owner)
Resets the repeating group.
SbeMessage() noexcept
Initializes a blank instance.
void init(MessageHeader::TemplateId value, MessageHeader::BlockLength minimalBlockLength, MessageHeader::BlockLength blockLength, SchemaId id) noexcept
VariableLengthFieldList variableLengthFields() noexcept
MessageSize BlockLength
Length of the message body representing a block of fixed-length fields.
void resetGroup(Callable callable, Owner &owner) noexcept
Sets the group to the initial state.
MessageSize calculateBinarySize(const void *tail) const noexcept
void constructGroup(Group &group, typename Group::Size entryCount, const void *messageTail)
Initializes the group header, sets all optional fields to null.
SbeVariableLengthFieldList(void *binary, BinarySize size, SchemaVersion version) noexcept
Initializes the list over the given memory block.
Definition SbeMessage.h:947
SbeVariableLengthFieldList tail() const noexcept
Definition SbeMessage.h:969
BinaryVariableLengthFieldType & head() const noexcept
Definition SbeMessage.h:962
SbeVariableLengthFieldList checkTail() const
Checks the variable-length field list consistency.
Definition SbeMessage.h:984
void checkSchemaId(SchemaId id)
Checks the compatibility with the provided SBE Schema ID.
constexpr MessageSize MaxMessageSize
Maximum supported message size.
const SbeMessage constructFromImmutableBlock(const void *data, MessageSize size, typename std::enable_if< std::is_same< typename std::remove_cv< Message >::type, SbeMessage >::value >::type *=nullptr)
Constructs the given message from an immutable memory block.
MessageHeader::Version SchemaVersion
Aliases SBE-encoded data version type.
char Char
Character type alias.
Definition String.h:30
UInt16 MessageSize
Message length type.
Definition Aliases.h:29
std::basic_string_view< Char > StrRef
Definition StrRef.h:46
void checkVersion(SchemaVersion version)
Checks the compatibility with the provided SBE Schema version.
MessageHeader::SchemaId SchemaId
void checkSchema(SchemaId id, SchemaVersion version)
Checks the compatibility with the provided SBE Schema version.
FloatingPointDecimal< DecimalMantissa, DecimalExponent > Decimal
Universal decimal type.
MessageHeader::TemplateId MessageTemplateId
Message type (template) identification.