OnixS C++ CME iLink 3 Binary Order Entry Handler 1.19.0
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 {
48 throwBinaryBlockIsTooSmall(length, minimalRequiredLength, Message::className());
49 }
50}
51
53ONIXS_ILINK3_LTWT_CLASS BinaryBlockBase
54{
55protected:
56 ~BinaryBlockBase() = default;
57};
58
64template < class Container, class BlockLength >
65ONIXS_ILINK3_LTWT_CLASS BinaryBlock : public BinaryBlockBase
66{
68 const Container& container() const noexcept
69 {
70 return *static_cast <const Container*> (this);
71 }
72
73protected:
75 BinaryBlock() = default;
76
77 ~BinaryBlock() = default;
78
80 template < class Value > ONIXS_ILINK3_HOTPATH
81 Value ordinary(BlockLength offset) const noexcept
82 {
83 assert(container().blockLength() >= (offset + size<Value>()) &&
84 "The requested field exceeds provided block boundaries.");
85
86 const void* const location = advanceByBytes(container().block(), offset);
87 return getValue<Value>(location);
88 }
89
91 template < class Value > ONIXS_ILINK3_HOTPATH
92 Value ordinary(BlockLength offset, SchemaVersion since) const
93 {
94 if ONIXS_ILINK3_UNLIKELY(since > container().version())
95 {
96 throwDisallowedField();
97 }
98
99 return ordinary<Value>(offset);
100 }
101
106 template <class Value, class NullValue > ONIXS_ILINK3_HOTPATH
107 bool ordinary(Value& value, BlockLength offset, NullValue null) const noexcept
108 {
109 value = ordinary<Value>(offset);
110
111 return (null != value);
112 }
113
118 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
119 bool ordinary(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
120 {
121 return (since <= container().version() && ordinary (value, offset, null ) );
122 }
123
125 template < class Enumeration > ONIXS_ILINK3_HOTPATH
126 typename Enumeration::Enum enumeration(BlockLength offset) const noexcept
127 {
128 typedef typename Enumeration::Base Base;
129 typedef typename Enumeration::Enum Enum;
130
131 return static_cast<Enum>(ordinary<Base>(offset));
132 }
133
135 template < class Enumeration, class NullValue > ONIXS_ILINK3_HOTPATH
136 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null) const noexcept
137 {
138 typedef typename Enumeration::Base Base;
139 typedef typename Enumeration::Enum Enum;
140
141 value = static_cast <Enum>(ordinary<Base>(offset));
142 return null != value;
143 }
144
146 template < class Enumeration, class NullValue > ONIXS_ILINK3_HOTPATH
147 bool enumeration(typename Enumeration::Enum& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
148 {
149 return (since <= container().version() && enumeration<Enumeration>(value, offset, null) );
150 }
151
153 template < class Value > ONIXS_ILINK3_HOTPATH
154 Value decimal(BlockLength offset) const noexcept
155 {
156 return ordinary<Value>(offset);
157 }
158
163 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
164 bool decimal(Value& value, BlockLength offset, NullValue null) const noexcept
165 {
166 value = ordinary<Value>(offset);
167 return null != value;
168 }
169
174 template < class Value, class NullValue > ONIXS_ILINK3_HOTPATH
175 bool decimal(Value& value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
176 {
177 return (since <= container().version() && decimal(value, offset, null));
178 }
179
181 template < BlockLength Length > ONIXS_ILINK3_HOTPATH
182 StrRef fixedStr(BlockLength offset) const noexcept
183 {
184 assert(container().blockLength() >= (offset + Length) && "The requested field exceeds provided block boundaries.");
185
186 const Char* const text = reinterpret_cast <const Char*> (advanceByBytes(container().block(), offset));
187
188 return StrRef(text, strnlen(text, Length));
189 }
190
195 template<BlockLength Length> ONIXS_ILINK3_HOTPATH
196 bool fixedStr(StrRef& value, BlockLength offset) const noexcept
197 {
198 value = fixedStr<Length>(offset);
199 return !value.empty();
200 }
201
206 template<BlockLength Length> ONIXS_ILINK3_HOTPATH
207 bool fixedStr(StrRef& value, BlockLength offset, SchemaVersion since) const noexcept
208 {
209 return (since <= container().version() && fixedStr<Length>(value, offset));
210 }
211};
212
217template <class Container, class BlockLength >
219{
220public:
222 Container& container() noexcept
223 {
224 return *static_cast<Container*>(this);
225 }
226
229 void zeroPaddingBytes(BlockLength offset) noexcept
230 {
231 const BlockLength encodedBlockLength = container().blockLength();
232
233 assert(encodedBlockLength >= offset);
234
235 const size_t paddingLength = encodedBlockLength - offset;
236 std::memset(advanceByBytes(container().block(), offset), 0, paddingLength);
237 }
238
240 template<class FieldValue> ONIXS_ILINK3_HOTPATH
241 void setOrdinary(BlockLength offset, FieldValue value) noexcept
242 {
243 assert(container().blockLength() >= (offset + size<FieldValue>()) && "The requested field exceeds provided block boundaries.");
244
245 void* const fieldPos = advanceByBytes(container().block(), offset);
246 setValue(fieldPos, value);
247 }
248
250 template<class FieldValue> ONIXS_ILINK3_HOTPATH
251 void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
252 {
254 {
255 throwDisallowedField();
256 }
257
258 setOrdinary(offset, value);
259 }
260
262 template<class Enumeration> ONIXS_ILINK3_HOTPATH
263 void setEnumeration(BlockLength offset, typename Enumeration::Enum value) noexcept
264 {
265 typedef typename Enumeration::Base Base;
266 setOrdinary<Base>(offset, static_cast<Base>(value));
267 }
268
270 template<class Enumeration> ONIXS_ILINK3_HOTPATH
271 void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
272 {
273 typedef typename Enumeration::Base Base;
274 setOrdinary(offset, static_cast<Base>(value), since);
275 }
276
278 template<BlockLength Size> ONIXS_ILINK3_HOTPATH
279 void setFixedStr(BlockLength offset, StrRef value) noexcept
280 {
281 assert(container().blockLength() >= (offset + Size) && "The requested field exceeds provided block boundaries.");
282 assert(value.size() <= Size && "The string is truncated.");
283
284 void* const fieldPos = advanceByBytes(container().block(), offset);
285 const size_t sizeToCopy = (std::min)(Size, static_cast<BlockLength>(value.size()));
286
287 if(sizeToCopy > 0)
288 std::memcpy(fieldPos, value.data(), sizeToCopy);
289
290 std::memset(advanceByBytes(fieldPos, sizeToCopy), 0, Size - sizeToCopy);
291 }
292
294 template<BlockLength Size> ONIXS_ILINK3_HOTPATH
295 void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
296 {
298 {
299 throwDisallowedField();
300 }
301
302 setFixedStr<Size>(offset, value);
303 }
304
305protected:
307 SbeFields() = default;
308
309 ~SbeFields() = default;
310};
311
313template <class BodySizeType>
315{
316public:
318 typedef BodySizeType BlockLength;
319
322 : encoded_(nullptr)
323 , size_(0)
324 , version_(0)
325 {
326 }
327
331 : encoded_(encoded)
332 , size_(size)
333 , version_(version)
334 {
335 assert(encoded);
336 }
337
339 bool valid() const noexcept
340 {
341 return (encoded_ != nullptr);
342 }
343
345 const void* encoded() const noexcept
346 {
347 assert(valid());
348
349 return encoded_;
350 }
351
353 void* encoded() noexcept
354 {
355 assert(valid());
356
357 return encoded_;
358 }
359
361 const void* block() const noexcept
362 {
363 assert(valid());
364
365 return encoded_;
366 }
367
369 void* block() noexcept
370 {
371 assert(valid());
372
373 return encoded_;
374 }
375
377 BlockLength blockLength() const noexcept
378 {
379 return size_;
380 }
381
383 SchemaVersion version() const noexcept
384 {
385 return version_;
386 }
387
388 private:
389 void* encoded_;
390 BodySizeType size_;
391 SchemaVersion version_;
392};
393
395template <class EntryType, class BlockLength, class NumInGroup, class Length >
397{
398public:
400 typedef Length EncodedLength;
401
403 typedef EntryType Entry;
404
406 typedef NumInGroup Size;
407
410 {
411 public:
412 typedef EntryType Entry;
414
415 typedef Entry* pointer;
416 typedef Entry& reference;
417
418 typedef ptrdiff_t difference_type;
419
420 typedef std::random_access_iterator_tag iterator_category;
421
423 Iterator() noexcept
424 : entry_(nullptr)
425 , size_(0)
426 , version_(0)
427 {
428 }
429
432 Iterator(void* entry, Size size, SchemaVersion version) noexcept
433 : entry_(entry)
434 , size_(size)
435 , version_(version)
436 {
437 assert(valid());
438 }
439
441 bool valid() const noexcept
442 {
443 return (entry_ != nullptr);
444 }
445
448 Entry get() const
449 {
450 assert(valid());
451
452 return Entry(entry_, size_, version_);
453 }
454
456 Entry operator *() const
457 {
458 return get();
459 }
460
462 bool operator == (const Iterator& other) const noexcept
463 {
464 return entry_ == other.entry_;
465 }
466
468 bool operator !=(const Iterator& other) const noexcept
469 {
470 return entry_ != other.entry_;
471 }
472
474 bool operator < (const Iterator& other) const noexcept
475 {
476 return entry_ < other.entry_;
477 }
478
480 bool operator > (const Iterator& other) const noexcept
481 {
482 return entry_ > other.entry_;
483 }
484
486 Iterator& operator ++()
487 {
488 assert(valid());
489
490 entry_ = advanceByBytes(entry_, size_);
491
492 return *this;
493 }
494
496 Iterator& operator --()
497 {
498 assert(valid());
499
500 entry_ = advanceBackByBytes(entry_, size_);
501
502 return *this;
503 }
504
507 Iterator operator +(difference_type distance) const
508 {
509 assert(valid());
510
511 return Iterator(advanceByBytes(entry_, distance * size_), size_, version_);
512 }
513
516 Iterator operator - (difference_type distance) const
517 {
518 assert(valid());
519
520 return Iterator(advanceBackByBytes(entry_, distance * size_), size_, version_);
521 }
522
523 private:
524 void* entry_;
525 Size size_;
526 SchemaVersion version_;
527 };
528
531 : encoded_(nullptr)
532 , blockLength_(0)
533 , size_(0)
534 , version_(0)
535 {
536 }
537
539 SbeGroupEntries(void* encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) noexcept
540 : encoded_(encoded)
541 , blockLength_(blockLength)
542 , size_(groupSize)
543 , version_(version)
544 {
545 assert(encoded_);
546 assert(blockLength > 0);
547 assert(version != 0);
548 }
549
551 bool valid() const noexcept
552 {
553 return (nullptr != encoded_);
554 }
555
557 bool empty() const noexcept
558 {
559 return (0 == size_);
560 }
561
563 Size size() const noexcept
564 {
565 return size_;
566 }
567
569 Iterator begin() const
570 {
571 return Iterator(encoded(), blockLength_, version_);
572 }
573
575 Iterator end() const
576 {
577 return Iterator(advanceByBytes(encoded(), encodedLength()), blockLength_, version_);
578 }
579
583 Entry operator [](Size index) const
584 {
585 assert(index < size_);
586 assert(encoded_);
587
588 return Entry(advanceByBytes(encoded_, static_cast<ptrdiff_t>(index) * blockLength_), blockLength_, version_);
589 }
590
592 void* encoded() const noexcept
593 {
594 return encoded_;
595 }
596
599 {
600 return (static_cast<EncodedLength>(blockLength_) * static_cast<EncodedLength>(size_) );
601 }
602
604 template<class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength >
606 : encoded_(other.encoded_)
607 , blockLength_(other.blockLength_)
608 , size_(other.size_)
609 , version_(other.version_)
610 {
611 // Dimension types may vary for the different instantiations of the template.
612 // Therefore, truncation of the dimensions must be avoided.
613
614 assert(blockLength_ == other.blockLength_);
615 assert(size_ == other.size_);
616 }
617
618 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength>
619 SbeGroupEntries& operator = (const SbeGroupEntries <OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength>& other) noexcept
620 {
621 encoded_ = other.encoded_;
622
623 blockLength_ = other.blockLength_;
624
625 assert(blockLength_ == other.blockLength_);
626
627 size_ = other.size_;
628
629 assert(size_ == other.size_);
630
631 version_ = other.version_;
632
633 return *this;
634 }
635
636private:
637 // Allows coping and cloning for different instantiations.
638 template <class OtherEntry, class OtherBlockLength, class OtherNumInGroup, class OtherLength> friend class SbeGroupEntries;
639
640 void* encoded_;
641 BlockLength blockLength_;
642 NumInGroup size_;
643 SchemaVersion version_;
644};
645
647template < class EntryType, class DimensionType, class GroupSizeType >
649{
650public:
652 typedef DimensionType Dimension;
653
655 typedef GroupSizeType BinarySize;
656
659
661 typedef typename DimensionType::BlockLength EntrySize;
662
664 typedef SbeGroupEntries <EntryType, typename Dimension::BlockLength, typename Dimension::NumInGroup, GroupSizeType > Entries;
665
667 typedef typename Entries::Iterator Iterator;
668
670 typedef typename Entries::Entry Entry;
671
673 typedef typename Entries::Size Size;
674
677 noexcept
678 : header_(nullptr)
679 , entries_(nullptr)
680 , version_(0)
681 {
682 }
683
687 : header_(static_cast <Dimension*>(data))
688 , entries_(advanceByBytes(data, Dimension::Size))
689 , version_(version)
690 {
691 ONIXS_ILINK3_ASSERT(size >= Dimension::Size);
692 assert(header_);
693 assert(entries_);
694
695 assert(valid());
696 }
697
699 bool valid() const noexcept
700 {
701 return (entries_ != nullptr);
702 }
703
705 bool empty() const noexcept
706 {
707 assert(valid());
708
709 return 0 == size();
710 }
711
714 Size size() const noexcept
715 {
716 assert(valid());
717 assert(header_);
718
719 const Dimension* const group = static_cast<const Dimension*>(header_);
720
721 return group->numInGroup();
722 }
723
726 Iterator begin() const noexcept
727 {
728 assert(valid());
729
730 return Iterator(entries_, numericCast<Size>(entrySize()), version_);
731 }
732
735 Iterator end() const noexcept
736 {
737 assert(valid());
738
739 return Iterator(advanceByBytes(binary(), binarySize()), numericCast<Size>(entrySize()), version_);
740 }
741
746 Entry operator [](Size index) const
747 {
748 assert(valid());
749 assert(index < size());
750
751 return Entry(advanceByBytes(entries_, static_cast<ptrdiff_t>(index) * entrySize()), entrySize(), version_);
752 }
753
756 Entries entries() const noexcept
757 {
758 assert(valid());
759 assert(header_);
760
761 return Entries (entries_, header_->blockLength(), header_->numInGroup(), version_);
762 }
763
765 const void* encoded() const noexcept
766 {
767 return header_;
768 }
769
771 const void* tail() const noexcept
772 {
773 return advanceByBytes(toByteBlock(encoded()), binarySize());
774 }
775
778 void* binary() const noexcept
779 {
780 return header_;
781 }
782
785 BinarySize binarySize() const noexcept
786 {
787 return Dimension::Size + (static_cast<BinarySize>(entrySize()) * static_cast<BinarySize>(size()));
788 }
789
792 EntrySize entrySize() const noexcept
793 {
794 assert(valid());
795 assert(header_);
796
797 Dimension* const group = static_cast<Dimension*>(header_);
798 return group->blockLength();
799 }
800
801private:
803 void init(EntrySize entrySize) noexcept
804 {
805 assert(valid());
806 assert(header_);
807
808 Dimension* const group = static_cast<Dimension*>(header_);
809 group->setBlockLength(entrySize);
810 group->setNumInGroup(0);
811 }
812
814 Size allocate(Size entryCount, const void* messageTail, const void* blockEnd)
815 {
816 assert(valid());
817 assert(blockEnd);
818 assert(messageTail);
819
820 Dimension* const group = static_cast<Dimension*>(header_);
821
822 const EntrySize entrySize = group->blockLength();
823
824 if ONIXS_ILINK3_UNLIKELY(entrySize < EntryType::blockLength(version_))
825 {
826 throwBadBinaryBlock();
827 }
828
829 const Size oldEntryCount = group->numInGroup();
830
831 if(oldEntryCount == entryCount)
832 return entryCount;
833
834 const ptrdiff_t memShift =
835 (entryCount - oldEntryCount) * static_cast<ptrdiff_t>(entrySize);
836
837 const void* const newMessageTail =
838 advanceByBytes(messageTail, memShift);
839
840 if ONIXS_ILINK3_UNLIKELY(byteDistance(blockEnd, newMessageTail) < 0)
841 {
842 throwNotEnoughSpace();
843 }
844
845 const void* const oldEndOfGroup =
846 advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * oldEntryCount);
847
848 void* const newEndGroup =
849 advanceByBytes(entries_, static_cast<ptrdiff_t>(entrySize) * entryCount);
850
851 std::memmove(
852 newEndGroup,
853 oldEndOfGroup,
854 byteDistance(messageTail, oldEndOfGroup));
855
856 group->setNumInGroup(entryCount);
857
858 return oldEntryCount;
859 }
860
863 void setup(Size entryCount, const void* messageTail, const void* blockEnd)
864 {
865 assert(valid());
866 assert(blockEnd);
867 assert(messageTail);
868
869 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
870
871 for(Size index = oldEntryCount; index < entryCount; ++index)
872 zeroPaddingBytes((*this)[index].resetVariableFields());
873 }
874
877 void construct(Size entryCount, const void* messageTail, const void* blockEnd)
878 {
879 assert(valid());
880 assert(blockEnd);
881 assert(messageTail);
882
883 const Size oldEntryCount = allocate(entryCount, messageTail, blockEnd);
884
885 for(Size index = oldEntryCount; index < entryCount; ++index)
886 zeroPaddingBytes((*this)[index].reset());
887 }
888
890 static void zeroPaddingBytes(Entry& entry)
891 {
892 assert(entry.valid());
893 entry.zeroPaddingBytes(EntryType::minimalBlockLength(entry.version()));
894 }
895
896private:
897 Dimension* header_;
898 void* entries_;
899 SchemaVersion version_;
900
901 friend class SbeMessage;
902};
903
905template < class BinarySize >
907{
908public:
911 SbeVariableLengthFieldList(void* binary, BinarySize size, SchemaVersion version) noexcept
912 : binary_(binary)
913 , size_(size)
914 , version_(version)
915 {
916 }
917
919 bool empty() const noexcept
920 {
921 return (0 == size_);
922 }
923
925 template<class BinaryVariableLengthFieldType>
926 BinaryVariableLengthFieldType& head() const noexcept
927 {
928 return *static_cast<BinaryVariableLengthFieldType*>(binary_);
929 }
930
932 template<class BinaryVariableLengthFieldType> ONIXS_ILINK3_HOTPATH
934 {
935 assert(!empty());
936
937 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
938
939 assert(headSize <= size_);
940
941 return SbeVariableLengthFieldList(advanceByBytes( binary_, headSize), size_ - headSize, version_);
942 }
943
947 template<class BinaryVariableLengthFieldType> ONIXS_ILINK3_HOTPATH
949 {
950 if ONIXS_ILINK3_UNLIKELY(empty() || (size_ < BinaryVariableLengthFieldType::Size))
951 {
952 throwBadBinaryBlock();
953 }
954
955 const BinarySize headSize = head<BinaryVariableLengthFieldType>().binarySize();
956
957 if ONIXS_ILINK3_UNLIKELY(headSize > size_)
958 {
959 throwBadBinaryBlock();
960 }
961
962 return SbeVariableLengthFieldList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
963 }
964
965 private:
966 void* binary_;
967 BinarySize size_;
968 SchemaVersion version_;
969
970};
971
973template <class BinarySize>
975{
976public:
979 SbeGroupList(void* binary, BinarySize size, SchemaVersion version) noexcept
980 : binary_(binary)
981 , size_(size)
982 , version_(version)
983 {
984 }
985
987 bool empty() const noexcept
988 {
989 return (0 == size_);
990 }
991
993 template<class Group> ONIXS_ILINK3_HOTPATH
994 Group head() const noexcept
995 {
996 assert(!empty());
997
998 return Group(binary_, size_, version_);
999 }
1000
1002 template<class Group> ONIXS_ILINK3_HOTPATH
1003 SbeGroupList tail() const noexcept
1004 {
1005 assert(!empty());
1006
1007 const BinarySize headSize = head<Group>().binarySize();
1008
1009 assert(headSize <= size_);
1010
1011 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1012 }
1013
1015 template <class Group> ONIXS_ILINK3_HOTPATH
1017 {
1018 assert(!empty());
1019
1020 const BinarySize headSize = head<Group>().binarySize();
1021
1022 assert(headSize <= size_);
1023
1024 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1025 }
1026
1030 template<class Group> ONIXS_ILINK3_HOTPATH
1032 {
1033 const BinarySize headSize = checkHead<Group>();
1034
1035 return SbeGroupList(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1036 }
1037
1041 template <class Group> ONIXS_ILINK3_HOTPATH
1043 {
1044 const BinarySize headSize = checkHead<Group>();
1045
1046 return SbeVariableLengthFieldList<BinarySize>(advanceByBytes(binary_, headSize), size_ - headSize, version_);
1047 }
1048
1049private:
1050 template<class Group>
1051 BinarySize checkHead() const
1052 {
1053 if ONIXS_ILINK3_UNLIKELY(size_ < Group::Dimension::Size)
1054 {
1055 throwBadBinaryBlock();
1056 }
1057
1058 const Group group = head<Group>();
1059
1060 const BinarySize headSize = group.binarySize();
1061
1062 if ONIXS_ILINK3_UNLIKELY(headSize > size_)
1063 {
1064 throwBadBinaryBlock();
1065 }
1066
1067 if(!group.empty())
1068 {
1069 const BinarySize entrySize = group.entrySize();
1070 const BinarySize expectedEntrySize = Group::Entry::minimalBlockLength(version_);
1071
1072 if ONIXS_ILINK3_UNLIKELY(entrySize < expectedEntrySize)
1073 {
1074 throwBadBinaryBlock();
1075 }
1076 }
1077
1078 return headSize;
1079 }
1080
1081 void* binary_;
1082 BinarySize size_;
1083 SchemaVersion version_;
1084};
1085
1087template<typename Traits>
1089{
1090 if ONIXS_ILINK3_UNLIKELY(version < Traits::MinimalVersion)
1091 {
1092 throwBadMessageVersion(version, Traits::MinimalVersion);
1093 }
1094}
1095
1097template<typename Traits>
1099{
1101
1102 if ONIXS_ILINK3_UNLIKELY(version < since)
1103 {
1104 throwBadMessageVersion(version, since);
1105 }
1106}
1107
1109template<typename Traits>
1111{
1112 if ONIXS_ILINK3_UNLIKELY(id != Traits::Id)
1113 {
1114 throwBadSchemaId(Traits::Id, id);
1115 }
1116}
1117
1119template<typename Traits>
1125
1128{
1129public:
1132 struct NoInit{};
1133 struct NoCheck{};
1134
1137
1140
1142 SbeMessage() noexcept
1143 : header_(nullptr)
1144 , size_(0)
1145 {
1146 }
1147
1151 : header_(static_cast<MessageHeader*>(data))
1152 , size_(size)
1153 {
1154 assert(data);
1155 assert(size <= MaxILink3MessageSize);
1156
1158 {
1159 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1160 }
1161
1162 this->version(version);
1163 }
1164
1167 SbeMessage(void* data, MessageSize size)
1168 : header_(static_cast<MessageHeader*>(data))
1169 , size_(size)
1170 {
1171 assert(data);
1172 assert(size <= MaxILink3MessageSize);
1173
1175 throwBinaryBlockIsTooSmall(size, MessageHeader::Size);
1176
1177 // Now it is safe to read header_.
1178 if ONIXS_ILINK3_UNLIKELY(size < (MessageHeader::Size + header_->blockLength()))
1179 {
1180 throwBinaryBlockIsTooSmall(size, MessageHeader::Size + header_->blockLength());
1181 }
1182 }
1183
1188 SbeMessage(void* data, MessageSize size, NoCheck) noexcept
1189 : header_(static_cast<MessageHeader*>(data))
1190 , size_(size)
1191 {
1192 assert(data);
1193 assert(size <= MaxILink3MessageSize);
1194
1195 assert(size >= MessageHeader::Size);
1196 assert(size >= MessageHeader::Size + header_->blockLength());
1197 }
1198
1200 void clear() noexcept
1201 {
1202 *this = SbeMessage();
1203 assert(!valid());
1204 }
1205
1207 bool valid() const noexcept
1208 {
1209 return (nullptr != header_);
1210 }
1211
1214 {
1215 assert(valid());
1216
1217 return header_->templateId();
1218 }
1219
1221 SchemaVersion version() const noexcept
1222 {
1223 assert(valid());
1224
1225 return header_->version();
1226 }
1227
1229 SchemaId schemaId() const noexcept
1230 {
1231 assert(valid());
1232
1233 return header_->schemaId();
1234 }
1235
1237 const void* binary() const noexcept
1238 {
1239 assert(valid());
1240
1241 return header_;
1242 }
1243
1245 void* binary() noexcept
1246 {
1247 assert(valid());
1248
1249 return header_;
1250 }
1251
1252 // \return the end of the memory block.
1253 const void* blockEnd() noexcept
1254 {
1255 assert(valid());
1256
1257 return advanceByBytes(header_, size_);
1258 }
1259
1260 // \return the end of the memory block.
1261 const void* blockEnd() const noexcept
1262 {
1263 assert(valid());
1264
1265 return advanceByBytes(header_, size_);
1266 }
1267
1269 MessageSize bufferSize() const noexcept
1270 {
1271 return size_;
1272 }
1273
1275 void* body() noexcept
1276 {
1277 assert(valid());
1278
1279 return advanceByBytes(header_, MessageHeader::Size);
1280 }
1281
1283 BlockLength blockLength() const noexcept
1284 {
1285 assert(valid());
1286
1287 return header_->blockLength();
1288 }
1289
1291 const void* block() const noexcept
1292 {
1293 assert(valid());
1294
1295 return advanceByBytes(header_, MessageHeader::Size);
1296 }
1297
1299 void* block() noexcept
1300 {
1301 assert(valid());
1302
1303 return advanceByBytes(header_, MessageHeader::Size);
1304 }
1305
1306protected:
1309
1312 {
1313 assert(valid());
1314
1315 header_->setVersion(version);
1316
1317 return *this;
1318 }
1319
1323 {
1324 assert(header_);
1325
1326 void* list = advanceByBytes<void>(body(), blockLength());
1327
1328 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1329
1330 return GroupList(list, listSize, header_->version());
1331 }
1332
1335 GroupList groups() const noexcept
1336 {
1337 assert(header_);
1338
1339 const void* list = advanceByBytes(block(), blockLength());
1340
1341 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1342
1343 return GroupList(const_cast<void*>(list), listSize, header_->version());
1344 }
1345
1347 template<typename Group>
1349 void initGroup(Group& group, typename Group::EntrySize entrySize) noexcept
1350 {
1351 assert(group.valid());
1352 group.init(entrySize);
1353 }
1354
1356 template<typename Group>
1358 void setupGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1359 {
1360 assert(messageTail);
1361 assert(group.valid());
1362 group.setup(entryCount, messageTail, blockEnd());
1363 }
1364
1366 template<typename Group>
1368 void constructGroup(Group& group, typename Group::Size entryCount, const void* messageTail)
1369 {
1370 assert(messageTail);
1371 assert(group.valid());
1372 group.construct(entryCount, messageTail, blockEnd());
1373 }
1374
1376 void setVarDataField(DATA& data, StrRef value, const void* oldMessageTail)
1377 {
1378 assert(oldMessageTail);
1379
1380 const ptrdiff_t lengthChange = static_cast<ptrdiff_t>(value.length() - data.length());
1381
1382 const void* const newMessageTail = advanceByBytes(oldMessageTail, lengthChange);
1383
1384 if ONIXS_ILINK3_UNLIKELY(byteDistance(blockEnd(), newMessageTail) < 0)
1385 {
1386 throwNotEnoughSpace();
1387 }
1388
1389 const void* const oldEndOfData = advanceByBytes(data.varData().data(), data.varData().size());
1390
1391 void* const newEndOfData = toOpaquePtr(advanceByBytes(&data, value.length() + DATA::Size));
1392
1393 std::memmove(newEndOfData, oldEndOfData, byteDistance(oldMessageTail, oldEndOfData));
1394
1395 data.varData(value);
1396 }
1397
1400
1404 {
1405 assert(header_);
1406
1407 void* list = advanceByBytes<void>(body(), blockLength());
1408
1409 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1410
1411 return VariableLengthFieldList(list, listSize, header_->version());
1412 }
1413
1417 {
1418 assert(header_);
1419
1420 const void* list = advanceByBytes(block(), blockLength());
1421
1422 const MessageSize listSize = size_ - MessageHeader::Size - header_->blockLength();
1423
1424 return VariableLengthFieldList(const_cast<void*>(list), listSize, header_->version());
1425 }
1426
1428 void init(
1430 MessageHeader::BlockLength minimalBlockLength,
1432 SchemaId id) noexcept
1433 {
1434 assert(header_);
1435 assert(blockLength >= minimalBlockLength);
1436
1437 header_->setTemplateId(value);
1438 header_->setBlockLength(blockLength);
1439 header_->setSchemaId(id);
1440
1441 zeroPaddingBytes(minimalBlockLength);
1442 }
1443
1445 MessageSize calculateBinarySize(const void* tail) const noexcept
1446 {
1447 assert(tail);
1448
1449 const ptrdiff_t distance = byteDistance(tail, binary());
1450
1451 assert(distance > 0);
1452
1453 assert(distance <= (std::numeric_limits<MessageSize>::max)());
1454
1455 const MessageSize size = static_cast<MessageSize>(distance);
1456
1457 assert(size <= size_);
1458
1459 return size;
1460 }
1461
1463 template<class Callable, class Owner>
1464 void setVariableLengthField(Callable callable, StrRef value, Owner& owner)
1465 {
1466 setVarDataField(callable(owner), value, owner.tail());
1467 }
1468
1470 template<class Callable, class Owner>
1471 void setVariableLengthField(Callable callable, StrRef value, SchemaVersion since, Owner& owner)
1472 {
1473 if ONIXS_ILINK3_UNLIKELY(since > version())
1474 {
1475 throwDisallowedField();
1476 }
1477
1478 setVariableLengthField(callable, value, owner);
1479 }
1480
1482 template<class Callable, class Owner>
1483 StrRef getVariableLengthField(Callable callable, const Owner& owner) const noexcept
1484 {
1485 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1486 return callable(owner).varData();
1487 }
1488
1490 template<class Callable, class Owner>
1491 StrRef getVariableLengthField(Callable callable, SchemaVersion since, Owner& owner) const noexcept
1492 {
1493 if ONIXS_ILINK3_UNLIKELY(since > version())
1494 {
1495 return StrRef();
1496 }
1497
1498 return getVariableLengthField(callable, owner);
1499 }
1500
1502 template<class Callable, class Owner>
1503 void setVariableLengthFieldToNull(Callable callable, Owner& owner) noexcept
1504 {
1505 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1506 callable(owner).length(0);
1507 }
1508
1510 template<class Group, class Callable, class Owner>
1511 void resetGroup(Callable callable, Owner& owner) noexcept
1512 {
1513 const typename Group::EntrySize entrySize = Group::Entry::blockLength(version());
1514
1515 Group grp = callable(owner);
1516
1517 initGroup(grp, entrySize);
1518 }
1519
1521 template<class Callable, class Owner>
1522 void setVariableLengthFieldToNull(Callable callable, SchemaVersion since, Owner& owner) noexcept
1523 {
1524 if ONIXS_ILINK3_UNLIKELY(since > version())
1525 {
1526 return;
1527 }
1528
1529 setVariableLengthFieldToNull(callable, owner);
1530 }
1531
1533 template<class Group, class Callable, class Owner>
1534 void resetGroup(Callable callable, SchemaVersion since, Owner& owner)
1535 {
1536 if ONIXS_ILINK3_UNLIKELY(since > version())
1537 {
1538 return;
1539 }
1540
1541 resetGroup<Group>(callable, owner);
1542 }
1543
1545 template<class Group, class Callable, class Owner>
1546 Group getGroup(Callable callable, Owner& owner) const noexcept
1547 {
1548 ONIXS_ILINK3_CHECK_NOTHROW(callable(owner));
1549 return callable(owner);
1550 }
1551
1553 template<class Group, class Callable, class Owner>
1554 Group getGroup(Callable callable, SchemaVersion since, Owner& owner) const noexcept
1555 {
1556 if ONIXS_ILINK3_UNLIKELY(since > version())
1557 {
1558 return Group();
1559 }
1560
1561 return getGroup<Group>(callable, owner);
1562 }
1563
1565 template<class Group, class Callable, class Owner>
1566 Group constructGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1567 {
1568 if ONIXS_ILINK3_UNLIKELY(since > version())
1569 {
1570 return Group();
1571 }
1572
1573 return constructGroup<Group>(callable, length, owner);
1574 }
1575
1577 template<class Group, class Callable, class Owner>
1578 Group constructGroup(Callable callable, typename Group::Size length, Owner& owner)
1579 {
1580 Group group = callable(owner);
1581
1582 constructGroup(group, length, owner.tail());
1583
1584 return group;
1585 }
1586
1588 template<class Group, class Callable, class Owner>
1589 Group setupGroup(Callable callable, typename Group::Size length, SchemaVersion since, Owner& owner)
1590 {
1591 if ONIXS_ILINK3_UNLIKELY(since > version())
1592 {
1593 return Group();
1594 }
1595
1596 return setupGroup<Group>(callable, length, owner);
1597 }
1598
1600 template<class Group, class Callable, class Owner>
1601 Group setupGroup(Callable callable, typename Group::Size length, Owner& owner)
1602 {
1603 Group group = callable(owner);
1604
1605 setupGroup(group, length, owner.tail());
1606
1607 return group;
1608 }
1609
1613 constexpr
1615 {
1616 return
1618 }
1619
1620private:
1621 MessageHeader* header_;
1622 MessageSize size_;
1623};
1624
#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_UNLIKELY(cond)
Definition Compiler.h:158
#define ONIXS_ILINK3_HOTPATH
Definition Compiler.h:148
#define ONIXS_ILINK3_NODISCARD
Definition Compiler.h:147
#define ONIXS_ILINK3_CHECK_NOTHROW(equation)
Definition Compiler.h:156
#define ONIXS_ILINK3_UNUSED
Definition Compiler.h:155
bool decimal(Value &value, BlockLength offset, NullValue null) const noexcept
Definition SbeMessage.h:164
bool fixedStr(StrRef &value, BlockLength offset) const noexcept
Provides access to an optional string field value.
Definition SbeMessage.h:196
Value ordinary(BlockLength offset) const noexcept
Definition SbeMessage.h:81
Value ordinary(BlockLength offset, SchemaVersion since) const
Definition SbeMessage.h:92
bool fixedStr(StrRef &value, BlockLength offset, SchemaVersion since) const noexcept
Provides access to an optional string field value.
Definition SbeMessage.h:207
bool ordinary(Value &value, BlockLength offset, NullValue null) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:107
bool decimal(Value &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Definition SbeMessage.h:175
Value decimal(BlockLength offset) const noexcept
Definition SbeMessage.h:154
Enumeration::Enum enumeration(BlockLength offset) const noexcept
Definition SbeMessage.h:126
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:136
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:119
StrRef fixedStr(BlockLength offset) const noexcept
Provides access to a string field value.
Definition SbeMessage.h:182
bool enumeration(typename Enumeration::Enum &value, BlockLength offset, NullValue null, SchemaVersion since) const noexcept
Provides access to an optional field value.
Definition SbeMessage.h:147
NumInGroup numInGroup() const noexcept
Definition Composites.h:116
BlockLength blockLength() const noexcept
Definition Composites.h:103
Template ID and length of message root.
Definition Composites.h:192
UInt16 BlockLength
Type alias for the BlockLength.
Definition Composites.h:198
UInt16 TemplateId
Type alias for the TemplateId.
Definition Composites.h:201
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:229
void setFixedStr(BlockLength offset, StrRef value) noexcept
Sets the field value.
Definition SbeMessage.h:279
void setOrdinary(BlockLength offset, FieldValue value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:251
void setEnumeration(BlockLength offset, typename Enumeration::Enum value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:271
void setEnumeration(BlockLength offset, typename Enumeration::Enum value) noexcept
Sets the field value.
Definition SbeMessage.h:263
void setOrdinary(BlockLength offset, FieldValue value) noexcept
Sets the field value.
Definition SbeMessage.h:241
void setFixedStr(BlockLength offset, StrRef value, SchemaVersion since)
Sets the field value.
Definition SbeMessage.h:295
An iterator over SBE-encoded group entries.
Definition SbeMessage.h:410
Iterator(void *entry, Size size, SchemaVersion version) noexcept
Initializes the instance to the given repeating group.
Definition SbeMessage.h:432
Iterator() noexcept
Initializes the instance that refers to nothing.
Definition SbeMessage.h:423
SbeGroupEntries() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:530
SbeGroupEntries(void *encoded, BlockLength blockLength, Size groupSize, SchemaVersion version) noexcept
Initializes the instance referencing to data.
Definition SbeMessage.h:539
EntryType Entry
The type of the repeating group entry.
Definition SbeMessage.h:403
Iterator end() const
Returns the iterator pointing to the entry behind the end of the group.
Definition SbeMessage.h:575
SbeGroupEntries(const SbeGroupEntries< OtherEntry, OtherBlockLength, OtherNumInGroup, OtherLength > &other) noexcept
Copy constructor.
Definition SbeMessage.h:605
Length EncodedLength
The length of the binary data occupied by the group entries.
Definition SbeMessage.h:400
NumInGroup Size
Number of entries in the collection.
Definition SbeMessage.h:406
SbeGroupEntry()
Initializes a blank instance.
Definition SbeMessage.h:321
const void * block() const noexcept
Definition SbeMessage.h:361
SbeGroupEntry(void *encoded, BlockLength size, SchemaVersion version)
Initializes the instance from the memory block of the encoded message.
Definition SbeMessage.h:330
BlockLength blockLength() const noexcept
Definition SbeMessage.h:377
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.
Definition SbeMessage.h:979
const void * tail() const noexcept
Definition SbeMessage.h:771
SbeGroup() noexcept
Initializes a blank instance referencing to nothing.
Definition SbeMessage.h:676
SbeGroup(void *data, BinarySize size, SchemaVersion version) noexcept
Initializes an instance referencing to a valid group of a given message.
Definition SbeMessage.h:686
Entries entries() const noexcept
Definition SbeMessage.h:756
Iterator end() const noexcept
Definition SbeMessage.h:735
const void * encoded() const noexcept
Definition SbeMessage.h:765
SbeGroupEntries< QuoteEntry, typename Dimension::BlockLength, typename Dimension::NumInGroup, MessageSize > Entries
Definition SbeMessage.h:664
Iterator begin() const noexcept
Definition SbeMessage.h:726
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:911
SbeVariableLengthFieldList tail() const noexcept
Definition SbeMessage.h:933
BinaryVariableLengthFieldType & head() const noexcept
Definition SbeMessage.h:926
SbeVariableLengthFieldList checkTail() const
Checks the variable-length field list consistency.
Definition SbeMessage.h:948
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.
const char * version() noexcept
StrRef varData() const noexcept
Definition Composites.h:61
Length length() const noexcept
Definition Composites.h:48