userver: userver/storages/postgres/io/integral_types.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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