Mangrove
The C++ Object Document Mapper for MongoDB
bson_archiver.hpp
1 // Derived from https://github.com/USCiLab/cereal/blob/master/include/cereal/archives/json.hpp with
2 // the following license:
3 
4 // Copyright (c) 2014, Randolph Voorhies, Shane Grant
5 // All rights reserved.
6 
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of cereal nor the
15 // names of its contributors may be used to endorse or promote products
16 // derived from this software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 // Modifications licensed under:
29 
30 // Copyright 2016 MongoDB Inc.
31 //
32 // Licensed under the Apache License, Version 2.0 (the "License");
33 // you may not use this file except in compliance with the License.
34 // You may obtain a copy of the License at
35 //
36 // http://www.apache.org/licenses/LICENSE-2.0
37 //
38 // Unless required by applicable law or agreed to in writing, software
39 // distributed under the License is distributed on an "AS IS" BASIS,
40 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41 // See the License for the specific language governing permissions and
42 // limitations under the License.
43 
44 #pragma once
45 
46 #include <chrono>
47 #include <memory>
48 #include <sstream>
49 #include <stack>
50 #include <string>
51 #include <vector>
52 
53 #include <cereal/cereal.hpp>
54 
55 #include <bsoncxx/builder/core.hpp>
56 #include <bsoncxx/types.hpp>
57 #include <bsoncxx/types/value.hpp>
58 
59 #include <boson/stdx/optional.hpp>
60 
61 // Includes for officially supported STL containers
62 #include <cereal/types/deque.hpp>
63 #include <cereal/types/forward_list.hpp>
64 #include <cereal/types/list.hpp>
65 #include <cereal/types/set.hpp>
66 #include <cereal/types/unordered_set.hpp>
67 #include <cereal/types/valarray.hpp>
68 #include <cereal/types/vector.hpp>
69 
70 namespace boson {
71 
75 struct Exception : public std::runtime_error {
76  explicit Exception(const std::string& desc) : std::runtime_error(desc) {
77  }
78  explicit Exception(const char* desc) : std::runtime_error(desc) {
79  }
80 };
81 
91  public:
92  void setUnderlyingBSONData(std::shared_ptr<uint8_t> ptr, size_t size) {
93  _underlyingBSONData = ptr;
94  _underlyingBSONDataSize = size;
95  }
96 
97  const bsoncxx::document::view getUnderlyingBSONData() {
98  return bsoncxx::document::view{_underlyingBSONData.get(), _underlyingBSONDataSize};
99  }
100 
101  private:
102  std::shared_ptr<uint8_t> _underlyingBSONData;
103 
104  // TODO: This will be unecessary once we can read the size directly from the data
105  // in both big and little endian.
106  size_t _underlyingBSONDataSize;
107 };
108 
113 template <class BsonT>
114 struct is_bson {
115  static constexpr auto value = std::is_same<BsonT, bsoncxx::types::b_double>::value ||
116  std::is_same<BsonT, bsoncxx::types::b_utf8>::value ||
117  std::is_same<BsonT, bsoncxx::types::b_document>::value ||
118  std::is_same<BsonT, bsoncxx::types::b_array>::value ||
119  std::is_same<BsonT, bsoncxx::types::b_binary>::value ||
120  std::is_same<BsonT, bsoncxx::types::b_oid>::value ||
121  std::is_same<BsonT, bsoncxx::types::b_bool>::value ||
122  std::is_same<BsonT, bsoncxx::types::b_date>::value ||
123  std::is_same<BsonT, bsoncxx::types::b_int32>::value ||
124  std::is_same<BsonT, bsoncxx::types::b_int64>::value ||
125  std::is_same<BsonT, bsoncxx::oid>::value ||
126  std::is_same<BsonT, bsoncxx::types::b_undefined>::value ||
127  std::is_same<BsonT, bsoncxx::types::b_null>::value ||
128  std::is_same<BsonT, bsoncxx::types::b_regex>::value ||
129  std::is_same<BsonT, bsoncxx::types::b_code>::value ||
130  std::is_same<BsonT, bsoncxx::types::b_symbol>::value ||
131  std::is_same<BsonT, bsoncxx::types::b_codewscope>::value ||
132  std::is_same<BsonT, bsoncxx::types::b_timestamp>::value ||
133  std::is_same<BsonT, bsoncxx::types::b_minkey>::value ||
134  std::is_same<BsonT, bsoncxx::types::b_maxkey>::value ||
135  std::is_same<BsonT, bsoncxx::types::b_dbpointer>::value;
136 };
137 
142 template <class BsonT>
143 struct is_bson_view {
144  static constexpr auto value = std::is_same<BsonT, bsoncxx::types::b_utf8>::value ||
145  std::is_same<BsonT, bsoncxx::types::b_document>::value ||
146  std::is_same<BsonT, bsoncxx::types::b_array>::value ||
147  std::is_same<BsonT, bsoncxx::types::b_binary>::value ||
148  std::is_same<BsonT, bsoncxx::types::b_regex>::value ||
149  std::is_same<BsonT, bsoncxx::types::b_dbpointer>::value ||
150  std::is_same<BsonT, bsoncxx::types::b_code>::value ||
151  std::is_same<BsonT, bsoncxx::types::b_symbol>::value ||
152  std::is_same<BsonT, bsoncxx::types::b_codewscope>::value;
153 };
154 
155 class BSONOutputArchive : public cereal::OutputArchive<BSONOutputArchive> {
159  enum class OutputNodeType { StartObject, InObject, StartArray, InArray };
160 
161  using BSONBuilder = bsoncxx::builder::core;
162 
163  public:
182  BSONOutputArchive(std::ostream& stream, bool dotNotationMode = false)
183  : OutputArchive<BSONOutputArchive>{this},
184  _bsonBuilder{false},
185  _writeStream{stream},
186  _nextName{nullptr},
187  _objAsRootElement{false},
188  _dotNotationMode{dotNotationMode},
189  _arrayNestingLevel{0} {
190  }
191 
192  private:
197  void writeDoc() {
198  _writeStream.write(reinterpret_cast<const char*>(_bsonBuilder.view_document().data()),
199  _bsonBuilder.view_document().length());
200  _bsonBuilder.clear();
201  }
202 
203  public:
208  void writeDocIfRoot() {
209  if (_nodeTypeStack.empty()) {
210  writeDoc();
211  }
212  }
213 
221  void startNode(bool inheritsUnderlyingBSONDataBase) {
222  writeName(true);
223  _nodeTypeStack.push(OutputNodeType::StartObject);
224  _curNodeInheritsUnderlyingBSONDataBase.push(inheritsUnderlyingBSONDataBase);
225  }
226 
231  void finishNode() {
232  // Iff we ended up serializing an empty object or array, writeName
233  // will never have been called - therefore the node type at the top
234  // of the stack will be StartArray or StartObject - so start and
235  // then immediately end the documents/array.
236 
237  // We'll also end any documents/arrays we happen to be in.
238 
239  if (_nodeTypeStack.empty()) {
240  throw boson::Exception("Attempting to finish a nonexistent node.");
241  }
242 
243  switch (_nodeTypeStack.top()) {
244  case OutputNodeType::StartArray:
245  _bsonBuilder.open_array();
246  ++_arrayNestingLevel;
247  // Don't break so that this array can also be closed.
248  case OutputNodeType::InArray:
249  _bsonBuilder.close_array();
250  --_arrayNestingLevel;
251  break;
252  case OutputNodeType::StartObject:
253  // Only consider creating a new document if we're not in dot notation mode, or if we
254  // are within an array somewhere.
255  if (!_dotNotationMode || _arrayNestingLevel > 0) {
256  if (_nodeTypeStack.size() > 1 || _objAsRootElement) {
257  _bsonBuilder.open_document();
258  }
259  } else if (_nodeTypeStack.size() > 1) {
260  // Push back a dummy name so we don't accidentally pop an empty stack when
261  // closing this empty document.
262  _embeddedNameStack.push_back("");
263  }
264  // Don't break so that this document can also be closed.
265  case OutputNodeType::InObject:
266  // Only close the document if we are not in dot notation mode or if we are within an
267  // array somewhere.
268  if (!_dotNotationMode || _arrayNestingLevel > 0) {
269  if (_nodeTypeStack.size() > 1) {
270  _bsonBuilder.close_document();
271  } else if (_objAsRootElement) {
272  _bsonBuilder.close_document();
273  }
274  } else if (_nodeTypeStack.size() > 1) {
275  // Pop the name of this embedded document off the stack.
276  _embeddedNameStack.pop_back();
277  }
278  break;
279  }
280 
281  _nodeTypeStack.pop();
282  _curNodeInheritsUnderlyingBSONDataBase.pop();
283 
284  // Reset the _objAsRootElement tracker bool if the stack was emptied.
285  if (_nodeTypeStack.empty()) {
286  _objAsRootElement = false;
287  }
288  writeDocIfRoot();
289  }
290 
297  void setNextName(const char* name) {
298  _nextName = name;
299  }
300 
308  template <class T>
309  typename std::enable_if<!is_bson_view<typename std::decay<T>::type>::value>::type saveValue(
310  T&& t) {
311  _bsonBuilder.append(std::forward<T>(t));
312  }
313 
321  template <class T>
322  typename std::enable_if<is_bson_view<typename std::decay<T>::type>::value>::type saveValue(
323  T&& t) {
324  if (_curNodeInheritsUnderlyingBSONDataBase.empty() ||
325  !_curNodeInheritsUnderlyingBSONDataBase.top()) {
326  throw boson::Exception(
327  "Cannot serialize bsoncxx view type (b_utf8, b_document, b_array, b_binary) unless "
328  "that type is wrapped in a class that inherits UnderlyingBSONDataBase.");
329  }
330  _bsonBuilder.append(std::forward<T>(t));
331  }
332 
338  void saveValue(std::chrono::system_clock::time_point tp) {
339  _bsonBuilder.append(bsoncxx::types::b_date{tp});
340  }
341 
360  void writeName(bool isNewNode = false) {
361  if (!_nodeTypeStack.empty()) {
362  const auto& topType = _nodeTypeStack.top();
363 
364  // Start up either an object or an array, depending on state.
365  if (topType == OutputNodeType::StartArray) {
366  _bsonBuilder.open_array();
367  ++_arrayNestingLevel;
368  _nodeTypeStack.top() = OutputNodeType::InArray;
369  } else if (topType == OutputNodeType::StartObject) {
370  _nodeTypeStack.top() = OutputNodeType::InObject;
371  // Only open a document if this document is not in the root node or this is a root
372  // element.
373  if (_nodeTypeStack.size() > 1 || _objAsRootElement) {
374  if (_dotNotationMode && _arrayNestingLevel == 0) {
375  _embeddedNameStack.push_back(_nextPotentialNodeName);
376  } else {
377  _bsonBuilder.open_document();
378  }
379  }
380  }
381 
382  // Elements in arrays do not have names.
383  if (topType == OutputNodeType::InArray) return;
384  }
385 
386  if (!_nextName && _nodeTypeStack.empty() && isNewNode) {
387  // This is a document at the root node with no name.
388  // Do nothing since no name is expected for non root-element documents in root.
389  return;
390  } else if (!_nextName) {
391  // Enforce the existence of a name-value pair if this is not a node in root,
392  // or this in an element in root.
393  throw boson::Exception("Missing a name for current node or element.");
394  } else {
395  // Set the key of this element to the name stored by the archiver.
396  if (!_dotNotationMode || _embeddedNameStack.empty() || _arrayNestingLevel > 0) {
397  _bsonBuilder.key_view(_nextName);
398  } else {
399  // If we are in dot notation mode and we're not nested in array, build the name of
400  // this key.
401  std::stringstream key;
402  for (const auto& name : _embeddedNameStack) {
403  key << name << ".";
404  }
405  key << _nextName;
406  _bsonBuilder.key_owned(key.str());
407  }
408 
409  // Save the name of this key in case it is the name of an embedded document.
410  _nextPotentialNodeName = _nextName;
411 
412  // Reset the name of the next key.
413  _nextName = nullptr;
414 
415  // If this a named node in the root node, set up this node as a root element.
416  if (_nodeTypeStack.empty() && isNewNode) {
417  _objAsRootElement = true;
418  }
419  }
420  }
421 
426  void makeArray() {
427  _nodeTypeStack.top() = OutputNodeType::StartArray;
428  }
429 
430  private:
431  // The BSONCXX builder for this archive.
432  BSONBuilder _bsonBuilder;
433 
434  // The stream to which to write the BSON archive.
435  std::ostream& _writeStream;
436 
437  // The name of the next element to be added to the archive.
438  char const* _nextName;
439 
440  // The name of the last element added to the archive, which may potentially be the name of the
441  // next embedded document. This is stored to support dot notation mode.
442  char const* _nextPotentialNodeName;
443 
444  // A stack maintaining the state of the nodes currently being written.
445  std::stack<OutputNodeType> _nodeTypeStack;
446 
447  // Stack maintaining whether or not the node we're serializing inherits from the underlying BSON
448  // data base class required for classes that use bsoncxx view types.
449  std::stack<bool> _curNodeInheritsUnderlyingBSONDataBase;
450 
451  // A stack of names maintained in dot notation mode that keeps track of the names of the
452  // embedded documents we are nested in.
453  std::vector<std::string> _embeddedNameStack;
454 
455  // Boolean value that tracks whether or not the current root BSON document or array is being
456  // treated as a root element.
457  bool _objAsRootElement;
458 
459  // Bool tracking whether or not the resulting document will specify the values of embedded
460  // fields in dot notation so they can be used as an argument to $set in an update operation.
461  bool _dotNotationMode;
462 
463  // Byte-sized unsigned int that tracks how many arrays we are currently nested in. If this is
464  // equal to 0, we are not in an array and can write keys in dot notation.
465  uint8_t _arrayNestingLevel;
466 
467 }; // BSONOutputArchive
468 
469 class BSONInputArchive : public cereal::InputArchive<BSONInputArchive> {
470  enum class InputNodeType { InObject, InEmbeddedObject, InEmbeddedArray, InRootElement };
471 
472  public:
479  BSONInputArchive(std::istream& stream)
480  : InputArchive<BSONInputArchive>(this),
481  _nextName(nullptr),
482  _readStream(stream),
483  _readFirstDoc(false) {
484  }
485 
486  private:
491  void readNextDoc() {
492  // Determine the size of the BSON document in bytes.
493  // TODO: Only works on little endian.
494  int32_t docsize;
495  char docsize_buf[sizeof(docsize)];
496  _readStream.read(docsize_buf, sizeof(docsize));
497  std::memcpy(&docsize, docsize_buf, sizeof(docsize));
498 
499  // Throw an exception if the end of the stream is prematurely reached.
500  if (_readStream.eof() || !_readStream || docsize < 5) {
501  throw boson::Exception("No more data in BSONInputArchive stream.");
502  }
503 
504  // Create a shared buffer to store the BSON document.
505  _curBsonData =
506  std::shared_ptr<uint8_t>{new uint8_t[docsize], [](uint8_t* p) { delete[] p; }};
507 
508  // Read the BSON data from the stream into the buffer.
509  std::memcpy(_curBsonData.get(), docsize_buf, sizeof(docsize));
510  _readStream.read(reinterpret_cast<char*>(_curBsonData.get() + sizeof(docsize)),
511  docsize - sizeof(docsize));
512 
513  // Make sure there were no errors reading the BSON data.
514  if (_readStream.eof() || !_readStream) {
515  throw boson::Exception("No more data in BSONInputArchive stream.");
516  }
517 
518  // Store the BSON data of the document in a view that we can access.
519  _curBsonDoc = bsoncxx::document::view{_curBsonData.get(), static_cast<size_t>(docsize)};
520  _curBsonDataSize = docsize;
521 
522  // Specify that we've read a document.
523  _readFirstDoc = true;
524  }
525 
532  inline bsoncxx::types::value search() {
533  // If our search result is cached, return the cached result instead of repeating the search.
534  if (_cachedSearchResult) {
535  auto val = *_cachedSearchResult;
536  _cachedSearchResult = stdx::nullopt;
537  return val;
538  }
539 
540  // Make sure the node stack is not empty.
541  if (_nodeTypeStack.empty()) {
542  throw boson::Exception("Cannot search for element if not in node.");
543  }
544 
545  // Check to make sure a document has been read.
546  if (!_readFirstDoc) {
547  throw boson::Exception("Error in element search, never loaded BSON data from file.");
548  }
549 
550  if (_nextName) {
551  // Reset _nextName
552  const char* nextName = _nextName;
553  _nextName = nullptr;
554 
555  if (_nodeTypeStack.top() == InputNodeType::InObject ||
556  _nodeTypeStack.top() == InputNodeType::InRootElement) {
557  // If we're in an object in the Root (InObject),
558  // look for the key in the current BSON view.
559  const auto& elemFromDoc = _curBsonDoc[nextName];
560  if (elemFromDoc) {
561  return elemFromDoc.get_value();
562  }
563  } else if (_nodeTypeStack.top() == InputNodeType::InEmbeddedObject) {
564  // If we're in an embedded object, look for the key in the object
565  // at the top of the embedded object stack.
566  const auto& elemFromDoc = _embeddedBsonDocStack.top()[nextName];
567  if (elemFromDoc) {
568  return elemFromDoc.get_value();
569  }
570  }
571 
572  // Provide an exception with an error message if the key is not found.
573  std::stringstream error_msg;
574  error_msg << "No element found with the key ";
575  error_msg << nextName;
576  error_msg << ".";
577  throw boson::Exception(error_msg.str());
578 
579  } else if (_nodeTypeStack.top() == InputNodeType::InEmbeddedArray) {
580  // If we're in an array (InEmbeddedArray), retrieve an element from
581  // the array iterator at the top of the stack, and increment it for
582  // the next retrieval.
583  auto& iter = _embeddedBsonArrayIteratorStack.top();
584  const auto elemFromArr = *iter;
585  ++iter;
586 
587  if (elemFromArr) {
588  return elemFromArr.get_value();
589  }
590 
591  throw boson::Exception("Invalid element found in array, or array is out of bounds.");
592  }
593 
594  throw boson::Exception("Missing name for element search.");
595  }
596 
597  public:
609  // Make sure the node stack is not empty.
610  if (_nodeTypeStack.empty()) {
611  throw boson::Exception("Cannot search for element if not in node.");
612  }
613 
614  // Check to make sure a document has been read.
615  if (!_readFirstDoc) {
616  throw boson::Exception("Error in element search, never loaded BSON data from file.");
617  }
618 
619  if (_nodeTypeStack.top() == InputNodeType::InEmbeddedArray) {
620  throw cereal::Exception(
621  "Should not be checking if search() will yield next value from an embedded array.");
622  }
623 
624  if (_nextName) {
625  const char* nextName = _nextName;
626  _nextName = nullptr;
627 
628  bsoncxx::document::element val{};
629 
630  if (_nodeTypeStack.top() == InputNodeType::InObject ||
631  _nodeTypeStack.top() == InputNodeType::InRootElement) {
632  val = _curBsonDoc[nextName];
633 
634  } else {
635  val = _embeddedBsonDocStack.top()[nextName];
636  }
637 
638  if (val) {
639  _cachedSearchResult = val.get_value();
640  return true;
641  }
642  }
643 
644  _cachedSearchResult = stdx::nullopt;
645  return false;
646  }
647 
654  if (_nodeTypeStack.empty()) {
655  readNextDoc();
656  _nodeTypeStack.push(InputNodeType::InRootElement);
657  return true;
658  }
659  return false;
660  }
661 
667  if (!_nodeTypeStack.empty() && _nodeTypeStack.top() == InputNodeType::InRootElement) {
668  _nodeTypeStack.pop();
669  }
670  }
671 
676  void startNode() {
677  if (_nodeTypeStack.empty()) {
678  // If we are in the root node, read in the next document from the stream,
679  // and update the state of the node we're currently in.
680  readNextDoc();
681 
682  // If there is a name, the new node is loading a BSON document or array as a root
683  // element.
684  if (_nextName) {
685  _nodeTypeStack.push(InputNodeType::InRootElement);
686  auto newNode = search();
687 
688  if (newNode.type() == bsoncxx::type::k_array) {
689  _embeddedBsonArrayStack.push(newNode.get_array().value);
690  _embeddedBsonArrayIteratorStack.push(_embeddedBsonArrayStack.top().begin());
691  _nodeTypeStack.push(InputNodeType::InEmbeddedArray);
692  } else if (newNode.type() == bsoncxx::type::k_document) {
693  _embeddedBsonDocStack.push(newNode.get_document().value);
694  _nodeTypeStack.push(InputNodeType::InEmbeddedObject);
695  } else {
696  throw boson::Exception("Node requested is neither document nor array.");
697  }
698  } else {
699  _nodeTypeStack.push(InputNodeType::InObject);
700  }
701  } else {
702  // If we're not in the root node, match the next key to an embedded document
703  // or array.
704  // From the BSON document we're currently in, fetch the value associated
705  // with this node and update the relevant stacks.
706  auto newNode = search();
707 
708  if (newNode.type() == bsoncxx::type::k_document) {
709  _embeddedBsonDocStack.push(newNode.get_document().value);
710  _nodeTypeStack.push(InputNodeType::InEmbeddedObject);
711  } else if (newNode.type() == bsoncxx::type::k_array) {
712  _embeddedBsonArrayStack.push(newNode.get_array().value);
713  _embeddedBsonArrayIteratorStack.push(_embeddedBsonArrayStack.top().begin());
714  _nodeTypeStack.push(InputNodeType::InEmbeddedArray);
715  } else {
716  throw boson::Exception("Node requested is neither document nor array.");
717  }
718  }
719  }
720 
725  void finishNode() {
726  // If we're in an embedded object or array, pop it from its respective
727  // stack(s).
728  if (_nodeTypeStack.top() == InputNodeType::InEmbeddedObject) {
729  _embeddedBsonDocStack.pop();
730  } else if (_nodeTypeStack.top() == InputNodeType::InEmbeddedArray) {
731  _embeddedBsonArrayStack.pop();
732  _embeddedBsonArrayIteratorStack.pop();
733  }
734 
735  // Pop the node type from the stack.
736  _nodeTypeStack.pop();
737 
738  if (!_nodeTypeStack.empty() && _nodeTypeStack.top() == InputNodeType::InRootElement) {
739  _nodeTypeStack.pop();
740  }
741  }
742 
749  void setNextName(const char* name) {
750  _nextName = name;
751  }
752 
753  private:
757  inline void assert_type(const bsoncxx::types::value& v, bsoncxx::type t) {
758  if (v.type() != t) {
759  throw boson::Exception("Type mismatch when loading values.");
760  }
761  }
762 
763  public:
770 #define BOSON_BSON_LOAD_VALUE_FUNC(btype) \
771  void loadValue(bsoncxx::types::b_##btype& val) { \
772  auto bsonVal = search(); \
773  assert_type(bsonVal, bsoncxx::type::k_##btype); \
774  val = bsonVal.get_##btype(); \
775  }
776 
777  // Invokes the macro for all non-deprecated, non-internal
778  // BSON types supported by bsoncxx
779  BOSON_BSON_LOAD_VALUE_FUNC(double)
780  BOSON_BSON_LOAD_VALUE_FUNC(utf8)
781  BOSON_BSON_LOAD_VALUE_FUNC(document)
782  BOSON_BSON_LOAD_VALUE_FUNC(array)
783  BOSON_BSON_LOAD_VALUE_FUNC(binary)
784  BOSON_BSON_LOAD_VALUE_FUNC(oid)
785  BOSON_BSON_LOAD_VALUE_FUNC(bool)
786  BOSON_BSON_LOAD_VALUE_FUNC(date)
787  BOSON_BSON_LOAD_VALUE_FUNC(int32)
788  BOSON_BSON_LOAD_VALUE_FUNC(int64)
789  BOSON_BSON_LOAD_VALUE_FUNC(undefined)
790  BOSON_BSON_LOAD_VALUE_FUNC(null)
791  BOSON_BSON_LOAD_VALUE_FUNC(regex)
792  BOSON_BSON_LOAD_VALUE_FUNC(code)
793  BOSON_BSON_LOAD_VALUE_FUNC(symbol)
794  BOSON_BSON_LOAD_VALUE_FUNC(codewscope)
795  BOSON_BSON_LOAD_VALUE_FUNC(timestamp)
796  BOSON_BSON_LOAD_VALUE_FUNC(minkey)
797  BOSON_BSON_LOAD_VALUE_FUNC(maxkey)
798  BOSON_BSON_LOAD_VALUE_FUNC(dbpointer)
799 
800 #undef BOSON_BSON_LOAD_VALUE_FUNC
801 
808 #define BOSON_NON_BSON_LOAD_VALUE_FUNC(cxxtype, btype) \
809  void loadValue(cxxtype& val) { \
810  auto bsonVal = search(); \
811  assert_type(bsonVal, bsoncxx::type::k_##btype); \
812  val = bsonVal.get_##btype().value; \
813  }
814 
815  BOSON_NON_BSON_LOAD_VALUE_FUNC(bsoncxx::oid, oid)
816  BOSON_NON_BSON_LOAD_VALUE_FUNC(bool, bool)
817  BOSON_NON_BSON_LOAD_VALUE_FUNC(std::int32_t, int32)
818  BOSON_NON_BSON_LOAD_VALUE_FUNC(std::int64_t, int64)
819  BOSON_NON_BSON_LOAD_VALUE_FUNC(double, double)
820 
821 #undef BOSON_NON_BSON_LOAD_VALUE_FUNC
822 
830  void loadValue(std::chrono::system_clock::time_point& val) {
831  auto bsonVal = search();
832  assert_type(bsonVal, bsoncxx::type::k_date);
833  val = std::chrono::system_clock::time_point(
834  std::chrono::milliseconds{bsonVal.get_date().value});
835  }
836 
843  void loadValue(std::string& val) {
844  auto bsonVal = search();
845  assert_type(bsonVal, bsoncxx::type::k_utf8);
846  val = bsonVal.get_utf8().value.to_string();
847  }
848 
857  void loadSize(cereal::size_type& size) {
858  if (!_nodeTypeStack.empty() && _nodeTypeStack.top() != InputNodeType::InEmbeddedArray) {
859  throw boson::Exception("Requesting a size tag when not in an array.");
860  }
861  size = std::distance(_embeddedBsonArrayStack.top().begin(),
862  _embeddedBsonArrayStack.top().end());
863  }
864 
870  if (_nodeTypeStack.empty()) {
871  throw boson::Exception("Cannot get data; not currently in a node.");
872  }
873 
874  switch (_nodeTypeStack.top()) {
875  case InputNodeType::InObject:
876  case InputNodeType::InRootElement:
877  underlyingData.setUnderlyingBSONData(std::shared_ptr<uint8_t>(_curBsonData),
878  _curBsonDataSize);
879  return;
880  case InputNodeType::InEmbeddedObject:
881  // Use the aliasing constructor of shared_ptr to build a reference pointing to the
882  // embedded document while reference counting the BSON doc as a whole.
883  underlyingData.setUnderlyingBSONData(
884  std::shared_ptr<uint8_t>(
885  _curBsonData, const_cast<uint8_t*>(_embeddedBsonDocStack.top().data())),
886  _embeddedBsonDocStack.top().length());
887  return;
888  case InputNodeType::InEmbeddedArray:
889  throw boson::Exception(
890  "Underlying BSON data does not support array views. Wrap the b_array, or your "
891  "container holding other bsoncxx view types in a class that inherits "
892  "boson::UnderlyingBSONDataBase");
893  return;
894  }
895  }
896 
897  private:
898  // The key name of the next element being searched.
899  const char* _nextName;
900 
901  // The stream of BSON being read.
902  std::istream& _readStream;
903 
904  // Bool that tracks whether or not a document has been read from the stream.
905  bool _readFirstDoc;
906 
907  // Cache for the next search result if willSearchYieldValue() returns true.
908  stdx::optional<bsoncxx::types::value> _cachedSearchResult;
909 
910  // The current root BSON document being viewed.
911  std::shared_ptr<uint8_t> _curBsonData;
912  size_t _curBsonDataSize;
913  bsoncxx::document::view _curBsonDoc;
914 
915  // Stack maintaining views of embedded BSON documents.
916  std::stack<bsoncxx::document::view> _embeddedBsonDocStack;
917 
918  // Stacks maintaining views of embedded BSON arrays, as well as their
919  // iterators.
920  std::stack<bsoncxx::array::view> _embeddedBsonArrayStack;
921  std::stack<bsoncxx::array::view::iterator> _embeddedBsonArrayIteratorStack;
922 
923  // A stack maintaining the state of the node currently being worked on.
924  std::stack<InputNodeType> _nodeTypeStack;
925 
926 }; // BSONInputArchive
927 
928 // ######################################################################
929 // BSONArchive prologue and epilogue functions
930 // ######################################################################
931 
932 // ######################################################################
933 // Prologue for NVPs for BSON output archives
934 // NVPs do not start or finish nodes - they just set up the names
935 template <class T>
936 inline void prologue(BSONOutputArchive&, cereal::NameValuePair<T> const&) {
937 }
938 
939 // Prologue for NVPs for BSON input archives
940 template <class T>
941 inline void prologue(BSONInputArchive&, cereal::NameValuePair<T> const&) {
942 }
943 
944 // ######################################################################
945 // Epilogue for NVPs for BSON output archives
946 // NVPs do not start or finish nodes - they just set up the names
947 template <class T>
948 inline void epilogue(BSONOutputArchive&, cereal::NameValuePair<T> const&) {
949 }
950 
951 // Epilogue for NVPs for BSON input archives
952 // NVPs do not start or finish nodes - they just set up the names
953 template <class T>
954 inline void epilogue(BSONInputArchive&, cereal::NameValuePair<T> const&) {
955 }
956 
957 // ######################################################################
958 // Prologue for stdx::optionals for BSON output archives
959 // stdx::optionals do not start or finish nodes - they just set up the names
960 template <class T>
961 inline void prologue(BSONOutputArchive&, stdx::optional<T> const&) {
962 }
963 
964 // Prologue for stdx::optionals for BSON input archives
965 template <class T>
966 inline void prologue(BSONInputArchive&, stdx::optional<T> const&) {
967 }
968 
969 // ######################################################################
970 // Epilogue for stdx::optionals for BSON output archives
971 // stdx::optionals do not start or finish nodes - they just set up the names
972 template <class T>
973 inline void epilogue(BSONOutputArchive&, stdx::optional<T> const&) {
974 }
975 
976 // Epilogue for stdx::optionals for BSON input archives
977 // stdx::optionals do not start or finish nodes - they just set up the names
978 template <class T>
979 inline void epilogue(BSONInputArchive&, stdx::optional<T> const&) {
980 }
981 
982 // ######################################################################
983 // Prologue for SizeTags for BSON output archives
984 // SizeTags are strictly ignored for BSON, they just indicate
985 // that the current node should be made into an array
986 template <class T>
987 inline void prologue(BSONOutputArchive& ar, cereal::SizeTag<T> const&) {
988  ar.makeArray();
989 }
990 
991 // Prologue for SizeTags for BSON input archives
992 template <class T>
993 inline void prologue(BSONInputArchive&, cereal::SizeTag<T> const&) {
994 }
995 
996 // ######################################################################
997 // Epilogue for SizeTags for BSON output archives
998 // SizeTags are strictly ignored for BSON
999 template <class T>
1000 inline void epilogue(BSONOutputArchive&, cereal::SizeTag<T> const&) {
1001 }
1002 
1003 // Epilogue for SizeTags for BSON input archives
1004 template <class T>
1005 inline void epilogue(BSONInputArchive&, cereal::SizeTag<T> const&) {
1006 }
1007 
1008 // ######################################################################
1009 // Prologue and Epilogue for BSON types, which should not be confused
1010 // as objects or arrays
1011 
1012 template <class BsonT, cereal::traits::EnableIf<
1014  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1015  cereal::traits::sfinae>
1016 inline void prologue(BSONOutputArchive& ar, BsonT const&) {
1017  ar.writeName();
1018 }
1019 
1020 template <class BsonT, cereal::traits::EnableIf<
1022  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1023  cereal::traits::sfinae>
1024 inline void epilogue(BSONOutputArchive& ar, BsonT const&) {
1025  ar.writeDocIfRoot();
1026 }
1027 
1028 template <class BsonT, cereal::traits::EnableIf<
1030  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1031  cereal::traits::sfinae>
1032 inline void prologue(BSONInputArchive& ar, BsonT const&) {
1033  if (ar.startRootElementIfRoot()) {
1035  throw boson::Exception(
1036  "Cannot deserialize a BSON view type into a root element. The BSON view type must "
1037  "be wrapped in a class that inherits boson::UnderlyingBSONDataBase");
1038  }
1039  }
1040 }
1041 
1042 template <class BsonT, cereal::traits::EnableIf<
1044  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1045  cereal::traits::sfinae>
1046 inline void epilogue(BSONInputArchive& ar, BsonT const&) {
1048 }
1049 
1050 // ######################################################################
1051 // Prologue for all other types for BSON output archives (except minimal types)
1052 // Starts a new node, named either automatically or by some NVP,
1053 // that may be given data by the type about to be archived
1054 // Minimal types do not start or finish nodes.
1055 
1056 // Prologue for all types which inherit from UnderlyingBSONDataBase for BSON output archives.
1057 template <class T, cereal::traits::EnableIf<std::is_base_of<UnderlyingBSONDataBase, T>::value> =
1058  cereal::traits::sfinae>
1059 inline void prologue(BSONOutputArchive& ar, T const&) {
1060  ar.startNode(true);
1061 }
1062 
1063 template <class T,
1064  cereal::traits::DisableIf<
1065  std::is_arithmetic<T>::value ||
1066  cereal::traits::has_minimal_base_class_serialization<
1067  T, cereal::traits::has_minimal_output_serialization, BSONOutputArchive>::value ||
1068  cereal::traits::has_minimal_output_serialization<T, BSONOutputArchive>::value ||
1069  is_bson<T>::value || std::is_same<T, std::chrono::system_clock::time_point>::value ||
1070  std::is_base_of<UnderlyingBSONDataBase, T>::value> = cereal::traits::sfinae>
1071 inline void prologue(BSONOutputArchive& ar, T const&) {
1072  ar.startNode(false);
1073 }
1074 
1075 // Prologue for all types which inherit from UnderlyingBSONDataBase for BSON input archives.
1076 template <class T, cereal::traits::EnableIf<std::is_base_of<UnderlyingBSONDataBase, T>::value> =
1077  cereal::traits::sfinae>
1078 inline void prologue(BSONInputArchive& ar, T& obj) {
1079  ar.startNode();
1081 }
1082 
1083 // Prologue for all other types for BSON input archives.
1084 template <class T,
1085  cereal::traits::DisableIf<
1086  std::is_arithmetic<T>::value ||
1087  cereal::traits::has_minimal_base_class_serialization<
1088  T, cereal::traits::has_minimal_input_serialization, BSONInputArchive>::value ||
1089  cereal::traits::has_minimal_input_serialization<T, BSONInputArchive>::value ||
1090  is_bson<T>::value || std::is_same<T, std::chrono::system_clock::time_point>::value ||
1091  std::is_base_of<UnderlyingBSONDataBase, T>::value> = cereal::traits::sfinae>
1092 inline void prologue(BSONInputArchive& ar, T const&) {
1093  ar.startNode();
1094 }
1095 
1096 // ######################################################################
1097 // Epilogue for all other types other for BSON output archives (except minimal
1098 // types
1099 // Finishes the node created in the prologue
1100 
1101 // Minimal types do not start or finish nodes
1102 template <class T,
1103  cereal::traits::DisableIf<
1104  std::is_arithmetic<T>::value ||
1105  cereal::traits::has_minimal_base_class_serialization<
1106  T, cereal::traits::has_minimal_output_serialization, BSONOutputArchive>::value ||
1107  cereal::traits::has_minimal_output_serialization<T, BSONOutputArchive>::value ||
1108  is_bson<T>::value || std::is_same<T, std::chrono::system_clock::time_point>::value> =
1109  cereal::traits::sfinae>
1110 inline void epilogue(BSONOutputArchive& ar, T const&) {
1111  ar.finishNode();
1112 }
1113 
1114 // Epilogue for all other types other for BSON input archives
1115 template <class T,
1116  cereal::traits::DisableIf<
1117  std::is_arithmetic<T>::value ||
1118  cereal::traits::has_minimal_base_class_serialization<
1119  T, cereal::traits::has_minimal_input_serialization, BSONInputArchive>::value ||
1120  cereal::traits::has_minimal_input_serialization<T, BSONInputArchive>::value ||
1121  is_bson<T>::value || std::is_same<T, std::chrono::system_clock::time_point>::value> =
1122  cereal::traits::sfinae>
1123 inline void epilogue(BSONInputArchive& ar, T const&) {
1124  ar.finishNode();
1125 }
1126 
1127 // ######################################################################
1128 // Prologue for arithmetic types for BSON output archives
1129 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1130 inline void prologue(BSONOutputArchive& ar, T const&) {
1131  ar.writeName();
1132 }
1133 
1134 // Prologue for arithmetic types for BSON input archives
1135 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1136 inline void prologue(BSONInputArchive& ar, T const&) {
1138 }
1139 
1140 // ######################################################################
1141 // Epilogue for arithmetic types for BSON output archives
1142 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1143 inline void epilogue(BSONOutputArchive& ar, T const&) {
1144  ar.writeDocIfRoot();
1145 }
1146 
1147 // Epilogue for arithmetic types for BSON input archives
1148 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1149 inline void epilogue(BSONInputArchive& ar, T const&) {
1151 }
1152 
1153 // ######################################################################
1154 // Prologue for strings for BSON output archives
1155 template <class CharT, class Traits, class Alloc>
1156 inline void prologue(BSONOutputArchive& ar, std::basic_string<CharT, Traits, Alloc> const&) {
1157  ar.writeName();
1158 }
1159 
1160 // Prologue for strings for BSON input archives
1161 template <class CharT, class Traits, class Alloc>
1162 inline void prologue(BSONInputArchive& ar, std::basic_string<CharT, Traits, Alloc> const&) {
1164 }
1165 
1166 // ######################################################################
1167 // Epilogue for strings for BSON output archives
1168 template <class CharT, class Traits, class Alloc>
1169 inline void epilogue(BSONOutputArchive& ar, std::basic_string<CharT, Traits, Alloc> const&) {
1170  ar.writeDocIfRoot();
1171 }
1172 
1173 // Epilogue for strings for BSON output archives
1174 template <class CharT, class Traits, class Alloc>
1175 inline void epilogue(BSONInputArchive& ar, std::basic_string<CharT, Traits, Alloc> const&) {
1177 }
1178 
1179 // ######################################################################
1180 // Common BSONArchive serialization functions
1181 // ######################################################################
1182 // Serializing NVP types to BSON
1183 template <class T>
1184 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive& ar, cereal::NameValuePair<T> const& t) {
1185  ar.setNextName(t.name);
1186  ar(t.value);
1187 }
1188 
1189 // Loading NVP types from BSON
1190 template <class T>
1191 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar, cereal::NameValuePair<T>& t) {
1192  ar.setNextName(t.name);
1193  ar(t.value);
1194 }
1195 
1196 // Serializing stdx::optional types to BSON
1197 template <class T>
1198 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive& ar, stdx::optional<T> const& t) {
1199  // Only serialize the value if it is present. Otherwise do nothing.
1200  if (t) {
1201  ar(*t);
1202  }
1203 }
1204 
1205 // Loading stdx::optional types from BSON
1206 //
1207 // Note that if a key for an optional is not present in the BSON from which we are loading values,
1208 // the BSONInputArchive will overwrite what was in the destination stdx::optional with a
1209 // stdx::nullopt, even if there was already a value.
1210 //
1211 template <class T,
1212  cereal::traits::DisableIf<is_bson<T>::value && !std::is_default_constructible<T>::value> =
1213  cereal::traits::sfinae>
1214 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar, stdx::optional<T>& t) {
1215  if (ar.willSearchYieldValue()) {
1216  T value;
1217  ar(value);
1218  t.emplace(value);
1219  } else {
1220  t = stdx::nullopt;
1221  }
1222 }
1223 
1224 // Overloads for the stdx::optional types wrapping non-default-constructible BSON b_ types.
1225 // TODO: Once CXX-966 is resolved (making all BSON b_ types default constructible) these overloads
1226 // will no longer be necessary.
1227 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1228  stdx::optional<bsoncxx::types::b_utf8>& t) {
1229  if (ar.willSearchYieldValue()) {
1230  bsoncxx::types::b_utf8 value{""};
1231  ar(value);
1232  t.emplace(value);
1233  } else {
1234  t = stdx::nullopt;
1235  }
1236 }
1237 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1238  stdx::optional<bsoncxx::types::b_date>& t) {
1239  if (ar.willSearchYieldValue()) {
1240  bsoncxx::types::b_date value{std::chrono::system_clock::time_point{}};
1241  ar(value);
1242  t.emplace(value);
1243  } else {
1244  t = stdx::nullopt;
1245  }
1246 }
1247 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1248  stdx::optional<bsoncxx::types::b_regex>& t) {
1249  if (ar.willSearchYieldValue()) {
1250  bsoncxx::types::b_regex value{"", ""};
1251  ar(value);
1252  t.emplace(value);
1253  } else {
1254  t = stdx::nullopt;
1255  }
1256 }
1257 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1258  stdx::optional<bsoncxx::types::b_code>& t) {
1259  if (ar.willSearchYieldValue()) {
1260  bsoncxx::types::b_code value{""};
1261  ar(value);
1262  t.emplace(value);
1263  } else {
1264  t = stdx::nullopt;
1265  }
1266 }
1267 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1268  stdx::optional<bsoncxx::types::b_codewscope>& t) {
1269  if (ar.willSearchYieldValue()) {
1270  bsoncxx::types::b_codewscope value{"", bsoncxx::document::view()};
1271  ar(value);
1272  t.emplace(value);
1273  } else {
1274  t = stdx::nullopt;
1275  }
1276 }
1277 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1278  stdx::optional<bsoncxx::types::b_symbol>& t) {
1279  if (ar.willSearchYieldValue()) {
1280  bsoncxx::types::b_symbol value{""};
1281  ar(value);
1282  t.emplace(value);
1283  } else {
1284  t = stdx::nullopt;
1285  }
1286 }
1287 
1288 // Saving for arithmetic to BSON
1289 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1290 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive& ar, T const& t) {
1291  ar.saveValue(t);
1292 }
1293 
1294 // Loading arithmetic from BSON
1295 template <class T, cereal::traits::EnableIf<std::is_arithmetic<T>::value> = cereal::traits::sfinae>
1296 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar, T& t) {
1297  ar.loadValue(t);
1298 }
1299 
1300 // saving string to BSON
1301 template <class CharT, class Traits, class Alloc>
1302 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive& ar,
1303  std::basic_string<CharT, Traits, Alloc> const& str) {
1304  ar.saveValue(str);
1305 }
1306 
1307 // loading string from BSON
1308 template <class CharT, class Traits, class Alloc>
1309 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar,
1310  std::basic_string<CharT, Traits, Alloc>& str) {
1311  ar.loadValue(str);
1312 }
1313 
1314 // ######################################################################
1315 // Saving SizeTags to BSON
1316 template <class T>
1317 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive&, cereal::SizeTag<T> const&) {
1318  // Nothing to do here, we don't explicitly save the size.
1319 }
1320 
1321 // Loading SizeTags from BSON
1322 template <class T>
1323 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar, cereal::SizeTag<T>& st) {
1324  ar.loadSize(st.size);
1325 }
1326 
1327 // ######################################################################
1328 // Saving BSON types to BSON
1329 template <class BsonT, cereal::traits::EnableIf<
1331  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1332  cereal::traits::sfinae>
1333 inline void CEREAL_SAVE_FUNCTION_NAME(BSONOutputArchive& ar, BsonT const& bsonVal) {
1334  ar.saveValue(bsonVal);
1335 }
1336 
1337 // Loading BSON types from BSON
1338 template <class BsonT, cereal::traits::EnableIf<
1340  std::is_same<BsonT, std::chrono::system_clock::time_point>::value> =
1341  cereal::traits::sfinae>
1342 inline void CEREAL_LOAD_FUNCTION_NAME(BSONInputArchive& ar, BsonT& bsonVal) {
1343  ar.loadValue(bsonVal);
1344 }
1345 
1346 } // namespace boson
1347 
1348 // Register archives for polymorphic support.
1349 CEREAL_REGISTER_ARCHIVE(boson::BSONInputArchive)
1350 CEREAL_REGISTER_ARCHIVE(boson::BSONOutputArchive)
1351 
1352 // Tie input and output archives together.
1353 CEREAL_SETUP_ARCHIVE_TRAITS(boson::BSONInputArchive, boson::BSONOutputArchive)
void loadUnderlyingDataForCurrentNode(UnderlyingBSONDataBase &underlyingData)
Returns a shared pointer to the underlying data of the current node, loading the size in bytes in a s...
Definition: bson_archiver.hpp:869
A templated struct containing a bool value that specifies whether the provided template parameter is ...
Definition: bson_archiver.hpp:114
An exception class thrown when things go wrong at runtime.
Definition: bson_archiver.hpp:75
bool startRootElementIfRoot()
Pushes a root element on the node stack if we&#39;re in root.
Definition: bson_archiver.hpp:653
void finishRootElementIfRootElement()
Pops the node stack and iterates to the next BSON view if the top of the stack specifies that we are ...
Definition: bson_archiver.hpp:666
Definition: bson_archiver.hpp:469
A base class that holds a shared_ptr to the binary data for a BSON document.
Definition: bson_archiver.hpp:90
void loadSize(cereal::size_type &size)
Loads the size for a SizeTag, which is used by Cereal to determine how many elements to put into a co...
Definition: bson_archiver.hpp:857
BSONInputArchive(std::istream &stream)
Construct a BSONInputArchive from an input stream of BSON data.
Definition: bson_archiver.hpp:479
bool willSearchYieldValue()
Checks if the next invocation of search() will yield a value.
Definition: bson_archiver.hpp:608
BSONOutputArchive(std::ostream &stream, bool dotNotationMode=false)
Construct a BSONOutputArchive that will output serialized classes as BSON to the provided stream...
Definition: bson_archiver.hpp:182
A templated struct containing a bool value that specifies whether the provided template parameter is ...
Definition: bson_archiver.hpp:143
Definition: bson_archiver.hpp:70
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: bson_archiver.hpp:749
void finishNode()
Finishes the most recently started node by popping relevant stacks and, if necessary, iterating to the next root BSON document.
Definition: bson_archiver.hpp:725
void loadValue(std::chrono::system_clock::time_point &val)
Loads a BSON datetime from the current node and puts it into a std::chrono::system_clock::time_point...
Definition: bson_archiver.hpp:830
void loadValue(std::string &val)
Loads a BSON UTF-8 value from the current node and puts it into a std::string.
Definition: bson_archiver.hpp:843
void startNode()
Starts a new node, and update the stacks so that we fetch the correct data when calling search()...
Definition: bson_archiver.hpp:676
Definition: bson_archiver.hpp:155