GeezerVison is showing github.com — Support void trailer type, i.e. frame consisting of only header and data · DelloStritto/AliceO2@49f6fcb
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Algorithm/include/Algorithm/Parser.h +50-4Lines changed: 50 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -86,15 +86,36 @@ class ForwardParser { | 86 | 86 | static const size_t tailOffset = typesize<TrailerType>::size; | 87 | 87 | static const size_t totalOffset = headOffset + tailOffset; | 88 | 88 |
| | 89 | + // alias for callback checking the header, return true if the object | | 90 | + // is a valid header | 89 | 91 | using CheckHeaderFct = std::function<bool(const HeaderType&)>; | 90 | | - using CheckTrailerFct = std::function<bool(const TrailerType&)>; | | 92 | + | | 93 | + // alias for the argument type to be used in the CheckTrailer function | | 94 | + // have to forward to a valid type in case of void TrailerType in order | | 95 | + // to allow passing by reference | | 96 | + using CheckTrailerFctArgumentT = typename std::conditional< | | 97 | + !std::is_void<TrailerType>::value, TrailerType, int>::type; | | 98 | + | | 99 | + // alias for callback checking the trailer, takes reference to trailer | | 100 | + // object if TrailerType is a valid type, no argument otherwise | | 101 | + template <typename U> | | 102 | + using CheckTrailerFct = typename std::conditional< | | 103 | + !std::is_void<U>::value, | | 104 | + std::function<bool(const CheckTrailerFctArgumentT&)>, | | 105 | + std::function<bool()>>::type; | | 106 | + | | 107 | + // alias for callback to get the complete frame size including header, | | 108 | + // trailer and the data | 91 | 109 | using GetFrameSizeFct = std::function<size_t(const HeaderType& )>; | | 110 | + | | 111 | + // function callback to insert/handle one frame into, sequentially called | | 112 | + // for all frames if the whole block has a valid format | 92 | 113 | using InsertFct = std::function<bool(FrameInfo&)>; | 93 | 114 |
| 94 | 115 | template<typename InputType> | 95 | 116 | int parse(const InputType* buffer, size_t bufferSize, | 96 | 117 | CheckHeaderFct checkHeader, | 97 | | - CheckTrailerFct checkTrailer, | | 118 | + CheckTrailerFct<TrailerType> checkTrailer, | 98 | 119 | GetFrameSizeFct getFrameSize, | 99 | 120 | InsertFct insert) { | 100 | 121 | static_assert(sizeof(InputType) == 1, | @@ -126,7 +147,7 @@ class ForwardParser { | 126 | 147 | } else { | 127 | 148 | auto trailerStart = buffer + position + frameSize - tailOffset; | 128 | 149 | entry.trailer = reinterpret_cast<const TrailerType*>(trailerStart); | 129 | | - if (!checkTrailer(*entry.trailer)) break; | | 150 | + if (!CheckTrailer(entry, checkTrailer)) break; | 130 | 151 | } | 131 | 152 |
| 132 | 153 | // store the extracted frame info and continue with remaining buffer | @@ -150,6 +171,29 @@ class ForwardParser { | 150 | 171 | // TODO: decide about error policy | 151 | 172 | return -1; | 152 | 173 | } | | 174 | + | | 175 | + template<typename InputType, typename U = TrailerType> | | 176 | + typename std::enable_if<std::is_void<U>::value, int>::type | | 177 | + parse(const InputType* buffer, size_t bufferSize, | | 178 | + CheckHeaderFct checkHeader, | | 179 | + GetFrameSizeFct getFrameSize, | | 180 | + InsertFct insert) { | | 181 | + auto checkTrailer = [] () {return true;}; | | 182 | + return parse(buffer, bufferSize, checkHeader, checkTrailer, getFrameSize, insert); | | 183 | + } | | 184 | + | | 185 | +private: | | 186 | + template <typename U = TrailerType> | | 187 | + typename std::enable_if<!std::is_void<U>::value, bool>::type | | 188 | + CheckTrailer(const FrameInfo& entry, CheckTrailerFct<TrailerType>& checkTrailer) const { | | 189 | + return checkTrailer(*entry.trailer); | | 190 | + } | | 191 | + | | 192 | + template <typename U = TrailerType> | | 193 | + typename std::enable_if<std::is_void<U>::value, bool>::type | | 194 | + CheckTrailer(const FrameInfo&, CheckTrailerFct<TrailerType>&) const { | | 195 | + return true; | | 196 | + } | 153 | 197 | }; | 154 | 198 |
| 155 | 199 | /** | @@ -198,9 +242,11 @@ class ReverseParser { | 198 | 242 | PtrT payload = nullptr; | 199 | 243 | size_t length = 0; | 200 | 244 | }; | 201 | | - // the length offset due to header and trailer | | 245 | + /// the length offset due to header | 202 | 246 | static const size_t headOffset = typesize<HeaderType>::size; | | 247 | + /// the length offset due to trailer | 203 | 248 | static const size_t tailOffset = typesize<TrailerType>::size; | | 249 | + /// total length offset due to header and trailer | 204 | 250 | static const size_t totalOffset = headOffset + tailOffset; | 205 | 251 |
| 206 | 252 | using CheckHeaderFct = std::function<bool(const HeaderType&)>; | |
Collapse file Copy file name to clipboardExpand all lines: Algorithm/test/StaticSequenceAllocator.h +27-8Lines changed: 27 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -21,21 +21,38 @@ namespace algorithm { | 21 | 21 | * and a trailer | 22 | 22 | */ | 23 | 23 | template <typename HeaderT | 24 | | - , typename TrailerT> | | 24 | + , typename TrailerT = void> | 25 | 25 | struct Composite { | 26 | 26 | using HeaderType = HeaderT; | 27 | 27 | using TrailerType = TrailerT; | 28 | 28 | size_t compositeLength = 0; | | 29 | + size_t trailerLength = 0; | 29 | 30 | size_t dataLength = 0; | 30 | 31 |
| 31 | | - template<size_t N> | 32 | | - constexpr Composite(const HeaderType& h, const char (&d)[N], const TrailerType& t) | | 32 | + template<size_t N, | | 33 | + typename U = TrailerType> | | 34 | + constexpr Composite(const HeaderType h, const char (&d)[N], | | 35 | + typename std::conditional<!std::is_void<U>::value, const TrailerType, int>::type t, | | 36 | + typename std::enable_if<!std::is_void<U>::value>::type* = nullptr) | 33 | 37 | : header(h) | 34 | 38 | , data(d) | 35 | 39 | , trailer(t) | 36 | 40 | { | 37 | 41 | dataLength = N; | 38 | | - compositeLength = sizeof(HeaderType) + dataLength + sizeof(TrailerType); | | 42 | + trailerLength = sizeof(TrailerType); | | 43 | + compositeLength = sizeof(HeaderType) + dataLength + trailerLength; | | 44 | + } | | 45 | + | | 46 | + template<size_t N, | | 47 | + typename U = TrailerType> | | 48 | + constexpr Composite(const HeaderType& h, const char (&d)[N], | | 49 | + typename std::enable_if<std::is_void<U>::value>::type* = nullptr) | | 50 | + : header(h) | | 51 | + , data(d) | | 52 | + { | | 53 | + dataLength = N; | | 54 | + trailerLength = 0; | | 55 | + compositeLength = sizeof(HeaderType) + dataLength + trailerLength; | 39 | 56 | } | 40 | 57 |
| 41 | 58 | constexpr size_t getLength() const noexcept { | @@ -54,14 +71,16 @@ struct Composite { | 54 | 71 | length += sizeof(HeaderType); | 55 | 72 | memcpy(buffer + length, data, dataLength); | 56 | 73 | length += dataLength; | 57 | | - memcpy(buffer + length, &trailer, sizeof(TrailerType)); | 58 | | - length += sizeof(TrailerType); | | 74 | + if (trailerLength > 0) { | | 75 | + memcpy(buffer + length, &trailer, trailerLength); | | 76 | + length += trailerLength; | | 77 | + } | 59 | 78 | return length; | 60 | 79 | } | 61 | 80 |
| 62 | | - const HeaderType& header; | | 81 | + const HeaderType header; | 63 | 82 | const char* data = nullptr; | 64 | | - const TrailerType& trailer; | | 83 | + typename std::conditional<!std::is_void<TrailerType>::value, const TrailerType, int>::type trailer; | 65 | 84 | }; | 66 | 85 |
| 67 | 86 | /// recursively calculate the length of the sequence | |
Collapse file Copy file name to clipboardExpand all lines: Algorithm/test/parser.cxx +121-1Lines changed: 121 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -68,6 +68,7 @@ BOOST_AUTO_TEST_CASE(test_forwardparser_header_and_trailer) | 68 | 68 | return trailer.identifier == 0xaaffee00; | 69 | 69 | }; | 70 | 70 | auto getFrameSize = [] (const typename ParserT::HeaderType& header) { | | 71 | + // frame size includes total offset from header and trailer | 71 | 72 | return header.payloadSize + ParserT::totalOffset; | 72 | 73 | }; | 73 | 74 |
| @@ -93,7 +94,126 @@ BOOST_AUTO_TEST_CASE(test_forwardparser_header_and_trailer) | 93 | 94 | BOOST_CHECK(memcmp(frames[2].payload, "dummydata", frames[2].length) == 0); | 94 | 95 | } | 95 | 96 |
| 96 | | -// TODO: make a test of a composite with header and payload | | 97 | +BOOST_AUTO_TEST_CASE(test_forwardparser_header_and_void_trailer) | | 98 | +{ | | 99 | + using FrameT = o2::algorithm::Composite<Header>; | | 100 | + // note: the length of the data is set in the header word | | 101 | + using TestFrame = o2::algorithm::StaticSequenceAllocator; | | 102 | + TestFrame tf(FrameT(16, "lotsofsillydata"), | | 103 | + FrameT(5, "test"), | | 104 | + FrameT(10, "dummydata") | | 105 | + ); | | 106 | + | | 107 | + using ParserT = o2::algorithm::ForwardParser<typename FrameT::HeaderType, | | 108 | + typename FrameT::TrailerType>; | | 109 | + | | 110 | + auto checkHeader = [] (const typename FrameT::HeaderType& header) { | | 111 | + return header.identifier == 0xdeadbeef; | | 112 | + }; | | 113 | + | | 114 | + auto getFrameSize = [] (const typename ParserT::HeaderType& header) { | | 115 | + // frame size includes total offset from header and trailer | | 116 | + return header.payloadSize + ParserT::totalOffset; | | 117 | + }; | | 118 | + | | 119 | + std::vector<typename ParserT::FrameInfo> frames; | | 120 | + auto insert = [&frames] (typename ParserT::FrameInfo& info) { | | 121 | + frames.emplace_back(info); | | 122 | + return true; | | 123 | + }; | | 124 | + | | 125 | + ParserT parser; | | 126 | + auto result = parser.parse(tf.buffer.get(), tf.size(), | | 127 | + checkHeader, | | 128 | + getFrameSize, | | 129 | + insert | | 130 | + ); | | 131 | + | | 132 | + BOOST_REQUIRE(result == 3); | | 133 | + BOOST_REQUIRE(frames.size() == 3); | | 134 | + | | 135 | + BOOST_CHECK(memcmp(frames[0].payload, "lotsofsillydata", frames[0].length) == 0); | | 136 | + BOOST_CHECK(memcmp(frames[1].payload, "test", frames[1].length) == 0); | | 137 | + BOOST_CHECK(memcmp(frames[2].payload, "dummydata", frames[2].length) == 0); | | 138 | +} | | 139 | + | | 140 | +BOOST_AUTO_TEST_CASE(test_forwardparser_no_frames) | | 141 | +{ | | 142 | + using FrameT = o2::algorithm::Composite<Header>; | | 143 | + // note: the length of the data is set in the header word | | 144 | + using TestFrame = o2::algorithm::StaticSequenceAllocator; | | 145 | + TestFrame tf(FrameT(16, "lotsofsillydata"), | | 146 | + FrameT(5, "test"), | | 147 | + FrameT(10, "dummydata") | | 148 | + ); | | 149 | + | | 150 | + using ParserT = o2::algorithm::ForwardParser<typename FrameT::HeaderType, | | 151 | + typename FrameT::TrailerType>; | | 152 | + | | 153 | + auto checkHeader = [] (const typename FrameT::HeaderType& header) { | | 154 | + // simply indicate invalid header to read no frames | | 155 | + return false; | | 156 | + }; | | 157 | + | | 158 | + auto getFrameSize = [] (const typename ParserT::HeaderType& header) { | | 159 | + // frame size includes total offset from header and trailer | | 160 | + return header.payloadSize + ParserT::totalOffset; | | 161 | + }; | | 162 | + | | 163 | + std::vector<typename ParserT::FrameInfo> frames; | | 164 | + auto insert = [&frames] (typename ParserT::FrameInfo& info) { | | 165 | + frames.emplace_back(info); | | 166 | + return true; | | 167 | + }; | | 168 | + | | 169 | + ParserT parser; | | 170 | + auto result = parser.parse(tf.buffer.get(), tf.size(), | | 171 | + checkHeader, | | 172 | + getFrameSize, | | 173 | + insert | | 174 | + ); | | 175 | + | | 176 | + // check that there are really no frames found | | 177 | + BOOST_REQUIRE(result == 0); | | 178 | +} | | 179 | + | | 180 | +BOOST_AUTO_TEST_CASE(test_forwardparser_format_error) | | 181 | +{ | | 182 | + using FrameT = o2::algorithm::Composite<Header>; | | 183 | + // note: the length of the data is set in the header word | | 184 | + using TestFrame = o2::algorithm::StaticSequenceAllocator; | | 185 | + TestFrame tf(FrameT(16, "lotsofsillydata"), | | 186 | + FrameT(4, "test"), // <- note wrong size | | 187 | + FrameT(10, "dummydata") | | 188 | + ); | | 189 | + | | 190 | + using ParserT = o2::algorithm::ForwardParser<typename FrameT::HeaderType, | | 191 | + typename FrameT::TrailerType>; | | 192 | + | | 193 | + auto checkHeader = [] (const typename FrameT::HeaderType& header) { | | 194 | + return header.identifier == 0xdeadbeef; | | 195 | + }; | | 196 | + | | 197 | + auto getFrameSize = [] (const typename ParserT::HeaderType& header) { | | 198 | + // frame size includes total offset from header and trailer | | 199 | + return header.payloadSize + ParserT::totalOffset; | | 200 | + }; | | 201 | + | | 202 | + std::vector<typename ParserT::FrameInfo> frames; | | 203 | + auto insert = [&frames] (typename ParserT::FrameInfo& info) { | | 204 | + frames.emplace_back(info); | | 205 | + return true; | | 206 | + }; | | 207 | + | | 208 | + ParserT parser; | | 209 | + auto result = parser.parse(tf.buffer.get(), tf.size(), | | 210 | + checkHeader, | | 211 | + getFrameSize, | | 212 | + insert | | 213 | + ); | | 214 | + | | 215 | + BOOST_REQUIRE(result == -1); | | 216 | +} | 97 | 217 |
| 98 | 218 | BOOST_AUTO_TEST_CASE(test_reverseparser) | 99 | 219 | { | |
Collapse file Copy file name to clipboardExpand all lines: Algorithm/test/tableview.cxx +34Lines changed: 34 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -120,3 +120,37 @@ BOOST_AUTO_TEST_CASE(test_tableview_reverse) | 120 | 120 | BOOST_CHECK(rowidx == requiredNofRowsInColumn[colidx]); | 121 | 121 | } | 122 | 122 | } | | 123 | + | | 124 | +BOOST_AUTO_TEST_CASE(test_tableview_formaterror) | | 125 | +{ | | 126 | + using FrameT = o2::algorithm::Composite<HeartbeatHeader, HeartbeatTrailer>; | | 127 | + using TestFrame = o2::algorithm::StaticSequenceAllocator; | | 128 | + // note: the length of the data is set in the trailer word | | 129 | + // specifying wrong length in the second entry, no frames should be added | | 130 | + TestFrame tf1(FrameT({0x1100000000000000}, "heartbeatdata", {0x510000000000000e}), | | 131 | + FrameT({0x1100000000000001}, "test", {0x5100000000000004}), | | 132 | + FrameT({0x1100000000000003}, "dummydata", {0x510000000000000a}) | | 133 | + ); | | 134 | + | | 135 | + // the payload length is set in the trailer, so we need a reverse parser | | 136 | + using ParserT = o2::algorithm::ReverseParser<typename FrameT::HeaderType, | | 137 | + typename FrameT::TrailerType>; | | 138 | + | | 139 | + // define the view type for DataHeader as row descriptor, | | 140 | + // HeartbeatHeader as column descriptor and the reverse parser | | 141 | + using ViewType = o2::algorithm::TableView<o2::header::DataHeader, | | 142 | + o2::header::HeartbeatHeader, | | 143 | + ParserT>; | | 144 | + ViewType heartbeatview; | | 145 | + | | 146 | + o2::Header::DataHeader dh; | | 147 | + dh.dataDescription = o2::Header::DataDescription("FIRSTSLOT"); | | 148 | + dh.dataOrigin = o2::Header::DataOrigin("TST"); | | 149 | + dh.subSpecification = 0; | | 150 | + dh.payloadSize = 0; | | 151 | + | | 152 | + heartbeatview.addRow(dh, tf1.buffer.get(), tf1.size()); | | 153 | + | | 154 | + BOOST_CHECK(heartbeatview.getNRows() == 0); | | 155 | + BOOST_CHECK(heartbeatview.getNColumns() == 0); | | 156 | +} |
|