85.39% Lines (76/89)
75.86% Functions (22/29)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/cppalliance/http | 7 | // Official repository: https://github.com/cppalliance/http | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | #ifndef BOOST_HTTP_POLYSTORE_HPP | 10 | #ifndef BOOST_HTTP_POLYSTORE_HPP | |||||
| 11 | #define BOOST_HTTP_POLYSTORE_HPP | 11 | #define BOOST_HTTP_POLYSTORE_HPP | |||||
| 12 | 12 | |||||||
| 13 | #include <boost/http/detail/config.hpp> | 13 | #include <boost/http/detail/config.hpp> | |||||
| 14 | #include <boost/http/detail/except.hpp> | 14 | #include <boost/http/detail/except.hpp> | |||||
| 15 | #include <boost/core/typeinfo.hpp> | 15 | #include <boost/core/typeinfo.hpp> | |||||
| 16 | #include <boost/core/detail/static_assert.hpp> | 16 | #include <boost/core/detail/static_assert.hpp> | |||||
| 17 | #include <cstring> | 17 | #include <cstring> | |||||
| 18 | #include <memory> | 18 | #include <memory> | |||||
| 19 | #include <type_traits> | 19 | #include <type_traits> | |||||
| 20 | #include <unordered_map> | 20 | #include <unordered_map> | |||||
| 21 | #include <vector> | 21 | #include <vector> | |||||
| 22 | 22 | |||||||
| 23 | #if ! defined( BOOST_NO_TYPEID ) | 23 | #if ! defined( BOOST_NO_TYPEID ) | |||||
| 24 | #include <typeindex> | 24 | #include <typeindex> | |||||
| 25 | #endif | 25 | #endif | |||||
| 26 | 26 | |||||||
| 27 | namespace boost { | 27 | namespace boost { | |||||
| 28 | namespace http { | 28 | namespace http { | |||||
| 29 | 29 | |||||||
| 30 | namespace detail { | 30 | namespace detail { | |||||
| 31 | 31 | |||||||
| 32 | #if defined( BOOST_NO_TYPEID ) | 32 | #if defined( BOOST_NO_TYPEID ) | |||||
| 33 | 33 | |||||||
| 34 | struct typeindex | 34 | struct typeindex | |||||
| 35 | { | 35 | { | |||||
| 36 | typeindex( | 36 | typeindex( | |||||
| 37 | core::typeinfo const& ti) noexcept | 37 | core::typeinfo const& ti) noexcept | |||||
| 38 | : n_(std::strlen(ti.name())) | 38 | : n_(std::strlen(ti.name())) | |||||
| 39 | , ti_(&ti) | 39 | , ti_(&ti) | |||||
| 40 | { | 40 | { | |||||
| 41 | } | 41 | } | |||||
| 42 | 42 | |||||||
| 43 | std::size_t hash_code() const noexcept | 43 | std::size_t hash_code() const noexcept | |||||
| 44 | { | 44 | { | |||||
| 45 | constexpr std::size_t offset_basis = | 45 | constexpr std::size_t offset_basis = | |||||
| 46 | (sizeof(std::size_t) == 8) | 46 | (sizeof(std::size_t) == 8) | |||||
| 47 | ? 1469598103934665603ull | 47 | ? 1469598103934665603ull | |||||
| 48 | : 2166136261u; | 48 | : 2166136261u; | |||||
| 49 | constexpr std::size_t prime = | 49 | constexpr std::size_t prime = | |||||
| 50 | (sizeof(std::size_t) == 8) | 50 | (sizeof(std::size_t) == 8) | |||||
| 51 | ? 1099511628211ull | 51 | ? 1099511628211ull | |||||
| 52 | : 16777619u; | 52 | : 16777619u; | |||||
| 53 | auto const s = ti_->name(); | 53 | auto const s = ti_->name(); | |||||
| 54 | std::size_t h = offset_basis; | 54 | std::size_t h = offset_basis; | |||||
| 55 | for(std::size_t i = 0; i < n_; ++i) | 55 | for(std::size_t i = 0; i < n_; ++i) | |||||
| 56 | h = (h ^ static_cast<unsigned char>(s[i])) * prime; | 56 | h = (h ^ static_cast<unsigned char>(s[i])) * prime; | |||||
| 57 | return h; | 57 | return h; | |||||
| 58 | } | 58 | } | |||||
| 59 | 59 | |||||||
| 60 | bool operator==(typeindex const& other) const noexcept | 60 | bool operator==(typeindex const& other) const noexcept | |||||
| 61 | { | 61 | { | |||||
| 62 | return n_ == other.n_ && *ti_ == *other.ti_; | 62 | return n_ == other.n_ && *ti_ == *other.ti_; | |||||
| 63 | } | 63 | } | |||||
| 64 | 64 | |||||||
| 65 | private: | 65 | private: | |||||
| 66 | std::size_t n_; | 66 | std::size_t n_; | |||||
| 67 | core::typeinfo const* ti_; | 67 | core::typeinfo const* ti_; | |||||
| 68 | }; | 68 | }; | |||||
| 69 | 69 | |||||||
| 70 | } // detail | 70 | } // detail | |||||
| 71 | } // http | 71 | } // http | |||||
| 72 | } // boost | 72 | } // boost | |||||
| 73 | namespace std { | 73 | namespace std { | |||||
| 74 | template<> | 74 | template<> | |||||
| 75 | struct hash< boost::http::detail::typeindex > | 75 | struct hash< boost::http::detail::typeindex > | |||||
| 76 | { | 76 | { | |||||
| 77 | std::size_t operator()( | 77 | std::size_t operator()( | |||||
| 78 | boost::http::detail::typeindex const& t) const noexcept | 78 | boost::http::detail::typeindex const& t) const noexcept | |||||
| 79 | { | 79 | { | |||||
| 80 | return t.hash_code(); | 80 | return t.hash_code(); | |||||
| 81 | } | 81 | } | |||||
| 82 | }; | 82 | }; | |||||
| 83 | } // std | 83 | } // std | |||||
| 84 | namespace boost { | 84 | namespace boost { | |||||
| 85 | namespace http { | 85 | namespace http { | |||||
| 86 | namespace detail { | 86 | namespace detail { | |||||
| 87 | 87 | |||||||
| 88 | #else | 88 | #else | |||||
| 89 | 89 | |||||||
| 90 | using typeindex = std::type_index; | 90 | using typeindex = std::type_index; | |||||
| 91 | 91 | |||||||
| 92 | #endif | 92 | #endif | |||||
| 93 | 93 | |||||||
| 94 | //------------------------------------------------ | 94 | //------------------------------------------------ | |||||
| 95 | // | 95 | // | |||||
| 96 | // call_traits | 96 | // call_traits | |||||
| 97 | // | 97 | // | |||||
| 98 | //------------------------------------------------ | 98 | //------------------------------------------------ | |||||
| 99 | 99 | |||||||
| 100 | template<class... Ts> | 100 | template<class... Ts> | |||||
| 101 | struct type_list {}; | 101 | struct type_list {}; | |||||
| 102 | 102 | |||||||
| 103 | template<class T> | 103 | template<class T> | |||||
| 104 | struct call_traits : std::false_type {}; | 104 | struct call_traits : std::false_type {}; | |||||
| 105 | 105 | |||||||
| 106 | template<class R, class... Args> | 106 | template<class R, class... Args> | |||||
| 107 | struct call_traits<R(*)(Args...)> : std::true_type | 107 | struct call_traits<R(*)(Args...)> : std::true_type | |||||
| 108 | { | 108 | { | |||||
| 109 | using return_type = R; | 109 | using return_type = R; | |||||
| 110 | using arg_types = type_list<Args...>; | 110 | using arg_types = type_list<Args...>; | |||||
| 111 | }; | 111 | }; | |||||
| 112 | 112 | |||||||
| 113 | template<class R, class... Args> | 113 | template<class R, class... Args> | |||||
| 114 | struct call_traits<R(&)(Args...)> : std::true_type | 114 | struct call_traits<R(&)(Args...)> : std::true_type | |||||
| 115 | { | 115 | { | |||||
| 116 | using return_type = R; | 116 | using return_type = R; | |||||
| 117 | using arg_types = type_list<Args...>; | 117 | using arg_types = type_list<Args...>; | |||||
| 118 | }; | 118 | }; | |||||
| 119 | 119 | |||||||
| 120 | template<class C, class R, class... Args> | 120 | template<class C, class R, class... Args> | |||||
| 121 | struct call_traits<R(C::*)(Args...)> : std::true_type | 121 | struct call_traits<R(C::*)(Args...)> : std::true_type | |||||
| 122 | { | 122 | { | |||||
| 123 | using class_type = C; | 123 | using class_type = C; | |||||
| 124 | using return_type = R; | 124 | using return_type = R; | |||||
| 125 | using arg_types = type_list<Args...>; | 125 | using arg_types = type_list<Args...>; | |||||
| 126 | }; | 126 | }; | |||||
| 127 | 127 | |||||||
| 128 | template<class C, class R, class... Args> | 128 | template<class C, class R, class... Args> | |||||
| 129 | struct call_traits<R(C::*)(Args...) const> : std::true_type | 129 | struct call_traits<R(C::*)(Args...) const> : std::true_type | |||||
| 130 | { | 130 | { | |||||
| 131 | using class_type = C; | 131 | using class_type = C; | |||||
| 132 | using return_type = R; | 132 | using return_type = R; | |||||
| 133 | using arg_types = type_list<Args...>; | 133 | using arg_types = type_list<Args...>; | |||||
| 134 | }; | 134 | }; | |||||
| 135 | 135 | |||||||
| 136 | template<class R, class... Args> | 136 | template<class R, class... Args> | |||||
| 137 | struct call_traits<R(*)(Args...) noexcept> : std::true_type | 137 | struct call_traits<R(*)(Args...) noexcept> : std::true_type | |||||
| 138 | { | 138 | { | |||||
| 139 | using return_type = R; | 139 | using return_type = R; | |||||
| 140 | using arg_types = type_list<Args...>; | 140 | using arg_types = type_list<Args...>; | |||||
| 141 | }; | 141 | }; | |||||
| 142 | 142 | |||||||
| 143 | template<class R, class... Args> | 143 | template<class R, class... Args> | |||||
| 144 | struct call_traits<R(&)(Args...) noexcept> : std::true_type | 144 | struct call_traits<R(&)(Args...) noexcept> : std::true_type | |||||
| 145 | { | 145 | { | |||||
| 146 | using return_type = R; | 146 | using return_type = R; | |||||
| 147 | using arg_types = type_list<Args...>; | 147 | using arg_types = type_list<Args...>; | |||||
| 148 | }; | 148 | }; | |||||
| 149 | 149 | |||||||
| 150 | template<class C, class R, class... Args> | 150 | template<class C, class R, class... Args> | |||||
| 151 | struct call_traits<R(C::*)(Args...) noexcept> : std::true_type | 151 | struct call_traits<R(C::*)(Args...) noexcept> : std::true_type | |||||
| 152 | { | 152 | { | |||||
| 153 | using class_type = C; | 153 | using class_type = C; | |||||
| 154 | using return_type = R; | 154 | using return_type = R; | |||||
| 155 | using arg_types = type_list<Args...>; | 155 | using arg_types = type_list<Args...>; | |||||
| 156 | }; | 156 | }; | |||||
| 157 | 157 | |||||||
| 158 | template<class C, class R, class... Args> | 158 | template<class C, class R, class... Args> | |||||
| 159 | struct call_traits<R(C::*)(Args...) const noexcept> : std::true_type | 159 | struct call_traits<R(C::*)(Args...) const noexcept> : std::true_type | |||||
| 160 | { | 160 | { | |||||
| 161 | using class_type = C; | 161 | using class_type = C; | |||||
| 162 | using return_type = R; | 162 | using return_type = R; | |||||
| 163 | using arg_types = type_list<Args...>; | 163 | using arg_types = type_list<Args...>; | |||||
| 164 | }; | 164 | }; | |||||
| 165 | 165 | |||||||
| 166 | template<class F> | 166 | template<class F> | |||||
| 167 | requires requires { &F::operator(); } && | 167 | requires requires { &F::operator(); } && | |||||
| 168 | std::is_member_function_pointer_v<decltype(&F::operator())> | 168 | std::is_member_function_pointer_v<decltype(&F::operator())> | |||||
| 169 | struct call_traits<F> : call_traits<decltype(&F::operator())> {}; | 169 | struct call_traits<F> : call_traits<decltype(&F::operator())> {}; | |||||
| 170 | 170 | |||||||
| 171 | } // detail | 171 | } // detail | |||||
| 172 | 172 | |||||||
| 173 | /** A container of type-erased objects | 173 | /** A container of type-erased objects | |||||
| 174 | 174 | |||||||
| 175 | Objects are stored and retrieved by their type. | 175 | Objects are stored and retrieved by their type. | |||||
| 176 | Each type may be stored at most once. Types | 176 | Each type may be stored at most once. Types | |||||
| 177 | may specify a nested `key_type` to be used | 177 | may specify a nested `key_type` to be used | |||||
| 178 | as the unique identifier instead of the type | 178 | as the unique identifier instead of the type | |||||
| 179 | itself. In this case, a reference to the type | 179 | itself. In this case, a reference to the type | |||||
| 180 | must be convertible to a reference to the key type. | 180 | must be convertible to a reference to the key type. | |||||
| 181 | 181 | |||||||
| 182 | @par Example | 182 | @par Example | |||||
| 183 | @code | 183 | @code | |||||
| 184 | struct A | 184 | struct A | |||||
| 185 | { | 185 | { | |||||
| 186 | int i = 1; | 186 | int i = 1; | |||||
| 187 | }; | 187 | }; | |||||
| 188 | struct B | 188 | struct B | |||||
| 189 | { | 189 | { | |||||
| 190 | char c = '2'; | 190 | char c = '2'; | |||||
| 191 | }; | 191 | }; | |||||
| 192 | struct C | 192 | struct C | |||||
| 193 | { | 193 | { | |||||
| 194 | double d; | 194 | double d; | |||||
| 195 | }; | 195 | }; | |||||
| 196 | struct D : C | 196 | struct D : C | |||||
| 197 | { | 197 | { | |||||
| 198 | using key_type = C; | 198 | using key_type = C; | |||||
| 199 | D() | 199 | D() | |||||
| 200 | { | 200 | { | |||||
| 201 | d = 3.14; | 201 | d = 3.14; | |||||
| 202 | } | 202 | } | |||||
| 203 | }; | 203 | }; | |||||
| 204 | polystore ps; | 204 | polystore ps; | |||||
| 205 | A& a = ps.emplace<A>(); | 205 | A& a = ps.emplace<A>(); | |||||
| 206 | B& b = ps.insert(B{}); | 206 | B& b = ps.insert(B{}); | |||||
| 207 | C& c = ps.emplace<C>(); | 207 | C& c = ps.emplace<C>(); | |||||
| 208 | assert(ps.get<A>().i == 1); | 208 | assert(ps.get<A>().i == 1); | |||||
| 209 | assert(ps.get<B>().c == '2'); | 209 | assert(ps.get<B>().c == '2'); | |||||
| 210 | assert(ps.get<C>().d == 3.14); | 210 | assert(ps.get<C>().d == 3.14); | |||||
| 211 | invoke(ps, [](A& a){ a.i = 0; }); | 211 | invoke(ps, [](A& a){ a.i = 0; }); | |||||
| 212 | invoke(ps, [](A const&, B& b){ b.c = 0; }); | 212 | invoke(ps, [](A const&, B& b){ b.c = 0; }); | |||||
| 213 | assert(ps.get<A>().i == 0); | 213 | assert(ps.get<A>().i == 0); | |||||
| 214 | assert(ps.get<B>().c == 0); | 214 | assert(ps.get<B>().c == 0); | |||||
| 215 | @endcode | 215 | @endcode | |||||
| 216 | */ | 216 | */ | |||||
| 217 | class polystore | 217 | class polystore | |||||
| 218 | { | 218 | { | |||||
| 219 | template<class T, class = void> | 219 | template<class T, class = void> | |||||
| 220 | struct get_key : std::false_type | 220 | struct get_key : std::false_type | |||||
| 221 | { | 221 | { | |||||
| 222 | }; | 222 | }; | |||||
| 223 | 223 | |||||||
| 224 | template<class T> | 224 | template<class T> | |||||
| 225 | struct get_key<T, typename std::enable_if< | 225 | struct get_key<T, typename std::enable_if< | |||||
| 226 | ! std::is_same<T, typename T::key_type>::value>::type> | 226 | ! std::is_same<T, typename T::key_type>::value>::type> | |||||
| 227 | : std::true_type | 227 | : std::true_type | |||||
| 228 | { | 228 | { | |||||
| 229 | using type = typename T::key_type; | 229 | using type = typename T::key_type; | |||||
| 230 | }; | 230 | }; | |||||
| 231 | 231 | |||||||
| 232 | public: | 232 | public: | |||||
| 233 | /** Destructor | 233 | /** Destructor | |||||
| 234 | 234 | |||||||
| 235 | All objects stored in the container are destroyed in | 235 | All objects stored in the container are destroyed in | |||||
| 236 | the reverse order of construction. | 236 | the reverse order of construction. | |||||
| 237 | */ | 237 | */ | |||||
| 238 | BOOST_HTTP_DECL | 238 | BOOST_HTTP_DECL | |||||
| 239 | ~polystore(); | 239 | ~polystore(); | |||||
| 240 | 240 | |||||||
| 241 | /** Constructor | 241 | /** Constructor | |||||
| 242 | The moved-from container will be empty. | 242 | The moved-from container will be empty. | |||||
| 243 | */ | 243 | */ | |||||
| 244 | BOOST_HTTP_DECL | 244 | BOOST_HTTP_DECL | |||||
| 245 | polystore(polystore&& other) noexcept; | 245 | polystore(polystore&& other) noexcept; | |||||
| 246 | 246 | |||||||
| 247 | /** Assignment operator | 247 | /** Assignment operator | |||||
| 248 | The moved-from container will be empty. | 248 | The moved-from container will be empty. | |||||
| 249 | @return A reference to `*this`. | 249 | @return A reference to `*this`. | |||||
| 250 | */ | 250 | */ | |||||
| 251 | BOOST_HTTP_DECL | 251 | BOOST_HTTP_DECL | |||||
| 252 | polystore& operator=(polystore&& other) noexcept; | 252 | polystore& operator=(polystore&& other) noexcept; | |||||
| 253 | 253 | |||||||
| 254 | /** Constructor | 254 | /** Constructor | |||||
| 255 | The container is initially empty. | 255 | The container is initially empty. | |||||
| 256 | */ | 256 | */ | |||||
| HITCBC | 257 | 234 | polystore() = default; | 257 | 234 | polystore() = default; | ||
| 258 | 258 | |||||||
| 259 | /** Return a pointer to the object associated with type `T`, or `nullptr` | 259 | /** Return a pointer to the object associated with type `T`, or `nullptr` | |||||
| 260 | 260 | |||||||
| 261 | If no object associated with `T` exists in the container, | 261 | If no object associated with `T` exists in the container, | |||||
| 262 | `nullptr` is returned. | 262 | `nullptr` is returned. | |||||
| 263 | 263 | |||||||
| 264 | @par Thread Safety | 264 | @par Thread Safety | |||||
| 265 | `const` member function calls are thread-safe. | 265 | `const` member function calls are thread-safe. | |||||
| 266 | Calls to non-`const` member functions must not run concurrently | 266 | Calls to non-`const` member functions must not run concurrently | |||||
| 267 | with other member functions on the same object. | 267 | with other member functions on the same object. | |||||
| 268 | 268 | |||||||
| 269 | @tparam T The type of object to find. | 269 | @tparam T The type of object to find. | |||||
| 270 | @return A pointer to the associated object, or `nullptr` if none exists. | 270 | @return A pointer to the associated object, or `nullptr` if none exists. | |||||
| 271 | */ | 271 | */ | |||||
| 272 | template<class T> | 272 | template<class T> | |||||
| HITCBC | 273 | 69 | T* find() const noexcept | 273 | 69 | T* find() const noexcept | ||
| 274 | { | 274 | { | |||||
| HITCBC | 275 | 69 | return static_cast<T*>(find(BOOST_CORE_TYPEID(T))); | 275 | 69 | return static_cast<T*>(find(BOOST_CORE_TYPEID(T))); | ||
| 276 | } | 276 | } | |||||
| 277 | 277 | |||||||
| 278 | /** Assign the pointer for the object associated with `T`, or `nullptr`. | 278 | /** Assign the pointer for the object associated with `T`, or `nullptr`. | |||||
| 279 | 279 | |||||||
| 280 | If no object of type `T` is stored, @p t is set to `nullptr`. | 280 | If no object of type `T` is stored, @p t is set to `nullptr`. | |||||
| 281 | 281 | |||||||
| 282 | @par Thread Safety | 282 | @par Thread Safety | |||||
| 283 | `const` member functions are thread-safe. Non-`const` functions | 283 | `const` member functions are thread-safe. Non-`const` functions | |||||
| 284 | must not run concurrently with any other member function on the | 284 | must not run concurrently with any other member function on the | |||||
| 285 | same instance. | 285 | same instance. | |||||
| 286 | 286 | |||||||
| 287 | @param t The pointer to assign. | 287 | @param t The pointer to assign. | |||||
| 288 | @return `true` if an object of type `T` is present, otherwise `false`. | 288 | @return `true` if an object of type `T` is present, otherwise `false`. | |||||
| 289 | */ | 289 | */ | |||||
| 290 | template<class T> | 290 | template<class T> | |||||
| 291 | bool find(T*& t) const noexcept | 291 | bool find(T*& t) const noexcept | |||||
| 292 | { | 292 | { | |||||
| 293 | t = find<T>(); | 293 | t = find<T>(); | |||||
| 294 | return t != nullptr; | 294 | return t != nullptr; | |||||
| 295 | } | 295 | } | |||||
| 296 | 296 | |||||||
| 297 | /** Return a reference to the object associated with type T | 297 | /** Return a reference to the object associated with type T | |||||
| 298 | 298 | |||||||
| 299 | If no such object exists in the container, an exception is thrown. | 299 | If no such object exists in the container, an exception is thrown. | |||||
| 300 | 300 | |||||||
| 301 | @par Exception Safety | 301 | @par Exception Safety | |||||
| 302 | Strong guarantee. | 302 | Strong guarantee. | |||||
| 303 | 303 | |||||||
| 304 | @par Thread Safety | 304 | @par Thread Safety | |||||
| 305 | Calls to `const` member functions are thread-safe. | 305 | Calls to `const` member functions are thread-safe. | |||||
| 306 | Calls to non-`const` member functions must not run concurrently | 306 | Calls to non-`const` member functions must not run concurrently | |||||
| 307 | with other member functions on the same object. | 307 | with other member functions on the same object. | |||||
| 308 | 308 | |||||||
| 309 | @throws std::bad_typeid | 309 | @throws std::bad_typeid | |||||
| 310 | If no object associated with type `T` is present. | 310 | If no object associated with type `T` is present. | |||||
| 311 | @tparam T The type of object to retrieve. | 311 | @tparam T The type of object to retrieve. | |||||
| 312 | @return A reference to the associated object. | 312 | @return A reference to the associated object. | |||||
| 313 | */ | 313 | */ | |||||
| 314 | template<class T> | 314 | template<class T> | |||||
| HITCBC | 315 | 34 | T& get() const | 315 | 34 | T& get() const | ||
| 316 | { | 316 | { | |||||
| HITCBC | 317 | 34 | if(auto t = find<T>()) | 317 | 34 | if(auto t = find<T>()) | ||
| HITCBC | 318 | 33 | return *t; | 318 | 33 | return *t; | ||
| HITCBC | 319 | 1 | detail::throw_bad_typeid(); | 319 | 1 | detail::throw_bad_typeid(); | ||
| 320 | } | 320 | } | |||||
| 321 | 321 | |||||||
| 322 | /** Construct and insert an anonymous object into the container | 322 | /** Construct and insert an anonymous object into the container | |||||
| 323 | 323 | |||||||
| 324 | A new object of type `T` is constructed in place using the provided | 324 | A new object of type `T` is constructed in place using the provided | |||||
| 325 | arguments and inserted into the container without associating it | 325 | arguments and inserted into the container without associating it | |||||
| 326 | with any key. A reference to the stored object is returned. | 326 | with any key. A reference to the stored object is returned. | |||||
| 327 | 327 | |||||||
| 328 | @par Exception Safety | 328 | @par Exception Safety | |||||
| 329 | Strong guarantee. | 329 | Strong guarantee. | |||||
| 330 | 330 | |||||||
| 331 | @par Thread Safety | 331 | @par Thread Safety | |||||
| 332 | Not thread-safe. | 332 | Not thread-safe. | |||||
| 333 | 333 | |||||||
| 334 | @tparam T The type of object to construct and insert. | 334 | @tparam T The type of object to construct and insert. | |||||
| 335 | @param args Arguments forwarded to the constructor of `T`. | 335 | @param args Arguments forwarded to the constructor of `T`. | |||||
| 336 | @return A reference to the inserted object. | 336 | @return A reference to the inserted object. | |||||
| 337 | */ | 337 | */ | |||||
| 338 | template<class T, class... Args> | 338 | template<class T, class... Args> | |||||
| HITCBC | 339 | 2 | T& emplace_anon(Args&&... args) | 339 | 2 | T& emplace_anon(Args&&... args) | ||
| 340 | { | 340 | { | |||||
| HITCBC | 341 | 4 | return *static_cast<T*>(insert_impl( | 341 | 4 | return *static_cast<T*>(insert_impl( | ||
| HITCBC | 342 | 4 | make_any<T>(std::forward<Args>(args)...))); | 342 | 4 | make_any<T>(std::forward<Args>(args)...))); | ||
| 343 | } | 343 | } | |||||
| 344 | 344 | |||||||
| 345 | /** Insert an anonymous object by moving or copying it into the container | 345 | /** Insert an anonymous object by moving or copying it into the container | |||||
| 346 | 346 | |||||||
| 347 | A new object of type `T` is inserted into the container without | 347 | A new object of type `T` is inserted into the container without | |||||
| 348 | associating it with any key. The object is move-constructed or | 348 | associating it with any key. The object is move-constructed or | |||||
| 349 | copy-constructed from the provided argument, and a reference to | 349 | copy-constructed from the provided argument, and a reference to | |||||
| 350 | the stored object is returned. | 350 | the stored object is returned. | |||||
| 351 | 351 | |||||||
| 352 | @par Exception Safety | 352 | @par Exception Safety | |||||
| 353 | Strong guarantee. | 353 | Strong guarantee. | |||||
| 354 | 354 | |||||||
| 355 | @par Thread Safety | 355 | @par Thread Safety | |||||
| 356 | Not thread-safe. | 356 | Not thread-safe. | |||||
| 357 | 357 | |||||||
| 358 | @tparam T The type of object to insert. | 358 | @tparam T The type of object to insert. | |||||
| 359 | @param t The object to insert. | 359 | @param t The object to insert. | |||||
| 360 | @return A reference to the inserted object. | 360 | @return A reference to the inserted object. | |||||
| 361 | */ | 361 | */ | |||||
| 362 | template<class T> | 362 | template<class T> | |||||
| 363 | T& insert_anon(T&& t) | 363 | T& insert_anon(T&& t) | |||||
| 364 | { | 364 | { | |||||
| 365 | return emplace_anon<typename | 365 | return emplace_anon<typename | |||||
| 366 | std::remove_cv<T>::type>( | 366 | std::remove_cv<T>::type>( | |||||
| 367 | std::forward<T>(t)); | 367 | std::forward<T>(t)); | |||||
| 368 | } | 368 | } | |||||
| 369 | 369 | |||||||
| 370 | /** Construct and insert an object with a nested key type | 370 | /** Construct and insert an object with a nested key type | |||||
| 371 | 371 | |||||||
| 372 | A new object of type `T` is constructed in place using the provided | 372 | A new object of type `T` is constructed in place using the provided | |||||
| 373 | arguments and inserted into the container. The type `T` must define | 373 | arguments and inserted into the container. The type `T` must define | |||||
| 374 | a nested type `key_type`, which is used as the key for insertion. | 374 | a nested type `key_type`, which is used as the key for insertion. | |||||
| 375 | No additional key types may be specified. The type `T&` must be | 375 | No additional key types may be specified. The type `T&` must be | |||||
| 376 | convertible to a reference to `key_type`. | 376 | convertible to a reference to `key_type`. | |||||
| 377 | 377 | |||||||
| 378 | @par Constraints | 378 | @par Constraints | |||||
| 379 | `T::key_type` must name a type. | 379 | `T::key_type` must name a type. | |||||
| 380 | 380 | |||||||
| 381 | @par Exception Safety | 381 | @par Exception Safety | |||||
| 382 | Strong guarantee. | 382 | Strong guarantee. | |||||
| 383 | 383 | |||||||
| 384 | @par Thread Safety | 384 | @par Thread Safety | |||||
| 385 | Not thread-safe. | 385 | Not thread-safe. | |||||
| 386 | 386 | |||||||
| 387 | @throws std::invalid_argument On duplicate insertion. | 387 | @throws std::invalid_argument On duplicate insertion. | |||||
| 388 | @tparam T The type of object to construct and insert. | 388 | @tparam T The type of object to construct and insert. | |||||
| 389 | @param args Arguments forwarded to the constructor of `T`. | 389 | @param args Arguments forwarded to the constructor of `T`. | |||||
| 390 | @return A reference to the inserted object. | 390 | @return A reference to the inserted object. | |||||
| 391 | */ | 391 | */ | |||||
| 392 | template<class T, class... Keys, class... Args> | 392 | template<class T, class... Keys, class... Args> | |||||
| HITCBC | 393 | 3 | auto emplace(Args&&... args) -> | 393 | 3 | auto emplace(Args&&... args) -> | ||
| 394 | typename std::enable_if<get_key<T>::value, T&>::type | 394 | typename std::enable_if<get_key<T>::value, T&>::type | |||||
| 395 | { | 395 | { | |||||
| 396 | // Can't have Keys with nested key_type | 396 | // Can't have Keys with nested key_type | |||||
| 397 | BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0); | 397 | BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0); | |||||
| 398 | // T& must be convertible to key_type& | 398 | // T& must be convertible to key_type& | |||||
| 399 | BOOST_CORE_STATIC_ASSERT(std::is_convertible< | 399 | BOOST_CORE_STATIC_ASSERT(std::is_convertible< | |||||
| 400 | T&, typename get_key<T>::type&>::value); | 400 | T&, typename get_key<T>::type&>::value); | |||||
| HITCBC | 401 | 3 | auto p = make_any<T>(std::forward<Args>(args)...); | 401 | 3 | auto p = make_any<T>(std::forward<Args>(args)...); | ||
| HITCBC | 402 | 3 | keyset<T, typename get_key<T>::type> ks( | 402 | 3 | keyset<T, typename get_key<T>::type> ks( | ||
| HITCBC | 403 | 3 | *static_cast<T*>(p->get())); | 403 | 3 | *static_cast<T*>(p->get())); | ||
| HITCBC | 404 | 6 | return *static_cast<T*>(insert_impl( | 404 | 6 | return *static_cast<T*>(insert_impl( | ||
| HITCBC | 405 | 7 | std::move(p), ks.kn, ks.N)); | 405 | 7 | std::move(p), ks.kn, ks.N)); | ||
| HITCBC | 406 | 3 | } | 406 | 3 | } | ||
| 407 | 407 | |||||||
| 408 | /** Construct and insert an object into the container | 408 | /** Construct and insert an object into the container | |||||
| 409 | 409 | |||||||
| 410 | A new object of type `T` is constructed in place using the provided | 410 | A new object of type `T` is constructed in place using the provided | |||||
| 411 | arguments and inserted into the container. The type `T` must not | 411 | arguments and inserted into the container. The type `T` must not | |||||
| 412 | already exist in the container, nor may any of the additional key | 412 | already exist in the container, nor may any of the additional key | |||||
| 413 | types refer to an existing object. The type `T&` must be convertible | 413 | types refer to an existing object. The type `T&` must be convertible | |||||
| 414 | to a reference to each specified key type. | 414 | to a reference to each specified key type. | |||||
| 415 | 415 | |||||||
| 416 | @par Constraints | 416 | @par Constraints | |||||
| 417 | `T::key_type` must not name a type. | 417 | `T::key_type` must not name a type. | |||||
| 418 | 418 | |||||||
| 419 | @par Exception Safety | 419 | @par Exception Safety | |||||
| 420 | Strong guarantee. | 420 | Strong guarantee. | |||||
| 421 | 421 | |||||||
| 422 | @par Thread Safety | 422 | @par Thread Safety | |||||
| 423 | Not thread-safe. | 423 | Not thread-safe. | |||||
| 424 | 424 | |||||||
| 425 | @throws std::invalid_argument On duplicate insertion. | 425 | @throws std::invalid_argument On duplicate insertion. | |||||
| 426 | @tparam T The type of object to construct and insert. | 426 | @tparam T The type of object to construct and insert. | |||||
| 427 | @tparam Keys Optional key types associated with the object. | 427 | @tparam Keys Optional key types associated with the object. | |||||
| 428 | @param args Arguments forwarded to the constructor of `T`. | 428 | @param args Arguments forwarded to the constructor of `T`. | |||||
| 429 | @return A reference to the inserted object. | 429 | @return A reference to the inserted object. | |||||
| 430 | */ | 430 | */ | |||||
| 431 | template<class T, class... Keys, class... Args> | 431 | template<class T, class... Keys, class... Args> | |||||
| HITCBC | 432 | 11 | auto emplace(Args&&... args) -> | 432 | 11 | auto emplace(Args&&... args) -> | ||
| 433 | typename std::enable_if<! get_key<T>::value, T&>::type | 433 | typename std::enable_if<! get_key<T>::value, T&>::type | |||||
| 434 | { | 434 | { | |||||
| 435 | // T& must be convertible to each of Keys& | 435 | // T& must be convertible to each of Keys& | |||||
| 436 | BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...)); | 436 | BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...)); | |||||
| HITCBC | 437 | 11 | auto p = make_any<T>(std::forward<Args>(args)...); | 437 | 11 | auto p = make_any<T>(std::forward<Args>(args)...); | ||
| HITCBC | 438 | 11 | keyset<T, Keys...> ks(*static_cast<T*>(p->get())); | 438 | 11 | keyset<T, Keys...> ks(*static_cast<T*>(p->get())); | ||
| HITCBC | 439 | 22 | return *static_cast<T*>(insert_impl( | 439 | 22 | return *static_cast<T*>(insert_impl( | ||
| HITCBC | 440 | 27 | std::move(p), ks.kn, ks.N)); | 440 | 27 | std::move(p), ks.kn, ks.N)); | ||
| HITCBC | 441 | 11 | } | 441 | 11 | } | ||
| 442 | 442 | |||||||
| 443 | /** Return an existing object, creating it if necessary | 443 | /** Return an existing object, creating it if necessary | |||||
| 444 | 444 | |||||||
| 445 | If an object of the exact type `T` already exists in the container, | 445 | If an object of the exact type `T` already exists in the container, | |||||
| 446 | a reference to that object is returned. Otherwise, a new object is | 446 | a reference to that object is returned. Otherwise, a new object is | |||||
| 447 | constructed in place using the provided arguments, and a reference | 447 | constructed in place using the provided arguments, and a reference | |||||
| 448 | to the newly created object is returned. The type `T` must not | 448 | to the newly created object is returned. The type `T` must not | |||||
| 449 | already exist in the container, nor may any of the additional key | 449 | already exist in the container, nor may any of the additional key | |||||
| 450 | types refer to an existing object. The type `T` must be convertible | 450 | types refer to an existing object. The type `T` must be convertible | |||||
| 451 | to a reference to each additional key type. | 451 | to a reference to each additional key type. | |||||
| 452 | 452 | |||||||
| 453 | @par Exception Safety | 453 | @par Exception Safety | |||||
| 454 | Strong guarantee. | 454 | Strong guarantee. | |||||
| 455 | 455 | |||||||
| 456 | @par Thread Safety | 456 | @par Thread Safety | |||||
| 457 | Not thread-safe. | 457 | Not thread-safe. | |||||
| 458 | 458 | |||||||
| 459 | @throws std::invalid_argument On duplicate insertion. | 459 | @throws std::invalid_argument On duplicate insertion. | |||||
| 460 | @tparam T The type of object to return or create. | 460 | @tparam T The type of object to return or create. | |||||
| 461 | @tparam Keys Optional key types associated with the object. | 461 | @tparam Keys Optional key types associated with the object. | |||||
| 462 | @param args Arguments forwarded to the constructor of `T`. | 462 | @param args Arguments forwarded to the constructor of `T`. | |||||
| 463 | @return A reference to the existing or newly created object. | 463 | @return A reference to the existing or newly created object. | |||||
| 464 | */ | 464 | */ | |||||
| 465 | template<class T, class... Keys, class... Args> | 465 | template<class T, class... Keys, class... Args> | |||||
| HITCBC | 466 | 2 | auto try_emplace(Args&&... args) -> | 466 | 2 | auto try_emplace(Args&&... args) -> | ||
| 467 | typename std::enable_if<get_key<T>::value, T&>::type | 467 | typename std::enable_if<get_key<T>::value, T&>::type | |||||
| 468 | { | 468 | { | |||||
| 469 | // Can't have Keys with nested key_type | 469 | // Can't have Keys with nested key_type | |||||
| 470 | BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0); | 470 | BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0); | |||||
| 471 | // T& must be convertible to key_type& | 471 | // T& must be convertible to key_type& | |||||
| 472 | BOOST_CORE_STATIC_ASSERT(std::is_convertible< | 472 | BOOST_CORE_STATIC_ASSERT(std::is_convertible< | |||||
| 473 | T&, typename get_key<T>::type&>::value); | 473 | T&, typename get_key<T>::type&>::value); | |||||
| HITCBC | 474 | 2 | if(auto t = find<T>()) | 474 | 2 | if(auto t = find<T>()) | ||
| HITCBC | 475 | 1 | return *t; | 475 | 1 | return *t; | ||
| HITCBC | 476 | 1 | auto p = make_any<T>(std::forward<Args>(args)...); | 476 | 1 | auto p = make_any<T>(std::forward<Args>(args)...); | ||
| HITCBC | 477 | 1 | keyset<T, typename get_key<T>::type> ks( | 477 | 1 | keyset<T, typename get_key<T>::type> ks( | ||
| HITCBC | 478 | 1 | *static_cast<T*>(p->get())); | 478 | 1 | *static_cast<T*>(p->get())); | ||
| HITCBC | 479 | 2 | return *static_cast<T*>(insert_impl( | 479 | 2 | return *static_cast<T*>(insert_impl( | ||
| HITCBC | 480 | 2 | std::move(p), ks.kn, ks.N)); | 480 | 2 | std::move(p), ks.kn, ks.N)); | ||
| HITCBC | 481 | 1 | } | 481 | 1 | } | ||
| 482 | 482 | |||||||
| 483 | /** Return an existing object, creating it if necessary | 483 | /** Return an existing object, creating it if necessary | |||||
| 484 | 484 | |||||||
| 485 | If an object of the exact type `T` already exists in the container, | 485 | If an object of the exact type `T` already exists in the container, | |||||
| 486 | a reference to that object is returned. Otherwise, a new object is | 486 | a reference to that object is returned. Otherwise, a new object is | |||||
| 487 | constructed in place using the provided arguments, and a reference | 487 | constructed in place using the provided arguments, and a reference | |||||
| 488 | to the newly created object is returned. The type `T` must not | 488 | to the newly created object is returned. The type `T` must not | |||||
| 489 | already exist in the container, nor may any of the additional key | 489 | already exist in the container, nor may any of the additional key | |||||
| 490 | types refer to an existing object. The type `T` must be convertible | 490 | types refer to an existing object. The type `T` must be convertible | |||||
| 491 | to a reference to each additional key type. | 491 | to a reference to each additional key type. | |||||
| 492 | 492 | |||||||
| 493 | @par Exception Safety | 493 | @par Exception Safety | |||||
| 494 | Strong guarantee. | 494 | Strong guarantee. | |||||
| 495 | 495 | |||||||
| 496 | @par Thread Safety | 496 | @par Thread Safety | |||||
| 497 | `const` member function calls are thread-safe. | 497 | `const` member function calls are thread-safe. | |||||
| 498 | Calls to non-`const` member functions must not run concurrently | 498 | Calls to non-`const` member functions must not run concurrently | |||||
| 499 | with other member functions on the same object. | 499 | with other member functions on the same object. | |||||
| 500 | 500 | |||||||
| 501 | @throws std::invalid_argument On duplicate insertion. | 501 | @throws std::invalid_argument On duplicate insertion. | |||||
| 502 | @tparam T The type of object to return or create. | 502 | @tparam T The type of object to return or create. | |||||
| 503 | @tparam Keys Optional key types associated with the object. | 503 | @tparam Keys Optional key types associated with the object. | |||||
| 504 | @param args Arguments forwarded to the constructor of `T`. | 504 | @param args Arguments forwarded to the constructor of `T`. | |||||
| 505 | @return A reference to the existing or newly created object. | 505 | @return A reference to the existing or newly created object. | |||||
| 506 | */ | 506 | */ | |||||
| 507 | template<class T, class... Keys, class... Args> | 507 | template<class T, class... Keys, class... Args> | |||||
| HITCBC | 508 | 2 | auto try_emplace(Args&&... args) -> | 508 | 2 | auto try_emplace(Args&&... args) -> | ||
| 509 | typename std::enable_if<! get_key<T>::value, T&>::type | 509 | typename std::enable_if<! get_key<T>::value, T&>::type | |||||
| 510 | { | 510 | { | |||||
| 511 | // T& must be convertible to each of Keys& | 511 | // T& must be convertible to each of Keys& | |||||
| 512 | BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...)); | 512 | BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...)); | |||||
| HITCBC | 513 | 2 | if(auto t = find<T>()) | 513 | 2 | if(auto t = find<T>()) | ||
| HITCBC | 514 | 1 | return *t; | 514 | 1 | return *t; | ||
| HITCBC | 515 | 1 | auto p = make_any<T>(std::forward<Args>(args)...); | 515 | 1 | auto p = make_any<T>(std::forward<Args>(args)...); | ||
| HITCBC | 516 | 1 | keyset<T, Keys...> ks(*static_cast<T*>(p->get())); | 516 | 1 | keyset<T, Keys...> ks(*static_cast<T*>(p->get())); | ||
| HITCBC | 517 | 2 | return *static_cast<T*>(insert_impl( | 517 | 2 | return *static_cast<T*>(insert_impl( | ||
| HITCBC | 518 | 2 | std::move(p), ks.kn, ks.N)); | 518 | 2 | std::move(p), ks.kn, ks.N)); | ||
| HITCBC | 519 | 1 | } | 519 | 1 | } | ||
| 520 | 520 | |||||||
| 521 | /** Insert an object by moving or copying it into the container | 521 | /** Insert an object by moving or copying it into the container | |||||
| 522 | 522 | |||||||
| 523 | If an object of the same type `T` already exists in the container, | 523 | If an object of the same type `T` already exists in the container, | |||||
| 524 | or if any of the additional key types would refer to an existing | 524 | or if any of the additional key types would refer to an existing | |||||
| 525 | object, an exception is thrown. Otherwise, the object is inserted | 525 | object, an exception is thrown. Otherwise, the object is inserted | |||||
| 526 | by move or copy construction, and a reference to the stored object | 526 | by move or copy construction, and a reference to the stored object | |||||
| 527 | is returned. The type `T` must be convertible to a reference to each | 527 | is returned. The type `T` must be convertible to a reference to each | |||||
| 528 | additional key type. | 528 | additional key type. | |||||
| 529 | 529 | |||||||
| 530 | @par Exception Safety | 530 | @par Exception Safety | |||||
| 531 | Strong guarantee. | 531 | Strong guarantee. | |||||
| 532 | 532 | |||||||
| 533 | @par Thread Safety | 533 | @par Thread Safety | |||||
| 534 | Not thread-safe. | 534 | Not thread-safe. | |||||
| 535 | 535 | |||||||
| 536 | @throws std::invalid_argument On duplicate insertion. | 536 | @throws std::invalid_argument On duplicate insertion. | |||||
| 537 | @tparam T The type of object to insert. | 537 | @tparam T The type of object to insert. | |||||
| 538 | @tparam Keys Optional key types associated with the object. | 538 | @tparam Keys Optional key types associated with the object. | |||||
| 539 | @param t The object to insert. | 539 | @param t The object to insert. | |||||
| 540 | @return A reference to the inserted object. | 540 | @return A reference to the inserted object. | |||||
| 541 | */ | 541 | */ | |||||
| 542 | template<class T, class... Keys> | 542 | template<class T, class... Keys> | |||||
| HITCBC | 543 | 3 | T& insert(T&& t) | 543 | 3 | T& insert(T&& t) | ||
| 544 | { | 544 | { | |||||
| 545 | return emplace<typename | 545 | return emplace<typename | |||||
| HITCBC | 546 | 3 | std::remove_cv<T>::type, Keys...>( | 546 | 3 | std::remove_cv<T>::type, Keys...>( | ||
| HITCBC | 547 | 3 | std::forward<T>(t)); | 547 | 3 | std::forward<T>(t)); | ||
| 548 | } | 548 | } | |||||
| 549 | 549 | |||||||
| 550 | /** Return an existing object or create a new one | 550 | /** Return an existing object or create a new one | |||||
| 551 | 551 | |||||||
| 552 | If an object of the exact type `T` already exists in the container, | 552 | If an object of the exact type `T` already exists in the container, | |||||
| 553 | a reference to that object is returned. Otherwise, a new object of | 553 | a reference to that object is returned. Otherwise, a new object of | |||||
| 554 | type `T` is default-constructed in the container, and a reference | 554 | type `T` is default-constructed in the container, and a reference | |||||
| 555 | to the newly created object is returned. This function ignores | 555 | to the newly created object is returned. This function ignores | |||||
| 556 | nested key types and cannot be used to specify additional keys. | 556 | nested key types and cannot be used to specify additional keys. | |||||
| 557 | 557 | |||||||
| 558 | @par Constraints | 558 | @par Constraints | |||||
| 559 | `T` must be default-constructible. | 559 | `T` must be default-constructible. | |||||
| 560 | 560 | |||||||
| 561 | @par Exception Safety | 561 | @par Exception Safety | |||||
| 562 | Strong guarantee. | 562 | Strong guarantee. | |||||
| 563 | 563 | |||||||
| 564 | @par Thread Safety | 564 | @par Thread Safety | |||||
| 565 | Not thread-safe. | 565 | Not thread-safe. | |||||
| 566 | 566 | |||||||
| 567 | @tparam T The type of object to retrieve or create. | 567 | @tparam T The type of object to retrieve or create. | |||||
| 568 | @return A reference to the stored object. | 568 | @return A reference to the stored object. | |||||
| 569 | */ | 569 | */ | |||||
| 570 | template<class T> | 570 | template<class T> | |||||
| HITCBC | 571 | 2 | T& use() | 571 | 2 | T& use() | ||
| 572 | { | 572 | { | |||||
| 573 | // T must be default constructible | 573 | // T must be default constructible | |||||
| 574 | BOOST_CORE_STATIC_ASSERT( | 574 | BOOST_CORE_STATIC_ASSERT( | |||||
| 575 | std::is_default_constructible<T>::value); | 575 | std::is_default_constructible<T>::value); | |||||
| HITCBC | 576 | 2 | if(auto t = find<T>()) | 576 | 2 | if(auto t = find<T>()) | ||
| MISUBC | 577 | ✗ | return *t; | 577 | ✗ | return *t; | ||
| HITCBC | 578 | 2 | return emplace<T>(); | 578 | 2 | return emplace<T>(); | ||
| 579 | } | 579 | } | |||||
| 580 | 580 | |||||||
| 581 | protected: | 581 | protected: | |||||
| 582 | struct any; | 582 | struct any; | |||||
| 583 | class elements; | 583 | class elements; | |||||
| 584 | 584 | |||||||
| 585 | /** Remove and destroy all objects in the container. | 585 | /** Remove and destroy all objects in the container. | |||||
| 586 | 586 | |||||||
| 587 | All stored objects are destroyed in the reverse order | 587 | All stored objects are destroyed in the reverse order | |||||
| 588 | of construction. The container is left empty. | 588 | of construction. The container is left empty. | |||||
| 589 | */ | 589 | */ | |||||
| 590 | BOOST_HTTP_DECL | 590 | BOOST_HTTP_DECL | |||||
| 591 | void | 591 | void | |||||
| 592 | clear() noexcept; | 592 | clear() noexcept; | |||||
| 593 | 593 | |||||||
| 594 | /** Return a range of all stored elements | 594 | /** Return a range of all stored elements | |||||
| 595 | @par Thread Safety | 595 | @par Thread Safety | |||||
| 596 | `const` member function calls are thread-safe. | 596 | `const` member function calls are thread-safe. | |||||
| 597 | Calls to non-`const` member functions must not run concurrently | 597 | Calls to non-`const` member functions must not run concurrently | |||||
| 598 | with other member functions on the same object. | 598 | with other member functions on the same object. | |||||
| 599 | @return An object representing the range of stored elements. | 599 | @return An object representing the range of stored elements. | |||||
| 600 | */ | 600 | */ | |||||
| 601 | BOOST_HTTP_DECL | 601 | BOOST_HTTP_DECL | |||||
| 602 | elements | 602 | elements | |||||
| 603 | get_elements() noexcept; | 603 | get_elements() noexcept; | |||||
| 604 | 604 | |||||||
| 605 | private: | 605 | private: | |||||
| 606 | template<class T, class = void> | 606 | template<class T, class = void> | |||||
| 607 | struct has_start : std::false_type {}; | 607 | struct has_start : std::false_type {}; | |||||
| 608 | 608 | |||||||
| 609 | template<class T> | 609 | template<class T> | |||||
| 610 | struct has_start<T, typename std::enable_if< | 610 | struct has_start<T, typename std::enable_if< | |||||
| 611 | std::is_same<decltype(std::declval<T>().start()), | 611 | std::is_same<decltype(std::declval<T>().start()), | |||||
| 612 | void>::value>::type> : std::true_type {}; | 612 | void>::value>::type> : std::true_type {}; | |||||
| 613 | 613 | |||||||
| 614 | template<class T, class = void> | 614 | template<class T, class = void> | |||||
| 615 | struct has_stop : std::false_type {}; | 615 | struct has_stop : std::false_type {}; | |||||
| 616 | 616 | |||||||
| 617 | template<class T> | 617 | template<class T> | |||||
| 618 | struct has_stop<T, typename std::enable_if< | 618 | struct has_stop<T, typename std::enable_if< | |||||
| 619 | std::is_same<decltype(std::declval<T>().stop()), | 619 | std::is_same<decltype(std::declval<T>().stop()), | |||||
| 620 | void>::value>::type> : std::true_type {}; | 620 | void>::value>::type> : std::true_type {}; | |||||
| 621 | 621 | |||||||
| 622 | struct key | 622 | struct key | |||||
| 623 | { | 623 | { | |||||
| 624 | detail::typeindex ti = | 624 | detail::typeindex ti = | |||||
| 625 | detail::typeindex(BOOST_CORE_TYPEID(void)); | 625 | detail::typeindex(BOOST_CORE_TYPEID(void)); | |||||
| 626 | void* p = nullptr; | 626 | void* p = nullptr; | |||||
| 627 | 627 | |||||||
| HITCBC | 628 | 6 | key() = default; | 628 | 6 | key() = default; | ||
| HITCBC | 629 | 24 | key(detail::typeindex const& ti_, | 629 | 24 | key(detail::typeindex const& ti_, | ||
| HITCBC | 630 | 24 | void* p_) noexcept : ti(ti_) , p(p_) {} | 630 | 24 | void* p_) noexcept : ti(ti_) , p(p_) {} | ||
| 631 | }; | 631 | }; | |||||
| 632 | 632 | |||||||
| 633 | template<class T, class... Key> | 633 | template<class T, class... Key> | |||||
| 634 | struct keyset; | 634 | struct keyset; | |||||
| 635 | 635 | |||||||
| 636 | template<class T> | 636 | template<class T> | |||||
| 637 | struct keyset<T> | 637 | struct keyset<T> | |||||
| 638 | { | 638 | { | |||||
| 639 | static constexpr std::size_t N = 1; | 639 | static constexpr std::size_t N = 1; | |||||
| 640 | key kn[1]; | 640 | key kn[1]; | |||||
| 641 | 641 | |||||||
| HITCBC | 642 | 10 | explicit keyset(T& t) noexcept | 642 | 10 | explicit keyset(T& t) noexcept | ||
| HITCBC | 643 | 10 | : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) } | 643 | 10 | : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) } | ||
| 644 | { | 644 | { | |||||
| HITCBC | 645 | 10 | } | 645 | 10 | } | ||
| 646 | }; | 646 | }; | |||||
| 647 | 647 | |||||||
| 648 | template<class T, class... Keys> | 648 | template<class T, class... Keys> | |||||
| 649 | struct keyset | 649 | struct keyset | |||||
| 650 | { | 650 | { | |||||
| 651 | static constexpr std::size_t N = 1 + sizeof...(Keys); | 651 | static constexpr std::size_t N = 1 + sizeof...(Keys); | |||||
| 652 | key kn[N + 1]; | 652 | key kn[N + 1]; | |||||
| 653 | 653 | |||||||
| HITCBC | 654 | 6 | explicit keyset(T& t) noexcept | 654 | 6 | explicit keyset(T& t) noexcept | ||
| HITCBC | 655 | 20 | : kn{ | 655 | 20 | : kn{ | ||
| HITCBC | 656 | 6 | key(detail::typeindex(BOOST_CORE_TYPEID(T)), | 656 | 6 | key(detail::typeindex(BOOST_CORE_TYPEID(T)), | ||
| HITCBC | 657 | 6 | std::addressof(t)), | 657 | 6 | std::addressof(t)), | ||
| HITCBC | 658 | 8 | key(detail::typeindex(BOOST_CORE_TYPEID(Keys)), | 658 | 8 | key(detail::typeindex(BOOST_CORE_TYPEID(Keys)), | ||
| HITCBC | 659 | 4 | &static_cast<Keys&>(t))..., } | 659 | 4 | &static_cast<Keys&>(t))..., } | ||
| 660 | { | 660 | { | |||||
| HITCBC | 661 | 6 | } | 661 | 6 | } | ||
| 662 | }; | 662 | }; | |||||
| 663 | 663 | |||||||
| 664 | template<class T> struct any_impl; | 664 | template<class T> struct any_impl; | |||||
| 665 | 665 | |||||||
| 666 | using any_ptr = std::unique_ptr<any>; | 666 | using any_ptr = std::unique_ptr<any>; | |||||
| 667 | 667 | |||||||
| 668 | template<class T, class... Args> | 668 | template<class T, class... Args> | |||||
| 669 | auto | 669 | auto | |||||
| HITCBC | 670 | 18 | make_any(Args&&... args) -> | 670 | 18 | make_any(Args&&... args) -> | ||
| 671 | std::unique_ptr<any_impl<T>> | 671 | std::unique_ptr<any_impl<T>> | |||||
| 672 | { | 672 | { | |||||
| HITCBC | 673 | 21 | return std::unique_ptr<any_impl<T>>(new | 673 | 21 | return std::unique_ptr<any_impl<T>>(new | ||
| HITCBC | 674 | 21 | any_impl<T>(std::forward<Args>(args)...)); | 674 | 21 | any_impl<T>(std::forward<Args>(args)...)); | ||
| 675 | } | 675 | } | |||||
| 676 | 676 | |||||||
| 677 | void destroy() noexcept; | 677 | void destroy() noexcept; | |||||
| 678 | BOOST_HTTP_DECL any& get(std::size_t i); | 678 | BOOST_HTTP_DECL any& get(std::size_t i); | |||||
| 679 | BOOST_HTTP_DECL void* find( | 679 | BOOST_HTTP_DECL void* find( | |||||
| 680 | core::typeinfo const& ti) const noexcept; | 680 | core::typeinfo const& ti) const noexcept; | |||||
| 681 | BOOST_HTTP_DECL void* insert_impl(any_ptr, | 681 | BOOST_HTTP_DECL void* insert_impl(any_ptr, | |||||
| 682 | key const* = nullptr, std::size_t = 0); | 682 | key const* = nullptr, std::size_t = 0); | |||||
| 683 | 683 | |||||||
| 684 | std::vector<any_ptr> v_; | 684 | std::vector<any_ptr> v_; | |||||
| 685 | std::unordered_map< | 685 | std::unordered_map< | |||||
| 686 | detail::typeindex, void*> m_; | 686 | detail::typeindex, void*> m_; | |||||
| 687 | }; | 687 | }; | |||||
| 688 | 688 | |||||||
| 689 | //------------------------------------------------ | 689 | //------------------------------------------------ | |||||
| 690 | 690 | |||||||
| 691 | struct BOOST_HTTP_DECL | 691 | struct BOOST_HTTP_DECL | |||||
| 692 | polystore::any | 692 | polystore::any | |||||
| 693 | { | 693 | { | |||||
| HITCBC | 694 | 18 | virtual ~any() = default; | 694 | 18 | virtual ~any() = default; | ||
| 695 | virtual void start() = 0; | 695 | virtual void start() = 0; | |||||
| 696 | virtual void stop() = 0; | 696 | virtual void stop() = 0; | |||||
| 697 | private: | 697 | private: | |||||
| 698 | friend class polystore; | 698 | friend class polystore; | |||||
| 699 | virtual void* get() noexcept = 0; | 699 | virtual void* get() noexcept = 0; | |||||
| 700 | }; | 700 | }; | |||||
| 701 | 701 | |||||||
| 702 | //------------------------------------------------ | 702 | //------------------------------------------------ | |||||
| 703 | 703 | |||||||
| 704 | class polystore::elements | 704 | class polystore::elements | |||||
| 705 | { | 705 | { | |||||
| 706 | public: | 706 | public: | |||||
| MISUBC | 707 | ✗ | std::size_t size() const noexcept | 707 | ✗ | std::size_t size() const noexcept | ||
| 708 | { | 708 | { | |||||
| MISUBC | 709 | ✗ | return n_; | 709 | ✗ | return n_; | ||
| 710 | } | 710 | } | |||||
| 711 | 711 | |||||||
| MISUBC | 712 | ✗ | any& operator[]( | 712 | ✗ | any& operator[]( | ||
| 713 | std::size_t i) noexcept | 713 | std::size_t i) noexcept | |||||
| 714 | { | 714 | { | |||||
| MISUBC | 715 | ✗ | return ps_.get(i); | 715 | ✗ | return ps_.get(i); | ||
| 716 | } | 716 | } | |||||
| 717 | 717 | |||||||
| 718 | private: | 718 | private: | |||||
| 719 | friend class polystore; | 719 | friend class polystore; | |||||
| 720 | 720 | |||||||
| MISUBC | 721 | ✗ | elements( | 721 | ✗ | elements( | ||
| 722 | std::size_t n, | 722 | std::size_t n, | |||||
| 723 | polystore& ps) | 723 | polystore& ps) | |||||
| MISUBC | 724 | ✗ | : n_(n) | 724 | ✗ | : n_(n) | ||
| MISUBC | 725 | ✗ | , ps_(ps) | 725 | ✗ | , ps_(ps) | ||
| 726 | { | 726 | { | |||||
| MISUBC | 727 | ✗ | } | 727 | ✗ | } | ||
| 728 | 728 | |||||||
| 729 | std::size_t n_; | 729 | std::size_t n_; | |||||
| 730 | polystore& ps_; | 730 | polystore& ps_; | |||||
| 731 | }; | 731 | }; | |||||
| 732 | 732 | |||||||
| 733 | //------------------------------------------------ | 733 | //------------------------------------------------ | |||||
| 734 | 734 | |||||||
| 735 | template<class T> | 735 | template<class T> | |||||
| 736 | struct polystore::any_impl : polystore::any | 736 | struct polystore::any_impl : polystore::any | |||||
| 737 | { | 737 | { | |||||
| 738 | T t; | 738 | T t; | |||||
| 739 | 739 | |||||||
| 740 | template<class... Args> | 740 | template<class... Args> | |||||
| HITCBC | 741 | 18 | explicit any_impl(Args&&... args) | 741 | 18 | explicit any_impl(Args&&... args) | ||
| HITCBC | 742 | 18 | : t(std::forward<Args>(args)...) | 742 | 18 | : t(std::forward<Args>(args)...) | ||
| 743 | { | 743 | { | |||||
| HITCBC | 744 | 18 | } | 744 | 18 | } | ||
| HITCBC | 745 | 34 | void* get() noexcept override { return std::addressof(t); } | 745 | 34 | void* get() noexcept override { return std::addressof(t); } | ||
| MISUBC | 746 | ✗ | void start() override { do_start(has_start<T>{}); } | 746 | ✗ | void start() override { do_start(has_start<T>{}); } | ||
| MISUBC | 747 | ✗ | void stop() override { do_stop(has_stop<T>{}); } | 747 | ✗ | void stop() override { do_stop(has_stop<T>{}); } | ||
| 748 | void do_start(std::true_type) { t.start(); } | 748 | void do_start(std::true_type) { t.start(); } | |||||
| MISUBC | 749 | ✗ | void do_start(std::false_type) {} | 749 | ✗ | void do_start(std::false_type) {} | ||
| 750 | void do_stop(std::true_type) { t.stop(); } | 750 | void do_stop(std::true_type) { t.stop(); } | |||||
| MISUBC | 751 | ✗ | void do_stop(std::false_type) {} | 751 | ✗ | void do_stop(std::false_type) {} | ||
| 752 | }; | 752 | }; | |||||
| 753 | 753 | |||||||
| 754 | //------------------------------------------------ | 754 | //------------------------------------------------ | |||||
| 755 | 755 | |||||||
| 756 | namespace detail { | 756 | namespace detail { | |||||
| 757 | 757 | |||||||
| 758 | template<class T> struct arg; | 758 | template<class T> struct arg; | |||||
| 759 | template<class T> struct arg<T const&> : arg<T&> {}; | 759 | template<class T> struct arg<T const&> : arg<T&> {}; | |||||
| 760 | template<class T> struct arg<T const*> : arg<T*> {}; | 760 | template<class T> struct arg<T const*> : arg<T*> {}; | |||||
| 761 | template<class T> struct arg<T&> | 761 | template<class T> struct arg<T&> | |||||
| 762 | { | 762 | { | |||||
| HITCBC | 763 | 8 | T& operator()(polystore& ps) const | 763 | 8 | T& operator()(polystore& ps) const | ||
| 764 | { | 764 | { | |||||
| HITCBC | 765 | 8 | return ps.get<T>(); | 765 | 8 | return ps.get<T>(); | ||
| 766 | } | 766 | } | |||||
| 767 | }; | 767 | }; | |||||
| 768 | template<class T> struct arg<T*> | 768 | template<class T> struct arg<T*> | |||||
| 769 | { | 769 | { | |||||
| HITCBC | 770 | 5 | T* operator()(polystore& ps) const | 770 | 5 | T* operator()(polystore& ps) const | ||
| 771 | { | 771 | { | |||||
| HITCBC | 772 | 5 | return ps.find<T>(); | 772 | 5 | return ps.find<T>(); | ||
| 773 | } | 773 | } | |||||
| 774 | }; | 774 | }; | |||||
| 775 | 775 | |||||||
| 776 | template<class F, class... Args> | 776 | template<class F, class... Args> | |||||
| 777 | auto | 777 | auto | |||||
| HITCBC | 778 | 10 | invoke(polystore& ps, F&& f, | 778 | 10 | invoke(polystore& ps, F&& f, | ||
| 779 | type_list<Args...> const&) -> | 779 | type_list<Args...> const&) -> | |||||
| 780 | typename call_traits<std::decay_t<F>>::return_type | 780 | typename call_traits<std::decay_t<F>>::return_type | |||||
| 781 | { | 781 | { | |||||
| HITCBC | 782 | 10 | return std::forward<F>(f)(arg<Args>()(ps)...); | 782 | 10 | return std::forward<F>(f)(arg<Args>()(ps)...); | ||
| 783 | } | 783 | } | |||||
| 784 | 784 | |||||||
| 785 | } // detail | 785 | } // detail | |||||
| 786 | 786 | |||||||
| 787 | /** Invoke a callable, injecting stored objects as arguments | 787 | /** Invoke a callable, injecting stored objects as arguments | |||||
| 788 | The callable is invoked with zero or more arguments. | 788 | The callable is invoked with zero or more arguments. | |||||
| 789 | For each argument type, if an object of that type | 789 | For each argument type, if an object of that type | |||||
| 790 | (or key type) is stored in the container, a reference | 790 | (or key type) is stored in the container, a reference | |||||
| 791 | to that object is passed to the callable. | 791 | to that object is passed to the callable. | |||||
| 792 | @par Example | 792 | @par Example | |||||
| 793 | @code | 793 | @code | |||||
| 794 | struct A { int i = 1; }; | 794 | struct A { int i = 1; }; | |||||
| 795 | polystore ps; | 795 | polystore ps; | |||||
| 796 | ps.emplace<A>(); | 796 | ps.emplace<A>(); | |||||
| 797 | ps.invoke([](A& a){ assert(a.i == 1; }); | 797 | ps.invoke([](A& a){ assert(a.i == 1; }); | |||||
| 798 | @endcode | 798 | @endcode | |||||
| 799 | @param f The callable to invoke. | 799 | @param f The callable to invoke. | |||||
| 800 | @return The result of the invocation. | 800 | @return The result of the invocation. | |||||
| 801 | @throws std::bad_typeid if any reference argument | 801 | @throws std::bad_typeid if any reference argument | |||||
| 802 | types are not found in the container. | 802 | types are not found in the container. | |||||
| 803 | */ | 803 | */ | |||||
| 804 | template<class F> | 804 | template<class F> | |||||
| 805 | auto | 805 | auto | |||||
| HITCBC | 806 | 10 | invoke(polystore& ps, F&& f) -> | 806 | 10 | invoke(polystore& ps, F&& f) -> | ||
| 807 | typename detail::call_traits<std::decay_t<F>>::return_type | 807 | typename detail::call_traits<std::decay_t<F>>::return_type | |||||
| 808 | { | 808 | { | |||||
| HITCBC | 809 | 20 | return detail::invoke(ps, std::forward<F>(f), | 809 | 20 | return detail::invoke(ps, std::forward<F>(f), | ||
| HITCBC | 810 | 20 | typename detail::call_traits<std::decay_t<F>>::arg_types{}); | 810 | 20 | typename detail::call_traits<std::decay_t<F>>::arg_types{}); | ||
| 811 | } | 811 | } | |||||
| 812 | 812 | |||||||
| 813 | } // http | 813 | } // http | |||||
| 814 | } // boost | 814 | } // boost | |||||
| 815 | 815 | |||||||
| 816 | #endif | 816 | #endif | |||||