diff --git a/arbor/backends/gpu/mechanism.cpp b/arbor/backends/gpu/mechanism.cpp index e6c0b46e71f29605ebd06ec0d97b858ba0d0e4b1..5aa114ecf81bc04f6f4f99661cee16dab774d0f4 100644 --- a/arbor/backends/gpu/mechanism.cpp +++ b/arbor/backends/gpu/mechanism.cpp @@ -1,6 +1,7 @@ #include <algorithm> #include <cstddef> #include <cmath> +#include <optional> #include <string> #include <utility> #include <vector> @@ -10,7 +11,6 @@ #include <arbor/fvm_types.hpp> #include <arbor/math.hpp> #include <arbor/mechanism.hpp> -#include <arbor/util/optional.hpp> #include "memory/memory.hpp" #include "util/index_into.hpp" @@ -25,8 +25,9 @@ namespace arb { namespace gpu { using memory::make_const_view; -using util::value_by_key; using util::make_span; +using util::ptr_by_key; +using util::value_by_key; template <typename T> memory::device_view<T> device_view(T* ptr, std::size_t n) { @@ -101,7 +102,7 @@ void mechanism::instantiate(unsigned id, for (auto i: ion_state_tbl) { auto ion_binding = value_by_key(overrides.ion_rebind, i.first).value_or(i.first); - util::optional<ion_state&> oion = value_by_key(shared.ion_data, ion_binding); + ion_state* oion = ptr_by_key(shared.ion_data, ion_binding); if (!oion) { throw arbor_internal_error("gpu/mechanism: mechanism holds ion with no corresponding shared state"); } @@ -156,7 +157,7 @@ void mechanism::instantiate(unsigned id, for (auto i: make_span(0, num_ions_)) { auto ion_binding = value_by_key(overrides.ion_rebind, ion_index_tbl[i].first).value_or(ion_index_tbl[i].first); - util::optional<ion_state&> oion = value_by_key(shared.ion_data, ion_binding); + ion_state* oion = ptr_by_key(shared.ion_data, ion_binding); if (!oion) { throw arbor_internal_error("gpu/mechanism: mechanism holds ion with no corresponding shared state"); } diff --git a/arbor/backends/multicore/mechanism.cpp b/arbor/backends/multicore/mechanism.cpp index 63f50a362949aee2ed5f34433842ce0109cc2fbd..2aec088c825c1091fe1d918d498a79e0ba51d387 100644 --- a/arbor/backends/multicore/mechanism.cpp +++ b/arbor/backends/multicore/mechanism.cpp @@ -1,6 +1,7 @@ #include <algorithm> #include <cstddef> #include <cmath> +#include <optional> #include <string> #include <utility> #include <vector> @@ -9,7 +10,6 @@ #include <arbor/common_types.hpp> #include <arbor/math.hpp> #include <arbor/mechanism.hpp> -#include <arbor/util/optional.hpp> #include "util/index_into.hpp" #include "util/maputil.hpp" @@ -26,6 +26,7 @@ namespace arb { namespace multicore { using util::make_range; +using util::ptr_by_key; using util::value_by_key; // Copy elements from source sequence into destination sequence, @@ -99,7 +100,7 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me for (auto i: ion_state_tbl) { auto ion_binding = value_by_key(overrides.ion_rebind, i.first).value_or(i.first); - util::optional<ion_state&> oion = value_by_key(shared.ion_data, ion_binding); + ion_state* oion = ptr_by_key(shared.ion_data, ion_binding); if (!oion) { throw arbor_internal_error("multicore/mechanism: mechanism holds ion with no corresponding shared state"); } @@ -161,7 +162,7 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me for (auto i: ion_index_table()) { auto ion_binding = value_by_key(overrides.ion_rebind, i.first).value_or(i.first); - util::optional<ion_state&> oion = value_by_key(shared.ion_data, ion_binding); + ion_state* oion = ptr_by_key(shared.ion_data, ion_binding); if (!oion) { throw arbor_internal_error("multicore/mechanism: mechanism holds ion with no corresponding shared state"); } diff --git a/arbor/event_binner.cpp b/arbor/event_binner.cpp index 6301a3499d84d0380a8ba5a7eea72c4db24994a9..84e182a835da7fd080438b2289eefb167f88b78e 100644 --- a/arbor/event_binner.cpp +++ b/arbor/event_binner.cpp @@ -1,20 +1,20 @@ #include <algorithm> #include <cmath> #include <limits> +#include <optional> #include <stdexcept> #include <unordered_map> #include <arbor/arbexcept.hpp> #include <arbor/common_types.hpp> #include <arbor/spike.hpp> -#include <arbor/util/optional.hpp> #include "event_binner.hpp" namespace arb { void event_binner::reset() { - last_event_time_ = util::nullopt; + last_event_time_ = std::nullopt; } time_type event_binner::bin(time_type t, time_type t_min) { diff --git a/arbor/event_binner.hpp b/arbor/event_binner.hpp index c1bcd72c5147972a77a258805e26da8ce8a1c8a4..7d12526457dc0365d57f7a93196a376ca4581938 100644 --- a/arbor/event_binner.hpp +++ b/arbor/event_binner.hpp @@ -1,11 +1,11 @@ #pragma once #include <limits> +#include <optional> #include <unordered_map> #include <arbor/common_types.hpp> #include <arbor/spike.hpp> -#include <arbor/util/optional.hpp> namespace arb { @@ -32,7 +32,7 @@ private: // Interval in which event times can be aliased. time_type bin_interval_; - util::optional<time_type> last_event_time_; + std::optional<time_type> last_event_time_; }; } // namespace arb diff --git a/arbor/event_queue.hpp b/arbor/event_queue.hpp index b785acd06299d6a3fb60e93d1afa50013e98793c..59885b4361bba861d2328f3e40f568392f0c0d00 100644 --- a/arbor/event_queue.hpp +++ b/arbor/event_queue.hpp @@ -2,6 +2,7 @@ #include <cstdint> #include <limits> +#include <optional> #include <ostream> #include <queue> #include <type_traits> @@ -9,7 +10,6 @@ #include <arbor/common_types.hpp> #include <arbor/spike_event.hpp> -#include <arbor/util/optional.hpp> #include <arbor/generic_event.hpp> namespace arb { @@ -46,20 +46,20 @@ public: } // Return time t of head of queue if `t_until` > `t`. - util::optional<event_time_type> time_if_before(const event_time_type& t_until) { + std::optional<event_time_type> time_if_before(const event_time_type& t_until) { if (queue_.empty()) { - return util::nullopt; + return std::nullopt; } using ::arb::event_time; auto t = event_time(queue_.top()); - return t_until > t? util::just(t): util::nullopt; + return t_until > t? std::optional(t): std::nullopt; } // Generic conditional pop: pop and return head of queue if // queue non-empty and the head satisfies predicate. template <typename Pred> - util::optional<value_type> pop_if(Pred&& pred) { + std::optional<value_type> pop_if(Pred&& pred) { using ::arb::event_time; if (!queue_.empty() && pred(queue_.top())) { auto ev = queue_.top(); @@ -67,12 +67,12 @@ public: return ev; } else { - return util::nullopt; + return std::nullopt; } } // Pop and return top event `ev` of queue if `t_until` > `event_time(ev)`. - util::optional<value_type> pop_if_before(const event_time_type& t_until) { + std::optional<value_type> pop_if_before(const event_time_type& t_until) { using ::arb::event_time; return pop_if( [&t_until](const value_type& ev) { return t_until > event_time(ev); } @@ -80,7 +80,7 @@ public: } // Pop and return top event `ev` of queue unless `event_time(ev)` > `t_until` - util::optional<value_type> pop_if_not_after(const event_time_type& t_until) { + std::optional<value_type> pop_if_not_after(const event_time_type& t_until) { using ::arb::event_time; return pop_if( [&t_until](const value_type& ev) { return !(event_time(ev) > t_until); } diff --git a/arbor/fvm_layout.cpp b/arbor/fvm_layout.cpp index 451002a97c27341fe7279c6ab3fd8d81031ec0bf..539aeeb53b75f700b214e52db1b3cd5969d2f89a 100644 --- a/arbor/fvm_layout.cpp +++ b/arbor/fvm_layout.cpp @@ -1,4 +1,5 @@ #include <algorithm> +#include <optional> #include <set> #include <stdexcept> #include <unordered_set> @@ -10,7 +11,6 @@ #include <arbor/morph/mcable_map.hpp> #include <arbor/morph/mprovider.hpp> #include <arbor/morph/morphology.hpp> -#include <arbor/util/optional.hpp> #include "fvm_layout.hpp" #include "threading/threading.hpp" @@ -45,7 +45,7 @@ struct get_value { }; template <typename V> -util::optional<V> operator|(const util::optional<V>& a, const util::optional<V>& b) { +std::optional<V> operator|(const std::optional<V>& a, const std::optional<V>& b) { return a? a: b; } diff --git a/arbor/fvm_layout.hpp b/arbor/fvm_layout.hpp index 72221e6bcb23c70d5e7b89d30e52e6197eb9e883..69557bc005414b57d1532908c2beb77296bd4913 100644 --- a/arbor/fvm_layout.hpp +++ b/arbor/fvm_layout.hpp @@ -9,7 +9,6 @@ #include <arbor/mechinfo.hpp> #include <arbor/mechcat.hpp> #include <arbor/recipe.hpp> -#include <arbor/util/optional.hpp> #include "execution_context.hpp" #include "util/piecewise.hpp" diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index d36c3bd78f3fb6f16c2824d0344fb0f9ef45236e..26e3a6458db352f499fe6e57d0893cea782ee007 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -10,6 +10,7 @@ #include <cmath> #include <iterator> #include <memory> +#include <optional> #include <queue> #include <stdexcept> #include <utility> @@ -21,7 +22,6 @@ #include <arbor/cable_cell_param.hpp> #include <arbor/recipe.hpp> #include <arbor/util/any_visitor.hpp> -#include <arbor/util/optional.hpp> #include "builtin_mechanisms.hpp" #include "execution_context.hpp" @@ -697,12 +697,12 @@ struct probe_resolution_data { }; // Index into ion data from location. - util::optional<fvm_index_type> ion_location_index(const std::string& ion, mlocation loc) const { + std::optional<fvm_index_type> ion_location_index(const std::string& ion, mlocation loc) const { if (state->ion_data.count(ion)) { return util::binary_search_index(M.ions.at(ion).cv, fvm_index_type(D.geometry.location_cv(cell_idx, loc, cv_prefer::cv_nonempty))); } - return util::nullopt; + return std::nullopt; } }; diff --git a/arbor/include/arbor/cable_cell_param.hpp b/arbor/include/arbor/cable_cell_param.hpp index 6f733ad2a41cec0738ef8a65e215dbdbb0a72e00..958cf2a7de8e4a79bdadb8fddf75b3e90c357c9c 100644 --- a/arbor/include/arbor/cable_cell_param.hpp +++ b/arbor/include/arbor/cable_cell_param.hpp @@ -1,14 +1,14 @@ #pragma once +#include <memory> +#include <optional> +#include <unordered_map> +#include <string> + #include <arbor/arbexcept.hpp> #include <arbor/cv_policy.hpp> #include <arbor/mechcat.hpp> #include <arbor/morph/locset.hpp> -#include <arbor/util/optional.hpp> - -#include <memory> -#include <unordered_map> -#include <string> namespace arb { @@ -26,9 +26,9 @@ struct cable_cell_error: arbor_exception { // separately (see below). struct cable_cell_ion_data { - util::optional<double> init_int_concentration; - util::optional<double> init_ext_concentration; - util::optional<double> init_reversal_potential; + std::optional<double> init_int_concentration; + std::optional<double> init_ext_concentration; + std::optional<double> init_reversal_potential; }; // Current clamp description for stimulus specification. @@ -172,15 +172,15 @@ struct ion_reversal_potential_method { // cell defaults can be individually set with `cable_cell:set_default()`. struct cable_cell_parameter_set { - util::optional<double> init_membrane_potential; // [mV] - util::optional<double> temperature_K; // [K] - util::optional<double> axial_resistivity; // [Ω·cm] - util::optional<double> membrane_capacitance; // [F/m²] + std::optional<double> init_membrane_potential; // [mV] + std::optional<double> temperature_K; // [K] + std::optional<double> axial_resistivity; // [Ω·cm] + std::optional<double> membrane_capacitance; // [F/m²] std::unordered_map<std::string, cable_cell_ion_data> ion_data; std::unordered_map<std::string, mechanism_desc> reversal_potential_method; - util::optional<cv_policy> discretization; + std::optional<cv_policy> discretization; }; extern cable_cell_parameter_set neuron_parameter_defaults; diff --git a/arbor/include/arbor/mechcat.hpp b/arbor/include/arbor/mechcat.hpp index 0018791f32818ef657a5ac2df0c74ed805e6ba70..d72394f7111948344f47ef3c45473365e3eecadb 100644 --- a/arbor/include/arbor/mechcat.hpp +++ b/arbor/include/arbor/mechcat.hpp @@ -8,7 +8,6 @@ #include <arbor/mechinfo.hpp> #include <arbor/mechanism.hpp> -#include <arbor/util/optional.hpp> // Mechanism catalogue maintains: // diff --git a/arbor/include/arbor/morph/label_dict.hpp b/arbor/include/arbor/morph/label_dict.hpp index 750b78710ed044386e0235b3fef3d4d7d9df2146..a68bab2b46d70e6fa68444ba74b873816b3a1924 100644 --- a/arbor/include/arbor/morph/label_dict.hpp +++ b/arbor/include/arbor/morph/label_dict.hpp @@ -1,11 +1,11 @@ #pragma once #include <memory> +#include <optional> #include <unordered_map> #include <arbor/morph/locset.hpp> #include <arbor/morph/region.hpp> -#include <arbor/util/optional.hpp> namespace arb { @@ -21,8 +21,8 @@ public: void set(const std::string& name, locset ls); void set(const std::string& name, region reg); - util::optional<const arb::region&> region(const std::string& name) const; - util::optional<const arb::locset&> locset(const std::string& name) const; + std::optional<arb::region> region(const std::string& name) const; + std::optional<arb::locset> locset(const std::string& name) const; const ps_map& locsets() const; const reg_map& regions() const; diff --git a/arbor/include/arbor/morph/mcable_map.hpp b/arbor/include/arbor/morph/mcable_map.hpp index 94b638b1e9e73db56b3440a057acca364170efa7..76fae77970873f46ea2c2d85a973b5798d87cb61 100644 --- a/arbor/include/arbor/morph/mcable_map.hpp +++ b/arbor/include/arbor/morph/mcable_map.hpp @@ -5,11 +5,11 @@ // The only mutating operations are insert, emplace, and clear. #include <algorithm> +#include <optional> #include <vector> #include <arbor/assert.hpp> #include <arbor/morph/primitives.hpp> -#include <arbor/util/optional.hpp> namespace arb { @@ -89,7 +89,7 @@ struct mcable_map { private: std::vector<value_type> elements_; - util::optional<typename std::vector<value_type>::iterator> insertion_point(const mcable& c) { + std::optional<typename std::vector<value_type>::iterator> insertion_point(const mcable& c) { struct as_mcable { mcable value; as_mcable(const value_type& x): value(x.first) {} @@ -102,13 +102,13 @@ private: if (it!=elements_.begin()) { mcable prior = std::prev(it)->first; if (prior.branch==c.branch && prior.dist_pos>c.prox_pos) { - return util::nullopt; + return std::nullopt; } } if (it!=elements_.end()) { mcable next = it->first; if (c.branch==next.branch && c.dist_pos>next.prox_pos) { - return util::nullopt; + return std::nullopt; } } return it; diff --git a/arbor/include/arbor/morph/stitch.hpp b/arbor/include/arbor/morph/stitch.hpp index b90e56dfd0b261145991806745022d5976e17288..d5086642a10dce1fc8a9ccfc31d7df2cc05cb532 100644 --- a/arbor/include/arbor/morph/stitch.hpp +++ b/arbor/include/arbor/morph/stitch.hpp @@ -2,6 +2,7 @@ #include <optional> #include <memory> +#include <optional> #include <string> #include <vector> diff --git a/arbor/include/arbor/simple_sampler.hpp b/arbor/include/arbor/simple_sampler.hpp index 3e98d21933647e0f6708f0335f545553908b622c..2776a931a27dfe9f6582f940f8edea53c6beb9e4 100644 --- a/arbor/include/arbor/simple_sampler.hpp +++ b/arbor/include/arbor/simple_sampler.hpp @@ -12,7 +12,6 @@ #include <arbor/common_types.hpp> #include <arbor/sampling.hpp> #include <arbor/util/any_ptr.hpp> -#include <arbor/util/optional.hpp> namespace arb { diff --git a/arbor/include/arbor/util/optional.hpp b/arbor/include/arbor/util/optional.hpp deleted file mode 100644 index 9692167687f309ff5125cdc27e3189591ff6281d..0000000000000000000000000000000000000000 --- a/arbor/include/arbor/util/optional.hpp +++ /dev/null @@ -1,434 +0,0 @@ -#pragma once - -/* An option class supporting a subset of C++17 std::optional functionality. - * - * Difference from C++17 std::optional: - * - * Missing functionality (to be added as required): - * - * 1. `constexpr` constructors. - * - * 2. Comparison operators other than `operator==`. - * - * 3. `std::hash` overload. - * - * 4. `swap()` method and ADL-available `swap()` function. - * - * 5. No `make_optional` function (but see `just` below). - * - * Additional/differing functionality: - * - * 1. Optional references. - * - * `util::optional<T&>` acts as a value-like wrapper about a possible - * reference of type T&. Methods such as `value()` or `value_or()` - * return this reference. - * - * 2. Optional void. - * - * Included primarily for ease of generic programming with `optional`. - * - * 3. `util::just` - * - * This function acts like the value-constructing `std::make_optional<T>(T&&)`, - * except that it will return an optional<T&> if given an lvalue T as an argument. - */ - -#include <type_traits> -#include <stdexcept> -#include <utility> - -#include <arbor/util/uninitialized.hpp> - -namespace arb { -namespace util { - -template <typename X> struct optional; - -struct optional_unset_error: std::runtime_error { - explicit optional_unset_error(const std::string& what_str) - : std::runtime_error(what_str) - {} - - optional_unset_error() - : std::runtime_error("optional value unset") - {} -}; - -struct nullopt_t {}; -constexpr nullopt_t nullopt{}; - -namespace detail { - template <typename Y> - struct lift_type { - using type = optional<Y>; - }; - - template <typename Y> - struct lift_type<optional<Y>> { - using type = optional<Y>; - }; - - template <typename Y> - using lift_type_t = typename lift_type<Y>::type; - - struct optional_tag {}; - - template <typename X> - using is_optional = std::is_base_of<optional_tag, std::decay_t<X>>; - - template <typename D, typename X> - struct wrapped_type_impl { - using type = X; - }; - - template <typename D, typename X> - struct wrapped_type_impl<optional<D>, X> { - using type = D; - }; - - template <typename X> - struct wrapped_type { - using type = typename wrapped_type_impl<std::decay_t<X>, X>::type; - }; - - template <typename X> - using wrapped_type_t = typename wrapped_type<X>::type; - - template <typename X> - struct optional_base: detail::optional_tag { - template <typename Y> friend struct optional; - - protected: - using data_type = util::uninitialized<X>; - using rvalue_reference = typename data_type::rvalue_reference; - using const_rvalue_reference = typename data_type::const_rvalue_reference; - - public: - using value_type = X; - using reference = typename data_type::reference; - using const_reference = typename data_type::const_reference; - using pointer = typename data_type::pointer; - using const_pointer = typename data_type::const_pointer; - - protected: - bool set; - data_type data; - - optional_base() : set(false) {} - - template <typename T> - optional_base(bool set_, T&& init) : set(set_) { - if (set) { - data.construct(std::forward<T>(init)); - } - } - - template <typename... Args> - optional_base(bool set_, std::in_place_t, Args&&... args) : set(set_) { - if (set) { - data.construct(std::forward<Args>(args)...); - } - } - - reference ref() { return data.ref(); } - const_reference ref() const { return data.cref(); } - - void assert_set() const { - if (!set) { - throw optional_unset_error(); - } - } - - public: - ~optional_base() { - if (set) { - data.destruct(); - } - } - - pointer operator->() { return data.ptr(); } - const_pointer operator->() const { return data.cptr(); } - - reference operator*() { return ref(); } - const_reference operator*() const { return ref(); } - - explicit operator bool() const { return set; } - - template <typename Y> - bool operator==(const Y& y) const { - return set && ref()==y; - } - - template <typename Y> - bool operator==(const optional<Y>& o) const { - return (set && o.set && ref()==o.ref()) || (!set && !o.set); - } - - void reset() { - if (set) { - data.destruct(); - } - set = false; - } - - template <typename Y> - void emplace(Y&& y) { - if (set) { - data.destruct(); - } - data.construct(std::forward<Y>(y)); - set = true; - } - }; - - // type utilities - template <typename T> - using enable_unless_optional_t = std::enable_if_t<!is_optional<T>::value>; - - // avoid nonnull address warnings when using operator| with e.g. char array constants - template <typename T> - bool decay_bool(const T* x) { return static_cast<bool>(x); } - - template <typename T> - bool decay_bool(const T& x) { return static_cast<bool>(x); } - -} // namespace detail - -template <typename X> -struct optional: detail::optional_base<X> { - using base = detail::optional_base<X>; - using base::set; - using base::ref; - using base::reset; - using base::data; - using base::assert_set; - - optional() noexcept: base() {} - optional(nullopt_t) noexcept: base() {} - - optional(const X& x) - noexcept(std::is_nothrow_copy_constructible<X>::value): base(true, x) {} - - optional(X&& x) - noexcept(std::is_nothrow_move_constructible<X>::value): base(true, std::move(x)) {} - - template <typename... Args> - optional(std::in_place_t, Args&&... args): base(true, std::in_place_t{}, std::forward<Args>(args)...) {} - - template <typename U, typename... Args> - optional(std::in_place_t, std::initializer_list<U> il, Args&&... args): base(true, std::in_place_t{}, il, std::forward<Args>(args)...) {} - - optional(const optional& ot): base(ot.set, ot.ref()) {} - - template <typename T> - optional(const optional<T>& ot) - noexcept(std::is_nothrow_constructible<X, T>::value): base(ot.set, ot.ref()) {} - - optional(optional&& ot) - noexcept(std::is_nothrow_move_constructible<X>::value): base(ot.set, std::move(ot.ref())) {} - - template <typename T> - optional(optional<T>&& ot) - noexcept(std::is_nothrow_constructible<X, T&&>::value): base(ot.set, std::move(ot.ref())) {} - - optional& operator=(nullopt_t) { - reset(); - return *this; - } - - template < - typename Y, - typename = detail::enable_unless_optional_t<Y> - > - optional& operator=(Y&& y) { - if (set) { - ref() = std::forward<Y>(y); - } - else { - set = true; - data.construct(std::forward<Y>(y)); - } - return *this; - } - - optional& operator=(const optional& o) { - if (set) { - if (o.set) { - ref() = o.ref(); - } - else { - reset(); - } - } - else { - set = o.set; - if (set) { - data.construct(o.ref()); - } - } - return *this; - } - - template < - typename Y = X, - typename = std::enable_if_t< - std::is_move_assignable<Y>::value && - std::is_move_constructible<Y>::value - > - > - optional& operator=(optional&& o) { - if (set) { - if (o.set) { - ref() = std::move(o.ref()); - } - else reset(); - } - else { - set = o.set; - if (set) { - data.construct(std::move(o.ref())); - } - } - return *this; - } - - X& value() & { - return assert_set(), ref(); - } - - const X& value() const& { - return assert_set(), ref(); - } - - X&& value() && { - return assert_set(), std::move(ref()); - } - - const X&& value() const&& { - return assert_set(), std::move(ref()); - } - - template <typename T> - X value_or(T&& alternative) const& { - return set? value(): static_cast<X>(std::forward<T>(alternative)); - } - - template <typename T> - X value_or(T&& alternative) && { - return set? std::move(value()): static_cast<X>(std::forward<T>(alternative)); - } -}; - -template <typename X> -struct optional<X&>: detail::optional_base<X&> { - using base=detail::optional_base<X&>; - using base::set; - using base::ref; - using base::data; - using base::reset; - using base::assert_set; - - optional() noexcept: base() {} - optional(nullopt_t) noexcept: base() {} - optional(X& x) noexcept: base(true, x) {} - - template <typename T> - optional(optional<T&>& ot) noexcept: base(ot.set, ot.ref()) {} - - optional& operator=(nullopt_t) { - reset(); - return *this; - } - - template <typename Y> - optional& operator=(Y& y) { - set = true; - data.construct(y); - return *this; - } - - template <typename Y> - optional& operator=(optional<Y&>& o) { - set = o.set; - if (o.set) { - data.construct(o.value()); - } - return *this; - } - - X& value() { - return assert_set(), ref(); - } - - const X& value() const { - return assert_set(), ref(); - } - - X& value_or(X& alternative) & { - return set? ref(): alternative; - } - - const X& value_or(const X& alternative) const& { - return set? ref(): alternative; - } - - template <typename T> - const X value_or(const T& alternative) && { - return set? ref(): static_cast<X>(alternative); - } -}; - -template <> -struct optional<void>: detail::optional_base<void> { - using base = detail::optional_base<void>; - using base::assert_set; - using base::set; - using base::reset; - - optional(): base() {} - optional(nullopt_t): base() {} - - template <typename T> - optional(T): base(true, true) {} - - template <typename T> - optional(const optional<T>& o): base(o.set, true) {} - - optional& operator=(nullopt_t) { - reset(); - return *this; - } - - template <typename T> - optional& operator=(T) { - set = true; - return *this; - } - - template <typename T> - optional& operator=(const optional<T>& o) { - set = o.set; - return *this; - } - - template <typename Y> - bool operator==(const Y& y) const { return false; } - - bool operator==(const optional<void>& o) const { - return (set && o.set) || (!set && !o.set); - } - - void value() const { assert_set(); } - - template <typename T> - void value_or(T) const {} // nop -}; - -template <typename X> -optional<X> just(X&& x) { - return optional<X>(std::forward<X>(x)); -} - -} // namespace util -} // namespace arb diff --git a/arbor/mc_cell_group.cpp b/arbor/mc_cell_group.cpp index 124734bec01cf29e6ad13bba9c0fd09289ae1ac4..ba77e032e51673045b3bb972d00aee2e5979b62e 100644 --- a/arbor/mc_cell_group.cpp +++ b/arbor/mc_cell_group.cpp @@ -1,4 +1,5 @@ #include <functional> +#include <optional> #include <unordered_set> #include <variant> #include <vector> @@ -506,7 +507,7 @@ void mc_cell_group::remove_all_samplers() { std::vector<probe_metadata> mc_cell_group::get_probe_metadata(cell_member_type probe_id) const { // Probe associations are fixed after construction, so we do not need to grab the mutex. - util::optional<probe_tag> maybe_tag = util::value_by_key(probe_map_.tag, probe_id); + std::optional<probe_tag> maybe_tag = util::value_by_key(probe_map_.tag, probe_id); if (!maybe_tag) { return {}; } diff --git a/arbor/mechcat.cpp b/arbor/mechcat.cpp index ab30845c3ee47a5aa049b0c96f9ca64eed8ac174..3fac9e805dc2aeabe7d479d6682c5ce57ab56ccc 100644 --- a/arbor/mechcat.cpp +++ b/arbor/mechcat.cpp @@ -59,7 +59,7 @@ namespace arb { -using util::value_by_key; +using util::ptr_by_key; using util::unexpected; using std::make_unique; @@ -209,10 +209,10 @@ struct catalogue_state { // Retrieve mechanism info for mechanism, derived mechanism, or implicitly // derived mechanism. hopefully<mechanism_info> info(const std::string& name) const { - if (const auto& deriv = value_by_key(derived_map_, name)) { + if (const auto* deriv = ptr_by_key(derived_map_, name)) { return *(deriv->derived_info.get()); } - else if (auto p = value_by_key(info_map_, name)) { + else if (auto* p = ptr_by_key(info_map_, name)) { return *(p->get()); } else if (auto deriv = derive(name)) { @@ -238,12 +238,12 @@ struct catalogue_state { } } - while (auto maybe_deriv = value_by_key(derived_map_, *base)) { - base = &maybe_deriv->parent; + while (auto* deriv = ptr_by_key(derived_map_, *base)) { + base = &deriv->parent; } - if (const auto& p = value_by_key(info_map_, *base)) { - return &p.value()->fingerprint; + if (const auto* p = ptr_by_key(info_map_, *base)) { + return &p->get()->fingerprint; } throw arbor_internal_error("inconsistent catalogue map state"); @@ -279,7 +279,7 @@ struct catalogue_state { const auto& param = kv.first; const auto& value = kv.second; - if (auto p = value_by_key(new_info->globals, param)) { + if (auto* p = ptr_by_key(new_info->globals, param)) { if (!p->valid(value)) { return unexpected_exception_ptr(invalid_parameter_value(name, param, value)); } @@ -302,7 +302,7 @@ struct catalogue_state { string_map<ion_dependency> new_ions; for (const auto& kv: new_info->ions) { - if (auto new_ion = value_by_key(ion_remap_map, kv.first)) { + if (auto* new_ion = ptr_by_key(ion_remap_map, kv.first)) { if (!new_ions.insert({*new_ion, kv.second}).second) { return unexpected_exception_ptr(invalid_ion_remap(name, kv.first, *new_ion)); } @@ -408,14 +408,14 @@ struct catalogue_state { } for (;;) { - if (const auto mech_impls = value_by_key(impl_map_, *impl_name)) { - if (auto p = value_by_key(mech_impls.value(), tidx)) { + if (const auto* mech_impls = ptr_by_key(impl_map_, *impl_name)) { + if (auto* p = ptr_by_key(*mech_impls, tidx)) { return p->get()->clone(); } } // Try parent instead. - if (const auto p = value_by_key(derived_map_, *impl_name)) { + if (const auto* p = ptr_by_key(derived_map_, *impl_name)) { impl_name = &p->parent; } else { @@ -436,13 +436,13 @@ struct catalogue_state { if (!deriv.ion_remap.empty()) { string_map<std::string> new_rebind = deriv.ion_remap; for (auto& kv: over.ion_rebind) { - if (auto opt_v = value_by_key(deriv.ion_remap, kv.second)) { + if (auto* v = ptr_by_key(deriv.ion_remap, kv.second)) { new_rebind.erase(kv.second); - new_rebind[kv.first] = *opt_v; + new_rebind[kv.first] = *v; } } for (auto& kv: over.ion_rebind) { - if (!value_by_key(deriv.ion_remap, kv.second)) { + if (!ptr_by_key(deriv.ion_remap, kv.second)) { new_rebind[kv.first] = kv.second; } } @@ -455,13 +455,13 @@ struct catalogue_state { // requested mechanism. auto apply_globals = [this, &apply_deriv](auto& self, const std::string& name, mechanism_overrides& over) -> void { - if (auto p = value_by_key(derived_map_, name)) { + if (auto* p = ptr_by_key(derived_map_, name)) { self(self, p->parent, over); apply_deriv(over, *p); } }; - util::optional<derivation> implicit_deriv; + std::optional<derivation> implicit_deriv; if (!defined(name)) { if (auto deriv = derive(name)) { implicit_deriv = std::move(deriv.value()); diff --git a/arbor/morph/label_dict.cpp b/arbor/morph/label_dict.cpp index 0d15b567ba21a1aaacf96a86e72c8d68f6d72d2d..9c514604a16c11159b963828d8303138ef3b67f1 100644 --- a/arbor/morph/label_dict.cpp +++ b/arbor/morph/label_dict.cpp @@ -1,4 +1,6 @@ +#include <optional> #include <unordered_map> +#include <utility> #include <arbor/morph/morphexcept.hpp> #include <arbor/morph/label_dict.hpp> @@ -34,13 +36,13 @@ void label_dict::import(const label_dict& other, const std::string& prefix) { } } -util::optional<const region&> label_dict::region(const std::string& name) const { +std::optional<region> label_dict::region(const std::string& name) const { auto it = regions_.find(name); if (it==regions_.end()) return {}; return it->second; } -util::optional<const locset&> label_dict::locset(const std::string& name) const { +std::optional<locset> label_dict::locset(const std::string& name) const { auto it = locsets_.find(name); if (it==locsets_.end()) return {}; return it->second; diff --git a/arbor/morph/region.cpp b/arbor/morph/region.cpp index 895666dcfacf4d367796af2b6699c35b6a4416b1..5e7c8a5afa243a49d0d9d56e0b5d7716b67399bd 100644 --- a/arbor/morph/region.cpp +++ b/arbor/morph/region.cpp @@ -1,4 +1,4 @@ -#include <any> +#include <optional> #include <stack> #include <string> #include <vector> @@ -9,7 +9,6 @@ #include <arbor/morph/morphexcept.hpp> #include <arbor/morph/mprovider.hpp> #include <arbor/morph/region.hpp> -#include <arbor/util/optional.hpp> #include "s_expr.hpp" #include "util/mergeview.hpp" @@ -21,12 +20,12 @@ namespace arb { namespace reg { -util::optional<mcable> intersect(const mcable& a, const mcable& b) { - if (a.branch!=b.branch) return util::nullopt; +std::optional<mcable> intersect(const mcable& a, const mcable& b) { + if (a.branch!=b.branch) return std::nullopt; double prox = std::max(a.prox_pos, b.prox_pos); double dist = std::min(a.dist_pos, b.dist_pos); - return prox<=dist? util::just(mcable{a.branch, prox, dist}): util::nullopt; + return prox<=dist? std::optional(mcable{a.branch, prox, dist}): std::nullopt; } // Empty region. diff --git a/arbor/util/hostname.cpp b/arbor/util/hostname.cpp index 7b335de98d85bbca787e3a42f0e030cc68206ec1..754a478516e61e553a5c037412443a3cdce6f743 100644 --- a/arbor/util/hostname.cpp +++ b/arbor/util/hostname.cpp @@ -1,7 +1,6 @@ +#include <optional> #include <string> -#include <arbor/util/optional.hpp> - #include "hostname.hpp" #ifdef __linux__ @@ -14,19 +13,19 @@ namespace arb { namespace util { #ifdef __linux__ -util::optional<std::string> hostname() { +std::optional<std::string> hostname() { // Hostnames can be up to 256 characters in length, however on many systems // it is limitted to 64. char name[256]; auto result = gethostname(name, sizeof(name)); if (result) { - return util::nullopt; + return std::nullopt; } return std::string(name); } #else -util::optional<std::string> hostname() { - return util::nullopt; +std::optional<std::string> hostname() { + return std::nullopt; } #endif diff --git a/arbor/util/hostname.hpp b/arbor/util/hostname.hpp index 4eaaf7f72e026f41d268b59223cd996d26dc928e..1108fce0c213288c644632643a9114b0735da77c 100644 --- a/arbor/util/hostname.hpp +++ b/arbor/util/hostname.hpp @@ -1,14 +1,13 @@ #pragma once +#include <optional> #include <string> -#include <arbor/util/optional.hpp> - namespace arb { namespace util { // Get the name of the host on which this process is running. -util::optional<std::string> hostname(); +std::optional<std::string> hostname(); } // namespace util } // namespace arb diff --git a/arbor/util/maputil.hpp b/arbor/util/maputil.hpp index bcecd481c8e28f64d1d41a510ae14245b389ad3e..693d91454b55104d3b242049a44bc24cbee88f37 100644 --- a/arbor/util/maputil.hpp +++ b/arbor/util/maputil.hpp @@ -3,11 +3,10 @@ #include <algorithm> #include <cstring> #include <iterator> +#include <optional> #include <utility> #include <type_traits> -#include <arbor/util/optional.hpp> - #include "util/meta.hpp" #include "util/transform.hpp" @@ -61,20 +60,30 @@ namespace maputil_impl { typename Seq, typename Key, typename Eq = std::equal_to<>, - typename Ret0 = decltype(get<1>(*begin(std::declval<Seq&&>()))), - typename Ret = std::conditional_t< - std::is_rvalue_reference<Seq&&>::value || !std::is_lvalue_reference<Ret0>::value, - std::remove_reference_t<Ret0>, - Ret0 - > + typename Ret = std::remove_reference_t<decltype(get<1>(*begin(std::declval<Seq&&>())))> > - optional<Ret> value_by_key(std::false_type, Seq&& seq, const Key& key, Eq eq=Eq{}) { + std::optional<Ret> value_by_key(std::false_type, Seq&& seq, const Key& key, Eq eq=Eq{}) { for (auto&& entry: seq) { if (eq(get<0>(entry), key)) { return get<1>(entry); } } - return nullopt; + return std::nullopt; + } + + template < + typename Seq, + typename Key, + typename Eq = std::equal_to<>, + typename Ret = std::remove_reference_t<decltype(get<1>(*begin(std::declval<Seq&&>())))> + > + Ret* ptr_by_key(std::false_type, Seq&& seq, const Key& key, Eq eq=Eq{}) { + for (auto&& entry: seq) { + if (eq(get<0>(entry), key)) { + return &get<1>(entry); + } + } + return nullptr; } // use map find @@ -82,22 +91,30 @@ namespace maputil_impl { typename Assoc, typename Key, typename FindRet = decltype(std::declval<Assoc&&>().find(std::declval<Key>())), - typename Ret0 = decltype(get<1>(*std::declval<FindRet>())), - typename Ret = std::conditional_t< - std::is_rvalue_reference<Assoc&&>::value || !std::is_lvalue_reference<Ret0>::value, - std::remove_reference_t<Ret0>, - Ret0 - > + typename Ret = std::remove_reference_t<decltype(get<1>(*std::declval<FindRet>()))> > - optional<Ret> value_by_key(std::true_type, Assoc&& map, const Key& key) { + std::optional<Ret> value_by_key(std::true_type, Assoc&& map, const Key& key) { auto it = map.find(key); if (it!=std::end(map)) { return get<1>(*it); } - return nullopt; + return std::nullopt; + } + + template < + typename Assoc, + typename Key, + typename FindRet = decltype(std::declval<Assoc&&>().find(std::declval<Key>())), + typename Ret = std::remove_reference_t<decltype(get<1>(*std::declval<FindRet>()))> + > + Ret* ptr_by_key(std::true_type, Assoc&& map, const Key& key) { + auto it = map.find(key); + return it!=std::end(map)? &get<1>(*it): nullptr; } } +// Return copy of value associated with key, wrapped in std::optional, or std::nullopty. + template <typename C, typename Key, typename Eq> auto value_by_key(C&& c, const Key& k, Eq eq) { return maputil_impl::value_by_key(std::false_type{}, std::forward<C>(c), k, eq); @@ -110,15 +127,29 @@ auto value_by_key(C&& c, const Key& k) { std::forward<C>(c), k); } +// Return pointer to value associated with key, or nullptr. + +template <typename C, typename Key, typename Eq> +auto ptr_by_key(C&& c, const Key& k, Eq eq) { + return maputil_impl::ptr_by_key(std::false_type{}, std::forward<C>(c), k, eq); +} + +template <typename C, typename Key> +auto ptr_by_key(C&& c, const Key& k) { + return maputil_impl::ptr_by_key( + std::integral_constant<bool, is_associative_container<C>::value>{}, + std::forward<C>(c), k); +} + // Find the index into an ordered sequence of a value by binary search; // returns optional<size_type> for the size_type associated with the sequence. // (Note: this is pretty much all we use algorthim::binary_find for.) template <typename C, typename Key> -optional<typename sequence_traits<C>::difference_type> binary_search_index(const C& c, const Key& key) { +std::optional<typename sequence_traits<C>::difference_type> binary_search_index(const C& c, const Key& key) { auto strict = strict_view(c); auto it = std::lower_bound(strict.begin(), strict.end(), key); - return it!=strict.end() && key==*it? just(std::distance(strict.begin(), it)): nullopt; + return it!=strict.end() && key==*it? std::optional(std::distance(strict.begin(), it)): std::nullopt; } // As binary_search_index above, but compare key against the proj(x) for elements @@ -126,11 +157,11 @@ optional<typename sequence_traits<C>::difference_type> binary_search_index(const // increasing. template <typename C, typename Key, typename Proj> -optional<typename sequence_traits<C>::difference_type> binary_search_index(const C& c, const Key& key, const Proj& proj) { +std::optional<typename sequence_traits<C>::difference_type> binary_search_index(const C& c, const Key& key, const Proj& proj) { auto strict = strict_view(c); auto projected = transform_view(strict, proj); auto it = std::lower_bound(projected.begin(), projected.end(), key); - return it!=strict.end() && key==*it? just(std::distance(projected.begin(), it)): nullopt; + return it!=strict.end() && key==*it? std::optional(std::distance(projected.begin(), it)): std::nullopt; } diff --git a/arborenv/gpu_uuid.cpp b/arborenv/gpu_uuid.cpp index 3d2c55d074510fe36b4eae339f102892b8751ae5..fe09cfbe57c5ce5e6ccc871fa85bca198fa32cfd 100644 --- a/arborenv/gpu_uuid.cpp +++ b/arborenv/gpu_uuid.cpp @@ -5,11 +5,11 @@ #include <iomanip> #include <ios> #include <numeric> +#include <optional> #include <ostream> #include <stdexcept> #include <vector> -#include <arbor/util/optional.hpp> #include <arbor/util/scope_exit.hpp> #include "gpu_uuid.hpp" #include "gpu_api.hpp" @@ -20,19 +20,19 @@ extern "C" { #include <unistd.h> } -arb::util::optional<std::string> get_hostname() { +std::optional<std::string> get_hostname() { // Hostnames can be up to 256 characters in length, however on many systems // it is limitted to 64. char name[256]; auto result = gethostname(name, sizeof(name)); if (result) { - return arb::util::nullopt; + return std::nullopt; } return std::string(name); } #else -arb::util::optional<std::string> get_hostname() { - return arb::util::nullopt; +std::optional<std::string> get_hostname() { + return std::nullopt; } #endif diff --git a/example/brunel/brunel.cpp b/example/brunel/brunel.cpp index 36c74da9cb8a31f805874afa9d69e23057809e75..03f63e8e1e2cb7f5896790624879de2471b3034b 100644 --- a/example/brunel/brunel.cpp +++ b/example/brunel/brunel.cpp @@ -4,6 +4,7 @@ #include <iomanip> #include <iostream> #include <memory> +#include <optional> #include <set> #include <vector> @@ -19,7 +20,6 @@ #include <arbor/profile/profiler.hpp> #include <arbor/recipe.hpp> #include <arbor/simulation.hpp> -#include <arbor/util/optional.hpp> #include <arbor/version.hpp> #include <arborenv/concurrency.hpp> @@ -68,7 +68,7 @@ struct cl_options { std::ostream& operator<<(std::ostream& o, const cl_options& opt); -util::optional<cl_options> read_options(int argc, char** argv); +std::optional<cl_options> read_options(int argc, char** argv); void banner(const context& ctx); @@ -346,7 +346,7 @@ std::vector<cell_gid_type> sample_subset(cell_gid_type gid, cell_gid_type start, } // Read options from (optional) json file and command line arguments. -util::optional<cl_options> read_options(int argc, char** argv) { +std::optional<cl_options> read_options(int argc, char** argv) { using namespace to; auto usage_str = "\n" "-n|--n-excitatory [Number of cells in the excitatory population]\n" diff --git a/python/cells.cpp b/python/cells.cpp index 54510c9070d5d3a359967fa45492ae3733f880a1..2ac158fcda90262a95b7c4a910c433a45864d222 100644 --- a/python/cells.cpp +++ b/python/cells.cpp @@ -21,7 +21,6 @@ #include <arbor/schedule.hpp> #include <arbor/spike_source_cell.hpp> #include <arbor/util/any_cast.hpp> -#include <arbor/util/optional.hpp> #include <arbor/util/unique_any.hpp> #include "cells.hpp" @@ -215,7 +214,7 @@ std::string mechanism_desc_str(const arb::mechanism_desc& md) { void register_cells(pybind11::module& m) { using namespace pybind11::literals; - using arb::util::optional; + using std::optional; // arb::spike_source_cell diff --git a/python/context.cpp b/python/context.cpp index bd70f1512030b0cf986b2d029763077e3aa96a40..e8cd4dbcb61a0cd5365f5d69c2c1f45f13ce234b 100644 --- a/python/context.cpp +++ b/python/context.cpp @@ -1,4 +1,5 @@ #include <iostream> +#include <optional> #include <sstream> #include <string> @@ -6,7 +7,6 @@ #include <arbor/context.hpp> #include <arbor/version.hpp> -#include <arbor/util/optional.hpp> #include "context.hpp" #include "conversion.hpp" @@ -33,7 +33,7 @@ std::ostream& operator<<(std::ostream& o, const context_shim& ctx) { // A Python shim that holds the information that describes an arb::proc_allocation. struct proc_allocation_shim { - arb::util::optional<int> gpu_id = {}; + std::optional<int> gpu_id = {}; int num_threads = 1; proc_allocation_shim(int threads, pybind11::object gpu) { @@ -53,7 +53,7 @@ struct proc_allocation_shim { num_threads = threads; }; - arb::util::optional<int> get_gpu_id() const { return gpu_id; } + std::optional<int> get_gpu_id() const { return gpu_id; } int get_num_threads() const { return num_threads; } bool has_gpu() const { return bool(gpu_id); } @@ -64,7 +64,7 @@ struct proc_allocation_shim { }; std::ostream& operator<<(std::ostream& o, const proc_allocation_shim& alloc) { - return o << "<arbor.proc_allocation: threads " << alloc.num_threads << ", gpu_id " << alloc.gpu_id << ">"; + return o << "<arbor.proc_allocation: threads " << alloc.num_threads << ", gpu_id " << util::to_string(alloc.gpu_id) << ">"; } void register_contexts(pybind11::module& m) { diff --git a/python/conversion.hpp b/python/conversion.hpp index eda94ba044a36997dbe6b58dc1a303fdfe4c985d..30b6c11aa851ad81f93860f5e357ec690abfe8bc 100644 --- a/python/conversion.hpp +++ b/python/conversion.hpp @@ -1,19 +1,13 @@ #pragma once +#include <optional> + #include <pybind11/pybind11.h> #include <pybind11/pytypes.h> #include <pybind11/stl.h> -#include <arbor/util/optional.hpp> - #include "error.hpp" -// from https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=boost%3A%3Aoptional#c-17-library-containers -namespace pybind11 { namespace detail { - template <typename T> - struct type_caster<arb::util::optional<T>>: optional_caster<arb::util::optional<T>> {}; -}} - namespace pyarb { struct is_nonneg { @@ -35,7 +29,7 @@ struct is_positive { // Throws an runtime_error exception with msg if either the Python object // can't be converted to type T, or if the predicate is false for the value. template <typename T, typename F> -arb::util::optional<T> py2optional(pybind11::object o, const char* msg, F&& pred) { +std::optional<T> py2optional(pybind11::object o, const char* msg, F&& pred) { bool ok = true; T value; @@ -53,11 +47,11 @@ arb::util::optional<T> py2optional(pybind11::object o, const char* msg, F&& pred throw pyarb_error(msg); } - return o.is_none()? arb::util::nullopt: arb::util::optional<T>(std::move(value)); + return o.is_none()? std::nullopt: std::optional<T>(std::move(value)); } template <typename T> -arb::util::optional<T> py2optional(pybind11::object o, const char* msg) { +std::optional<T> py2optional(pybind11::object o, const char* msg) { T value; if (!o.is_none()) { @@ -69,7 +63,7 @@ arb::util::optional<T> py2optional(pybind11::object o, const char* msg) { } } - return o.is_none()? arb::util::nullopt: arb::util::optional<T>(std::move(value)); + return o.is_none()? std::nullopt: std::optional<T>(std::move(value)); } // Attempt to cast a Python object to a C++ type T. @@ -77,8 +71,8 @@ arb::util::optional<T> py2optional(pybind11::object o, const char* msg) { // to T, otherwise it is empty. Hence not being able // to cast is not an error. template <typename T> -arb::util::optional<T> try_cast(pybind11::object o) { - if (o.is_none()) return arb::util::nullopt; +std::optional<T> try_cast(pybind11::object o) { + if (o.is_none()) return std::nullopt; try { return o.cast<T>(); @@ -86,7 +80,7 @@ arb::util::optional<T> try_cast(pybind11::object o) { // Ignore cast_error: if unable to perform cast. catch (pybind11::cast_error& e) {} - return arb::util::nullopt; + return std::nullopt; } } // namespace arb diff --git a/python/event_generator.cpp b/python/event_generator.cpp index ceb5ec53dc54dc60e1ba52e8c84cde2d96675f44..957e75e2d56e8ceea5d73889e5358035f025953a 100644 --- a/python/event_generator.cpp +++ b/python/event_generator.cpp @@ -1,17 +1,10 @@ -#include <stdexcept> -#include <sstream> -#include <string> - #include <pybind11/pybind11.h> #include <pybind11/pytypes.h> #include <pybind11/stl.h> #include <arbor/common_types.hpp> #include <arbor/schedule.hpp> -#include <arbor/util/optional.hpp> -#include "conversion.hpp" -#include "error.hpp" #include "event_generator.hpp" #include "schedule.hpp" diff --git a/python/mechanism.cpp b/python/mechanism.cpp index c710c013f12a966473bba6075828480da13c0b20..09356d66ce84130c9722252c4c2f4272a97bdb96 100644 --- a/python/mechanism.cpp +++ b/python/mechanism.cpp @@ -1,3 +1,6 @@ +#include <optional> +#include <stdexcept> + #include <pybind11/pybind11.h> #include "pybind11/pytypes.h" #include <pybind11/stl.h> @@ -5,8 +8,6 @@ #include <arbor/cable_cell_param.hpp> #include <arbor/mechanism.hpp> #include <arbor/mechcat.hpp> -#include <arbor/util/optional.hpp> -#include <stdexcept> #include "arbor/mechinfo.hpp" @@ -37,7 +38,7 @@ void apply_derive(arb::mechanism_catalogue& m, } void register_mechanisms(pybind11::module& m) { - using arb::util::optional; + using std::optional; using namespace pybind11::literals; pybind11::class_<arb::mechanism_field_spec> field_spec(m, "mechanism_field", diff --git a/python/schedule.cpp b/python/schedule.cpp index f186fe0c2881d0fc206cabc7a05eac6d30ce6186..ff51408b63ae719f4467191a9d70925ab5001524 100644 --- a/python/schedule.cpp +++ b/python/schedule.cpp @@ -1,6 +1,5 @@ #include <arbor/schedule.hpp> #include <arbor/common_types.hpp> -#include <arbor/util/optional.hpp> #include <pybind11/pybind11.h> #include <pybind11/stl.h> @@ -13,9 +12,9 @@ namespace pyarb { std::ostream& operator<<(std::ostream& o, const regular_schedule_shim& x) { return o << "<arbor.regular_schedule: tstart " - << x.tstart << " ms, dt " + << util::to_string(x.tstart) << " ms, dt " << x.dt << " ms, tstop " - << x.tstop << " ms>"; + << util::to_string(x.tstop) << " ms>"; } std::ostream& operator<<(std::ostream& o, const explicit_schedule_shim& e) { diff --git a/python/schedule.hpp b/python/schedule.hpp index 072160713bb0e15a2b8c693b85b9d50ebf0b1a00..5aefeb5fcbc5e783e0764d01688469f2cdf23197 100644 --- a/python/schedule.hpp +++ b/python/schedule.hpp @@ -1,11 +1,14 @@ #pragma once +#include <optional> +#include <random> +#include <vector> + #include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <arbor/schedule.hpp> #include <arbor/common_types.hpp> -#include <arbor/util/optional.hpp> namespace pyarb { @@ -15,7 +18,7 @@ namespace pyarb { // an arb::regular_schedule when a C++ recipe is created from a Python recipe. struct regular_schedule_shim { using time_type = arb::time_type; - using opt_time_type = arb::util::optional<time_type>; + using opt_time_type = std::optional<time_type>; opt_time_type tstart = {}; opt_time_type tstop = {}; diff --git a/python/strprintf.hpp b/python/strprintf.hpp index 5e2699bd41d3a91194d6107cf4d0b0e054eb11f7..638016772661773b093a20fbde94b9b2046c181c 100644 --- a/python/strprintf.hpp +++ b/python/strprintf.hpp @@ -4,18 +4,44 @@ #include <cstdio> #include <memory> +#include <optional> #include <string> #include <sstream> #include <system_error> +#include <type_traits> #include <unordered_map> #include <utility> #include <vector> -#include <arbor/util/optional.hpp> - namespace pyarb { namespace util { +namespace impl { + // Wrapper for formatted output of optional values. + template <typename T> + struct opt_wrap { + const T& ref; + opt_wrap(const T& ref): ref(ref) {} + friend std::ostream& operator<<(std::ostream& out, const opt_wrap& wrap) { + return out << wrap.ref; + } + }; + + template <typename T> + struct opt_wrap<std::optional<T>> { + const std::optional<T>& ref; + opt_wrap(const std::optional<T>& ref): ref(ref) {} + friend std::ostream& operator<<(std::ostream& out, const opt_wrap& wrap) { + if (wrap.ref) { + return out << *wrap.ref; + } + else { + return out << "None"; + } + } + }; +} + // Use ADL to_string or std::to_string, falling back to ostream formatting: namespace impl_to_string { @@ -25,17 +51,13 @@ namespace impl_to_string { struct select { static std::string str(const T& value) { std::ostringstream o; - o << value; + o << impl::opt_wrap(value); return o.str(); } }; - // Can be eplaced with std::void_t in c++17. - template <typename ...Args> - using void_t = void; - template <typename T> - struct select<T, void_t<decltype(to_string(std::declval<T>()))>> { + struct select<T, std::void_t<decltype(to_string(std::declval<T>()))>> { static std::string str(const T& v) { return to_string(v); } @@ -100,7 +122,7 @@ namespace impl { } o.write(s, t-s); if (*t) { - o << std::forward<T>(value); + o << opt_wrap{value}; pprintf_(o, t+2, std::forward<Tail>(tail)...); } } @@ -217,14 +239,4 @@ std::string dictionary_csv(const std::unordered_map<Key, T>& dict) { } } // namespace util - -} - -namespace arb { -namespace util { -template <typename T> -std::ostream& operator<<(std::ostream& o, const arb::util::optional<T>& x) { - return o << (x? pyarb::util::to_string(*x): "None"); -} -} -} +} // namespace pyarb diff --git a/sup/include/sup/json_params.hpp b/sup/include/sup/json_params.hpp index fdcf0a20e2be4df7bffa7ec8ca06a5b457743c33..05ce805d1b4a0ca761ed9fd715e18f9dd0f07d71 100644 --- a/sup/include/sup/json_params.hpp +++ b/sup/include/sup/json_params.hpp @@ -2,8 +2,7 @@ #include <array> #include <exception> - -#include <arbor/util/optional.hpp> +#include <optional> #include <nlohmann/json.hpp> @@ -12,10 +11,10 @@ namespace sup { // Search a json object for an entry with a given name. // If found, return the value and remove from json object. template <typename T> -arb::util::optional<T> find_and_remove_json(const char* name, nlohmann::json& j) { +std::optional<T> find_and_remove_json(const char* name, nlohmann::json& j) { auto it = j.find(name); if (it==j.end()) { - return arb::util::nullopt; + return std::nullopt; } T value = std::move(*it); j.erase(name); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 7bf826b14ec94a8f10a1af85325f653cf48eb12b..eb3ef8d6476ae54cc0b3bcd512c037bb1502dd72 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -128,7 +128,6 @@ set(unit_sources test_morph_primitives.cpp test_morph_stitch.cpp test_multi_event_stream.cpp - test_optional.cpp test_ordered_forest.cpp test_padded.cpp test_partition.cpp diff --git a/test/unit/test_cv_geom.cpp b/test/unit/test_cv_geom.cpp index a007a86b7277905b06a4b9ed8abae7c01f7302eb..8e883ab0809037cf63baaf328c0e10bf0ec027bd 100644 --- a/test/unit/test_cv_geom.cpp +++ b/test/unit/test_cv_geom.cpp @@ -1,7 +1,6 @@ #include <algorithm> #include <utility> -#include <arbor/util/optional.hpp> #include <arbor/cable_cell.hpp> #include <arbor/morph/morphology.hpp> #include <arbor/morph/locset.hpp> diff --git a/test/unit/test_cv_layout.cpp b/test/unit/test_cv_layout.cpp index 8502318d9e66b6b03a3a8f7255baee08b4c21625..bcc0c5a32cf35a46281f2ccfebb84e9fe0617791 100644 --- a/test/unit/test_cv_layout.cpp +++ b/test/unit/test_cv_layout.cpp @@ -5,7 +5,6 @@ #include <arbor/math.hpp> #include <arbor/morph/morphology.hpp> #include <arbor/morph/locset.hpp> -#include <arbor/util/optional.hpp> #include "fvm_layout.hpp" #include "util/span.hpp" diff --git a/test/unit/test_cv_policy.cpp b/test/unit/test_cv_policy.cpp index 2ffbfbc3afe4281020b6ccbbe2e12a9998d7031f..7a4dc6327e35b5bebec9b2d006e076a1864636fc 100644 --- a/test/unit/test_cv_policy.cpp +++ b/test/unit/test_cv_policy.cpp @@ -3,7 +3,6 @@ #include <utility> #include <vector> -#include <arbor/util/optional.hpp> #include <arbor/cable_cell.hpp> #include <arbor/cable_cell_param.hpp> #include <arbor/morph/morphology.hpp> diff --git a/test/unit/test_fvm_layout.cpp b/test/unit/test_fvm_layout.cpp index 3613a251cc6cbb997cccd579baf00f40e6e16051..4c6dc4cbfe9b81896af722b4e9bb92e8d8dc170a 100644 --- a/test/unit/test_fvm_layout.cpp +++ b/test/unit/test_fvm_layout.cpp @@ -5,7 +5,6 @@ #include <arbor/cable_cell.hpp> #include <arbor/math.hpp> #include <arbor/mechcat.hpp> -#include <arbor/util/optional.hpp> #include "arbor/morph/morphology.hpp" #include "arbor/morph/segment_tree.hpp" @@ -25,6 +24,7 @@ using namespace arb; using util::make_span; using util::count_along; +using util::ptr_by_key; using util::value_by_key; namespace { @@ -190,12 +190,12 @@ struct exp_instance { bool is_in(const arb::fvm_mechanism_config& C) const { std::vector<unsigned> _; auto part = util::make_partition(_, C.multiplicity); - auto& evals = *value_by_key(C.param_values, "e"); + auto& evals = *ptr_by_key(C.param_values, "e"); // Handle both expsyn and exp2syn by looking for "tau1" if "tau" // parameter is not found. - auto& tauvals = value_by_key(C.param_values, "tau")? - *value_by_key(C.param_values, "tau"): - *value_by_key(C.param_values, "tau1"); + auto& tauvals = *(value_by_key(C.param_values, "tau")? + ptr_by_key(C.param_values, "tau"): + ptr_by_key(C.param_values, "tau1")); for (auto i: make_span(C.multiplicity.size())) { exp_instance other(C.cv[i], @@ -445,11 +445,11 @@ TEST(fvm_layout, synapse_targets) { auto& expsyn_cv = M.mechanisms.at("expsyn").cv; auto& expsyn_target = M.mechanisms.at("expsyn").target; - auto& expsyn_e = value_by_key(M.mechanisms.at("expsyn").param_values, "e"s).value(); + auto& expsyn_e = *ptr_by_key(M.mechanisms.at("expsyn").param_values, "e"s); auto& exp2syn_cv = M.mechanisms.at("exp2syn").cv; auto& exp2syn_target = M.mechanisms.at("exp2syn").target; - auto& exp2syn_e = value_by_key(M.mechanisms.at("exp2syn").param_values, "e"s).value(); + auto& exp2syn_e = *ptr_by_key(M.mechanisms.at("exp2syn").param_values, "e"s); EXPECT_TRUE(util::is_sorted(expsyn_cv)); EXPECT_TRUE(util::is_sorted(exp2syn_cv)); @@ -597,8 +597,8 @@ TEST(fvm_layout, density_norm_area) { ASSERT_EQ(1u, M.mechanisms.count("hh")); auto& hh_params = M.mechanisms.at("hh").param_values; - auto& gkbar = value_by_key(hh_params, "gkbar"s).value(); - auto& gl = value_by_key(hh_params, "gl"s).value(); + auto& gkbar = *ptr_by_key(hh_params, "gkbar"s); + auto& gl = *ptr_by_key(hh_params, "gl"s); EXPECT_TRUE(testing::seq_almost_eq<double>(expected_gkbar, gkbar)); EXPECT_TRUE(testing::seq_almost_eq<double>(expected_gl, gl)); @@ -676,9 +676,9 @@ TEST(fvm_layout, density_norm_area_partial) { auto& hh_params = M.mechanisms.at("hh").param_values; - auto& gkbar = value_by_key(hh_params, "gkbar"s).value(); - auto& gnabar = value_by_key(hh_params, "gnabar"s).value(); - auto& gl = value_by_key(hh_params, "gl"s).value(); + auto& gkbar = *ptr_by_key(hh_params, "gkbar"s); + auto& gnabar = *ptr_by_key(hh_params, "gnabar"s); + auto& gl = *ptr_by_key(hh_params, "gl"s); ASSERT_EQ(1u, gkbar.size()); ASSERT_EQ(1u, gnabar.size()); diff --git a/test/unit/test_maputil.cpp b/test/unit/test_maputil.cpp index 4cb6ed06d547de60005bbf56d41715ea2d748330..ea97cd5348426744ccd785ef61dbd298c0e41215 100644 --- a/test/unit/test_maputil.cpp +++ b/test/unit/test_maputil.cpp @@ -97,16 +97,11 @@ namespace { return std::map<K, V>::find(key); } }; - - template <typename X> - constexpr bool is_optional_reference(X) { return false; } - - template <typename X> - constexpr bool is_optional_reference(util::optional<X&>) { return true; } } TEST(maputil, value_by_key_map) { using util::value_by_key; + using util::ptr_by_key; check_map<std::string, int> map_s2i = { {"fish", 4}, @@ -117,25 +112,22 @@ TEST(maputil, value_by_key_map) { EXPECT_FALSE(value_by_key(map_s2i, "deer")); EXPECT_EQ(1, S.count); - // Should get an optional reference if argument is an lvalue. - S.count = 0; auto r1 = value_by_key(map_s2i, "sheep"); EXPECT_EQ(1, S.count); EXPECT_TRUE(r1); EXPECT_EQ(5, r1.value()); - EXPECT_TRUE(is_optional_reference(r1)); - r1.value() = 6; - EXPECT_EQ(6, value_by_key(map_s2i, "sheep").value()); - // Should not get an optional reference if argument is an rvalue. + auto p1 = ptr_by_key(map_s2i, "sheep"); + ASSERT_TRUE(p1); + *p1 = 6; + EXPECT_EQ(6, value_by_key(map_s2i, "sheep").value()); S.count = 0; auto r2 = value_by_key(check_map<std::string, int>(map_s2i), "fish"); EXPECT_EQ(1, S.count); EXPECT_TRUE(r2); EXPECT_EQ(4, r2.value()); - EXPECT_FALSE(is_optional_reference(r2)); // Providing an explicit comparator should fall-back to serial search. @@ -149,6 +141,7 @@ TEST(maputil, value_by_key_map) { TEST(maputil, value_by_key_sequence) { using util::value_by_key; + using util::ptr_by_key; // Note: value_by_key returns the value of `get<1>` on the // entries in the map or sequence. @@ -165,14 +158,15 @@ TEST(maputil, value_by_key_sequence) { auto r1 = value_by_key(table, 3); EXPECT_TRUE(r1); EXPECT_EQ("three"s, r1.value()); - EXPECT_TRUE(is_optional_reference(r1)); - r1.value() = "four"; + + auto p1 = ptr_by_key(table, 3); + ASSERT_TRUE(p1); + *p1 = "four"; EXPECT_EQ("four"s, value_by_key(table, 3).value()); auto r2 = value_by_key(std::move(table), 1); EXPECT_TRUE(r2); EXPECT_EQ("one", r2.value()); - EXPECT_FALSE(is_optional_reference(r2)); } TEST(maputil, binary_search_index) { diff --git a/test/unit/test_optional.cpp b/test/unit/test_optional.cpp deleted file mode 100644 index 760e4a683a1d2ab7d8b64823c2c3323360b266f3..0000000000000000000000000000000000000000 --- a/test/unit/test_optional.cpp +++ /dev/null @@ -1,304 +0,0 @@ -#include <algorithm> -#include <array> -#include <string> -#include <typeinfo> - -#include "../gtest.h" - -#include <arbor/util/optional.hpp> - -#include "common.hpp" - -using namespace std::string_literals; -using namespace arb::util; - -TEST(optional, ctors) { - optional<int> a, b(3), c = b, d = 4; - - ASSERT_FALSE((bool)a); - ASSERT_TRUE((bool)b); - ASSERT_TRUE((bool)c); - ASSERT_TRUE((bool)d); - - EXPECT_EQ(3, b.value()); - EXPECT_EQ(3, c.value()); - EXPECT_EQ(4, d.value()); -} - -TEST(optional, unset_throw) { - optional<int> a; - int check = 10; - - try { - a.value(); - } - catch (optional_unset_error& e) { - ++check; - } - EXPECT_EQ(11, check); - - check = 20; - a = 2; - try { - a.value(); - } - catch (optional_unset_error& e) { - ++check; - } - EXPECT_EQ(20, check); - - check = 30; - a.reset(); - try { - a.value(); - } - catch (optional_unset_error& e) { - ++check; - } - EXPECT_EQ(31, check); -} - -TEST(optional, deref) { - struct foo { - int a; - explicit foo(int a_): a(a_) {} - double value() { return 3.0*a; } - }; - - optional<foo> f = foo(2); - EXPECT_EQ(6.0, f->value()); - EXPECT_EQ(2, (*f).a); -} - -TEST(optional, ctor_conv) { - optional<std::array<int, 3>> x{{1, 2, 3}}; - EXPECT_EQ(3u, x->size()); -} - -TEST(optional, ctor_ref) { - int v = 10; - optional<int&> a(v); - - EXPECT_EQ(10, a.value()); - v = 20; - EXPECT_EQ(20, a.value()); - - optional<int&> b(a), c = b, d = v; - EXPECT_EQ(&(a.value()), &(b.value())); - EXPECT_EQ(&(a.value()), &(c.value())); - EXPECT_EQ(&(a.value()), &(d.value())); -} - -TEST(optional, assign_returns) { - optional<int> a = 3; - - auto b = (a = 4); - EXPECT_EQ(typeid(optional<int>), typeid(b)); - - auto bp = &(a = 4); - EXPECT_EQ(&a, bp); - - auto b2 = (a = optional<int>(10)); - EXPECT_EQ(typeid(optional<int>), typeid(b2)); - - auto bp2 = &(a = 4); - EXPECT_EQ(&a, bp2); - - auto b3 = (a = nullopt); - EXPECT_EQ(typeid(optional<int>), typeid(b3)); - - auto bp3 = &(a = 4); - EXPECT_EQ(&a, bp3); -} - -TEST(optional, assign_reference) { - double a = 3.0; - optional<double&> ar; - optional<double&> br; - - ar = a; - EXPECT_TRUE(ar); - *ar = 5.0; - EXPECT_EQ(5.0, a); - - auto& check_rval = (br = ar); - EXPECT_TRUE(br); - EXPECT_EQ(&br, &check_rval); - - *br = 7.0; - EXPECT_EQ(7.0, a); - - auto& check_rval2 = (br = nullopt); - EXPECT_FALSE(br); - EXPECT_EQ(&br, &check_rval2); -} - -TEST(optional, ctor_nomove) { - using nomove = testing::nomove<int>; - - optional<nomove> a(nomove(3)); - EXPECT_EQ(nomove(3), a.value()); - - optional<nomove> b; - b = a; - EXPECT_EQ(nomove(3), b.value()); - - b = optional<nomove>(nomove(4)); - EXPECT_EQ(nomove(4), b.value()); -} - -TEST(optional, ctor_nocopy) { - using nocopy = testing::nocopy<int>; - - optional<nocopy> a(nocopy(5)); - EXPECT_EQ(nocopy(5), a.value()); - - nocopy::reset_counts(); - optional<nocopy> b(std::move(a)); - EXPECT_EQ(nocopy(5), b.value()); - EXPECT_EQ(0, a.value().value); - EXPECT_EQ(1, nocopy::move_ctor_count); - EXPECT_EQ(0, nocopy::move_assign_count); - - nocopy::reset_counts(); - b = optional<nocopy>(nocopy(6)); - EXPECT_EQ(nocopy(6), b.value()); - EXPECT_EQ(1, nocopy::move_ctor_count); - EXPECT_EQ(1, nocopy::move_assign_count); - - nocopy::reset_counts(); - nocopy v = optional<nocopy>(nocopy(9)).value(); - EXPECT_EQ(2, nocopy::move_ctor_count); - EXPECT_EQ(nocopy(9), v.value); - - const optional<nocopy> ccheck(nocopy(1)); - EXPECT_TRUE(std::is_rvalue_reference<decltype(std::move(ccheck).value())>::value); - EXPECT_TRUE(std::is_const<std::remove_reference_t<decltype(std::move(ccheck).value())>>::value); -} - -TEST(optional, value_or) { - optional<double> x = 3; - EXPECT_EQ(3., x.value_or(5)); - - x = nullopt; - EXPECT_EQ(5., x.value_or(5)); - - // `value_or` returns T for optional<T>: - struct check_conv { - bool value = false; - explicit check_conv(bool value): value(value) {} - - explicit operator std::string() const { - return value? "true": "false"; - } - }; - check_conv cc{true}; - - optional<std::string> present = "present"s; - optional<std::string> absent; // nullopt - - auto result = present.value_or(cc); - EXPECT_EQ(typeid(std::string), typeid(result)); - EXPECT_EQ("present"s, result); - - result = absent.value_or(cc); - EXPECT_EQ("true"s, result); - - // Check move semantics in argument: - - using nocopy = testing::nocopy<int>; - - nocopy::reset_counts(); - nocopy z1 = optional<nocopy>().value_or(nocopy(7)); - - EXPECT_EQ(7, z1.value); - EXPECT_EQ(1, nocopy::move_ctor_count); - - nocopy::reset_counts(); - nocopy z2 = optional<nocopy>(nocopy(3)).value_or(nocopy(7)); - - EXPECT_EQ(3, z2.value); - EXPECT_EQ(2, nocopy::move_ctor_count); -} - -TEST(optional, ref_value_or) { - double a = 2.0; - double b = 3.0; - - optional<double&> x = a; - double& ref1 = x.value_or(b); - - EXPECT_EQ(2., ref1); - - x = nullopt; - double& ref2 = x.value_or(b); - - EXPECT_EQ(3., ref2); - - ref1 = 12.; - ref2 = 13.; - EXPECT_EQ(12., a); - EXPECT_EQ(13., b); - - const optional<double&> cx = x; - auto& ref3 = cx.value_or(b); - EXPECT_TRUE(std::is_const<std::remove_reference_t<decltype(ref3)>>::value); - EXPECT_EQ(&b, &ref3); -} - -TEST(optional, void) { - optional<void> a, b(true), c(a), d = b, e(false), f(nullopt); - - EXPECT_FALSE((bool)a); - EXPECT_TRUE((bool)b); - EXPECT_FALSE((bool)c); - EXPECT_TRUE((bool)d); - EXPECT_TRUE((bool)e); - EXPECT_FALSE((bool)f); - - auto& check_rval = (b = nullopt); - EXPECT_FALSE((bool)b); - EXPECT_EQ(&b, &check_rval); -} - -TEST(optional, conversion) { - optional<double> a(3), b = 5; - EXPECT_TRUE((bool)a); - EXPECT_TRUE((bool)b); - EXPECT_EQ(3.0, a.value()); - EXPECT_EQ(5.0, b.value()); - - optional<int> x; - optional<double> c(x); - optional<double> d = optional<int>(); - EXPECT_FALSE((bool)c); - EXPECT_FALSE((bool)d); -} - -TEST(optional, just) { - int x = 3; - - optional<int&> o1 = just(x); - optional<int> o2 = just(x); - - o1.value() = 4; - optional<int> o3 = just(x); - EXPECT_EQ(4, o1.value()); - EXPECT_EQ(3, o2.value()); - EXPECT_EQ(4, o3.value()); -} - -TEST(optional, emplace) { - optional<int> o1(7); - optional<std::array<double, 3>> o2{{22., 22., 22.}}; - int x = 42; - std::array<double, 3> arr{{4.5, 7.1, 1.2}}; - - o1.emplace(x); - o2.emplace(arr); - - EXPECT_EQ(42, o1.value()); - EXPECT_EQ(4.5, o2.value()[0]); - EXPECT_EQ(7.1, o2.value()[1]); - EXPECT_EQ(1.2, o2.value()[2]); -} diff --git a/test/unit/test_synapses.cpp b/test/unit/test_synapses.cpp index de1a796b88763ffe33e31b3dc96c84469d43516e..6c9bdeb2b0e820870b317a27671da497d2a47e40 100644 --- a/test/unit/test_synapses.cpp +++ b/test/unit/test_synapses.cpp @@ -6,7 +6,6 @@ #include <arbor/constants.hpp> #include <arbor/mechcat.hpp> -#include <arbor/util/optional.hpp> #include <arbor/cable_cell.hpp> #include "backends/multicore/fvm.hpp"