userver: userver/storages/postgres/io/integral_types.hpp Source File
Loading...
Searching...
No Matches
integral_types.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/integral_types.hpp
4/// @brief Integral types I/O support
5/// @ingroup userver_postgres_parse_and_format
6
7#include <boost/endian/conversion.hpp>
8
9#include <type_traits>
10
11#include <userver/storages/postgres/exceptions.hpp>
12#include <userver/storages/postgres/io/buffer_io_base.hpp>
13#include <userver/storages/postgres/io/traits.hpp>
14#include <userver/storages/postgres/io/type_mapping.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::postgres::io {
19
20namespace detail {
21
22template <std::size_t Size>
23struct IntegralType;
24
25template <>
26struct IntegralType<2> {
27 using type = Smallint;
28};
29
30template <>
31struct IntegralType<4> {
32 using type = Integer;
33};
34
35template <>
36struct IntegralType<8> {
37 using type = Bigint;
38};
39
40template <std::size_t Size>
41struct IntegralBySizeParser {
42 using IntType = typename IntegralType<Size>::type;
43 constexpr static std::size_t size = Size;
44
45 static IntType ParseBuffer(const FieldBuffer& buf) {
46 IntType i;
47 std::memcpy(&i, buf.buffer, size);
48 return boost::endian::big_to_native(i);
49 }
50};
51
52template <typename T>
53struct IntegralBinaryParser : BufferParserBase<T> {
54 using BaseType = BufferParserBase<T>;
55 using BaseType::BaseType;
56
57 void operator()(const FieldBuffer& buf) {
58 switch (buf.length) {
59 case 2:
60 this->value = IntegralBySizeParser<2>::ParseBuffer(buf);
61 break;
62 case 4:
63 this->value = IntegralBySizeParser<4>::ParseBuffer(buf);
64 break;
65 case 8:
66 this->value = IntegralBySizeParser<8>::ParseBuffer(buf);
67 break;
68 default:
69 throw InvalidInputBufferSize{buf.length, "for an integral value type"};
70 }
71 }
72};
73
74template <typename T>
75struct IntegralBinaryFormatter {
76 static constexpr std::size_t size = sizeof(T);
77 using BySizeType = typename IntegralType<size>::type;
78
79 T value;
80
81 explicit IntegralBinaryFormatter(T val) : value{val} {}
82 template <typename Buffer>
83 void operator()(const UserTypes&, Buffer& buf) const {
84 buf.reserve(buf.size() + size);
85 auto tmp = boost::endian::native_to_big(static_cast<BySizeType>(value));
86 const char* p = reinterpret_cast<char const*>(&tmp);
87 const char* e = p + size;
88 std::copy(p, e, std::back_inserter(buf));
89 }
90
91 /// Write the value to char buffer, the buffer MUST be already resized
92 template <typename Iterator>
93 void operator()(Iterator buffer) const {
94 auto tmp = boost::endian::native_to_big(static_cast<BySizeType>(value));
95 const char* p = reinterpret_cast<char const*>(&tmp);
96 const char* e = p + size;
97 std::copy(p, e, buffer);
98 }
99};
100
101#if defined(__x86_64__) || defined(__aarch64__)
102// 64bit architectures have two types for 64bit integers, this is the second one
103using AltInteger =
104 std::conditional_t<std::is_same_v<Bigint, long>, long long, long>;
105static_assert(sizeof(AltInteger) == sizeof(Bigint));
106#else
107// 32bit architectures have two types for 32bit integers, this is the second one
108using AltInteger =
109 std::conditional_t<std::is_same_v<Integer, int>, long int, int>;
110static_assert(sizeof(AltInteger) == sizeof(Integer));
111#endif
112
113} // namespace detail
114
115//@{
116/** @name 2 byte integer */
117template <>
120};
121
122template <>
125};
126//@}
127
128//@{
129/** @name 4 byte integer */
130template <>
133};
134
135template <>
138};
139//@}
140
141//@{
142/** @name 8 byte integer */
143template <>
146};
147
148template <>
151};
152
153/// @cond
154template <>
158};
159
160template <>
165};
166/// @endcond
167
168//@}
169
170//@{
171/** @name boolean */
172template <>
173struct BufferParser<bool> {
174 bool& value;
175 explicit BufferParser(bool& val) : value{val} {}
176 void operator()(const FieldBuffer& buf);
177};
178
179template <>
180struct BufferFormatter<bool> {
181 bool value;
182 explicit BufferFormatter(bool val) : value(val) {}
183 template <typename Buffer>
184 void operator()(const UserTypes&, Buffer& buf) const {
185 buf.push_back(value ? 1 : 0);
186 }
187};
188//@}
189
190//@{
191/** @name C++ to PostgreSQL mapping for integral types */
192template <>
193struct CppToSystemPg<Smallint> : PredefinedOid<PredefinedOids::kInt2> {};
194template <>
195struct CppToSystemPg<Integer> : PredefinedOid<PredefinedOids::kInt4> {};
196template <>
197struct CppToSystemPg<Bigint> : PredefinedOid<PredefinedOids::kInt8> {};
198template <>
199struct CppToSystemPg<bool> : PredefinedOid<PredefinedOids::kBoolean> {};
200
201/// @cond
202template <>
205 : PredefinedOids::kInt4> {};
206/// @endcond
207
208//@}
209
210} // namespace storages::postgres::io
211
212USERVER_NAMESPACE_END