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{
70 buf.length,
71 "for an integral value type (expecting size 2, 4, or 8). Not an "
72 "integer was returned from query."};
73 }
74 }
75};
76
77template <typename T>
78struct IntegralBinaryFormatter {
79 static constexpr std::size_t size = sizeof(T);
80 using BySizeType = typename IntegralType<size>::type;
81
82 T value;
83
84 explicit IntegralBinaryFormatter(T val) : value{val} {}
85 template <typename Buffer>
86 void operator()(const UserTypes&, Buffer& buf) const {
87 buf.reserve(buf.size() + size);
88 auto tmp = boost::endian::native_to_big(static_cast<BySizeType>(value));
89 const char* p = reinterpret_cast<char const*>(&tmp);
90 const char* e = p + size;
91 std::copy(p, e, std::back_inserter(buf));
92 }
93
94 /// Write the value to char buffer, the buffer MUST be already resized
95 template <typename Iterator>
96 void operator()(Iterator buffer) const {
97 auto tmp = boost::endian::native_to_big(static_cast<BySizeType>(value));
98 const char* p = reinterpret_cast<char const*>(&tmp);
99 const char* e = p + size;
100 std::copy(p, e, buffer);
101 }
102};
103
104#if defined(__x86_64__) || defined(__aarch64__)
105// 64bit architectures have two types for 64bit integers, this is the second one
106using AltInteger = std::conditional_t<std::is_same_v<Bigint, long>, long long, long>;
107static_assert(sizeof(AltInteger) == sizeof(Bigint));
108#else
109// 32bit architectures have two types for 32bit integers, this is the second one
110using AltInteger = std::conditional_t<std::is_same_v<Integer, int>, long int, int>;
111static_assert(sizeof(AltInteger) == sizeof(Integer));
112#endif
113
114} // namespace detail
115
116//@{
117/** @name 2 byte integer */
118template <>
121};
122
123template <>
126};
127//@}
128
129//@{
130/** @name 4 byte integer */
131template <>
134};
135
136template <>
139};
140//@}
141
142//@{
143/** @name 8 byte integer */
144template <>
147};
148
149template <>
152};
153
154/// @cond
155template <>
158};
159
160template <>
163};
164/// @endcond
165
166//@}
167
168//@{
169/** @name boolean */
170template <>
171struct BufferParser<bool> {
172 bool& value;
173 explicit BufferParser(bool& val) : value{val} {}
174 void operator()(const FieldBuffer& buf);
175};
176
177template <>
178struct BufferFormatter<bool> {
179 bool value;
180 explicit BufferFormatter(bool val) : value(val) {}
181 template <typename Buffer>
182 void operator()(const UserTypes&, Buffer& buf) const {
183 buf.push_back(value ? 1 : 0);
184 }
185};
186//@}
187
188//@{
189/** @name C++ to PostgreSQL mapping for integral types */
190template <>
191struct CppToSystemPg<Smallint> : PredefinedOid<PredefinedOids::kInt2> {};
192template <>
193struct CppToSystemPg<Integer> : PredefinedOid<PredefinedOids::kInt4> {};
194template <>
195struct CppToSystemPg<Bigint> : PredefinedOid<PredefinedOids::kInt8> {};
196template <>
197struct CppToSystemPg<bool> : PredefinedOid<PredefinedOids::kBoolean> {};
198
199/// @cond
200template <>
203/// @endcond
204
205//@}
206
207} // namespace storages::postgres::io
208
209USERVER_NAMESPACE_END