View on GitHub
jbson
C++11/1y BSON library
set.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_SET_HPP
7 #define JBSON_SET_HPP
8 
9 #include "../element_fwd.hpp"
10 #include "traits.hpp"
11 
12 namespace jbson {
13 
14 template <typename Container> void value_set(basic_element<Container>&, ...) {
15  static_assert(std::is_void<Container>::value,
16  "A valid overload of value_set must be supplied for user-defined types.");
17 }
18 
19 namespace detail {
20 
21 // setters
22 
23 // arithmetic
24 template <typename Container, typename IteratorT, typename T>
25 void serialise(Container& c, IteratorT& it, T val, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr) {
26  auto data = detail::native_to_little_endian(val);
27  it = c.insert(it, std::begin(data), std::end(data));
28  if(it != std::end(c))
29  std::advance(it, boost::distance(data));
30 }
31 
32 // string
33 template <typename Container, typename IteratorT> void serialise(Container& c, IteratorT& it, boost::string_ref val) {
34  serialise(c, it, static_cast<int32_t>(val.size() + 1));
35  it = c.insert(it, std::begin(val), std::end(val));
36  if(it != std::end(c))
37  std::advance(it, boost::distance(val));
38  it = std::next(c.insert(it, '\0'));
39 }
40 
41 // document
42 template <typename Container, typename IteratorT, typename DocContainer, typename DocEContainer>
43 void serialise(Container& c, IteratorT& it, const basic_document<DocContainer, DocEContainer>& val) {
44  if(c.empty()) {
45  c = Container{val.data().begin(), val.data().end()};
46  it = c.end();
47  return;
48  }
49  it = c.insert(it, std::begin(val.data()), std::end(val.data()));
50  if(it != std::end(c))
51  std::advance(it, boost::distance(val.data()));
52 }
53 
54 // array
55 template <typename Container, typename IteratorT, typename DocContainer, typename DocEContainer>
56 void serialise(Container& c, IteratorT& it, const basic_array<DocContainer, DocEContainer>& val) {
57  if(c.empty()) {
58  c = Container{val.data().begin(), val.data().end()};
59  it = c.end();
60  return;
61  }
62  it = c.insert(it, std::begin(val.data()), std::end(val.data()));
63  if(it != std::end(c))
64  std::advance(it, boost::distance(val.data()));
65 }
66 
67 // oid
68 template <typename Container, typename IteratorT>
69 void serialise(Container& c, IteratorT& it, const std::array<char, 12>& val) {
70  it = c.insert(it, std::begin(val), std::end(val));
71  if(it != std::end(c))
72  std::advance(it, 12);
73 }
74 
75 // regex
76 template <typename Container, typename IteratorT, typename StringT>
77 void serialise(Container& c, IteratorT& it, const std::tuple<StringT, StringT>& val,
78  std::enable_if_t<std::is_convertible<StringT, boost::string_ref>::value>* = nullptr) {
79  boost::string_ref str1 = std::get<0>(val);
80  it = c.insert(it, std::begin(str1), std::end(str1));
81  if(it != std::end(c))
82  std::advance(it, boost::distance(str1));
83  it = std::next(c.insert(it, '\0'));
84 
85  boost::string_ref str2 = std::get<1>(val);
86  it = c.insert(it, std::begin(str2), std::end(str2));
87  if(it != std::end(c))
88  std::advance(it, boost::distance(str2));
89  it = std::next(c.insert(it, '\0'));
90 }
91 
92 // db_pointer
93 template <typename Container, typename IteratorT, typename StringT>
94 void serialise(Container& c, IteratorT& it, const std::tuple<StringT, std::array<char, 12>>& val) {
95  serialise(c, it, std::get<0>(val));
96  serialise(c, it, std::get<1>(val));
97 }
98 
99 // scoped javascript
100 template <typename Container, typename IteratorT, typename StringT, typename DocContainer, typename DocEContainer>
101 void serialise(Container&, IteratorT&, const std::tuple<StringT, basic_document<DocContainer, DocEContainer>>&,
102  std::enable_if_t<std::is_convertible<StringT, boost::string_ref>::value>* = nullptr) {
103  assert(false);
104  BOOST_THROW_EXCEPTION(incompatible_type_conversion{});
105 }
106 
107 // set visitor
108 template <element_type EType, typename C, typename It, typename A, typename Enable = void> struct set_visitor;
109 
110 #ifndef DOXYGEN_SHOULD_SKIP_THIS
111 
112 // voids
113 template <element_type EType, typename C, typename It, typename A>
114 struct set_visitor<EType, C, It, A, std::enable_if_t<std::is_void<ElementTypeMapSet<EType, std::decay_t<C>>>::value>> {
115  template <typename... Args> void operator()(Args&&...) const {
116  BOOST_THROW_EXCEPTION(incompatible_type_conversion{});
117  }
118 };
119 
120 // everything else
121 template <element_type EType, typename Container, typename IteratorT, typename A>
122 struct set_visitor<EType, Container, IteratorT, A,
123  std::enable_if_t<!std::is_void<ElementTypeMapSet<EType, std::decay_t<Container>>>::value>> {
124  static_assert(detail::container_has_push_back<Container>::value,
125  "Cannot set value of an element without a modifiable container");
126 
127  using container_type = std::decay_t<Container>;
128  using set_type = ElementTypeMapSet<EType, container_type>;
129 
130  template <typename T> void operator()(container_type& data, T&& val) const {
131  (*this)(data, std::end(data), std::forward<T>(val));
132  }
133 
134  void operator()(container_type& data, typename container_type::const_iterator it, set_type val) const {
135  serialise(data, it, std::move(val));
136  }
137 
138  template <typename T>
139  void
140  operator()(container_type& data, typename container_type::const_iterator it, T&& val,
141  std::enable_if_t<std::is_constructible<set_type, T>::value || std::is_convertible<T, set_type>::value>* =
142  nullptr) const {
143  serialise(data, it, set_type(std::forward<T>(val)));
144  }
145 
146  template <typename T>
147  void operator()(container_type&, typename container_type::const_iterator const&, T&&,
148  std::enable_if_t<!std::is_constructible<set_type, T>::value>* = nullptr,
149  std::enable_if_t<!std::is_convertible<std::decay_t<T>, set_type>::value>* = nullptr) const {
150  BOOST_THROW_EXCEPTION(incompatible_type_conversion{} << expected_type(typeid(set_type))
151  << actual_type(typeid(T)));
152  }
153 };
154 
155 #endif // DOXYGEN_SHOULD_SKIP_THIS
156 
157 } // namespace detail
158 } // namespace jbson
159 
160 #endif // JBSON_SET_HPP
Exception thrown when an element has a value not convertible to that requested.
Definition: error.hpp:47