OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
composite.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 <ozo/io/size_of.h>
7 #include <boost/hana/adapt_struct.hpp>
8 #include <boost/hana/members.hpp>
9 #include <boost/hana/size.hpp>
10 #include <boost/hana/fold.hpp>
11 #include <boost/fusion/adapted/struct/adapt_struct.hpp>
12 #include <boost/fusion/include/fold.hpp>
13 
14 namespace ozo::detail {
15 
16 struct pg_composite {
17  BOOST_HANA_DEFINE_STRUCT(pg_composite,
18  (std::int32_t, count)
19  );
20 };
21 
22 } // namespace ozo::detail
23 
24 namespace ozo {
25 
26 namespace detail {
27 
28 constexpr auto size_of(const pg_composite&) noexcept {
29  return size_constant<sizeof(std::int32_t)>{};
30 }
31 
32 template <typename T>
33 constexpr auto fields_number(const T& v) -> Require<FusionSequence<T>&&!HanaStruct<T>, size_type> {
34  return size_type(fusion::size(v));
35 }
36 
37 template <typename T>
38 constexpr auto fields_number(const T& v) -> Require<HanaStruct<T>, size_type> {
39  return size_type(hana::value(hana::size(hana::members(v))));
40 }
41 
42 template <typename T>
43 constexpr auto data_size(const T& v) -> Require<FusionSequence<T>&&!HanaStruct<T>, size_type> {
44  return fusion::fold(v, size_type(0),
45  [&] (auto r, const auto& item) { return r + frame_size(item); });
46 }
47 
48 template <typename T>
49 constexpr auto data_size(const T& v) -> Require<HanaStruct<T>, size_type>{
50  return hana::unpack(hana::members(v),
51  [&] (const auto& ...x) { return (frame_size(x) + ... + 0); });
52 }
53 
54 template <typename T>
55 struct size_of_composite {
56  static constexpr auto apply(const T& v) {
57  using ozo::size_of;
58  constexpr const auto header_size = size_of(detail::pg_composite{});
59  return header_size + data_size(v);
60  }
61 };
62 
63 template <typename T, typename Func>
64 constexpr auto for_each_member(T&& v, Func&& f) -> Require<FusionSequence<T>&&!HanaStruct<T>> {
65  fusion::for_each(std::forward<T>(v), std::forward<Func>(f));
66 }
67 
68 template <typename T, typename Func>
69 constexpr auto for_each_member(T&& v, Func&& f) -> Require<HanaStruct<T>>{
70  hana::for_each(hana::members(std::forward<T>(v)), std::forward<Func>(f));
71 }
72 
73 template <typename T>
74 struct size_of_impl_dispatcher<T, Require<Composite<T>>> { using type = size_of_composite<std::decay_t<T>>; };
75 
76 template <typename T>
77 struct send_composite_impl {
78  template <typename OidMap>
79  static ostream& apply(ostream& out, const OidMap& oid_map, const T& in) {
80  write(out, pg_composite{fields_number(in)});
81  for_each_member(in, [&] (const auto& v) {
82  send_frame(out, oid_map, v);
83  });
84  return out;
85  }
86 };
87 
88 template <typename T>
89 struct send_impl_dispatcher<T, Require<Composite<T>>> { using type = send_composite_impl<std::decay_t<T>>; };
90 
91 template <typename T>
92 inline Require<Composite<T>> read_and_verify_header(istream& in, const T& v) {
93  pg_composite header;
94  read(in, header);
95  if (header.count != fields_number(v)) {
97  "incoming composite fields count " + std::to_string(header.count)
98  + " does not match fields count " + std::to_string(fields_number(v))
99  + " of type " + boost::core::demangle(typeid(v).name()));
100  }
101 }
102 
103 template <typename T>
104 struct recv_fusion_adapted_composite_impl {
105  template <typename OidMap>
106  static istream& apply(istream& in, size_type, const OidMap& oid_map, T& out) {
107  read_and_verify_header(in, out);
108  fusion::for_each(out, [&] (auto& v) {
109  recv_frame(in, oid_map, v);
110  });
111  return in;
112  }
113 };
114 
115 template <typename T>
116 struct recv_hana_adapted_composite_impl {
117  template <typename OidMap>
118  static istream& apply(istream& in, size_type, const OidMap& oid_map, T& out) {
119  read_and_verify_header(in, out);
120  hana::for_each(hana::keys(out), [&in, &out, &oid_map](auto key) {
121  recv_frame(in, oid_map, hana::at_key(out, key));
122  });
123  return in;
124  }
125 };
126 
127 template <typename T>
128 struct recv_impl_dispatcher<T, Require<Composite<T>&&FusionSequence<T>>> {
129  using type = recv_fusion_adapted_composite_impl<std::decay_t<T>>;
130 };
131 
132 template <typename T>
133 struct recv_impl_dispatcher<T, Require<Composite<T>&&!FusionSequence<T>>> {
134  using type = recv_hana_adapted_composite_impl<std::decay_t<T>>;
135 };
136 
137 } // namespace detail
138 } //namespace ozo
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::frame_size
constexpr size_type frame_size(const T &v)
Returns size of full IO frame.
Definition: size_of.h:146
ozo::error::bad_composite_size
@ bad_composite_size
a composite's fields number received does not equal to the expected or not supported by the type
Definition: error.h:96
ozo::system_error
boost::system::system_error system_error
Error code contaning exception of the library.
Definition: error.h:45
ozo::OidMap
constexpr auto OidMap
Map of C++ types to corresponding PostgreSQL types OIDs.
Definition: type_traits.h:534
ozo::recv_frame
istream & recv_frame(istream &in, const OidMap &oids, Out &out)
Receive full frame of an object from an input stream.
Definition: recv.h:242
Composite
Composite concept represents PostgreSQL composite types.
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::send_frame
ostream & send_frame(ostream &out, const OidMap &oid_map, const In &in)
Send full frame of an object to an output stream.
Definition: send.h:131