10#include <userver/storages/postgres/exceptions.hpp>
11#include <userver/storages/postgres/io/buffer_io.hpp>
12#include <userver/storages/postgres/io/buffer_io_base.hpp>
13#include <userver/storages/postgres/io/type_mapping.hpp>
15#include <userver/utils/flags.hpp>
17USERVER_NAMESPACE_BEGIN
23template <
typename BitContainer>
26template <
typename Enum>
29template <std::size_t N>
32template <std::size_t N>
36inline constexpr bool kIsBitStringCompatible = IsBitStringCompatible<T>::value;
38template <
typename BitContainer,
typename Enable =
void>
39struct BitContainerTraits;
41template <
typename BitContainer>
42struct BitContainerTraits<BitContainer, std::enable_if_t<std::is_integral_v<BitContainer>>> {
43 static bool TestBit(
const BitContainer& bits, std::uint8_t i) {
return bits & (1ull << i); }
44 static void SetBit(BitContainer& bits, std::uint8_t i) { bits |= (1ull << i); }
45 static constexpr std::size_t BitCount()
noexcept {
return sizeof(BitContainer) * 8; }
46 static void Reset(BitContainer& bits)
noexcept { bits = 0; }
49template <std::size_t N>
50struct BitContainerTraits<std::array<
bool, N>> {
51 static_assert(N > 0,
"Length for bit container must be at least 1");
52 using BitContainer = std::array<
bool, N>;
53 static bool TestBit(
const BitContainer& bits, std::uint8_t i) {
return bits[i]; }
54 static void SetBit(BitContainer& bits, std::uint8_t i) { bits[i] =
true; }
55 static constexpr std::size_t BitCount()
noexcept {
return N; }
56 static void Reset(BitContainer& bits)
noexcept { bits.fill(
false); }
59template <std::size_t N>
60struct BitContainerTraits<std::bitset<N>> {
61 static_assert(N > 0,
"Length for bit container must be at least 1");
62 using BitContainer = std::bitset<N>;
63 static bool TestBit(
const BitContainer& bits, std::uint8_t i) {
return bits.test(i); }
64 static void SetBit(BitContainer& bits, std::uint8_t i) { bits.set(i); }
65 static constexpr std::size_t BitCount()
noexcept {
return N; }
66 static void Reset(BitContainer& bits)
noexcept { bits.reset(); }
71enum class BitStringType { kBit, kBitVarying };
75enum class BitContainerInterface { kCommon, kFlags };
77template <
typename BitContainerRef, BitContainerInterface, BitStringType>
78struct BitStringRefWrapper {
79 static_assert(std::is_reference<BitContainerRef>::value,
"The container must be passed by reference");
81 using BitContainer = std::decay_t<BitContainerRef>;
83 io::
traits::kIsBitStringCompatible<BitContainer>,
84 "This C++ type cannot be used with PostgreSQL 'bit' and 'bit "
93template <
typename BitContainer, BitStringType>
95 static_assert(!std::is_reference<BitContainer>::value,
"The container must not be passed by reference");
98 io::
traits::kIsBitStringCompatible<BitContainer>,
99 "This C++ type cannot be used with PostgreSQL 'bit' and 'bit "
106template <BitStringType kBitStringType,
typename BitContainer>
107constexpr detail::BitStringRefWrapper<
const BitContainer&, detail::BitContainerInterface::kCommon, kBitStringType>
108BitString(
const BitContainer& bits) {
112template <BitStringType kBitStringType,
typename BitContainer>
113constexpr detail::BitStringRefWrapper<BitContainer&, detail::BitContainerInterface::kCommon, kBitStringType> BitString(
119template <BitStringType kBitStringType,
typename Enum>
120constexpr detail::BitStringRefWrapper<
121 const USERVER_NAMESPACE::utils::Flags<Enum>&,
122 detail::BitContainerInterface::kFlags,
124BitString(
const USERVER_NAMESPACE::utils::Flags<Enum>& bits) {
128template <BitStringType kBitStringType,
typename Enum>
129constexpr detail::BitStringRefWrapper<
130 USERVER_NAMESPACE::utils::Flags<Enum>&,
131 detail::BitContainerInterface::kFlags,
133BitString(USERVER_NAMESPACE::utils::Flags<Enum>& bits) {
137template <
typename BitContainer>
138constexpr auto Varbit(BitContainer&& bits) {
139 return BitString<BitStringType::kBitVarying>(std::forward<BitContainer>(bits));
142template <
typename BitContainer>
143constexpr auto Bit(BitContainer&& bits) {
144 return BitString<BitStringType::kBit>(std::forward<BitContainer>(bits));
149template <
typename BitContainerRef, BitStringType kBitStringType>
150struct BufferParser<
postgres::detail::BitStringRefWrapper<
152 postgres::detail::BitContainerInterface::kCommon,
154 : detail::BufferParserBase<
postgres::detail::BitStringRefWrapper<
156 postgres::detail::BitContainerInterface::kCommon,
158 using BitContainer = std::decay_t<BitContainerRef>;
159 using BaseType = detail::BufferParserBase<
postgres::detail::BitStringRefWrapper<
161 postgres::detail::BitContainerInterface::kCommon,
163 using BaseType::BaseType;
166 Integer bit_count{0};
168 if (
static_cast<std::size_t>((bit_count + 7) / 8) > buffer.length) {
172 auto& bits =
this->value.bits;
173 if (
const Integer target_bit_count = io::
traits::BitContainerTraits<BitContainer>::BitCount();
174 target_bit_count < bit_count)
180 io::
traits::BitContainerTraits<BitContainer>::Reset(bits);
181 for (Integer i = 0; i < bit_count; ++i) {
182 const auto* byte_cptr = buffer.buffer + (i / 8);
183 if ((*byte_cptr) & (0x80 >> (i % 8))) {
184 io::
traits::BitContainerTraits<BitContainer>::SetBit(bits, bit_count - i - 1);
190template <
typename BitContainerRef, BitStringType kBitStringType>
191struct BufferParser<
postgres::detail::BitStringRefWrapper<
193 postgres::detail::BitContainerInterface::kFlags,
195 : detail::BufferParserBase<
postgres::detail::BitStringRefWrapper<
197 postgres::detail::BitContainerInterface::kFlags,
199 using BitContainer = std::decay_t<BitContainerRef>;
200 using BaseType = detail::BufferParserBase<
postgres::detail::BitStringRefWrapper<
202 postgres::detail::BitContainerInterface::kFlags,
204 using BaseType::BaseType;
207 typename BitContainer::ValueType bits{0};
208 ReadBuffer(buffer, BitString<kBitStringType>(bits));
209 this->value.bits.SetValue(bits);
213template <
typename BitContainer, BitStringType kBitStringType>
217 using BaseType::BaseType;
219 void operator()(
const FieldBuffer& buffer) { ReadBuffer(buffer, BitString<kBitStringType>(
this->value.bits)); }
222template <std::size_t N>
223struct BufferParser<std::bitset<N>> : detail::BufferParserBase<std::bitset<N>> {
224 using BaseType = detail::BufferParserBase<std::bitset<N>>;
225 using BaseType::BaseType;
227 void operator()(
const FieldBuffer& buffer) { ReadBuffer(buffer, Varbit(
this->value)); }
230template <
typename BitContainerRef, BitStringType kBitStringType>
231struct BufferFormatter<
postgres::detail::BitStringRefWrapper<
233 postgres::detail::BitContainerInterface::kCommon,
235 : detail::BufferFormatterBase<
postgres::detail::BitStringRefWrapper<
237 postgres::detail::BitContainerInterface::kCommon,
239 using BitContainer = std::decay_t<BitContainerRef>;
240 using BaseType = detail::BufferFormatterBase<
postgres::detail::BitStringRefWrapper<
242 postgres::detail::BitContainerInterface::kCommon,
244 using BaseType::BaseType;
246 template <
typename Buffer>
247 void operator()(
const UserTypes& types, Buffer& buffer)
const {
250 const auto& bits =
this->value.bits;
251 constexpr auto bit_count = io::
traits::BitContainerTraits<BitContainer>::BitCount();
253 std::array<std::uint8_t, (bit_count + 7) / 8> data{};
254 for (std::size_t i = 0; i < bit_count; ++i) {
256 static_cast<std::uint8_t>(io::
traits::BitContainerTraits<BitContainer>::TestBit(bits, bit_count - i - 1)
261 buffer.reserve(buffer.size() +
sizeof(Integer) + data.size());
262 WriteBuffer(types, buffer,
static_cast<Integer>(bit_count));
263 buffer.insert(buffer.end(), data.begin(), data.end());
267template <
typename BitContainerRef, BitStringType kBitStringType>
268struct BufferFormatter<
postgres::detail::BitStringRefWrapper<
270 postgres::detail::BitContainerInterface::kFlags,
272 : detail::BufferFormatterBase<
postgres::detail::BitStringRefWrapper<
274 postgres::detail::BitContainerInterface::kFlags,
276 using BitContainer = std::decay_t<BitContainerRef>;
277 using BaseType = detail::BufferFormatterBase<
postgres::detail::BitStringRefWrapper<
279 postgres::detail::BitContainerInterface::kFlags,
281 using BaseType::BaseType;
283 template <
typename Buffer>
284 void operator()(
const UserTypes& types, Buffer& buffer)
const {
285 WriteBuffer(types, buffer, BitString<kBitStringType>(
this->value.bits.GetValue()));
289template <
typename BitContainer, BitStringType kBitStringType>
293 using BaseType::BaseType;
295 template <
typename Buffer>
296 void operator()(
const UserTypes& types, Buffer& buffer)
const {
297 WriteBuffer(types, buffer, BitString<kBitStringType>(
this->value.bits));
303template <std::size_t N>
304struct BufferFormatter<std::bitset<N>> : detail::BufferFormatterBase<std::bitset<N>> {
305 using BitContainer = std::bitset<N>;
306 using BaseType = detail::BufferFormatterBase<std::bitset<N>>;
307 using BaseType::BaseType;
309 template <
typename Buffer>
310 void operator()(
const UserTypes& types, Buffer& buffer)
const {
311 WriteBuffer(types, buffer, Varbit(
this->value));
315template <
typename BitContainer,
postgres::detail::BitContainerInterface ContainerInterface>
317 postgres::detail::BitStringRefWrapper<BitContainer, ContainerInterface,
postgres::BitStringType::kBitVarying>>
319template <
typename BitContainer>
323template <
typename BitContainer,
postgres::detail::BitContainerInterface ContainerInterface>
325 postgres::detail::BitStringRefWrapper<BitContainer, ContainerInterface,
postgres::BitStringType::kBit>>
327template <
typename BitContainer>
331template <std::size_t N>