Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:18

0001 /* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
0002  *
0003  * Distributed under the Boost Software License, Version 1.0. (See
0004  * accompanying file LICENSE.txt)
0005  */
0006 
0007 #ifndef BOOST_REDIS_ADAPTER_ADAPTERS_HPP
0008 #define BOOST_REDIS_ADAPTER_ADAPTERS_HPP
0009 
0010 #include <boost/redis/error.hpp>
0011 #include <boost/redis/resp3/type.hpp>
0012 #include <boost/redis/resp3/serialization.hpp>
0013 #include <boost/redis/resp3/node.hpp>
0014 #include <boost/redis/adapter/result.hpp>
0015 #include <boost/assert.hpp>
0016 
0017 #include <set>
0018 #include <optional>
0019 #include <unordered_set>
0020 #include <forward_list>
0021 #include <system_error>
0022 #include <map>
0023 #include <unordered_map>
0024 #include <list>
0025 #include <deque>
0026 #include <vector>
0027 #include <array>
0028 #include <string_view>
0029 #include <charconv>
0030 
0031 // See https://stackoverflow.com/a/31658120/1077832
0032 #include<ciso646>
0033 #ifdef _LIBCPP_VERSION
0034 #else
0035 #include <cstdlib>
0036 #endif
0037 
0038 namespace boost::redis::adapter::detail
0039 {
0040 
0041 // Serialization.
0042 
0043 template <class T>
0044 auto boost_redis_from_bulk(T& i, std::string_view sv, system::error_code& ec) -> typename std::enable_if<std::is_integral<T>::value, void>::type
0045 {
0046    auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), i);
0047    if (res.ec != std::errc())
0048       ec = redis::error::not_a_number;
0049 }
0050 
0051 inline
0052 void boost_redis_from_bulk(bool& t, std::string_view sv, system::error_code&)
0053 {
0054    t = *sv.data() == 't';
0055 }
0056 
0057 inline
0058 void boost_redis_from_bulk(double& d, std::string_view sv, system::error_code& ec)
0059 {
0060 #ifdef _LIBCPP_VERSION
0061    // The string in sv is not null terminated and we also don't know
0062    // if there is enough space at the end for a null char. The easiest
0063    // thing to do is to create a temporary.
0064    std::string const tmp{sv.data(), sv.data() + std::size(sv)};
0065    char* end{};
0066    d = std::strtod(tmp.data(), &end);
0067    if (d == HUGE_VAL || d == 0)
0068       ec = redis::error::not_a_double;
0069 #else
0070    auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), d);
0071    if (res.ec != std::errc())
0072       ec = redis::error::not_a_double;
0073 #endif // _LIBCPP_VERSION
0074 }
0075 
0076 template <class CharT, class Traits, class Allocator>
0077 void
0078 boost_redis_from_bulk(
0079    std::basic_string<CharT, Traits, Allocator>& s,
0080    std::string_view sv,
0081    system::error_code&)
0082 {
0083   s.append(sv.data(), sv.size());
0084 }
0085 
0086 //================================================
0087 
0088 template <class Result>
0089 class general_aggregate {
0090 private:
0091    Result* result_;
0092 
0093 public:
0094    explicit general_aggregate(Result* c = nullptr): result_(c) {}
0095    template <class String>
0096    void operator()(resp3::basic_node<String> const& nd, system::error_code&)
0097    {
0098       BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer");
0099       switch (nd.data_type) {
0100          case resp3::type::blob_error:
0101          case resp3::type::simple_error:
0102             *result_ = error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}};
0103             break;
0104          default:
0105             result_->value().push_back({nd.data_type, nd.aggregate_size, nd.depth, std::string{std::cbegin(nd.value), std::cend(nd.value)}});
0106       }
0107    }
0108 };
0109 
0110 template <class Node>
0111 class general_simple {
0112 private:
0113    Node* result_;
0114 
0115 public:
0116    explicit general_simple(Node* t = nullptr) : result_(t) {}
0117 
0118    template <class String>
0119    void operator()(resp3::basic_node<String> const& nd, system::error_code&)
0120    {
0121       BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer");
0122       switch (nd.data_type) {
0123          case resp3::type::blob_error:
0124          case resp3::type::simple_error:
0125             *result_ = error{nd.data_type, std::string{std::cbegin(nd.value), std::cend(nd.value)}};
0126             break;
0127          default:
0128             result_->value().data_type = nd.data_type;
0129             result_->value().aggregate_size = nd.aggregate_size;
0130             result_->value().depth = nd.depth;
0131             result_->value().value.assign(nd.value.data(), nd.value.size());
0132       }
0133    }
0134 };
0135 
0136 template <class Result>
0137 class simple_impl {
0138 public:
0139    void on_value_available(Result&) {}
0140 
0141    template <class String>
0142    void operator()(Result& result, resp3::basic_node<String> const& n, system::error_code& ec)
0143    {
0144       if (is_aggregate(n.data_type)) {
0145          ec = redis::error::expects_resp3_simple_type;
0146          return;
0147       }
0148 
0149       boost_redis_from_bulk(result, n.value, ec);
0150    }
0151 };
0152 
0153 template <class Result>
0154 class set_impl {
0155 private:
0156    typename Result::iterator hint_;
0157 
0158 public:
0159    void on_value_available(Result& result)
0160       { hint_ = std::end(result); }
0161 
0162    template <class String>
0163    void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
0164    {
0165       if (is_aggregate(nd.data_type)) {
0166          if (nd.data_type != resp3::type::set)
0167             ec = redis::error::expects_resp3_set;
0168          return;
0169       }
0170 
0171       BOOST_ASSERT(nd.aggregate_size == 1);
0172 
0173       if (nd.depth < 1) {
0174      ec = redis::error::expects_resp3_set;
0175      return;
0176       }
0177 
0178       typename Result::key_type obj;
0179       boost_redis_from_bulk(obj, nd.value, ec);
0180       hint_ = result.insert(hint_, std::move(obj));
0181    }
0182 };
0183 
0184 template <class Result>
0185 class map_impl {
0186 private:
0187    typename Result::iterator current_;
0188    bool on_key_ = true;
0189 
0190 public:
0191    void on_value_available(Result& result)
0192       { current_ = std::end(result); }
0193 
0194    template <class String>
0195    void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
0196    {
0197       if (is_aggregate(nd.data_type)) {
0198          if (element_multiplicity(nd.data_type) != 2)
0199            ec = redis::error::expects_resp3_map;
0200          return;
0201       }
0202 
0203       BOOST_ASSERT(nd.aggregate_size == 1);
0204 
0205       if (nd.depth < 1) {
0206      ec = redis::error::expects_resp3_map;
0207      return;
0208       }
0209 
0210       if (on_key_) {
0211          typename Result::key_type obj;
0212          boost_redis_from_bulk(obj, nd.value, ec);
0213          current_ = result.insert(current_, {std::move(obj), {}});
0214       } else {
0215          typename Result::mapped_type obj;
0216          boost_redis_from_bulk(obj, nd.value, ec);
0217          current_->second = std::move(obj);
0218       }
0219 
0220       on_key_ = !on_key_;
0221    }
0222 };
0223 
0224 template <class Result>
0225 class vector_impl {
0226 public:
0227    void on_value_available(Result& ) { }
0228 
0229    template <class String>
0230    void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
0231    {
0232       if (is_aggregate(nd.data_type)) {
0233          auto const m = element_multiplicity(nd.data_type);
0234          result.reserve(result.size() + m * nd.aggregate_size);
0235       } else {
0236          result.push_back({});
0237          boost_redis_from_bulk(result.back(), nd.value, ec);
0238       }
0239    }
0240 };
0241 
0242 template <class Result>
0243 class array_impl {
0244 private:
0245    int i_ = -1;
0246 
0247 public:
0248    void on_value_available(Result& ) { }
0249 
0250    template <class String>
0251    void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
0252    {
0253       if (is_aggregate(nd.data_type)) {
0254      if (i_ != -1) {
0255             ec = redis::error::nested_aggregate_not_supported;
0256             return;
0257          }
0258 
0259          if (result.size() != nd.aggregate_size * element_multiplicity(nd.data_type)) {
0260             ec = redis::error::incompatible_size;
0261             return;
0262          }
0263       } else {
0264          if (i_ == -1) {
0265             ec = redis::error::expects_resp3_aggregate;
0266             return;
0267          }
0268 
0269          BOOST_ASSERT(nd.aggregate_size == 1);
0270          boost_redis_from_bulk(result.at(i_), nd.value, ec);
0271       }
0272 
0273       ++i_;
0274    }
0275 };
0276 
0277 template <class Result>
0278 struct list_impl {
0279 
0280    void on_value_available(Result& ) { }
0281 
0282    template <class String>
0283    void operator()(Result& result, resp3::basic_node<String> const& nd, system::error_code& ec)
0284    {
0285       if (!is_aggregate(nd.data_type)) {
0286         BOOST_ASSERT(nd.aggregate_size == 1);
0287         if (nd.depth < 1) {
0288            ec = redis::error::expects_resp3_aggregate;
0289            return;
0290         }
0291 
0292         result.push_back({});
0293         boost_redis_from_bulk(result.back(), nd.value, ec);
0294       }
0295    }
0296 };
0297 
0298 //---------------------------------------------------
0299 
0300 template <class T>
0301 struct impl_map { using type = simple_impl<T>; };
0302 
0303 template <class Key, class Compare, class Allocator>
0304 struct impl_map<std::set<Key, Compare, Allocator>> { using type = set_impl<std::set<Key, Compare, Allocator>>; };
0305 
0306 template <class Key, class Compare, class Allocator>
0307 struct impl_map<std::multiset<Key, Compare, Allocator>> { using type = set_impl<std::multiset<Key, Compare, Allocator>>; };
0308 
0309 template <class Key, class Hash, class KeyEqual, class Allocator>
0310 struct impl_map<std::unordered_set<Key, Hash, KeyEqual, Allocator>> { using type = set_impl<std::unordered_set<Key, Hash, KeyEqual, Allocator>>; };
0311 
0312 template <class Key, class Hash, class KeyEqual, class Allocator>
0313 struct impl_map<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> { using type = set_impl<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>>; };
0314 
0315 template <class Key, class T, class Compare, class Allocator>
0316 struct impl_map<std::map<Key, T, Compare, Allocator>> { using type = map_impl<std::map<Key, T, Compare, Allocator>>; };
0317 
0318 template <class Key, class T, class Compare, class Allocator>
0319 struct impl_map<std::multimap<Key, T, Compare, Allocator>> { using type = map_impl<std::multimap<Key, T, Compare, Allocator>>; };
0320 
0321 template <class Key, class Hash, class KeyEqual, class Allocator>
0322 struct impl_map<std::unordered_map<Key, Hash, KeyEqual, Allocator>> { using type = map_impl<std::unordered_map<Key, Hash, KeyEqual, Allocator>>; };
0323 
0324 template <class Key, class Hash, class KeyEqual, class Allocator>
0325 struct impl_map<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>> { using type = map_impl<std::unordered_multimap<Key, Hash, KeyEqual, Allocator>>; };
0326 
0327 template <class T, class Allocator>
0328 struct impl_map<std::vector<T, Allocator>> { using type = vector_impl<std::vector<T, Allocator>>; };
0329 
0330 template <class T, std::size_t N>
0331 struct impl_map<std::array<T, N>> { using type = array_impl<std::array<T, N>>; };
0332 
0333 template <class T, class Allocator>
0334 struct impl_map<std::list<T, Allocator>> { using type = list_impl<std::list<T, Allocator>>; };
0335 
0336 template <class T, class Allocator>
0337 struct impl_map<std::deque<T, Allocator>> { using type = list_impl<std::deque<T, Allocator>>; };
0338 
0339 //---------------------------------------------------
0340 
0341 template <class>
0342 class wrapper;
0343 
0344 template <class Result>
0345 class wrapper<result<Result>> {
0346 public:
0347    using response_type = result<Result>;
0348 private:
0349    response_type* result_;
0350    typename impl_map<Result>::type impl_;
0351 
0352    template <class String>
0353    bool set_if_resp3_error(resp3::basic_node<String> const& nd) noexcept
0354    {
0355       switch (nd.data_type) {
0356          case resp3::type::null:
0357          case resp3::type::simple_error:
0358          case resp3::type::blob_error:
0359             *result_ = error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}};
0360             return true;
0361          default:
0362             return false;
0363       }
0364    }
0365 
0366 public:
0367    explicit wrapper(response_type* t = nullptr) : result_(t)
0368    {
0369       if (result_) {
0370          result_->value() = Result{};
0371          impl_.on_value_available(result_->value());
0372       }
0373    }
0374 
0375    template <class String>
0376    void operator()(resp3::basic_node<String> const& nd, system::error_code& ec)
0377    {
0378       BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer");
0379 
0380       if (result_->has_error())
0381          return;
0382 
0383       if (set_if_resp3_error(nd))
0384          return;
0385 
0386       BOOST_ASSERT(result_);
0387       impl_(result_->value(), nd, ec);
0388    }
0389 };
0390 
0391 template <class T>
0392 class wrapper<result<std::optional<T>>> {
0393 public:
0394    using response_type = result<std::optional<T>>;
0395 
0396 private:
0397    response_type* result_;
0398    typename impl_map<T>::type impl_{};
0399 
0400    template <class String>
0401    bool set_if_resp3_error(resp3::basic_node<String> const& nd) noexcept
0402    {
0403       switch (nd.data_type) {
0404          case resp3::type::blob_error:
0405          case resp3::type::simple_error:
0406             *result_ = error{nd.data_type, {std::cbegin(nd.value), std::cend(nd.value)}};
0407             return true;
0408          default:
0409             return false;
0410       }
0411    }
0412 
0413 public:
0414    explicit wrapper(response_type* o = nullptr) : result_(o) {}
0415 
0416    template <class String>
0417    void
0418    operator()(
0419       resp3::basic_node<String> const& nd,
0420       system::error_code& ec)
0421    {
0422       BOOST_ASSERT_MSG(!!result_, "Unexpected null pointer");
0423 
0424       if (result_->has_error())
0425          return;
0426 
0427       if (set_if_resp3_error(nd))
0428          return;
0429 
0430       if (nd.data_type == resp3::type::null)
0431          return;
0432 
0433       if (!result_->value().has_value()) {
0434         result_->value() = T{};
0435         impl_.on_value_available(result_->value().value());
0436       }
0437 
0438       impl_(result_->value().value(), nd, ec);
0439    }
0440 };
0441 
0442 } // boost::redis::adapter::detail
0443 
0444 #endif // BOOST_REDIS_ADAPTER_ADAPTERS_HPP