/****************************************************************************** * Copyright (c) 2019, Connor Manning (connor@hobu.co) * * Entwine -- Point cloud indexing * * Entwine is available under the terms of the LGPL2 license. See COPYING * for specific license text and more information. * ******************************************************************************/ #pragma once #include #include #include namespace entwine { constexpr struct in_place_t { } in_place { }; class bad_optional_access : public std::logic_error { public: explicit bad_optional_access(const std::string& s) : std::logic_error(s) { } explicit bad_optional_access(const char* s) : std::logic_error(s) { } }; // This is a very poor implementation of optional since it uses the heap, but // it's just a stopgap until the project upgrades to C++17 and matches the API // of std::optional. Functionally, this implementation acts as a unique_ptr // but with a cloning copy constructor. template class optional { public: optional() = default; optional(const T& v) : m_value(makeUnique(v)) { } optional(T&& v) : m_value(makeUnique(std::move(v))) { } template optional(in_place_t, Args&&... args) : m_value(makeUnique(std::forward(args)...)) { } optional(const optional& other) : optional() { if (other) m_value = makeUnique(*other); } optional(optional&& other) : optional() { if (other) m_value = makeUnique(std::move(*other)); } optional(const json& j) : optional() { if (!j.is_null()) m_value = makeUnique(j); } optional& operator=(const optional& other) { if (!other) reset(); else m_value = makeUnique(*other); return *this; } // Inspection. bool has_value() const noexcept { return static_cast(m_value); } explicit operator bool() const noexcept { return has_value(); } // Unchecked access. T* operator->() { return m_value.get(); } const T* operator->() const { return m_value.get(); } T& operator*() { return *m_value; } const T& operator*() const { return *m_value; } // Checked access. T& value() { if (!has_value()) throw bad_optional_access("Bad optional access"); return **this; } const T& value() const { if (!has_value()) throw bad_optional_access("Bad optional access"); return **this; } template T value_or(U&& def) const { return has_value() ? **this : static_cast(std::forward(def)); } // Modifiers. void reset() { m_value.reset(); } private: std::unique_ptr m_value; }; template inline optional maybeCreate(const json& j) { if (!j.is_null()) return j.get(); return { }; } template inline void to_json(json& j, const optional& v) { if (v) j = *v; } template inline void from_json(const json& j, optional& v) { if (!j.is_null()) v = j.get(); } } // namespace entwine