69 array(std::string_view data, connection
const &cx) :
76 constexpr std::size_t
dimensions() noexcept {
return DIMENSIONS; }
83 std::array<std::size_t, DIMENSIONS>
const &
sizes() noexcept
88 template<
typename... INDEX> ELEMENT
const &
at(INDEX... index)
const
90 static_assert(
sizeof...(index) == DIMENSIONS);
91 check_bounds(index...);
92 return m_elts.at(locate(index...));
104 template<
typename... INDEX> ELEMENT
const &
operator[](INDEX... index)
const
106 static_assert(
sizeof...(index) == DIMENSIONS);
107 return m_elts[locate(index...)];
116 constexpr auto cbegin() const noexcept {
return m_elts.cbegin(); }
118 constexpr auto cend() const noexcept {
return m_elts.cend(); }
120 constexpr auto crbegin() const noexcept {
return m_elts.crbegin(); }
122 constexpr auto crend() const noexcept {
return m_elts.crend(); }
128 constexpr std::size_t
size() const noexcept {
return m_elts.size(); }
146 constexpr auto ssize() const noexcept
148 return static_cast<std::ptrdiff_t
>(
size());
154 constexpr auto front() const noexcept {
return m_elts.front(); }
159 constexpr auto back() const noexcept {
return m_elts.back(); }
171 void check_dims(std::string_view data)
173 auto sz{std::size(data)};
174 if (sz < DIMENSIONS * 2)
176 "Trying to parse a ", DIMENSIONS,
"-dimensional array out of '", data,
189 throw conversion_error{
"Malformed array: does not start with '{'."};
190 for (std::size_t i{0}; i < DIMENSIONS; ++i)
193 "Expecting ", DIMENSIONS,
"-dimensional array, but found ", i,
".")};
194 if (data[DIMENSIONS] ==
'{')
196 "Tried to parse ", DIMENSIONS,
197 "-dimensional array from array data that has more dimensions.")};
198 for (std::size_t i{0}; i < DIMENSIONS; ++i)
199 if (data[sz - 1 - i] !=
'}')
200 throw conversion_error{
201 "Malformed array: does not end in the right number of '}'."};
206 friend class ::pqxx::field;
213 case group::MONOBYTE: parse<group::MONOBYTE>(data);
break;
214 case group::BIG5: parse<group::BIG5>(data);
break;
215 case group::EUC_CN: parse<group::EUC_CN>(data);
break;
216 case group::EUC_JP: parse<group::EUC_JP>(data);
break;
217 case group::EUC_KR: parse<group::EUC_KR>(data);
break;
218 case group::EUC_TW: parse<group::EUC_TW>(data);
break;
219 case group::GB18030: parse<group::GB18030>(data);
break;
220 case group::GBK: parse<group::GBK>(data);
break;
221 case group::JOHAB: parse<group::JOHAB>(data);
break;
222 case group::MULE_INTERNAL: parse<group::MULE_INTERNAL>(data);
break;
223 case group::SJIS: parse<group::SJIS>(data);
break;
224 case group::UHC: parse<group::UHC>(data);
break;
225 case group::UTF8: parse<group::UTF8>(data);
break;
234 std::size_t parse_field_end(std::string_view data, std::size_t here)
const
236 auto const sz{std::size(data)};
243 throw conversion_error{
"Array looks truncated."};
247 throw conversion_error{
"Array contains double separator."};
248 case '}':
throw conversion_error{
"Array contains trailing separator."};
255 "Unexpected character in array: ",
256 static_cast<unsigned>(
static_cast<unsigned char>(data[here])),
257 " where separator or closing brace expected.")};
268 constexpr std::size_t estimate_elements(std::string_view data)
const noexcept
273 auto const separators{
274 std::count(std::begin(data), std::end(data), SEPARATOR)};
278 return static_cast<std::size_t
>(separators + 1);
281 template<pqxx::
internal::encoding_group ENC>
282 void parse(std::string_view data)
284 static_assert(DIMENSIONS > 0u,
"Can't create a zero-dimensional array.");
285 auto const sz{std::size(data)};
288 m_elts.reserve(estimate_elements(data));
294 std::size_t know_extents_from{DIMENSIONS};
302 constexpr std::size_t outer{std::size_t{0u} - std::size_t{1u}};
307 std::size_t dim{outer};
311 std::array<std::size_t, DIMENSIONS> extents{};
318 if (data[here] ==
'{')
323 if (know_extents_from != DIMENSIONS)
324 throw conversion_error{
325 "Array text representation closed and reopened its outside "
332 if (dim >= (DIMENSIONS - 1))
333 throw conversion_error{
334 "Array seems to have inconsistent number of dimensions."};
342 else if (data[here] ==
'}')
345 throw conversion_error{
"Array has spurious '}'."};
346 if (dim < know_extents_from)
350 m_extents[dim] = extents[dim];
351 know_extents_from = dim;
355 if (extents[dim] != m_extents[dim])
356 throw conversion_error{
"Rows in array have inconsistent sizes."};
362 here = parse_field_end(data, here);
368 if (dim != DIMENSIONS - 1)
369 throw conversion_error{
370 "Malformed array: found element where sub-array was expected."};
371 assert(dim != outer);
376 case '\0':
throw conversion_error{
"Unexpected zero byte in array."};
377 case ',':
throw conversion_error{
"Array contains empty field."};
389 std::data(data), std::size(data), here);
391 std::string
const buf{
393 std::data(data), end, here)};
402 std::data(data), std::size(data), here);
403 std::string_view
const field{
404 std::string_view{std::data(data) + here, end - here}};
412 ". Consider making it an array of std::optional<",
421 here = parse_field_end(data, here);
426 throw conversion_error{
"Malformed array; may be truncated."};
427 assert(know_extents_from == 0);
434 void init_factors() noexcept
436 std::size_t factor{1};
437 for (std::size_t dim{DIMENSIONS - 1}; dim > 0; --dim)
439 factor *= m_extents[dim];
440 m_factors[dim - 1] = factor;
445 template<
typename... INDEX> std::size_t locate(INDEX... index)
const noexcept
448 sizeof...(index) == DIMENSIONS,
449 "Indexing array with wrong number of dimensions.");
450 return add_index(index...);
453 template<
typename OUTER,
typename... INDEX>
454 constexpr std::size_t add_index(OUTER outer, INDEX... indexes)
const noexcept
457 if constexpr (
sizeof...(indexes) == 0)
463 static_assert(
sizeof...(indexes) < DIMENSIONS);
465 constexpr auto dimension{DIMENSIONS - (
sizeof...(indexes) + 1)};
466 static_assert(dimension < DIMENSIONS);
467 return first * m_factors[dimension] + add_index(indexes...);
474 template<
typename OUTER,
typename... INDEX>
475 constexpr void check_bounds(OUTER outer, INDEX... indexes)
const
478 static_assert(
sizeof...(indexes) < DIMENSIONS);
480 constexpr auto dimension{DIMENSIONS - (
sizeof...(indexes) + 1)};
481 static_assert(dimension < DIMENSIONS);
482 if (first >= m_extents[dimension])
484 "Array index for dimension ", dimension,
" is out of bounds: ", first,
485 " >= ", m_extents[dimension])};
488 if constexpr (
sizeof...(indexes) > 0)
489 check_bounds(indexes...);
493 std::vector<ELEMENT> m_elts;
496 std::array<std::size_t, DIMENSIONS> m_extents;
506 std::array<std::size_t, DIMENSIONS - 1> m_factors;
554 explicit array_parser(
555 std::string_view input,
556 internal::encoding_group = internal::encoding_group::MONOBYTE);
565 std::pair<juncture, std::string> get_next() {
return (this->*m_impl)(); }
568 std::string_view m_input;
571 std::size_t m_pos = 0u;
579 using implementation = std::pair<juncture, std::string> (array_parser::*)();
582 static implementation
586 implementation m_impl;
589 template<pqxx::
internal::encoding_group>
590 std::pair<juncture, std::string> parse_array_step();
592 template<pqxx::
internal::encoding_group>
594 template<pqxx::
internal::encoding_group>
596 template<pqxx::
internal::encoding_group>
598 template<pqxx::
internal::encoding_group>
601 template<pqxx::
internal::encoding_group>
602 std::string::size_type scan_glyph(std::string::size_type pos)
const;
603 template<pqxx::
internal::encoding_group>
604 std::string::size_type
605 scan_glyph(std::string::size_type pos, std::string::size_type end)
const;