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;
51 static_assert(
N > 0,
"Length for bit container must be at least 1");
61 static_assert(
N > 0,
"Length for bit container must be at least 1");
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>
130 BitStringRefWrapper<USERVER_NAMESPACE::
utils::Flags<Enum>&, detail::BitContainerInterface::kFlags, kBitStringType>
131 BitString(USERVER_NAMESPACE::
utils::Flags<Enum>& bits) {
135template <
typename BitContainer>
136constexpr auto Varbit(BitContainer&& bits) {
137 return BitString<BitStringType::kBitVarying>(std::forward<BitContainer>(bits));
140template <
typename BitContainer>
141constexpr auto Bit(BitContainer&& bits) {
142 return BitString<BitStringType::kBit>(std::forward<BitContainer>(bits));
147template <
typename BitContainerRef, BitStringType kBitStringType>
150 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kCommon, kBitStringType>>
151 : detail::BufferParserBase<postgres::detail::BitStringRefWrapper<
153 postgres::detail::BitContainerInterface::kCommon,
155 using BitContainer = std::decay_t<BitContainerRef>;
156 using BaseType = detail::BufferParserBase<
158 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kCommon, kBitStringType>&&>;
159 using BaseType::BaseType;
161 void operator()(FieldBuffer buffer) {
162 Integer bit_count{0};
163 buffer.Read(bit_count, BufferCategory::kPlainBuffer);
164 if (
static_cast<std::size_t>((bit_count + 7) / 8) > buffer.length)
throw InvalidBitStringRepresentation{};
166 auto& bits =
this->value.bits;
167 if (
const Integer target_bit_count = io::traits::BitContainerTraits<BitContainer>::BitCount();
168 target_bit_count < bit_count) {
169 throw BitStringOverflow(bit_count, target_bit_count);
173 io::traits::BitContainerTraits<BitContainer>::Reset(bits);
174 for (Integer i = 0; i < bit_count; ++i) {
175 const auto* byte_cptr = buffer.buffer + (i / 8);
176 if ((*byte_cptr) & (0x80 >> (i % 8))) {
177 io::traits::BitContainerTraits<BitContainer>::SetBit(bits, bit_count - i - 1);
183template <
typename BitContainerRef, BitStringType kBitStringType>
186 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>>
187 : detail::BufferParserBase<
189 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>&&> {
190 using BitContainer = std::decay_t<BitContainerRef>;
191 using BaseType = detail::BufferParserBase<
193 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>&&>;
194 using BaseType::BaseType;
196 void operator()(FieldBuffer buffer) {
197 typename BitContainer::ValueType bits{0};
198 ReadBuffer(buffer, BitString<kBitStringType>(bits));
199 this->value.bits.SetValue(bits);
203template <
typename BitContainer, BitStringType kBitStringType>
204struct BufferParser<postgres::BitStringWrapper<BitContainer, kBitStringType>>
205 : detail::BufferParserBase<postgres::BitStringWrapper<BitContainer, kBitStringType>> {
206 using BaseType = detail::BufferParserBase<postgres::BitStringWrapper<BitContainer, kBitStringType>>;
207 using BaseType::BaseType;
209 void operator()(
const FieldBuffer& buffer) { ReadBuffer(buffer, BitString<kBitStringType>(
this->value.bits)); }
212template <std::size_t N>
213struct BufferParser<std::bitset<N>> : detail::BufferParserBase<std::bitset<N>> {
214 using BaseType = detail::BufferParserBase<std::bitset<N>>;
215 using BaseType::BaseType;
217 void operator()(
const FieldBuffer& buffer) { ReadBuffer(buffer, Varbit(
this->value)); }
220template <
typename BitContainerRef, BitStringType kBitStringType>
221struct BufferFormatter<
223 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kCommon, kBitStringType>>
224 : detail::BufferFormatterBase<
226 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kCommon, kBitStringType>> {
227 using BitContainer = std::decay_t<BitContainerRef>;
228 using BaseType = detail::BufferFormatterBase<
230 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kCommon, kBitStringType>>;
231 using BaseType::BaseType;
233 template <
typename Buffer>
234 void operator()(
const UserTypes& types, Buffer& buffer)
const {
237 const auto& bits =
this->value.bits;
238 constexpr auto bit_count = io::traits::BitContainerTraits<BitContainer>::BitCount();
240 std::array<std::uint8_t, (bit_count + 7) / 8> data{};
241 for (std::size_t i = 0; i < bit_count; ++i) {
243 static_cast<std::uint8_t>(io::traits::BitContainerTraits<BitContainer>::TestBit(bits, bit_count - i - 1)
248 buffer.reserve(buffer.size() +
sizeof(Integer) + data.size());
249 WriteBuffer(types, buffer,
static_cast<Integer>(bit_count));
250 buffer.insert(buffer.end(), data.begin(), data.end());
254template <
typename BitContainerRef, BitStringType kBitStringType>
255struct BufferFormatter<
257 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>>
258 : detail::BufferFormatterBase<
260 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>> {
261 using BitContainer = std::decay_t<BitContainerRef>;
262 using BaseType = detail::BufferFormatterBase<
264 BitStringRefWrapper<BitContainerRef, postgres::detail::BitContainerInterface::kFlags, kBitStringType>>;
265 using BaseType::BaseType;
267 template <
typename Buffer>
268 void operator()(
const UserTypes& types, Buffer& buffer)
const {
269 WriteBuffer(types, buffer, BitString<kBitStringType>(
this->value.bits.GetValue()));
273template <
typename BitContainer, BitStringType kBitStringType>
274struct BufferFormatter<postgres::BitStringWrapper<BitContainer, kBitStringType>>
275 : detail::BufferFormatterBase<postgres::BitStringWrapper<BitContainer, kBitStringType>> {
276 using BaseType = detail::BufferFormatterBase<postgres::BitStringWrapper<BitContainer, kBitStringType>>;
277 using BaseType::BaseType;
279 template <
typename Buffer>
280 void operator()(
const UserTypes& types, Buffer& buffer)
const {
281 WriteBuffer(types, buffer, BitString<kBitStringType>(
this->value.bits));
287template <std::size_t N>
288struct BufferFormatter<std::bitset<N>> : detail::BufferFormatterBase<std::bitset<N>> {
289 using BitContainer = std::bitset<N>;
290 using BaseType = detail::BufferFormatterBase<std::bitset<N>>;
291 using BaseType::BaseType;
293 template <
typename Buffer>
294 void operator()(
const UserTypes& types, Buffer& buffer)
const {
295 WriteBuffer(types, buffer, Varbit(
this->value));
299template <
typename BitContainer,
postgres::detail::BitContainerInterface kContainerInterface>
301 postgres::detail::BitStringRefWrapper<BitContainer, kContainerInterface,
postgres::BitStringType::kBitVarying>>
302 : PredefinedOid<PredefinedOids::kVarbit> {};
303template <
typename BitContainer>
305 : PredefinedOid<PredefinedOids::kVarbit> {};
307template <
typename BitContainer,
postgres::detail::BitContainerInterface kContainerInterface>
309 postgres::detail::BitStringRefWrapper<BitContainer, kContainerInterface,
postgres::BitStringType::kBit>>
310 : PredefinedOid<PredefinedOids::kBit> {};
311template <
typename BitContainer>
313 : PredefinedOid<PredefinedOids::kBit> {};
315template <std::size_t N>
316struct CppToSystemPg<std::bitset<N>> : PredefinedOid<PredefinedOids::kVarbit> {};