OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
array.h
1 #pragma once
2 
3 #include <ozo/type_traits.h>
4 #include <ozo/io/send.h>
5 #include <ozo/io/recv.h>
6 #include <boost/hana/adapt_struct.hpp>
7 #include <boost/hana/size.hpp>
8 #include <boost/hana/fold.hpp>
9 #include <boost/fusion/adapted/struct/adapt_struct.hpp>
10 #include <boost/range/numeric.hpp>
11 #include <boost/range/algorithm/for_each.hpp>
12 
13 namespace ozo {
14 
15 template <typename T>
16 struct fit_array_size_impl {
17  static void apply(T& array, size_type count) { array.resize(count); }
18 };
19 
59 template <typename T>
60 inline void fit_array_size(T& array, size_type count) {
61  fit_array_size_impl<T>::apply(array, count);
62 }
63 
64 } // namespace ozo
65 
66 namespace ozo::detail {
67 
68 struct pg_array {
69  BOOST_HANA_DEFINE_STRUCT(pg_array,
70  (std::int32_t, dimensions_count),
71  (std::int32_t, dataoffset),
72  (::Oid, elemtype)
73  );
74 };
75 
76 struct pg_array_dimension {
77  BOOST_HANA_DEFINE_STRUCT(pg_array_dimension,
78  (size_type, size),
79  (std::int32_t, index)
80  );
81 };
82 
83 } //namespace ozo::detail
84 
85 namespace ozo::detail {
86 
87 template <typename T>
88 struct size_of_array_impl {
89  constexpr static size_type data_size(const T& v) {
90  using ozo::size_of;
91  if constexpr (StaticSize<typename T::value_type>) {
92  return std::empty(v) ? 0 : data_frame_size(*std::begin(v)) * std::size(v);
93  }
94  return boost::accumulate(v, size_type(0),
95  [&] (auto r, const auto& item) { return r + data_frame_size(item);});
96  }
97 
98  static constexpr auto apply(const T& v) {
99  constexpr const auto header_size = hana::unpack(
100  hana::members(pg_array{}),
101  [] (const auto& ...x) { return (sizeof(x) + ... + 0); });
102 
103  constexpr const auto dimension_header_size = hana::unpack(
104  hana::members(pg_array_dimension{}),
105  [] (const auto& ...x) { return (sizeof(x) + ... + 0); });
106 
107  return header_size + dimension_header_size + data_size(v);
108  }
109 };
110 
111 template <typename T>
112 struct size_of_impl_dispatcher<T, Require<Array<T>>> { using type = size_of_array_impl<std::decay_t<T>>; };
113 
114 template <typename T>
115 struct send_array_impl {
116  template <typename OidMap>
117  static ostream& apply(ostream& out, const OidMap& oid_map, const T& in) {
118  using value_type = typename T::value_type;
119  write(out, pg_array {1, 0, type_oid<value_type>(oid_map)});
120  write(out, pg_array_dimension {std::int32_t(std::size(in)), 0});
121  boost::for_each(in, [&] (const auto& v) { send_data_frame(out, oid_map, v);});
122  return out;
123  }
124 };
125 
126 template <typename T>
127 struct send_impl_dispatcher<T, Require<Array<T>>> { using type = send_array_impl<std::decay_t<T>>; };
128 
129 template <typename T>
130 struct recv_array_impl {
131  using out_type = T;
132 
133  template <typename OidMap>
134  static istream& apply(istream& in, size_type, const OidMap& oids, out_type& out) {
135  pg_array array_header;
136  pg_array_dimension dim_header;
137 
138  read(in, array_header);
139 
140  if (array_header.dimensions_count > 1) {
142  "multiply dimension count is not supported: "
143  + std::to_string(array_header.dimensions_count));
144  }
145 
146  using item_type = unwrap_type<typename out_type::value_type>;
147 
148  if (!accepts_oid<item_type>(oids, array_header.elemtype)) {
150  "unexpected oid " + std::to_string(array_header.elemtype)
151  + " for element type of " + boost::core::demangle(typeid(item_type).name()));
152  }
153 
154  if (array_header.dimensions_count < 1) {
155  return in;
156  }
157 
158  read(in, dim_header);
159 
160  if (dim_header.size == 0) {
161  return in;
162  }
163 
164  fit_array_size(out, dim_header.size);
165 
166  for (auto& item : out) {
167  recv_data_frame(in, oids, item);
168  }
169  return in;
170  }
171 };
172 
173 template <typename T>
174 struct recv_impl_dispatcher<T, Require<Array<T>>> { using type = recv_array_impl<std::decay_t<T>>; };
175 
176 } // namespace ozo::detail
ozo::size_of
constexpr size_type size_of(const T &v)
Returns size of object binary representation in bytes.
Definition: size_of.h:105
ozo::system_error
boost::system::system_error system_error
Error code contaning exception of the library.
Definition: error.h:45
Array
Array concept represents PostgreSQL array.
ozo::error::bad_array_dimension
@ bad_array_dimension
an array dimension count received does not equal to the expected or not supported by the type
Definition: error.h:95
ozo::send_data_frame
ostream & send_data_frame(ostream &out, const OidMap &oid_map, const In &in)
Send data frame of an object to an output stream.
Definition: send.h:111
ozo::OidMap
constexpr auto OidMap
Map of C++ types to corresponding PostgreSQL types OIDs.
Definition: type_traits.h:534
ozo::empty
constexpr bool empty(const oid_map_t< Ts... > &map) noexcept
Definition: type_traits.h:674
ozo::recv_data_frame
istream & recv_data_frame(istream &in, const OidMap &oids, Out &out)
Receive data frame of an object from an input stream.
Definition: recv.h:221
ozo::error::oid_type_mismatch
@ oid_type_mismatch
no conversion possible from oid to user-supplied type - the type what user expected is not the same a...
Definition: error.h:81
ozo::Require
Type Require
Concept requirement emulation.
Definition: concept.h:54
ozo::size_type
std::int32_t size_type
PostgreSQL size type.
Definition: type_traits.h:265
ozo::begin
decltype(auto) begin(ConnectionProvider &&provider, TimeConstraint time_constraint, CompletionToken &&token)
Start new transaction.
ozo::fit_array_size
void fit_array_size(T &array, size_type count)
Fits array container size to reqired one.
Definition: array.h:60
ozo::data_frame_size
constexpr size_type data_frame_size(const T &v)
Returns size of IO data frame.
Definition: size_of.h:127