OnixS C++ CME iLink 3 Binary Order Entry Handler 1.18.9
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
31
32#include <cassert>
33#include <limits>
34#include <stdexcept>
35
37
39typedef
40MessageHeader::TemplateId MessageTemplateId;
41
43template<typename Message> inline
44void checkBinaryLength(const Message&, MessageSize length, MessageSize minimalRequiredLength)
45{
46 if ONIXS_ILINK3_UNLIKELY(length < minimalRequiredLength)
47 throwBinaryBlockIsTooSmall(length, minimalRequiredLength, Message::className());
48}
49
51ONIXS_ILINK3_LTWT_CLASS BinaryBlockBase
52{
53protected:
54 ~BinaryBlockBase() ONIXS_ILINK3_DEFAULT;
55};
56
62template < class Container, class BlockLength >
63ONIXS_ILINK3_LTWT_CLASS BinaryBlock : public BinaryBlockBase
64{
66 const Container& container() const ONIXS_ILINK3_NOTHROW
67 {
68 return *static_cast <const Container*> (this);
69 }
70
71protected:
74
76
78 template < class Value > ONIXS_ILINK3_HOTPATH
79 Value ordinary(BlockLength offset) const ONIXS_ILINK3_NOTHROW
80 {
81 assert(container().blockLength() >= (offset + size<Value>()) &&
82 "The requested field exceeds provided block boundaries.");
83
84 const void* const location = advanceByBytes(container().block(), offset);
85 return getValue<Value>(location);
86 }
87
92 template <class Value, class NullValue > ONIXS_ILINK3_HOTPATH
93 bool ordinary(Value& value, BlockLength offset, NullValue null) const ONIXS_ILINK3_NOTHROW
94 {
95 value = ordinary<Value>(offset);
96
97 return (null != value);
98 }
99
104 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
105 bool ordinary(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const ONIXS_ILINK3_NOTHROW
106 {
107 return (since <= container().version() && ordinary (value, offset, null ) );
108 }
109
111 template < class Enumeration > ONIXS_ILINK3_HOTPATH
112 typename Enumeration::Enum enumeration(BlockLength offset) const ONIXS_ILINK3_NOTHROW
113 {
114 typedef typename Enumeration::Base Base;
115 typedef typename Enumeration::Enum Enum;
116
117 return static_cast<Enum>(ordinary<Base>(offset));
118 }
119
121 template < class Enumeration, class NullValue > ONIXS_ILINK3_HOTPATH
122 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null) const ONIXS_ILINK3_NOTHROW
123 {
124 typedef typename Enumeration::Base Base;
125 typedef typename Enumeration::Enum Enum;
126
127 value = static_cast <Enum>(ordinary<Base>(offset));
128 return null != value;
129 }
130
132 template < class Enumeration, class NullValue > ONIXS_ILINK3_HOTPATH
133 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null, SchemaVersion since) const ONIXS_ILINK3_NOTHROW
134 {
135 return (since <= container().version() && enumeration<Enumeration>(value, offset, null) );
136 }
137
139 template < class Value > ONIXS_ILINK3_HOTPATH
140 Value decimal(BlockLength offset) const ONIXS_ILINK3_NOTHROW
141 {
142 return ordinary<Value>(offset);
143 }
144
149 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
150 bool decimal(Value& value, BlockLength offset, NullValue null) const ONIXS_ILINK3_NOTHROW
151 {
152 value = ordinary<Value>(offset);
153 return null != value;
154 }
155
160 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
161 bool decimal(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const ONIXS_ILINK3_NOTHROW
162 {
163 return (since <= container().version() && decimal(value, offset, null));
164 }
165
167 template < BlockLength Length > ONIXS_ILINK3_HOTPATH
168 StrRef fixedStr(BlockLength offset) const ONIXS_ILINK3_NOTHROW
169 {
170 assert(container().blockLength() >= (offset + Length) && "The requested field exceeds provided block boundaries.");
171
172 const Char* const text = reinterpret_cast <const Char*> (advanceByBytes(container().block(), offset));
173
174 return StrRef(text, strnlen(text, Length));
175 }
176
181 template<BlockLength Length> ONIXS_ILINK3_HOTPATH
182 bool fixedStr(StrRef& value, BlockLength offset) const ONIXS_ILINK3_NOTHROW
183 {
184 value = fixedStr<Length>(offset);
185 return !value.empty();
186 }
187
192 template<BlockLength Length> ONIXS_ILINK3_HOTPATH
193 bool fixedStr(StrRef& value, BlockLength offset, SchemaVersion since) const ONIXS_ILINK3_NOTHROW
194 {
195 return (since <= container().version() && fixedStr<Length>(value, offset));
196 }
197};
198
203template <class Container, class BlockLength >
205{
206public:
209 {
210 return *static_cast<Container*>(this);
211 }
212
215 void zeroPaddingBytes(BlockLength offset) ONIXS_ILINK3_NOTHROW
216 {
217 const BlockLength encodedBlockLength = container().blockLength();
218
219 assert(encodedBlockLength >= offset);
220
221 const size_t paddingLength = encodedBlockLength - offset;
222 std::memset(advanceByBytes(container().block(), offset), 0, paddingLength);
223 }
224
226 template<class FieldValue> ONIXS_ILINK3_HOTPATH
227 void setOrdinary(BlockLength offset, FieldValue value) ONIXS_ILINK3_NOTHROW
228 {
229 assert(container().blockLength() >= (offset + size<FieldValue>()) && "The requested field exceeds provided block boundaries.");
230
231 void* const fieldPos = advanceByBytes(container().block(), offset);
232 setValue(fieldPos, value);
233 }
234
236 template<class FieldValue> ONIXS_ILINK3_HOTPATH
237 void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
238 {
239 if ONIXS_ILINK3_UNLIKELY(since > container().version())
240 throwDisallowedField();
241
242 setOrdinary(offset, value);
243 }
244
246 template<class Enumeration> ONIXS_ILINK3_HOTPATH
247 void setEnumeration(BlockLength offset, typename Enumeration::Enum value) ONIXS_ILINK3_NOTHROW
248 {
249 typedef typename Enumeration::Base Base;
250 setOrdinary<Base>(offset, static_cast<Base>(value));
251 }
252
254 template<class Enumeration> ONIXS_ILINK3_HOTPATH
255 void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
256 {
257 typedef typename Enumeration::Base Base;
258 setOrdinary(offset, static_cast<Base>(value), since);
259 }
260
262 template<BlockLength Size> ONIXS_ILINK3_HOTPATH
263 void setFixedStr(BlockLength offset, StrRef value) ONIXS_ILINK3_NOTHROW
264 {
265 assert(container().blockLength() >= (offset + Size) && "The requested field exceeds provided block boundaries.");
266 assert(value.size() <= Size && "The string is truncated.");
267
268 void* const fieldPos = advanceByBytes(container().block(), offset);
269 const size_t sizeToCopy = (std::min)(Size, static_cast<BlockLength>(value.size()));
270
271 if(sizeToCopy > 0)
272 std::memcpy(fieldPos, value.data(), sizeToCopy);
273
274 std::memset(advanceByBytes(fieldPos, sizeToCopy), 0, Size - sizeToCopy);
275 }
276
278 template<BlockLength Size> ONIXS_ILINK3_HOTPATH
279 void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
280 {
281 if ONIXS_ILINK3_UNLIKELY(since > container().version())
282 throwDisallowedField();
283
284 setFixedStr<Size>(offset, value);
285 }
286
287protected:
290
292};
293
295template <class BodySizeType>
297{
298public:
300 typedef BodySizeType BlockLength;
301
304 : encoded_(ONIXS_ILINK3_NULLPTR)
305 , size_(0)
306 , version_(0)
307 {
308 }
309
313 : encoded_(encoded)
314 , size_(size)
315 , version_(version)
316 {
317 assert(encoded);
318 }
319
322 {
323 return (encoded_ != ONIXS_ILINK3_NULLPTR);
324 }
325
327 const void* encoded() const ONIXS_ILINK3_NOTHROW
328 {
329 assert(valid());
330
331 return encoded_;
332 }
333
336 {
337 assert(valid());
338
339 return encoded_;
340 }
341
343 const void* block() const ONIXS_ILINK3_NOTHROW
344 {
345 assert(valid());
346
347 return encoded_;
348 }
349
352 {
353 assert(valid());
354
355 return encoded_;
356 }
357
360 {
361 return size_;
362 }
363
366 {
367 return version_;
368 }
369
370 private:
371 void* encoded_;
372 BodySizeType size_;
373 SchemaVersion version_;
374};
375
377template <class EntryType, class BlockLength, class NumInGroup, class Length >
379{
380public:
382 typedef Length EncodedLength;
383
385 typedef EntryType Entry;
386
388 typedef NumInGroup Size;
389
392 {
393 public:
394 typedef EntryType Entry;
396
397 typedef Entry* pointer;
398 typedef Entry& reference;
399
400 typedef ptrdiff_t difference_type;
401
402 typedef std::random_access_iterator_tag iterator_category;
403
406 : entry_(ONIXS_ILINK3_NULLPTR)
407 , size_(0)
408 , version_(0)
409 {
410 }
411
415 : entry_(entry)
416 , size_(size)
417 , version_(version)
418 {
419 assert(valid());
420 }
421
424 {
425 return (entry_ != ONIXS_ILINK3_NULLPTR);
426 }
427
430 Entry get() const
431 {
432 assert(valid());
433
434 return Entry(entry_, size_, version_);
435 }
436
438 Entry operator *() const
439 {
440 return get();
441 }
442
444 bool operator == (const Iterator& other) const ONIXS_ILINK3_NOTHROW
445 {
446 return entry_ == other.entry_;
447 }
448
450 bool operator !=(const Iterator& other) const ONIXS_ILINK3_NOTHROW
451 {
452 return entry_ != other.entry_;
453 }
454
456 bool operator < (const Iterator& other) const ONIXS_ILINK3_NOTHROW
457 {
458 return entry_ < other.entry_;
459 }
460
462 bool operator > (const Iterator& other) const ONIXS_ILINK3_NOTHROW
463 {
464 return entry_ > other.entry_;
465 }
466
468 Iterator& operator ++()
469 {
470 assert(valid());
471
472 entry_ = advanceByBytes(entry_, size_);
473
474 return *this;
475 }
476
478 Iterator& operator --()
479 {
480 assert(valid());
481
482 entry_ = advanceBackByBytes(entry_, size_);
483
484 return *this;
485 }
486
489 Iterator operator +(difference_type distance) const
490 {
491 assert(valid());
492
493 return Iterator(advanceByBytes(entry_, distance * size_), size_, version_);
494 }
495
498 Iterator operator - (difference_type distance) const
499 {
500 assert(valid());
501
502 return Iterator(advanceBackByBytes(entry_, distance * size_), size_, version_);
503 }
504
505 private:
506 void* entry_;
507 Size size_;
508 SchemaVersion version_;
509 };
510
513 : encoded_(ONIXS_ILINK3_NULLPTR)
514 , blockLength_(0)
515 , size_(0)
516 , version_(0)
517 {
518 }
519
521 SbeGroupEntries(void* encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) ONIXS_ILINK3_NOTHROW
522 : encoded_(encoded)
523 , blockLength_(blockLength)
524 , size_(groupSize)
525 , version_(version)
526 {
527 assert(encoded_);
528 assert(blockLength > 0);
529 assert(version != 0);
530 }
531
534 {
535 return (ONIXS_ILINK3_NULLPTR != encoded_);
536 }
537
540 {
541 return (0 == size_);
542 }
543
546 {
547 return size_;
548 }
549
551 Iterator begin() const
552 {
553 return Iterator(encoded(), blockLength_, version_);
554 }
555
557 Iterator end() const
558 {
559 return Iterator(advanceByBytes(encoded(), encodedLength()), blockLength_, version_);
560 }
561
565 Entry operator [](Size index) const
566 {
567 assert(index < size_);
568 assert(encoded_);
569
570 return Entry(advanceByBytes(encoded_, static_cast<ptrdiff_t>(index) * blockLength_), blockLength_, version_);
571 }
572
575 {
576 return encoded_;
577 }
578
581 {
582 return (static_cast<EncodedLength>(blockLength_) * static_cast<EncodedLength>(size_) );
583 }
584
586 template<class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength >
588 : encoded_(other.encoded_)
589 , blockLength_(other.blockLength_)
590 , size_(other.size_)
591 , version_(other.version_)
592 {
593 // Dimension types may vary for the different instantiations of the template.
594 // Therefore, truncation of the dimensions must be avoided.
595
596 assert(blockLength_ == other.blockLength_);
597 assert(size_ == other.size_);
598 }
599
600 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength>
601 SbeGroupEntries& operator = (const SbeGroupEntries <OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength>& other) ONIXS_ILINK3_NOTHROW
602 {
603 encoded_ = other.encoded_;
604
605 blockLength_ = other.blockLength_;
606
607 assert(blockLength_ == other.blockLength_);
608
609 size_ = other.size_;
610
611 assert(size_ == other.size_);
612
613 version_ = other.version_;
614
615 return *this;
616 }
617
618private:
619 // Allows coping and cloning for different instantiations.
620 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength> friend class SbeGroupEntries;
621
622 void* encoded_;
623 BlockLength blockLength_;
624 NumInGroup size_;
625 SchemaVersion version_;
626};
627
629template < class EntryType, class DimensionType, class GroupSizeType >
631{
632public:
634 typedef DimensionType Dimension;
635
637 typedef GroupSizeType BinarySize;
638
641
643 typedef typename DimensionType::BlockLength EntrySize;
644
646 typedef SbeGroupEntries <EntryType, typename Dimension::BlockLength, typename Dimension::NumInGroup, GroupSizeType > Entries;
647
649 typedef typename Entries::Iterator Iterator;
650
652 typedef typename Entries::Entry Entry;
653
655 typedef typename Entries::Size Size;
656
660 : header_(ONIXS_ILINK3_NULLPTR)
661 , entries_(ONIXS_ILINK3_NULLPTR)
662 , version_(0)
663 {
664 }
665
669 : header_(static_cast <Dimension*>(data))
670 , entries_(advanceByBytes(data, Dimension::Size))
671 , version_(version)
672 {
673 ONIXS_ILINK3_ASSERT(size >= Dimension::Size);
674 assert(header_);
675 assert(entries_);
676
677 assert(valid());
678 }
679
682 {
683 return (entries_ != ONIXS_ILINK3_NULLPTR);
684 }
685
688 {
689 assert(valid());
690
691 return 0 == size();
692 }
693
697 {
698 assert(valid());
699 assert(header_);
700
701 const Dimension* const group = static_cast<const Dimension*>(header_);
702
703 return group->numInGroup();
704 }
705
709 {
710 assert(valid());
711
712 return Iterator(entries_, numericCast<Size>(entrySize()), version_);
713 }
714
718 {
719 assert(valid());
720
721 return Iterator(advanceByBytes(binary(), binarySize()), numericCast<Size>(entrySize()), version_);
722 }
723
728 Entry operator [](Size index) const
729 {
730 assert(valid());
731 assert(index < size());
732
733 return Entry(advanceByBytes(entries_, static_cast<ptrdiff_t>(index) * entrySize()), entrySize(), version_);
734 }
735
739 {
740 assert(valid());
741 assert(header_);
742
743 return Entries (entries_, header_->blockLength(), header_->numInGroup(), version_);
744 }
745
747 const void* encoded() const ONIXS_ILINK3_NOTHROW
748 {
749 return header_;
750 }
751
753 const void* tail() const ONIXS_ILINK3_NOTHROW
754 {
755 return advanceByBytes(toByteBlock(encoded()), binarySize());
756 }
757
761 {
762 return header_;
763 }
764
768 {
769 return Dimension::Size + (static_cast<BinarySize>(entrySize()) * static_cast<BinarySize>(size()));
770 }
771
775 {
776 assert(valid());
777 assert(header_);
778
779 Dimension* const group = static_cast<Dimension*>(header_);
780 return group->blockLength();
781 }
782
783private:
785 void init(EntrySize entrySize) ONIXS_ILINK3_NOTHROW
786 {
787 assert(valid());
788 assert(header_);
789
790 Dimension* const group = static_cast<Dimension*>(header_);
791 group->setBlockLength(entrySize);
792 group->setNumInGroup(0);
793 }
794
796 Size allocate(Size entryCount, const void* messageTail, const void* blockEnd)
797 {
798 assert(valid());
799 assert(blockEnd);
800 assert(messageTail);
801
802 Dimension* const group = static_cast<Dimension*>(header_);
803
804 const EntrySize entrySize = group->blockLength();
805
806 if ONIXS_ILINK3_UNLIKELY(
807 entrySize < EntryType::blockLength(version_))
808 {
809 throwBadBinaryBlock();
810 }
811
812 const Size oldEntryCount = group->numInGroup();
813
814 if(oldEntryCount == entryCount)
815 return entryCount;
816
817 const ptrdiff_t memShift =
818 (entryCount - oldEntryCount) * static_cast<ptrdiff_t>(entrySize);
819
820 const void* const newMessageTail =
821 advanceByBytes(messageTail, memShift);
822
823 if ONIXS_ILINK3_UNLIKELY(byteDistance(blockEnd, newMessageTail) < 0)
824 throwNotEnoughSpace();
825
826 const void* const oldEndOfGroup =
827 advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * oldEntryCount);
828
829 void* const newEndGroup =
830 advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * entryCount);
831
832 std::memmove(
833 newEndGroup,
834 oldEndOfGroup,
835 byteDistance(messageTail, oldEndOfGroup));
836
837 group->setNumInGroup(entryCount);
838
839 return oldEntryCount;
840 }
841
844 void setup(Size entryCount, const void* messageTail, const void* blockEnd)
845 {
846 assert(valid());
847 assert(blockEnd);
848 assert(messageTail);
849
850 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
851
852 for(Size index = oldEntryCount; index < entryCount; ++index)
853 zeroPaddingBytes((*this)[index].resetVariableFields());
854 }
855
858 void construct(Size entryCount, const void* messageTail, const void* blockEnd)
859 {
860 assert(valid());
861 assert(blockEnd);
862 assert(messageTail);
863
864 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
865
866 for(Size index = oldEntryCount; index < entryCount; ++index)
867 zeroPaddingBytes((*this)[index].reset());
868 }
869
871 static void zeroPaddingBytes(Entry& entry)
872 {
873 assert(entry.valid());
874 entry.zeroPaddingBytes(EntryType::minimalBlockLength(entry.version()));
875 }
876
877private:
878 Dimension* header_;
879 void* entries_;
880 SchemaVersion version_;
881
882 friend class SbeMessage;
883};
884
886template < class BinarySize >
888{
889public:
892 SbeVariableLengthFieldList(void* binary, BinarySize size, SchemaVersion version) ONIXS_ILINK3_NOTHROW
893 : binary_(binary)
894 , size_(size)
895 , version_(version)
896 {
897 }
898
901 {
902 return (0 == size_);
903 }
904
906 template<class BinaryVariableLengthFieldType>
907 BinaryVariableLengthFieldType& head() const ONIXS_ILINK3_NOTHROW
908 {
909 return *static_cast<BinaryVariableLengthFieldType*>(binary_);
910 }
911
913 template<class BinaryVariableLengthFieldType> ONIXS_ILINK3_HOTPATH
915 {
916 assert(!empty());
917
918 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
919
920 assert(headSize <= size_);
921
922 return SbeVariableLengthFieldList(advanceByBytes( binary_, headSize), size_ - headSize, version_);
923 }
924
928 template<class BinaryVariableLengthFieldType> ONIXS_ILINK3_HOTPATH
930 {
931 if ONIXS_ILINK3_UNLIKELY(empty() || (size_ < BinaryVariableLengthFieldType::Size))
932 {
933 throwBadBinaryBlock();
934 }
935
936 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
937
938 if ONIXS_ILINK3_UNLIKELY(headSize > size_)
939 {
940 throwBadBinaryBlock();
941 }
942
943 return SbeVariableLengthFieldList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
944 }
945
946 private:
947 void* binary_;
948 BinarySize size_;
949 SchemaVersion version_;
950
951};
952
954template <class BinarySize>
956{
957public:
960 SbeGroupList(void* binary, BinarySize size, SchemaVersion version) ONIXS_ILINK3_NOTHROW
961 : binary_(binary)
962 , size_(size)
963 , version_(version)
964 {
965 }
966
969 {
970 return (0 == size_);
971 }
972
974 template<class Group> ONIXS_ILINK3_HOTPATH
976 {
977 assert(!empty());
978
979 return Group(binary_, size_, version_);
980 }
981
983 template<class Group> ONIXS_ILINK3_HOTPATH
985 {
986 assert(!empty());
987
988 const BinarySize headSize = head<Group>().binarySize();
989
990 assert(headSize <= size_);
991
992 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
993 }
994
996 template <class Group> ONIXS_ILINK3_HOTPATH
998 {
999 assert(!empty());
1000
1001 const BinarySize headSize = head<Group>().binarySize();
1002
1003 assert(headSize <= size_);
1004
1005 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1006 }
1007
1011 template<class Group> ONIXS_ILINK3_HOTPATH
1013 {
1014 const BinarySize headSize = checkHead<Group>();
1015
1016 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1017 }
1018
1022 template <class Group> ONIXS_ILINK3_HOTPATH
1024 {
1025 const BinarySize headSize = checkHead<Group>();
1026
1027 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1028 }
1029
1030private:
1031 template<class Group>
1032 BinarySize checkHead() const
1033 {
1034 if ONIXS_ILINK3_UNLIKELY(size_ < Group::Dimension::Size)
1035 {
1036 throwBadBinaryBlock();
1037 }
1038
1039 const Group group = head<Group>();
1040
1041 const BinarySize headSize = group.binarySize();
1042
1043 if ONIXS_ILINK3_UNLIKELY(headSize > size_)
1044 {
1045 throwBadBinaryBlock();
1046 }
1047
1048 if(!group.empty())
1049 {
1050 const BinarySize entrySize = group.entrySize();
1051 const BinarySize expectedEntrySize = Group::Entry::minimalBlockLength(version_);
1052
1053 if ONIXS_ILINK3_UNLIKELY(entrySize < expectedEntrySize)
1054 {
1055 throwBadBinaryBlock();
1056 }
1057 }
1058
1059 return headSize;
1060 }
1061
1062 void* binary_;
1063 BinarySize size_;
1064 SchemaVersion version_;
1065};
1066
1068template<typename Traits>
1070{
1071 if ONIXS_ILINK3_UNLIKELY(version < Traits::MinimalVersion)
1072 {
1073 throwBadMessageVersion(version, Traits::MinimalVersion);
1074 }
1075}
1076
1078template<typename Traits>
1080{
1081 checkVersion<Traits>(version);
1082
1083 if ONIXS_ILINK3_UNLIKELY(version < since)
1084 {
1085 throwBadMessageVersion(version, since);
1086 }
1087}
1088
1090template<typename Traits>
1092{
1093 if ONIXS_ILINK3_UNLIKELY(id != Traits::Id)
1094 {
1095 throwBadSchemaId(Traits::Id, id);
1096 }
1097}
1098
1100template<typename Traits>
1102{
1104 checkVersion<Traits>(version);
1105}
1106
1109{
1110public:
1113 struct NoInit{};
1114 struct NoCheck{};
1115
1118
1121
1124 : header_(ONIXS_ILINK3_NULLPTR)
1125 , size_(0)
1126 {
1127 }
1128
1132 : header_(static_cast<MessageHeader*>(data))
1133 , size_(size)
1134 {
1135 assert(data);
1136 assert(size <= MaxILink3MessageSize);
1137
1138 if ONIXS_ILINK3_UNLIKELY(size < MessageHeader::Size)
1139 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1140
1141 this->version(version);
1142 }
1143
1146 SbeMessage(void* data, MessageSize size)
1147 : header_(static_cast<MessageHeader*>(data))
1148 , size_(size)
1149 {
1150 assert(data);
1151 assert(size <= MaxILink3MessageSize);
1152
1153 if ONIXS_ILINK3_UNLIKELY(size < MessageHeader::Size)
1154 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1155
1156 // Now it is safe to read header_.
1157 if ONIXS_ILINK3_UNLIKELY(size < (MessageHeader::Size + header_->blockLength()))
1158 throwBinaryBlockIsTooSmall(size, MessageHeader::Size + header_->blockLength());
1159 }
1160
1166 : header_(static_cast<MessageHeader*>(data))
1167 , size_(size)
1168 {
1169 assert(data);
1170 assert(size <= MaxILink3MessageSize);
1171
1172 assert(size >= MessageHeader::Size);
1173 assert(size >= MessageHeader::Size + header_->blockLength());
1174 }
1175
1178 {
1179 *this = SbeMessage();
1180 assert(!valid());
1181 }
1182
1185 {
1186 return (ONIXS_ILINK3_NULLPTR != header_);
1187 }
1188
1191 {
1192 assert(valid());
1193
1194 return header_->templateId();
1195 }
1196
1199 {
1200 assert(valid());
1201
1202 return header_->version();
1203 }
1204
1207 {
1208 assert(valid());
1209
1210 return header_->schemaId();
1211 }
1212
1214 const void* binary() const ONIXS_ILINK3_NOTHROW
1215 {
1216 assert(valid());
1217
1218 return header_;
1219 }
1220
1223 {
1224 assert(valid());
1225
1226 return header_;
1227 }
1228
1229 // \return the end of the memory block.
1231 {
1232 assert(valid());
1233
1234 return advanceByBytes(header_, size_);
1235 }
1236
1237 // \return the end of the memory block.
1238 const void* blockEnd() const ONIXS_ILINK3_NOTHROW
1239 {
1240 assert(valid());
1241
1242 return advanceByBytes(header_, size_);
1243 }
1244
1247 {
1248 return size_;
1249 }
1250
1253 {
1254 assert(valid());
1255
1256 return advanceByBytes(header_, MessageHeader::Size);
1257 }
1258
1261 {
1262 assert(valid());
1263
1264 return header_->blockLength();
1265 }
1266
1268 const void* block() const ONIXS_ILINK3_NOTHROW
1269 {
1270 assert(valid());
1271
1272 return advanceByBytes(header_, MessageHeader::Size);
1273 }
1274
1277 {
1278 assert(valid());
1279
1280 return advanceByBytes(header_, MessageHeader::Size);
1281 }
1282
1283protected:
1286
1289 {
1290 assert(valid());
1291
1292 header_->setVersion(version);
1293
1294 return *this;
1295 }
1296
1300 {
1301 assert(header_);
1302
1303 void* list = advanceByBytes<void>(body(), blockLength());
1304
1305 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1306
1307 return GroupList(list, listSize, header_->version());
1308 }
1309
1313 {
1314 assert(header_);
1315
1316 const void* list = advanceByBytes(block(), blockLength());
1317
1318 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1319
1320 return GroupList(const_cast<void*>(list), listSize, header_->version());
1321 }
1322
1324 template<typename Group>
1326 void initGroup(Group& group, typename Group::EntrySize entrySize) ONIXS_ILINK3_NOTHROW
1327 {
1328 assert(group.valid());
1329 group.init(entrySize);
1330 }
1331
1333 template<typename Group>
1335 void setupGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1336 {
1337 assert(messageTail);
1338 assert(group.valid());
1339 group.setup(entryCount, messageTail, blockEnd());
1340 }
1341
1343 template<typename Group>
1345 void constructGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1346 {
1347 assert(messageTail);
1348 assert(group.valid());
1349 group.construct(entryCount, messageTail, blockEnd());
1350 }
1351
1353 void setVarDataField(DATA& data, StrRef value, const void* oldMessageTail)
1354 {
1355 assert(oldMessageTail);
1356
1357 const ptrdiff_t lengthChange = static_cast<ptrdiff_t>(value.length() - data.length());
1358
1359 const void* const newMessageTail = advanceByBytes(oldMessageTail, lengthChange);
1360
1361 if ONIXS_ILINK3_UNLIKELY(byteDistance(blockEnd(), newMessageTail) < 0)
1362 throwNotEnoughSpace();
1363
1364 const void* const oldEndOfData = advanceByBytes(data.varData().data(), data.varData().size());
1365
1366 void* const newEndOfData = toOpaquePtr(advanceByBytes(&data, value.length() + DATA::Size));
1367
1368 std::memmove(newEndOfData, oldEndOfData, byteDistance(oldMessageTail, oldEndOfData));
1369
1370 data.varData(value);
1371 }
1372
1375
1379 {
1380 assert(header_);
1381
1382 void* list = advanceByBytes<void>(body(), blockLength());
1383
1384 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1385
1386 return VariableLengthFieldList(list, listSize, header_->version());
1387 }
1388
1392 {
1393 assert(header_);
1394
1395 const void* list = advanceByBytes(block(), blockLength());
1396
1397 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1398
1399 return VariableLengthFieldList(const_cast<void*>(list), listSize, header_->version());
1400 }
1401
1403 void init(
1405 MessageHeader::BlockLength minimalBlockLength,
1408 {
1409 assert(header_);
1410 assert(blockLength >= minimalBlockLength);
1411
1412 header_->setTemplateId(value);
1413 header_->setBlockLength(blockLength);
1414 header_->setSchemaId(id);
1415
1416 zeroPaddingBytes(minimalBlockLength);
1417 }
1418
1421 {
1422 assert(tail);
1423
1424 const ptrdiff_t distance = byteDistance(tail, binary());
1425
1426 assert(distance > 0);
1427
1428 assert(distance <= (std::numeric_limits<MessageSize>::max)());
1429
1430 const MessageSize size = static_cast<MessageSize>(distance);
1431
1432 assert(size <= size_);
1433
1434 return size;
1435 }
1436
1438 template<class Callable, class Owner>
1439 void setVariableLengthField(Callable callable, StrRef value, Owner& owner)
1440 {
1441 setVarDataField(callable(owner), value, owner.tail());
1442 }
1443
1445 template<class Callable, class Owner>
1446 void setVariableLengthField(Callable callable, StrRef value, SchemaVersion since, Owner& owner)
1447 {
1448 if ONIXS_ILINK3_UNLIKELY(since > version())
1449 throwDisallowedField();
1450
1451 setVariableLengthField(callable, value, owner);
1452 }
1453
1455 template<class Callable, class Owner>
1456 StrRef getVariableLengthField(Callable callable, const Owner& owner) const ONIXS_ILINK3_NOTHROW
1457 {
1458 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1459 return callable(owner).varData();
1460 }
1461
1463 template<class Callable, class Owner>
1464 StrRef getVariableLengthField(Callable callable, SchemaVersion since, Owner& owner) const ONIXS_ILINK3_NOTHROW
1465 {
1466 if ONIXS_ILINK3_UNLIKELY(since > version())
1467 return StrRef();
1468
1469 return getVariableLengthField(callable, owner);
1470 }
1471
1473 template<class Callable, class Owner>
1474 void setVariableLengthFieldToNull(Callable callable, Owner& owner) ONIXS_ILINK3_NOTHROW
1475 {
1476 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1477 callable(owner).length(0);
1478 }
1479
1481 template<class Group, class Callable, class Owner>
1482 void resetGroup(Callable callable, Owner& owner) ONIXS_ILINK3_NOTHROW
1483 {
1484 const typename Group::EntrySize entrySize = Group::Entry::blockLength(version());
1485
1486 Group grp = callable(owner);
1487
1488 initGroup(grp, entrySize);
1489 }
1490
1492 template<class Callable, class Owner>
1493 void setVariableLengthFieldToNull(Callable callable, SchemaVersion since, Owner& owner) ONIXS_ILINK3_NOTHROW
1494 {
1495 if ONIXS_ILINK3_UNLIKELY(since > version())
1496 return;
1497
1498 setVariableLengthFieldToNull(callable, owner);
1499 }
1500
1502 template<class Group, class Callable, class Owner>
1503 void resetGroup(Callable callable, SchemaVersion since, Owner& owner)
1504 {
1505 if ONIXS_ILINK3_UNLIKELY(since > version())
1506 return;
1507
1508 resetGroup<Group>(callable, owner);
1509 }
1510
1512 template<class Group, class Callable, class Owner>
1513 Group getGroup(Callable callable, Owner& owner) const ONIXS_ILINK3_NOTHROW
1514 {
1515 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1516 return callable(owner);
1517 }
1518
1520 template<class Group, class Callable, class Owner>
1521 Group getGroup(Callable callable, SchemaVersion since, Owner& owner) const ONIXS_ILINK3_NOTHROW
1522 {
1523 if ONIXS_ILINK3_UNLIKELY(since > version())
1524 return Group();
1525
1526 return getGroup<Group>(callable, owner);
1527 }
1528
1530 template<class Group, class Callable, class Owner>
1531 Group constructGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1532 {
1533 if ONIXS_ILINK3_UNLIKELY(since > version())
1534 return Group();
1535
1536 return constructGroup<Group>(callable, length, owner);
1537 }
1538
1540 template<class Group, class Callable, class Owner>
1541 Group constructGroup(Callable callable, typename Group::Size length, Owner& owner)
1542 {
1543 Group group = callable(owner);
1544
1545 constructGroup(group, length, owner.tail());
1546
1547 return group;
1548 }
1549
1551 template<class Group, class Callable, class Owner>
1552 Group setupGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1553 {
1554 if ONIXS_ILINK3_UNLIKELY(since > version())
1555 return Group();
1556
1557 return setupGroup<Group>(callable, length, owner);
1558 }
1559
1561 template<class Group, class Callable, class Owner>
1562 Group setupGroup(Callable callable, typename Group::Size length, Owner& owner)
1563 {
1564 Group group = callable(owner);
1565
1566 setupGroup(group, length, owner.tail());
1567
1568 return group;
1569 }
1570
1580
1581private:
1582 MessageHeader* header_;
1583 MessageSize size_;
1584};
1585
#define ONIXS_ILINK3_MESSAGING_NAMESPACE_END
Definition ABI.h:144
#define ONIXS_ILINK3_LTWT_CLASS
Definition ABI.h:84
#define ONIXS_ILINK3_MESSAGING_NAMESPACE_BEGIN
Definition ABI.h:140
#define ONIXS_ILINK3_LTWT_EXPORTED
Definition ABI.h:92
#define ONIXS_ILINK3_HOTPATH
Definition Compiler.h:187
#define ONIXS_ILINK3_NODISCARD
Definition Compiler.h:185
#define ONIXS_ILINK3_NULLPTR
Definition Compiler.h:182
#define ONIXS_ILINK3_CONSTEXPR
Definition Compiler.h:179
#define ONIXS_ILINK3_UNUSED
Definition Compiler.h:201
#define ONIXS_ILINK3_DEFAULT
Definition Compiler.h:202
#define ONIXS_ILINK3_NOTHROW
Definition Compiler.h:176
bool decimal(Value &value, BlockLength offset, NullValue null) const noexcept
Definition SbeMessage.h:150
bool fixedStr(StrRef &value, BlockLength offset) const noexcept
Provides access to an optional string field value.
Definition SbeMessage.h:182
Value ordinary(BlockLength offset) const noexcept
Definition SbeMessage.h:79
bool fixedStr(StrRef &value, BlockLength offset, SchemaVersion since) const noexcept
Provides access to an optional string field value.
Definition SbeMessage.h:193
bool ordinary(Value &value, BlockLength offset, NullValue null) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:93
bool decimal(Value &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Definition SbeMessage.h:161
Value decimal(BlockLength offset) const noexcept
Definition SbeMessage.h:140
Enumeration::Enum enumeration(BlockLength offset) const noexcept
Definition SbeMessage.h:112
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:122
BinaryBlock()=default
Initializes a blank instance.
bool ordinary(Value &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:105
StrRef fixedStr(BlockLength offset) const noexcept
Provides access to a string field value.
Definition SbeMessage.h:168
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:133
NumInGroup numInGroup() const noexcept
Definition Composites.h:123
BlockLength blockLength() const noexcept
Definition Composites.h:108
Template ID and length of message root.
Definition Composites.h:205
UInt16 BlockLength
Type alias for the BlockLength.
Definition Composites.h:211
UInt16 TemplateId
Type alias for the TemplateId.
Definition Composites.h:214
SbeFields()=default
Initializes a blank instance.
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:215
void setFixedStr(BlockLength offset, StrRef value) noexcept
Sets the field value.
Definition SbeMessage.h:263
void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:237
void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:255
void setEnumeration(BlockLength offset, typename Enumeration::Enum value) noexcept
Sets the field value.
Definition SbeMessage.h:247
void setOrdinary(BlockLength offset, FieldValue value) noexcept
Sets the field value.
Definition SbeMessage.h:227
void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:279
An iterator over SBE-encoded group entries.
Definition SbeMessage.h:392
Iterator(void *entry, Size size, SchemaVersion version) noexcept
Initializes the instance to the given repeating group.
Definition SbeMessage.h:414
Iterator() noexcept
Initializes the instance that refers to nothing.
Definition SbeMessage.h:405
SbeGroupEntries() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:512
SbeGroupEntries(void *encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) noexcept
Initializes the instance referencing to data.
Definition SbeMessage.h:521
EntryType Entry
The type of the repeating group entry.
Definition SbeMessage.h:385
Iterator end() const
Returns the iterator pointing to the entry behind the end of the group.
Definition SbeMessage.h:557
SbeGroupEntries(const SbeGroupEntries< OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength > &other) noexcept
Copy constructor.
Definition SbeMessage.h:587
Length EncodedLength
The length of the binary data occupied by the group entries.
Definition SbeMessage.h:382
NumInGroup Size
Number of entries in the collection.
Definition SbeMessage.h:388
SbeGroupEntry()
Initializes a blank instance.
Definition SbeMessage.h:303
const void * block() const noexcept
Definition SbeMessage.h:343
SbeGroupEntry(void *encoded, BlockLength size, SchemaVersion version)
Initializes the instance from the memory block of the encoded message.
Definition SbeMessage.h:312
BlockLength blockLength() const noexcept
Definition SbeMessage.h:359
SbeVariableLengthFieldList< BinarySize > checkVariableLengthFields() const
Checks the variable length fields list consistency.
SbeGroupList tail() const noexcept
Definition SbeMessage.h:984
SbeGroupList checkTail() const
Checks the list consistency.
SbeVariableLengthFieldList< BinarySize > variableLengthFields() const noexcept
Definition SbeMessage.h:997
SbeGroupList(void *binary, BinarySize size, SchemaVersion version) noexcept
Initializes the list over the memory block.
Definition SbeMessage.h:960
const void * tail() const noexcept
Definition SbeMessage.h:753
SbeGroup() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:658
SbeGroup(void *data, BinarySize size, SchemaVersion version) noexcept
Initializes an instance referencing to a valid group of a given message.
Definition SbeMessage.h:668
Entries entries() const noexcept
Definition SbeMessage.h:738
Iterator end() const noexcept
Definition SbeMessage.h:717
const void * encoded() const noexcept
Definition SbeMessage.h:747
SbeGroupEntries< QuoteEntry, typename Dimension::BlockLength, typename Dimension::NumInGroup, MessageSize > Entries
Definition SbeMessage.h:646
Iterator begin() const noexcept
Definition SbeMessage.h:708
void clear() noexcept
Blank the instance.
const void * binary() const noexcept
MessageTemplateId templateId() 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.
StrRef getVariableLengthField(Callable callable, SchemaVersion since, Owner &owner) const noexcept
const void * blockEnd() const noexcept
void setVariableLengthField(Callable callable, StrRef value, SchemaVersion since, Owner &owner)
Sets the value of the variable length field.
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)
Creates a repeating group with the given number of entries, sets all optional fields of the group ent...
Group constructGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner &owner)
Creates a repeating group with the given number of entries, sets all optional fields of the group ent...
void setVariableLengthFieldToNull(Callable callable, SchemaVersion since, Owner &owner) noexcept
Sets the variable length field to null.
BlockLength blockLength() const noexcept
void setVariableLengthFieldToNull(Callable callable, Owner &owner) noexcept
Resets the variable length field.
void resetGroup(Callable callable, SchemaVersion since, Owner &owner)
Resets the repeating group.
SbeMessage() noexcept
Initializes a blank instance.
void setVariableLengthField(Callable callable, StrRef value, Owner &owner)
Sets the value of the variable length field.
void setVarDataField(DATA &data, StrRef value, const void *oldMessageTail)
Sets the variable length field value.
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.
StrRef getVariableLengthField(Callable callable, const Owner &owner) const noexcept
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:892
SbeVariableLengthFieldList tail() const noexcept
Definition SbeMessage.h:914
BinaryVariableLengthFieldType & head() const noexcept
Definition SbeMessage.h:907
SbeVariableLengthFieldList checkTail() const
Checks the variable-length field list consistency.
Definition SbeMessage.h:929
void checkSchemaId(SchemaId id)
Checks the compatibility with the provided SBE Schema ID.
MessageHeader::Version SchemaVersion
SBE-encoded data version type.
constexpr UInt16 MaxILink3MessageSize
Maximum supported message size.
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.
MessageHeader::TemplateId MessageTemplateId
Message type (template) identification.
StrRef varData() const noexcept
Definition Composites.h:63
Length length() const noexcept
Definition Composites.h:48