View on GitHub
jbson
C++11/1y BSON library
builder.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_BUILDER_HPP
7 #define JBSON_BUILDER_HPP
8 
9 #include <vector>
10 
11 #include <jbson/element.hpp>
12 #include <jbson/document.hpp>
13 
14 namespace jbson {
15 
44 struct builder {
52  builder() = default;
53 
66  template <typename Arg1, typename... ArgN> explicit builder(Arg1&& arg, ArgN&&... args) {
67  emplace(std::forward<Arg1>(arg), std::forward<ArgN>(args)...);
68  }
69 
70  // lvalue funcs
71 
81  template <typename... Args> builder& operator()(Args&&... args) & {
82  emplace(std::forward<Args>(args)...);
83  return *this;
84  }
85 
98  template <typename... Args> builder& emplace(Args&&... args) & {
99  auto old_size = m_elements.size();
100  try {
101  basic_element<decltype(m_elements)>::write_to_container(m_elements, m_elements.end(),
102  std::forward<Args>(args)...);
103  }
104  catch(...) {
105  m_elements.resize(old_size);
106  throw;
107  }
108 
109  return *this;
110  }
111 
112  // rvalue funcs
113 
127  template <typename... Args> builder&& operator()(Args&&... args) && {
128  return std::move(emplace(std::forward<Args>(args)...));
129  }
130 
144  template <typename... Args> builder&& emplace(Args&&... args) && {
145  return std::move(emplace(std::forward<Args>(args)...));
146  }
147 
153  template <typename Container, typename EContainer> operator basic_document<Container, EContainer>() const& {
155  m_elements.push_back('\0');
156  auto size = jbson::detail::native_to_little_endian(static_cast<int32_t>(m_elements.size()));
157  static_assert(4 == size.size(), "");
158 
159  boost::range::copy(size, m_elements.begin());
160  auto doc = basic_document<Container, EContainer>(m_elements);
161  m_elements.pop_back();
162  return std::move(doc);
163  }
164 
170  template <typename Container, typename EContainer> operator basic_document<Container, EContainer>() && {
172  m_elements.push_back('\0');
173  auto size = jbson::detail::native_to_little_endian(static_cast<int32_t>(m_elements.size()));
174  static_assert(4 == size.size(), "");
175 
176  boost::range::copy(size, m_elements.begin());
177  return basic_document<Container, EContainer>(std::move(m_elements));
178  }
179 
180  private:
181  mutable std::vector<char> m_elements{{0, 0, 0, 0}};
182 };
183 
190  array_builder() = default;
191 
192  template <typename Arg1, typename... ArgN> explicit array_builder(Arg1&& arg, ArgN&&... args) {
193  emplace(std::forward<Arg1>(arg), std::forward<ArgN>(args)...);
194  }
195 
196  // lvalue funcs
197 
198  template <typename... Args> array_builder& operator()(Args&&... args) & {
199  static_assert(sizeof...(Args) > 0, "");
200  emplace(std::forward<Args>(args)...);
201  return *this;
202  }
203 
204  template <typename... Args> array_builder& emplace(Args&&... args) & {
205  static_assert(sizeof...(Args) > 0, "");
206  std::array<char, std::numeric_limits<decltype(m_count)>::digits10 + 1> int_str;
207  auto n = std::snprintf(int_str.data(), int_str.size(), "%zd", m_count);
208  if(n <= 0) {
209  if(errno)
210  BOOST_THROW_EXCEPTION(std::system_error(errno, std::generic_category()));
211  return *this;
212  }
213  auto old_size = m_elements.size();
214  try {
216  m_elements, m_elements.end(), boost::string_ref{int_str.data(), static_cast<size_t>(n)},
217  std::forward<Args>(args)...);
218  m_count++;
219  }
220  catch(...) {
221  m_elements.resize(old_size);
222  throw;
223  }
224 
225  return *this;
226  }
227 
228  // rvalue funcs
229 
230  template <typename... Args> array_builder&& operator()(Args&&... args) && {
231  return std::move(emplace(std::forward<Args>(args)...));
232  }
233 
234  template <typename... Args> array_builder&& emplace(Args&&... args) && {
235  return std::move(emplace(std::forward<Args>(args)...));
236  }
237 
238  template <typename Container, typename EContainer> operator basic_array<Container, EContainer>() const& {
239  m_elements.push_back('\0');
240  auto size = jbson::detail::native_to_little_endian(static_cast<int32_t>(m_elements.size()));
241  static_assert(4 == size.size(), "");
242 
243  boost::range::copy(size, m_elements.begin());
244  auto doc = basic_array<Container, EContainer>(m_elements);
245  m_elements.pop_back();
246  return std::move(doc);
247  }
248 
249  template <typename Container, typename EContainer> operator basic_array<Container, EContainer>() && {
250  m_elements.push_back('\0');
251  auto size = jbson::detail::native_to_little_endian(static_cast<int32_t>(m_elements.size()));
252  static_assert(4 == size.size(), "");
253 
254  boost::range::copy(size, m_elements.begin());
255  return basic_array<Container, EContainer>(std::move(m_elements));
256  }
257 
258  private:
259  mutable std::vector<char> m_elements{{0, 0, 0, 0}};
260  uint32_t m_count{0u};
261 };
262 
263 // builder
264 template <typename Container> void value_set(basic_element<Container>& c, builder val) {
265  c.value(document(std::move(val)));
266 }
267 
268 // array_builder
269 template <typename Container, typename IteratorT> void value_set(basic_element<Container>& c, array_builder val) {
270  c.value(array(std::move(val)));
271 }
272 
273 } // namespace jbson
274 
275 #endif // JBSON_BUILDER_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
array_builder provides a simple interface for array construction
Definition: builder.hpp:189
builder && operator()(Args &&...args)&&
Rvalue overload. Forwards *this as an rvalue reference. Constructs a BSON element in place with the s...
Definition: builder.hpp:127
BSON document.
Definition: document.hpp:191
BSON element.
Definition: element.hpp:69
Type trait to determine whether a type is a boost::iterator_range.
Definition: traits.hpp:155
builder & emplace(Args &&...args)&
Constructs a BSON element in place with the supplied args.
Definition: builder.hpp:98
builder()=default
Default constructor.
basic_array< std::vector< char >> array
Default basic_array type alias for owned BSON data.
builder & operator()(Args &&...args)&
Forwards to emplace.
Definition: builder.hpp:81
builder(Arg1 &&arg, ArgN &&...args)
Constructor which forwards to emplace.
Definition: builder.hpp:66
basic_document< std::vector< char >> document
Default basic_document type alias for owned BSON data.
BSON array.
Definition: document.hpp:534
builder provides a simple interface for document construction.
Definition: builder.hpp:44
builder && emplace(Args &&...args)&&
Rvalue overload. Forwards *this as an rvalue reference. Constructs a BSON element in place with the s...
Definition: builder.hpp:144