// Copyright 2020 Arthur Sonzogni. All rights reserved. // Use of this source code is governed by the MIT license that can be found in // the LICENSE file. #ifndef FTXUI_UTIL_REF_HPP #define FTXUI_UTIL_REF_HPP #include #include #include #include #include namespace ftxui { /// @brief An adapter. Own or reference an immutable object. template class ConstRef { public: ConstRef() = default; ConstRef(T t) : variant_(std::move(t)) {} // NOLINT ConstRef(const T* t) : variant_(t) {} // NOLINT ConstRef& operator=(ConstRef&&) noexcept = default; ConstRef(const ConstRef&) = default; ConstRef(ConstRef&&) noexcept = default; ~ConstRef() = default; // Make a "reseatable" reference ConstRef& operator=(const ConstRef&) = default; // Accessors: const T& operator()() const { return *Address(); } const T& operator*() const { return *Address(); } const T* operator->() const { return Address(); } private: std::variant variant_ = T{}; const T* Address() const { return std::holds_alternative(variant_) ? &std::get(variant_) : std::get(variant_); } }; /// @brief An adapter. Own or reference an mutable object. template class Ref { public: Ref() = default; Ref(T t) : variant_(std::move(t)) {} // NOLINT Ref(T* t) : variant_(t) {} // NOLINT ~Ref() = default; Ref& operator=(Ref&&) noexcept = default; Ref(const Ref&) = default; Ref(Ref&&) noexcept = default; // Make a "reseatable" reference. Ref& operator=(const Ref&) = default; // Accessors: T& operator()() { return *Address(); } T& operator*() { return *Address(); } T* operator->() { return Address(); } const T& operator()() const { return *Address(); } const T& operator*() const { return *Address(); } const T* operator->() const { return Address(); } private: std::variant variant_ = T{}; const T* Address() const { return std::holds_alternative(variant_) ? &std::get(variant_) : std::get(variant_); } T* Address() { return std::holds_alternative(variant_) ? &std::get(variant_) : std::get(variant_); } }; /// @brief An adapter. Own or reference a constant string. For convenience, this /// class convert multiple mutable string toward a shared representation. class StringRef : public Ref { public: using Ref::Ref; StringRef(const wchar_t* ref) // NOLINT : StringRef(to_string(std::wstring(ref))) {} StringRef(const char* ref) // NOLINT : StringRef(std::string(ref)) {} }; /// @brief An adapter. Own or reference a constant string. For convenience, this /// class convert multiple immutable string toward a shared representation. class ConstStringRef : public ConstRef { public: using ConstRef::ConstRef; ConstStringRef(const std::wstring* ref) // NOLINT : ConstStringRef(to_string(*ref)) {} ConstStringRef(const std::wstring ref) // NOLINT : ConstStringRef(to_string(ref)) {} ConstStringRef(const wchar_t* ref) // NOLINT : ConstStringRef(to_string(std::wstring(ref))) {} ConstStringRef(const char* ref) // NOLINT : ConstStringRef(std::string(ref)) {} }; /// @brief An adapter. Reference a list of strings. /// /// Supported input: /// - `std::vector` /// - `std::vector*` /// - `std::vector*` /// - `Adapter*` /// - `std::unique_ptr` class ConstStringListRef { public: // Bring your own adapter: class Adapter { public: Adapter() = default; Adapter(const Adapter&) = default; Adapter& operator=(const Adapter&) = default; Adapter(Adapter&&) = default; Adapter& operator=(Adapter&&) = default; virtual ~Adapter() = default; virtual size_t size() const = 0; virtual std::string operator[](size_t i) const = 0; }; using Variant = std::variant, // const std::vector*, // const std::vector*, // Adapter*, // std::unique_ptr // >; ConstStringListRef() = default; ~ConstStringListRef() = default; ConstStringListRef& operator=(const ConstStringListRef&) = default; ConstStringListRef& operator=(ConstStringListRef&&) = default; ConstStringListRef(ConstStringListRef&&) = default; ConstStringListRef(const ConstStringListRef&) = default; ConstStringListRef(std::vector value) // NOLINT { variant_ = std::make_shared(value); } ConstStringListRef(const std::vector* value) // NOLINT { variant_ = std::make_shared(value); } ConstStringListRef(const std::vector* value) // NOLINT { variant_ = std::make_shared(value); } ConstStringListRef(Adapter* adapter) // NOLINT { variant_ = std::make_shared(adapter); } template ConstStringListRef(std::unique_ptr adapter) // NOLINT { variant_ = std::make_shared( static_cast>(std::move(adapter))); } size_t size() const { return variant_ ? std::visit(SizeVisitor(), *variant_) : 0; } std::string operator[](size_t i) const { return variant_ ? std::visit(IndexedGetter(i), *variant_) : ""; } private: struct SizeVisitor { size_t operator()(const std::vector& v) const { return v.size(); } size_t operator()(const std::vector* v) const { return v->size(); } size_t operator()(const std::vector* v) const { return v->size(); } size_t operator()(const Adapter* v) const { return v->size(); } size_t operator()(const std::unique_ptr& v) const { return v->size(); } }; struct IndexedGetter { IndexedGetter(size_t index) // NOLINT : index_(index) {} size_t index_; std::string operator()(const std::vector& v) const { return v[index_]; } std::string operator()(const std::vector* v) const { return (*v)[index_]; } std::string operator()(const std::vector* v) const { return to_string((*v)[index_]); } std::string operator()(const Adapter* v) const { return (*v)[index_]; } std::string operator()(const std::unique_ptr& v) const { return (*v)[index_]; } }; std::shared_ptr variant_; }; } // namespace ftxui #endif /* end of include guard: FTXUI_UTIL_REF_HPP */