00001 #ifndef artdaq_core_Data_Fragment_hh
00002 #define artdaq_core_Data_Fragment_hh
00003
00004 #include <algorithm>
00005 #include <cassert>
00006 #include <cstddef>
00007 #include <iosfwd>
00008 #include <iterator>
00009 #include <vector>
00010 #include <memory>
00011 #include <map>
00012 #include <cmath>
00013 #include <stdint.h>
00014 #include <string.h>
00015
00016 #include "artdaq-core/Data/detail/RawFragmentHeader.hh"
00017 #include "artdaq-core/Data/dictionarycontrol.hh"
00018
00019 namespace artdaq {
00020 # include "QuickVec.hh"
00021 # define DATAVEC_T QuickVec<RawDataType>
00022
00023 typedef detail::RawFragmentHeader::RawDataType RawDataType;
00024
00025 class Fragment;
00026 bool fragmentSequenceIDCompare(Fragment i, Fragment j);
00027
00028 std::ostream & operator<<(std::ostream & os, Fragment const & f);
00029 }
00030
00031 class artdaq::Fragment {
00032 public:
00033
00034 Fragment();
00035
00036
00037
00038
00039
00040 typedef uint8_t byte_t;
00041
00042
00043 #if HIDE_FROM_ROOT
00044 typedef detail::RawFragmentHeader::version_t version_t;
00045 typedef detail::RawFragmentHeader::type_t type_t;
00046 typedef detail::RawFragmentHeader::sequence_id_t sequence_id_t;
00047 typedef detail::RawFragmentHeader::fragment_id_t fragment_id_t;
00048 typedef detail::RawFragmentHeader::timestamp_t timestamp_t;
00049
00050 static constexpr version_t InvalidVersion =
00051 detail::RawFragmentHeader::InvalidVersion;
00052 static constexpr sequence_id_t InvalidSequenceID =
00053 detail::RawFragmentHeader::InvalidSequenceID;
00054 static constexpr fragment_id_t InvalidFragmentID =
00055 detail::RawFragmentHeader::InvalidFragmentID;
00056 static constexpr timestamp_t InvalidTimestamp =
00057 detail::RawFragmentHeader::InvalidTimestamp;
00058
00059 static constexpr type_t InvalidFragmentType =
00060 detail::RawFragmentHeader::InvalidFragmentType;
00061 static constexpr type_t EndOfDataFragmentType =
00062 detail::RawFragmentHeader::EndOfDataFragmentType;
00063 static constexpr type_t DataFragmentType =
00064 detail::RawFragmentHeader::DataFragmentType;
00065 static constexpr type_t InitFragmentType =
00066 detail::RawFragmentHeader::InitFragmentType;
00067 static constexpr type_t EndOfRunFragmentType =
00068 detail::RawFragmentHeader::EndOfRunFragmentType;
00069 static constexpr type_t EndOfSubrunFragmentType =
00070 detail::RawFragmentHeader::EndOfSubrunFragmentType;
00071 static constexpr type_t ShutdownFragmentType =
00072 detail::RawFragmentHeader::ShutdownFragmentType;
00073 static constexpr type_t FirstUserFragmentType =
00074 detail::RawFragmentHeader::FIRST_USER_TYPE;
00075 static constexpr type_t EmptyFragmentType =
00076 detail::RawFragmentHeader::EmptyFragmentType;
00077 static constexpr type_t ContainerFragmentType =
00078 detail::RawFragmentHeader::ContainerFragmentType;
00079
00080 static constexpr bool isUserFragmentType(type_t fragmentType);
00081 static constexpr bool isSystemFragmentType(type_t fragmentType);
00082 static std::map<type_t, std::string> MakeSystemTypeMap()
00083 {
00084 return detail::RawFragmentHeader::MakeSystemTypeMap();
00085 }
00086
00087 typedef DATAVEC_T::reference reference;
00088 typedef DATAVEC_T::iterator iterator;
00089 typedef DATAVEC_T::const_iterator const_iterator;
00090 typedef DATAVEC_T::value_type value_type;
00091 typedef DATAVEC_T::difference_type difference_type;
00092 typedef DATAVEC_T::size_type size_type;
00093
00094
00095
00096 explicit Fragment(std::size_t n);
00097
00098
00099
00100
00101
00102 static std::unique_ptr<Fragment> FragmentBytes(std::size_t nbytes) {
00103 RawDataType nwords = ceil(nbytes / static_cast<double>(sizeof(RawDataType)));
00104 return std::unique_ptr<Fragment>(new Fragment(nwords));
00105 }
00106
00107
00108
00109
00110 template <class T>
00111 Fragment(std::size_t payload_size, sequence_id_t sequence_id,
00112 fragment_id_t fragment_id, type_t type, const T & metadata,
00113 timestamp_t timestamp = Fragment::InvalidTimestamp);
00114
00115
00116
00117
00118
00119 template <class T>
00120 static std::unique_ptr<Fragment> FragmentBytes(std::size_t payload_size_in_bytes,
00121 sequence_id_t sequence_id,
00122 fragment_id_t fragment_id,
00123 type_t type, const T & metadata,
00124 timestamp_t timestamp = Fragment::InvalidTimestamp) {
00125 RawDataType nwords = ceil(payload_size_in_bytes /
00126 static_cast<double>(sizeof(RawDataType)));
00127 return std::unique_ptr<Fragment>(new Fragment(nwords, sequence_id, fragment_id, type, metadata, timestamp));
00128 }
00129
00130
00131
00132 Fragment(sequence_id_t sequenceID,
00133 fragment_id_t fragID,
00134 type_t type = Fragment::DataFragmentType,
00135 timestamp_t timestamp = Fragment::InvalidTimestamp);
00136
00137
00138 void print(std::ostream & os) const;
00139
00140
00141 std::size_t size() const;
00142 version_t version() const;
00143 type_t type() const;
00144 sequence_id_t sequenceID() const;
00145 fragment_id_t fragmentID() const;
00146 timestamp_t timestamp() const;
00147
00148
00149 void setVersion(version_t version);
00150 void setUserType(type_t type);
00151 void setSystemType(type_t type);
00152 void setSequenceID(sequence_id_t sequence_id);
00153 void setFragmentID(fragment_id_t fragment_id);
00154 void setTimestamp(timestamp_t timestamp);
00155
00156
00157 std::size_t sizeBytes() const { return sizeof(RawDataType) * size(); }
00158
00159
00160
00161 std::size_t dataSize() const;
00162
00163
00164 std::size_t dataSizeBytes() const {
00165 return sizeof(RawDataType) * dataSize();
00166 }
00167
00168
00169 bool hasMetadata() const;
00170
00171
00172
00173 template <class T> T * metadata();
00174 template <class T> T const * metadata() const;
00175
00176
00177
00178
00179 template <class T> void setMetadata(const T & md);
00180
00181
00182 template <class T> void updateMetadata(const T & md);
00183
00184
00185 void resize(std::size_t sz);
00186 void resize(std::size_t sz, RawDataType v);
00187
00188
00189
00190
00191
00192 void resizeBytes(std::size_t szbytes);
00193 void resizeBytes(std::size_t szbytes, byte_t v);
00194
00195
00196 void autoResize();
00197
00198
00199 iterator dataBegin();
00200
00201 iterator dataEnd();
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 template <typename T>
00221 T reinterpret_cast_checked(const RawDataType* in) const {
00222 T newpointer = reinterpret_cast<T>(in);
00223
00224 if (static_cast<const void*>(newpointer) != static_cast<const void*>(in)) {
00225 throw cet::exception("Error in Fragment.hh: reinterpret_cast failed to return expected address-- please contact John Freeman at jcfree@fnal.gov");
00226 }
00227
00228 return newpointer;
00229 }
00230
00231
00232 template <typename T>
00233 T reinterpret_cast_checked(RawDataType* in) {
00234 T newpointer = reinterpret_cast<T>(in);
00235
00236 if (static_cast<void*>(newpointer) != static_cast<void*>(in)) {
00237 throw cet::exception("Error in Fragment.hh: reinterpret_cast failed to return expected address-- please contact John Freeman at jcfree@fnal.gov");
00238 }
00239
00240 return newpointer;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249 byte_t* dataBeginBytes() { return reinterpret_cast_checked<byte_t*>(&* dataBegin()); }
00250 byte_t* dataEndBytes() { return reinterpret_cast_checked<byte_t*>(&* dataEnd()); }
00251
00252
00253
00254 iterator headerBegin();
00255
00256
00257 byte_t* headerBeginBytes() { return reinterpret_cast_checked<byte_t*>(&* headerBegin()); }
00258
00259
00260 const_iterator dataBegin() const;
00261 const_iterator dataEnd() const;
00262
00263 const byte_t* dataBeginBytes() const {
00264 return reinterpret_cast_checked<const byte_t*>(&* dataBegin());
00265 }
00266
00267 const byte_t* dataEndBytes() const {
00268 return reinterpret_cast_checked<const byte_t*>(&* dataEnd());
00269 }
00270
00271
00272 const_iterator headerBegin() const;
00273
00274 const byte_t* headerBeginBytes() const {
00275 return reinterpret_cast_checked<const byte_t*>(&* headerBegin());
00276 }
00277
00278
00279 void clear();
00280 bool empty();
00281 void reserve(std::size_t cap);
00282 void swap(Fragment & other);
00283 void swap(DATAVEC_T & other) { vals_.swap(other); };
00284
00285 RawDataType * dataAddress();
00286 RawDataType * metadataAddress();
00287 RawDataType * headerAddress();
00288
00289 static std::unique_ptr<Fragment> eodFrag(size_t nFragsToExpect);
00290
00291
00292 template <class InputIterator>
00293 static
00294 Fragment
00295 dataFrag(sequence_id_t sequenceID,
00296 fragment_id_t fragID,
00297 InputIterator i,
00298 InputIterator e);
00299
00300 static
00301 Fragment
00302 dataFrag(sequence_id_t sequenceID,
00303 fragment_id_t fragID,
00304 RawDataType const * dataPtr,
00305 size_t dataSize,
00306 timestamp_t timestamp = Fragment::InvalidTimestamp);
00307 #endif
00308
00309 private:
00310 template <typename T> static std::size_t validatedMetadataSize_();
00311 void updateFragmentHeaderWC_();
00312
00313 DATAVEC_T vals_;
00314
00315 #if HIDE_FROM_ROOT
00316 detail::RawFragmentHeader * fragmentHeader();
00317 detail::RawFragmentHeader const * fragmentHeader() const;
00318 #endif
00319 };
00320
00321 #if HIDE_FROM_ROOT
00322 inline
00323 bool
00324 constexpr
00325 artdaq::Fragment::
00326 isUserFragmentType(type_t fragmentType)
00327 {
00328 return fragmentType >= detail::RawFragmentHeader::FIRST_USER_TYPE &&
00329 fragmentType <= detail::RawFragmentHeader::LAST_USER_TYPE;
00330 }
00331
00332 inline
00333 bool
00334 constexpr
00335 artdaq::Fragment::
00336 isSystemFragmentType(type_t fragmentType)
00337 {
00338 return fragmentType >= detail::RawFragmentHeader::FIRST_SYSTEM_TYPE;
00339 }
00340
00341 template<typename T>
00342 std::size_t
00343 artdaq::Fragment::
00344 validatedMetadataSize_()
00345 {
00346
00347
00348
00349 static_assert(sizeof(size_t) >=
00350 sizeof(decltype(std::numeric_limits<detail::RawFragmentHeader::metadata_word_count_t>::max())),
00351 "metadata_word_count_t is too big!");
00352
00353 static size_t constexpr max_md_wc =
00354 std::numeric_limits<detail::RawFragmentHeader::metadata_word_count_t>::max();
00355 size_t requested_md_wc =
00356 std::ceil(sizeof(T) / static_cast<double>(sizeof(artdaq::RawDataType)));
00357 if (requested_md_wc > max_md_wc) {
00358 throw cet::exception("InvalidRequest")
00359 << "The requested metadata structure is too large: "
00360 << "requested word count = " << requested_md_wc
00361 << ", maximum word count = " << max_md_wc;
00362 }
00363 return requested_md_wc;
00364 }
00365
00366 template <class T>
00367 artdaq::Fragment::
00368 Fragment(std::size_t payload_size, sequence_id_t sequence_id,
00369 fragment_id_t fragment_id,
00370 type_t type, const T & metadata, timestamp_t timestamp) :
00371 vals_((artdaq::detail::RawFragmentHeader::num_words() +
00372 validatedMetadataSize_<T>() +
00373 payload_size),
00374 0)
00375 {
00376 updateFragmentHeaderWC_();
00377 fragmentHeader()->sequence_id = sequence_id;
00378 fragmentHeader()->fragment_id = fragment_id;
00379 fragmentHeader()->timestamp = timestamp;
00380 fragmentHeader()->type = type;
00381
00382 fragmentHeader()->metadata_word_count =
00383 vals_.size() -
00384 (artdaq::detail::RawFragmentHeader::num_words() + payload_size);
00385
00386 memcpy(metadataAddress(), &metadata, sizeof(T));
00387 }
00388
00389 inline
00390 std::size_t
00391 artdaq::Fragment::size() const
00392 {
00393 return fragmentHeader()->word_count;
00394 }
00395
00396 inline
00397 artdaq::Fragment::version_t
00398 artdaq::Fragment::version() const
00399 {
00400 return fragmentHeader()->version;
00401 }
00402
00403 inline
00404 artdaq::Fragment::type_t
00405 artdaq::Fragment::type() const
00406 {
00407 return static_cast<type_t>(fragmentHeader()->type);
00408 }
00409
00410 inline
00411 artdaq::Fragment::sequence_id_t
00412 artdaq::Fragment::sequenceID() const
00413 {
00414 return fragmentHeader()->sequence_id;
00415 }
00416
00417 inline
00418 artdaq::Fragment::fragment_id_t
00419 artdaq::Fragment::fragmentID() const
00420 {
00421 return fragmentHeader()->fragment_id;
00422 }
00423
00424 inline
00425 artdaq::Fragment::timestamp_t
00426 artdaq::Fragment::timestamp() const
00427 {
00428 return fragmentHeader()->timestamp;
00429 }
00430
00431 inline
00432 void
00433 artdaq::Fragment::setVersion(version_t version)
00434 {
00435 fragmentHeader()->version = version;
00436 }
00437
00438 inline
00439 void
00440 artdaq::Fragment::setUserType(type_t type)
00441 {
00442 fragmentHeader()->setUserType(static_cast<uint8_t>(type));
00443 }
00444
00445 inline
00446 void
00447 artdaq::Fragment::setSystemType(type_t type)
00448 {
00449 fragmentHeader()->setSystemType(static_cast<uint8_t>(type));
00450 }
00451
00452 inline
00453 void
00454 artdaq::Fragment::setSequenceID(sequence_id_t sequence_id)
00455 {
00456 assert(sequence_id <= detail::RawFragmentHeader::InvalidSequenceID);
00457 fragmentHeader()->sequence_id = sequence_id;
00458 }
00459
00460 inline
00461 void
00462 artdaq::Fragment::setFragmentID(fragment_id_t fragment_id)
00463 {
00464 fragmentHeader()->fragment_id = fragment_id;
00465 }
00466
00467 inline
00468 void
00469 artdaq::Fragment::setTimestamp(timestamp_t timestamp)
00470 {
00471 fragmentHeader()->timestamp = timestamp;
00472 }
00473
00474 inline
00475 void
00476 artdaq::Fragment::updateFragmentHeaderWC_()
00477 {
00478
00479
00480 assert(vals_.size() < (1ULL << 32));
00481 fragmentHeader()->word_count = vals_.size();
00482 }
00483
00484 inline
00485 std::size_t
00486 artdaq::Fragment::dataSize() const
00487 {
00488 return vals_.size() - detail::RawFragmentHeader::num_words() -
00489 fragmentHeader()->metadata_word_count;
00490 }
00491
00492 inline
00493 bool
00494 artdaq::Fragment::hasMetadata() const
00495 {
00496 return fragmentHeader()->metadata_word_count != 0;
00497 }
00498
00499 template <class T>
00500 T *
00501 artdaq::Fragment::metadata()
00502 {
00503 if (fragmentHeader()->metadata_word_count == 0) {
00504 throw cet::exception("InvalidRequest")
00505 << "No metadata has been stored in this Fragment.";
00506 }
00507
00508 return reinterpret_cast_checked<T *>
00509 (&vals_[detail::RawFragmentHeader::num_words()]);
00510 }
00511
00512 template <class T>
00513 T const *
00514 artdaq::Fragment::metadata() const
00515 {
00516 if (fragmentHeader()->metadata_word_count == 0) {
00517 throw cet::exception("InvalidRequest")
00518 << "No metadata has been stored in this Fragment.";
00519 }
00520 return reinterpret_cast_checked<T const *>
00521 (&vals_[detail::RawFragmentHeader::num_words()]);
00522 }
00523
00524 template <class T>
00525 void
00526 artdaq::Fragment::setMetadata(const T & metadata)
00527 {
00528 if (fragmentHeader()->metadata_word_count != 0) {
00529 throw cet::exception("InvalidRequest")
00530 << "Metadata has already been stored in this Fragment.";
00531 }
00532 auto const mdSize = validatedMetadataSize_<T>();
00533 vals_.insert(dataBegin(), mdSize, 0);
00534 updateFragmentHeaderWC_();
00535 fragmentHeader()->metadata_word_count = mdSize;
00536
00537 memcpy(metadataAddress(), &metadata, sizeof(T));
00538 }
00539
00540 template <class T>
00541 void
00542 artdaq::Fragment::updateMetadata(const T & metadata)
00543 {
00544 if (fragmentHeader()->metadata_word_count == 0) {
00545 throw cet::exception("InvalidRequest")
00546 << "No metadata in fragment; please use Fragment::setMetadata instead of Fragment::updateMetadata";
00547 }
00548
00549 auto const mdSize = validatedMetadataSize_<T>();
00550
00551 if (fragmentHeader()->metadata_word_count != mdSize) {
00552 throw cet::exception("InvalidRequest")
00553 << "Mismatch between type of metadata struct passed to updateMetadata and existing metadata struct";
00554 }
00555
00556 memcpy(metadataAddress(), &metadata, sizeof(T));
00557 }
00558
00559 inline void
00560 artdaq::Fragment::resize(std::size_t sz)
00561 {
00562 vals_.resize(sz + fragmentHeader()->metadata_word_count +
00563 detail::RawFragmentHeader::num_words());
00564 updateFragmentHeaderWC_();
00565 }
00566 inline
00567 void
00568 artdaq::Fragment::resize(std::size_t sz, RawDataType v)
00569 {
00570 vals_.resize(sz + fragmentHeader()->metadata_word_count +
00571 detail::RawFragmentHeader::num_words(), v);
00572 updateFragmentHeaderWC_();
00573 }
00574
00575 inline void
00576 artdaq::Fragment::resizeBytes(std::size_t szbytes)
00577 {
00578 RawDataType nwords = ceil(szbytes / static_cast<double>(sizeof(RawDataType)));
00579 resize(nwords);
00580 }
00581 inline
00582 void
00583 artdaq::Fragment::resizeBytes(std::size_t szbytes, byte_t v)
00584 {
00585 RawDataType defaultval;
00586 byte_t* ptr = reinterpret_cast_checked<byte_t*>(&defaultval);
00587
00588 for (uint8_t i = 0; i < sizeof(RawDataType); ++i) {
00589 *ptr = v;
00590 ptr++;
00591 }
00592
00593 RawDataType nwords = ceil(szbytes / static_cast<double>(sizeof(RawDataType)));
00594
00595 resize(nwords, defaultval);
00596 }
00597
00598
00599 inline
00600 void
00601 artdaq::Fragment::autoResize()
00602 {
00603 vals_.resize(fragmentHeader()->word_count);
00604 updateFragmentHeaderWC_();
00605 }
00606
00607 inline
00608 artdaq::Fragment::iterator
00609 artdaq::Fragment::dataBegin()
00610 {
00611 return vals_.begin() + detail::RawFragmentHeader::num_words() +
00612 fragmentHeader()->metadata_word_count;
00613 }
00614
00615 inline
00616 artdaq::Fragment::iterator
00617 artdaq::Fragment::dataEnd()
00618 {
00619 return vals_.end();
00620 }
00621
00622 inline
00623 artdaq::Fragment::iterator
00624 artdaq::Fragment::headerBegin()
00625 {
00626 return vals_.begin();
00627 }
00628
00629 inline
00630 artdaq::Fragment::const_iterator
00631 artdaq::Fragment::dataBegin() const
00632 {
00633 return vals_.begin() + detail::RawFragmentHeader::num_words() +
00634 fragmentHeader()->metadata_word_count;
00635 }
00636
00637 inline
00638 artdaq::Fragment::const_iterator
00639 artdaq::Fragment::dataEnd() const
00640 {
00641 return vals_.end();
00642 }
00643
00644 inline
00645 artdaq::Fragment::const_iterator
00646 artdaq::Fragment::headerBegin() const
00647 {
00648 return vals_.begin();
00649 }
00650
00651
00652 inline
00653 void
00654 artdaq::Fragment::clear()
00655 {
00656 vals_.erase(dataBegin(), dataEnd());
00657 updateFragmentHeaderWC_();
00658 }
00659
00660 inline
00661 bool
00662 artdaq::Fragment::empty()
00663 {
00664 return (vals_.size() - detail::RawFragmentHeader::num_words() -
00665 fragmentHeader()->metadata_word_count) == 0;
00666 }
00667
00668 inline
00669 void
00670 artdaq::Fragment::reserve(std::size_t cap)
00671 {
00672 vals_.reserve(cap + detail::RawFragmentHeader::num_words() +
00673 fragmentHeader()->metadata_word_count);
00674 }
00675
00676 inline
00677 void
00678 artdaq::Fragment::swap(Fragment & other)
00679 {
00680 vals_.swap(other.vals_);
00681 }
00682
00683 inline
00684 artdaq::RawDataType *
00685 artdaq::Fragment::dataAddress()
00686 {
00687 return &vals_[0] + detail::RawFragmentHeader::num_words() +
00688 fragmentHeader()->metadata_word_count;
00689 }
00690
00691 inline
00692 artdaq::RawDataType *
00693 artdaq::Fragment::metadataAddress()
00694 {
00695 if (fragmentHeader()->metadata_word_count == 0) {
00696 throw cet::exception("InvalidRequest")
00697 << "No metadata has been stored in this Fragment.";
00698 }
00699 return &vals_[0] + detail::RawFragmentHeader::num_words();
00700 }
00701
00702 inline
00703 artdaq::RawDataType *
00704 artdaq::Fragment::headerAddress()
00705 {
00706 return &vals_[0];
00707 }
00708
00709
00710 template <class InputIterator>
00711 artdaq::Fragment
00712 artdaq::Fragment::
00713 dataFrag(sequence_id_t sequenceID,
00714 fragment_id_t fragID,
00715 InputIterator i,
00716 InputIterator e)
00717 {
00718 Fragment result(sequenceID, fragID);
00719 result.vals_.reserve(std::distance(i, e) + detail::RawFragmentHeader::num_words());
00720 std::copy(i, e, std::back_inserter(result.vals_));
00721 return result;
00722 }
00723
00724 inline
00725 artdaq::detail::RawFragmentHeader *
00726 artdaq::Fragment::fragmentHeader()
00727 {
00728 return reinterpret_cast_checked<detail::RawFragmentHeader *>(&vals_[0]);
00729 }
00730
00731 inline
00732 artdaq::detail::RawFragmentHeader const *
00733 artdaq::Fragment::fragmentHeader() const
00734 {
00735 return reinterpret_cast_checked<detail::RawFragmentHeader const *>(&vals_[0]);
00736 }
00737
00738 inline
00739 void
00740 swap(artdaq::Fragment & x, artdaq::Fragment & y)
00741 {
00742 x.swap(y);
00743 }
00744
00745 inline
00746 std::ostream &
00747 artdaq::operator<<(std::ostream & os, artdaq::Fragment const & f)
00748 {
00749 f.print(os);
00750 return os;
00751 }
00752 #endif
00753
00754 #endif
00755