View on GitHub
jbson
C++11/1y BSON library
element.hpp
1 // Copyright Christian Manning 2013.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef JBSON_ELEMENT_HPP
7 #define JBSON_ELEMENT_HPP
8 
9 #include <string>
10 #include <vector>
11 
12 #include "detail/config.hpp"
13 
14 JBSON_PUSH_DISABLE_DOCUMENTATION_WARNING
15 #include <boost/range/algorithm.hpp>
16 #include <boost/range/algorithm_ext.hpp>
17 #include <boost/utility/string_ref.hpp>
18 #include <boost/mpl/or.hpp>
19 JBSON_CLANG_POP_WARNINGS
20 
21 #include "element_fwd.hpp"
22 #include "document_fwd.hpp"
23 #include "detail/error.hpp"
24 #include "detail/get.hpp"
25 #include "detail/set.hpp"
26 #include "detail/traits.hpp"
27 #include "detail/visit.hpp"
28 
29 JBSON_PUSH_DISABLE_DEPRECATED_WARNING
30 
31 namespace jbson {
32 namespace detail {
33 
35 template <element_type EType, typename Element, typename Enable = void> struct typeid_visitor;
36 
37 #ifndef DOXYGEN_SHOULD_SKIP_THIS
38 template <element_type EType, typename Element>
39 struct typeid_visitor<EType, Element, std::enable_if_t<is_element<std::decay_t<Element>>::value>> {
41  template <typename... Args> std::type_index operator()(Args&&...) const {
43  }
44 };
45 
46 template <element_type EType, typename Element>
47 struct typeid_visitor<EType, Element, std::enable_if_t<!is_element<std::decay_t<Element>>::value>> {
49  template <typename... Args> std::type_index operator()(Args&&...) const {
50  return typeid(ElementTypeMap<EType, std::decay_t<Element>>);
51  }
52 };
53 #endif // DOXYGEN_SHOULD_SKIP_THIS
54 
55 } // namespace detail
56 
69 template <class Container> struct basic_element {
71  using container_type = std::decay_t<Container>;
72  static_assert(!std::is_convertible<container_type, std::string>::value,
73  "container_type must not be a string type (or convertible)");
74  static_assert(std::is_same<typename container_type::value_type, char>::value,
75  "container_type's value_type must be char");
76  static_assert(detail::is_nothrow_swappable<container_type>::value, "container_type must have noexcept swap()");
77 
83  basic_element() = default;
84 
86  template <typename OtherContainer>
88  std::enable_if_t<std::is_constructible<container_type, OtherContainer>::value>* = nullptr);
89 
91  template <typename OtherContainer>
93  std::enable_if_t<!std::is_constructible<container_type, OtherContainer>::value>* = nullptr,
94  std::enable_if_t<std::is_constructible<container_type, typename OtherContainer::const_iterator,
95  typename OtherContainer::const_iterator>::value>* = nullptr);
96 
98  template <typename OtherContainer>
100  std::enable_if_t<std::is_constructible<container_type, OtherContainer&&>::value>* = nullptr);
101 
103  template <typename ForwardRange>
104  explicit basic_element(
105  ForwardRange&&, std::enable_if_t<!std::is_constructible<std::string, ForwardRange>::value>* = nullptr,
107  nullptr);
108 
110 
117  template <typename ForwardIterator>
118  basic_element(ForwardIterator&& first, ForwardIterator&& last,
119  std::enable_if_t<
120  !std::is_constructible<boost::string_ref, ForwardIterator>::value ||
121  std::is_convertible<ForwardIterator, typename container_type::const_iterator>::value>* = nullptr,
122  std::enable_if_t<detail::is_range_of_same_value<decltype(boost::make_iterator_range(first, last)),
123  typename Container::value_type>::value>* = nullptr)
124  : basic_element(boost::make_iterator_range(first, last)) {}
125 
132  template <typename T> basic_element(std::string name, element_type type, T&& val) : basic_element(std::move(name)) {
133  value(type, std::forward<T>(val));
134  }
135 
137  template <typename ForwardIterator> basic_element(std::string, element_type, ForwardIterator, ForwardIterator);
138 
140  explicit basic_element(std::string, element_type = element_type::null_element);
141 
151  template <typename T> basic_element(std::string name, T&& val) : basic_element(std::move(name)) {
152  value(std::forward<T>(val));
153  }
154 
160  boost::string_ref name() const
161  noexcept(std::is_nothrow_constructible<boost::string_ref, const std::string&>::value) {
162  return m_name;
163  }
164 
170  void name(std::string n) { m_name.swap(n); }
171 
173  size_t size() const noexcept;
174 
176  element_type type() const noexcept { return m_type; }
177 
188  void type(element_type new_type) {
189  if(!detail::valid_type(new_type))
190  BOOST_THROW_EXCEPTION(invalid_element_type{});
191  m_type = new_type;
192  }
193 
205  template <typename T>
206  std::enable_if_t<detail::is_valid_element_value_type<container_type, T>::value, T> value() const {
207  static_assert(!std::is_void<T>::value, "Cannot assign value to void.");
208  static_assert(std::is_default_constructible<T>::value, "Return type must be default constructible.");
209 
210  if(!valid_type<T>(type()))
211  BOOST_THROW_EXCEPTION(incompatible_type_conversion{}
212  << detail::actual_type(typeid(T))
213  << detail::expected_type(detail::visit<detail::typeid_visitor>(type(), *this)));
214 
215  namespace mpl = boost::mpl;
216  using element_pair = typename mpl::deref<
217  detail::find_if_second<typename detail::TypeMap<container_type>::map_type,
218  mpl::bind<detail::quote<detail::is_convertible>, T, mpl::_1>>>::type;
219  typename mpl::second<element_pair>::type ret{};
220  detail::deserialise(m_data, ret);
221  return T(std::move(ret));
222  }
223 
235  template <typename T>
236  std::enable_if_t<!detail::is_valid_element_value_type<container_type, T>::value, T> value() const {
237  static_assert(!std::is_void<T>::value, "Cannot assign value to void.");
238  static_assert(std::is_default_constructible<T>::value, "Return type must be default constructible.");
239  T ret{};
240  value_get(*this, ret);
241  return std::move(ret);
242  }
243 
254  template <typename T>
255  void value(T&& val, std::enable_if_t<detail::is_valid_element_set_type<container_type, T>::value>* = nullptr) {
256  namespace mpl = boost::mpl;
257  using element_pair = typename mpl::deref<
258  detail::find_if_second<typename detail::TypeMap<container_type, true>::map_type,
259  mpl::bind<detail::quote<detail::is_constructible>, mpl::_1, T>>>::type;
260 
261  value<mpl::first<element_pair>::type::value>(std::forward<T>(val));
262  }
263 
273  template <typename T>
274  void value(T&& val, std::enable_if_t<!detail::is_valid_element_set_type<container_type, T>::value>* = nullptr) {
275  container_type old_data;
276  auto old_type = m_type;
277  using std::swap;
278  swap(m_data, old_data);
279 
280  try {
281  value_set(*this, std::forward<T>(val));
282  }
283  catch(...) {
284  m_type = old_type;
285  swap(m_data, old_data);
286  throw;
287  }
288  }
289 
304  template <typename T>
305  void value(element_type new_type, T&& val,
306  std::enable_if_t<detail::is_valid_element_set_type<container_type, T>::value>* = nullptr) {
307  container_type data;
308  detail::visit<detail::set_visitor>(new_type, data, data.end(), std::forward<T>(val));
309 
310  if(detail::detect_size(new_type, data.begin(), data.end()) != static_cast<ptrdiff_t>(boost::distance(data)))
311  BOOST_THROW_EXCEPTION(invalid_element_size{}
312  << detail::actual_size(static_cast<ptrdiff_t>(boost::distance(data)))
313  << detail::expected_size(detail::detect_size(new_type, data.begin(), data.end())));
314  type(new_type);
315  using std::swap;
316  swap(m_data, data);
317  }
318 
331  template <typename T>
332  void value(element_type new_type, T&& val,
333  std::enable_if_t<!detail::is_valid_element_set_type<container_type, T>::value>* = nullptr) {
334  if(!detail::valid_type(new_type))
335  BOOST_THROW_EXCEPTION(invalid_element_type{});
336 
337  container_type old_data;
338  auto old_type = m_type;
339  using std::swap;
340  swap(m_data, old_data);
341 
342  try {
343  value_set(*this, std::forward<T>(val));
344 
345  if(detail::detect_size(new_type, m_data.begin(), m_data.end()) !=
346  static_cast<ptrdiff_t>(boost::distance(m_data)))
347  BOOST_THROW_EXCEPTION(
349  << detail::actual_size(static_cast<ptrdiff_t>(boost::distance(m_data)))
350  << detail::expected_size(detail::detect_size(new_type, m_data.begin(), m_data.end())));
351  type(new_type);
352  }
353  catch(...) {
354  m_type = old_type;
355  swap(m_data, old_data);
356  throw;
357  }
358  }
359 
372  template <element_type EType, typename T>
373  void
374  value(T&& val,
375  std::enable_if_t<std::is_same<std::decay_t<T>, detail::ElementTypeMapSet<EType, container_type>>::value>* =
376  nullptr) {
378  using T2 = ElementTypeMapSet<EType>;
379  static_assert(std::is_same<std::decay_t<T>, T2>::value, "");
380 
381  container_type data;
382  auto it = data.end();
383  detail::serialise(data, it, std::forward<T>(val));
384 
385  if(detail::size_func<EType, decltype(data.begin())> {}(data.begin(), data.end()) !=
386  static_cast<ptrdiff_t>(boost::distance(data)))
387  BOOST_THROW_EXCEPTION(invalid_element_size{}
388  << detail::actual_size(static_cast<ptrdiff_t>(boost::distance(data)))
389  << detail::expected_size(detail::size_func<EType, decltype(data.begin())> {}(
390  data.begin(), data.end())));
391 
392  type(EType);
393  using std::swap;
394  swap(m_data, data);
395  }
396 
409  template <element_type EType, typename T>
410  void
411  value(T&& val,
412  std::enable_if_t<!std::is_same<std::decay_t<T>, detail::ElementTypeMapSet<EType, container_type>>::value>* =
413  nullptr) {
415  using T2 = ElementTypeMapSet<EType>;
416  static_assert(std::is_constructible<T2, T>::value || std::is_convertible<std::decay_t<T>, T2>::value, "");
417 
418  value<EType>(static_cast<T2>(std::forward<T>(val)));
419  }
420 
422  template <typename Visitor>
423  void visit(Visitor&&, std::enable_if_t<std::is_void<decltype(std::declval<Visitor>()(
424  "", std::declval<element_type>(), std::declval<double>()))>::value>* = nullptr) const;
426  template <typename Visitor>
427  auto visit(Visitor&&, std::enable_if_t<!std::is_void<decltype(std::declval<Visitor>()(
428  "", std::declval<element_type>(), std::declval<double>()))>::value>* = nullptr) const
429  -> decltype(std::declval<Visitor>()("", std::declval<element_type>(), std::declval<double>()));
430 
432  static void write_to_container(container_type&, typename container_type::const_iterator, boost::string_ref,
433  element_type);
435  template <typename T>
436  static void write_to_container(container_type&, typename container_type::const_iterator, boost::string_ref, T&&);
438  template <typename T>
439  static void
440  write_to_container(container_type&, typename container_type::const_iterator, boost::string_ref, element_type, T&&,
441  std::enable_if_t<detail::is_valid_element_set_type<container_type, T>::value>* = nullptr);
442 
444  template <typename T>
445  static void
446  write_to_container(container_type&, typename container_type::const_iterator, boost::string_ref, element_type, T&&,
447  std::enable_if_t<!detail::is_valid_element_set_type<container_type, T>::value>* = nullptr);
448 
450  template <typename OutContainer>
451  void write_to_container(OutContainer&, typename OutContainer::const_iterator) const;
452 
455  template <typename OutContainer> explicit operator OutContainer() const;
456 
458  bool operator==(const basic_element& other) const {
459  return m_name == other.m_name && m_type == other.m_type && boost::range::equal(m_data, other.m_data);
460  }
462  bool operator!=(const basic_element& other) const { return !(*this == other); }
463 
475  bool operator<(const basic_element& other) const {
476  auto res = name().compare(other.name());
477  if(res == 0 && type() == other.type()) {
479  return value<double>() < other.value<double>();
481  auto a_str = this->value<detail::ElementTypeMap<element_type::string_element, container_type>>();
483  return std::use_facet<std::collate<char>>({}).compare(a_str.data(), a_str.data() + a_str.size(),
484  b_str.data(), b_str.data() + b_str.size()) < 0;
485  }
486  return m_data < other.m_data;
487  }
488  return res < 0;
489  }
490 
492  void swap(basic_element& other) noexcept {
493  static_assert(detail::is_nothrow_swappable<decltype(m_name)>::value, "");
496  using std::swap;
497  swap(m_name, other.m_name);
498  swap(m_type, other.m_type);
499  swap(m_data, other.m_data);
500  }
501 
502  private:
503  std::string m_name;
505  container_type m_data;
506 
507  template <element_type EType> using ElementTypeMap = detail::ElementTypeMap<EType, container_type>;
508  template <element_type EType> using ElementTypeMapSet = detail::ElementTypeMapSet<EType, container_type>;
509  template <typename T> static bool valid_type(element_type);
510  template <typename T> static bool valid_set_type(element_type);
511 
512  template <typename> friend struct basic_element;
513 };
514 
516 template <typename Container>
517 void swap(basic_element<Container>& a, basic_element<Container>& b) noexcept(noexcept(a.swap(b))) {
518  a.swap(b);
519 }
520 
530 template <class Container>
531 template <typename OutContainer>
532 void basic_element<Container>::write_to_container(OutContainer& c, typename OutContainer::const_iterator it) const {
533  static_assert(std::is_same<typename OutContainer::value_type, char>::value, "");
534  if(!detail::valid_type(m_type))
535  BOOST_THROW_EXCEPTION(invalid_element_type{});
536 
537  if(detail::detect_size(m_type, m_data.begin(), m_data.end()) != static_cast<ptrdiff_t>(boost::distance(m_data)))
538  BOOST_THROW_EXCEPTION(invalid_element_size{}
539  << detail::actual_size(static_cast<ptrdiff_t>(boost::distance(m_data)))
540  << detail::expected_size(detail::detect_size(m_type, m_data.begin(), m_data.end())));
541 
542  it = std::next(c.insert(it, static_cast<uint8_t>(m_type)));
543  it = c.insert(it, m_name.begin(), m_name.end());
544  std::advance(it, m_name.size());
545  it = std::next(c.insert(it, '\0'));
546 
547  c.insert(it, m_data.begin(), m_data.end());
548 }
549 
560 template <typename Container>
561 template <typename T>
562 void basic_element<Container>::write_to_container(container_type& c, typename container_type::const_iterator it,
563  boost::string_ref name, T&& val) {
564  static_assert(!std::is_same<element_type, T>::value, "");
565  static_assert(detail::is_valid_element_set_type<container_type, T>::value, "T must be compatible for deduction");
566 
567  namespace mpl = boost::mpl;
568  using element_pair = typename mpl::deref<
569  detail::find_if_second<typename detail::TypeMap<container_type, true>::map_type,
570  mpl::bind<detail::quote<detail::is_constructible>, mpl::_1, T>>>::type;
571 
572  it = std::next(c.insert(it, static_cast<uint8_t>(mpl::first<element_pair>::type::value)));
573  it = c.insert(it, name.begin(), name.end());
574  std::advance(it, name.size());
575  it = std::next(c.insert(it, '\0'));
576 
577  detail::serialise(c, it, static_cast<typename mpl::second<element_pair>::type>(std::forward<T>(val)));
578 }
579 
592 template <typename Container>
593 template <typename T>
595  container_type& c, typename container_type::const_iterator it, boost::string_ref name, element_type type, T&& val,
596  std::enable_if_t<detail::is_valid_element_set_type<container_type, T>::value>*) {
597  if(!detail::valid_type(type))
598  BOOST_THROW_EXCEPTION(invalid_element_type{});
599 
600  if(!valid_set_type<T>(type))
601  BOOST_THROW_EXCEPTION(incompatible_type_conversion{}
602  << detail::actual_type(typeid(T))
603  << detail::expected_type(detail::visit<detail::typeid_visitor>(type, Container{})));
604 
605  it = std::next(c.insert(it, static_cast<uint8_t>(type)));
606  it = c.insert(it, name.begin(), name.end());
607  std::advance(it, name.size());
608  it = std::next(c.insert(it, '\0'));
609 
610  detail::visit<detail::set_visitor>(type, c, it, std::forward<T>(val));
611 }
612 
628 template <typename Container>
629 template <typename T>
631  container_type& c, typename container_type::const_iterator it, boost::string_ref name, element_type type, T&& val,
632  std::enable_if_t<!detail::is_valid_element_set_type<container_type, T>::value>*) {
633  auto e = basic_element{name.to_string(), type, std::forward<T>(val)};
634  e.write_to_container(c, it);
635 }
636 
648 template <typename Container>
649 void basic_element<Container>::write_to_container(container_type& c, typename container_type::const_iterator it,
650  boost::string_ref name, element_type type) {
651  if(!detail::valid_type(type))
652  BOOST_THROW_EXCEPTION(invalid_element_type{});
653 
655  type != element_type::max_key)
656  BOOST_THROW_EXCEPTION(incompatible_type_conversion{}
657  << detail::actual_type(typeid(void))
658  << detail::expected_type(detail::visit<detail::typeid_visitor>(type, basic_element())));
659 
660  it = std::next(c.insert(it, static_cast<uint8_t>(type)));
661  it = c.insert(it, name.begin(), name.end());
662  std::advance(it, name.size());
663  it = std::next(c.insert(it, '\0'));
664 }
665 
666 template <class Container> template <typename OutContainer> basic_element<Container>::operator OutContainer() const {
667  OutContainer c;
668  write_to_container(c, c.end());
669  return std::move(c);
670 }
671 
676 template <class Container>
677 template <typename OtherContainer>
679  std::enable_if_t<std::is_constructible<container_type, OtherContainer>::value>*)
680  : m_name(elem.m_name), m_type(elem.m_type), m_data(elem.m_data) {}
681 
687 template <class Container>
688 template <typename OtherContainer>
690  const basic_element<OtherContainer>& elem,
691  std::enable_if_t<!std::is_constructible<container_type, OtherContainer>::value>*,
692  std::enable_if_t<std::is_constructible<container_type, typename OtherContainer::const_iterator,
693  typename OtherContainer::const_iterator>::value>*)
694  : m_name(elem.m_name), m_type(elem.m_type), m_data(elem.m_data.begin(), elem.m_data.end()) {}
695 
700 template <class Container>
701 template <typename OtherContainer>
704  std::enable_if_t<std::is_constructible<container_type, OtherContainer&&>::value>*)
705  : m_name(std::move(elem.m_name)), m_type(std::move(elem.m_type)), m_data(std::move(elem.m_data)) {}
706 
713 template <class Container>
714 template <typename ForwardRange>
716  ForwardRange&& range, std::enable_if_t<!std::is_constructible<std::string, ForwardRange>::value>*,
718  if(boost::distance(range) < 2)
719  BOOST_THROW_EXCEPTION(invalid_element_size{} << detail::expected_size(2)
720  << detail::actual_size(boost::distance(range)));
721 
722  auto first = std::begin(range), last = std::end(range);
723 
724  this->type(static_cast<element_type>(*first++));
725 
726  auto str_end = std::find(first, last, '\0');
727  m_name.assign(first, str_end++);
728  first = str_end;
729  const auto elem_size = detail::detect_size(m_type, first, last);
730  if(std::distance(first, last) < elem_size)
731  BOOST_THROW_EXCEPTION(invalid_element_size{} << detail::expected_size(elem_size)
732  << detail::actual_size(std::distance(first, last)));
733  last = std::next(first, elem_size);
734  m_data = container_type{first, last};
735 }
736 
745 template <class Container>
746 template <typename ForwardIterator>
747 basic_element<Container>::basic_element(std::string name, element_type type, ForwardIterator first,
748  ForwardIterator last)
749  : m_name(std::move(name)), m_data(first, last) {
750  this->type(type);
751 }
752 
758 template <class Container>
760  : m_name(std::move(name)) {
761  this->type(type);
762 }
763 
764 template <class Container> size_t basic_element<Container>::size() const noexcept {
765  return sizeof(m_type) + boost::distance(m_data) + m_name.size() + sizeof('\0');
766 }
767 
768 namespace detail {
769 
776 template <element_type EType, typename Visitor, typename Element> struct element_visitor {
778  auto operator()(Visitor&& visitor, Element&& elem) const {
779  return visitor(
780  elem.name(), EType,
781  elem.template value<detail::ElementTypeMap<EType, typename std::decay_t<Element>::container_type>>());
782  }
783 };
784 
785 #ifndef DOXYGEN_SHOULD_SKIP_THIS
786 
787 template <typename Visitor, typename Element>
788 struct element_visitor<element_type::undefined_element, Visitor, Element> {
789  auto operator()(Visitor&& visitor, Element&& elem) const {
790  return visitor(elem.name(), element_type::undefined_element);
791  }
792 };
793 
794 template <typename Visitor, typename Element> struct element_visitor<element_type::null_element, Visitor, Element> {
795  auto operator()(Visitor&& visitor, Element&& elem) const {
796  return visitor(elem.name(), element_type::null_element);
797  }
798 };
799 
800 template <typename Visitor, typename Element> struct element_visitor<element_type::min_key, Visitor, Element> {
801  auto operator()(Visitor&& visitor, Element&& elem) const { return visitor(elem.name(), element_type::min_key); }
802 };
803 
804 template <typename Visitor, typename Element> struct element_visitor<element_type::max_key, Visitor, Element> {
805  auto operator()(Visitor&& visitor, Element&& elem) const { return visitor(elem.name(), element_type::max_key); }
806 };
807 
808 #endif // DOXYGEN_SHOULD_SKIP_THIS
809 
810 } // namespace detail
811 
812 namespace detail {
813 
819 struct elem_compare {
821  using is_transparent = std::true_type;
823  template <typename EContainer, typename EContainer2>
825  return lhs < rhs;
826  }
828  template <typename EContainer> bool operator()(const basic_element<EContainer>& lhs, boost::string_ref rhs) const {
829  return lhs.name() < rhs;
830  }
832  template <typename EContainer> bool operator()(boost::string_ref lhs, const basic_element<EContainer>& rhs) const {
833  return lhs < rhs.name();
834  }
835 };
836 
838 template <typename T, typename Container> struct is_valid_func {
840  template <element_type EType, typename... Args>
841  struct inner : std::integral_constant<
842  bool, mpl::or_<std::is_convertible<T, detail::ElementTypeMap<EType, Container>>,
843  std::is_constructible<detail::ElementTypeMap<EType, Container>, T>>::value> {
844  static_assert(sizeof...(Args) == 0, "");
845  };
847  template <element_type EType, typename... Args>
848  struct set_inner
849  : std::integral_constant<
850  bool, mpl::or_<std::is_convertible<T, detail::ElementTypeMapSet<EType, Container>>,
851  std::is_constructible<detail::ElementTypeMapSet<EType, Container>, T>>::value> {
852  static_assert(sizeof...(Args) == 0, "");
853  };
854 };
855 
856 } // namespace detail
857 
858 template <class Container> template <typename T> bool basic_element<Container>::valid_type(element_type type) {
859  return detail::visit<detail::is_valid_func<T, Container>::template inner>(type);
860 }
861 
862 template <class Container> template <typename T> bool basic_element<Container>::valid_set_type(element_type type) {
863  return detail::visit<detail::is_valid_func<T, Container>::template set_inner>(type);
864 }
865 
874 template <element_type EType, typename Container>
876  if(EType != elem.type())
877  BOOST_THROW_EXCEPTION(incompatible_element_conversion{} << detail::expected_element_type(EType)
878  << detail::actual_element_type(elem.type()));
879 
880  return elem.template value<detail::ElementTypeMap<EType, Container>>();
881 }
882 
890 template <typename ReturnT, typename Container> ReturnT get(const basic_element<Container>& elem) {
891  return elem.template value<ReturnT>();
892 }
893 
895 template <typename CharT, typename TraitsT>
896 inline std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, element_type e) {
897  switch(e) {
899  os << "double_element";
900  break;
902  os << "string_element";
903  break;
905  os << "document_element";
906  break;
908  os << "array_element";
909  break;
911  os << "binary_element";
912  break;
914  os << "undefined_element";
915  break;
917  os << "oid_element";
918  break;
920  os << "boolean_element";
921  break;
923  os << "date_element";
924  break;
926  os << "null_element";
927  break;
929  os << "regex_element";
930  break;
932  os << "db_pointer_element";
933  break;
935  os << "javascript_element";
936  break;
938  os << "symbol_element";
939  break;
941  os << "scoped_javascript_element";
942  break;
944  os << "int32_element";
945  break;
947  os << "timestamp_element";
948  break;
950  os << "int64_element";
951  break;
953  os << "min_key";
954  break;
956  os << "max_key";
957  break;
958  default:
959  os << "unknown element_type";
960  break;
961  };
962 
963  return os;
964 }
965 
980 template <class Container>
981 template <typename Visitor>
982 void basic_element<Container>::visit(Visitor&& visitor,
983  std::enable_if_t<std::is_void<decltype(std::declval<Visitor>()(
984  "", std::declval<element_type>(), std::declval<double>()))>::value>*) const {
985  detail::visit<detail::element_visitor>(m_type, std::forward<Visitor>(visitor), *this);
986  return;
987 }
988 
1004 template <class Container>
1005 template <typename Visitor>
1006 auto basic_element<Container>::visit(Visitor&& visitor,
1007  std::enable_if_t<!std::is_void<decltype(std::declval<Visitor>()(
1008  "", std::declval<element_type>(), std::declval<double>()))>::value>*) const
1009  -> decltype(std::declval<Visitor>()("", std::declval<element_type>(), std::declval<double>())) {
1010  return detail::visit<detail::element_visitor>(m_type, std::forward<Visitor>(visitor), *this);
1011 }
1012 
1013 } // namespace jbson
1014 
1015 JBSON_POP_WARNINGS
1016 
1017 #endif // JBSON_ELEMENT_HPP
std::enable_if_t< detail::is_valid_element_value_type< container_type, T >::value, T > value() const
Returns the value data in the form of a specific type.
Definition: element.hpp:206
basic_element()=default
Default constructor.
Visitor for checking validity of a type for setting.
Definition: element.hpp:848
void value(T &&val, std::enable_if_t<!std::is_same< std::decay_t< T >, detail::ElementTypeMapSet< EType, container_type >>::value > *=nullptr)
Sets value. Statically ensures type compatibility.
Definition: element.hpp:411
element_type
The element_type enum represents a BSON data type.
Definition: element_fwd.hpp:36
bool operator()(const basic_element< EContainer > &lhs, const basic_element< EContainer2 > &rhs) const
Functor call operator. Normal comparison.
Definition: element.hpp:824
std::string or boost::string_ref (string_type)
basic_element(std::string name, element_type type, T &&val)
Construct an element with specified name, type and value.
Definition: element.hpp:132
void value(T &&val, std::enable_if_t<!detail::is_valid_element_set_type< container_type, T >::value > *=nullptr)
Sets value from a user-defined type.
Definition: element.hpp:274
BSON element.
Definition: element.hpp:69
void visit(Visitor &&, std::enable_if_t< std::is_void< decltype(std::declval< Visitor >()("", std::declval< element_type >(), std::declval< double >()))>::value > *=nullptr) const
Apply the visitor pattern with a void-return visitor.
Definition: element.hpp:982
std::true_type is_transparent
Enables heterogeneous comparison in some standard algorithms and containers.
Definition: element.hpp:821
std::enable_if_t<!detail::is_valid_element_value_type< container_type, T >::value, T > value() const
Returns the value data in the form of a specific type.
Definition: element.hpp:236
Exception thrown when an element has a value not convertible to that requested.
Definition: error.hpp:47
is_range_of_value< RangeT, mpl::bind2< mpl::quote2< std::is_same >, ElementT, mpl::_1 >> is_range_of_same_value
Type trait to determine equivalence of the value_type of a Range.
Definition: traits.hpp:212
void name(std::string n)
Sets name to n.
Definition: element.hpp:170
typename mpl::eval_if< has_iterator< std::decay_t< Container >>, container_has_push_back_impl< std::decay_t< Container >>, std::false_type >::type container_has_push_back
Type trait to determine if type is a container with a push_back() function.
Definition: traits.hpp:183
bool operator<(const basic_element &other) const
Checks if this is less than (<) other.
Definition: element.hpp:475
typename mpl::at< typename TypeMap< Container, true >::map_type, element_type_c< EType >>::type ElementTypeMapSet
Type alias to perform boost::mpl::at on TypeMap::map_type.
Definition: traits.hpp:146
Visitor for obtaining std::type_index of a mapped element_type.
Definition: element.hpp:35
void value(T &&val, std::enable_if_t< detail::is_valid_element_set_type< container_type, T >::value > *=nullptr)
Sets value from a detail::TypeMap compatible type.
Definition: element.hpp:255
void swap(basic_document< Container, EContainer > &a, basic_document< Container, EContainer > &b) noexcept(noexcept(a.swap(b)))
Non-member swap for basic_document. Calls basic_document::swap.
Definition: document.hpp:619
void type(element_type new_type)
Sets type of this element.
Definition: element.hpp:188
void value(element_type new_type, T &&val, std::enable_if_t<!detail::is_valid_element_set_type< container_type, T >::value > *=nullptr)
Sets element_type, and value from a user-defined type.
Definition: element.hpp:332
bool operator()(boost::string_ref lhs, const basic_element< EContainer > &rhs) const
Functor call operator. Heterogeneous comparison.
Definition: element.hpp:832
void value(element_type new_type, T &&val, std::enable_if_t< detail::is_valid_element_set_type< container_type, T >::value > *=nullptr)
Sets element_type, and value from a detail::TypeMap compatible type.
Definition: element.hpp:305
Type trait to determine if a type is nothrow/noexcept swappable.
Definition: traits.hpp:282
bool operator()(const basic_element< EContainer > &lhs, boost::string_ref rhs) const
Functor call operator. Heterogeneous comparison.
Definition: element.hpp:828
Helper class to implement basic_element::visit with detail::visit.
Definition: element.hpp:776
size_t size() const noexcept
Returns size in bytes.
Definition: element.hpp:764
void value(T &&val, std::enable_if_t< std::is_same< std::decay_t< T >, detail::ElementTypeMapSet< EType, container_type >>::value > *=nullptr)
Sets value. Statically ensures type compatibility.
Definition: element.hpp:374
Visitor for checking validity of a type for fetching.
Definition: element.hpp:841
auto operator()(Visitor &&visitor, Element &&elem) const
Functor call operator.
Definition: element.hpp:778
Exception thrown when an element's data size differs from that reported.
Definition: error.hpp:55
Exception type thrown when a call to get() has an incorrect type parameter.
Definition: error.hpp:39
basic_document> (document_type)
Wrapper for type validity checking visitors.
Definition: element.hpp:838
element_type type() const noexcept
Returns BSON type of this element.
Definition: element.hpp:176
Exception type thrown when an element has a type value not represented by element_type.
Definition: error.hpp:31
basic_element(std::string name, T &&val)
Construct an element with specified name and value.
Definition: element.hpp:151
basic_element(ForwardIterator &&first, ForwardIterator &&last, std::enable_if_t< !std::is_constructible< boost::string_ref, ForwardIterator >::value||std::is_convertible< ForwardIterator, typename container_type::const_iterator >::value > *=nullptr, std::enable_if_t< detail::is_range_of_same_value< decltype(boost::make_iterator_range(first, last)), typename Container::value_type >::value > *=nullptr)
Construct an element from raw BSON byte sequence.
Definition: element.hpp:118
static void write_to_container(container_type &, typename container_type::const_iterator, boost::string_ref, element_type)
Constructs a BSON element without data, in-place into a container.
Definition: element.hpp:649
typename mpl::at< typename TypeMap< Container >::map_type, element_type_c< EType >>::type ElementTypeMap
Type alias to perform boost::mpl::at on TypeMap::map_type.
Definition: traits.hpp:137
bool operator!=(const basic_element &other) const
Checks if this and other are not equal.
Definition: element.hpp:462
std::decay_t< Container > container_type
Underlying storage container.
Definition: element.hpp:71
void swap(basic_element &other) noexcept
Swaps contents with other.
Definition: element.hpp:492
Functor for basic_element comparison.
Definition: element.hpp:819
boost::string_ref name() const noexcept(std::is_nothrow_constructible< boost::string_ref, const std::string & >::value)
Returns name of element.
Definition: element.hpp:160