From 06ba1c10b901980cead8c268035dfc445fc0c8eb Mon Sep 17 00:00:00 2001 From: mr-mocap <16119203+mr-mocap@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:18:33 -0400 Subject: [PATCH] Possible clarification and reimplementation of Ref classes (#719) Co-authored-by: ArthurSonzogni --- include/ftxui/util/ref.hpp | 132 +++++++++++++++------------------- src/ftxui/component/input.cpp | 6 +- src/ftxui/dom/canvas.cpp | 5 +- 3 files changed, 62 insertions(+), 81 deletions(-) diff --git a/include/ftxui/util/ref.hpp b/include/ftxui/util/ref.hpp index e47743f..a4d4b0b 100644 --- a/include/ftxui/util/ref.hpp +++ b/include/ftxui/util/ref.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace ftxui { @@ -10,104 +11,85 @@ namespace ftxui { template class ConstRef { public: - ConstRef() {} - ConstRef(T t) : owned_(t) {} - ConstRef(const T* t) : address_(t) {} - ConstRef(const ConstRef& t) : owned_(t.owned_), address_(t.address_) {} - ConstRef& operator=(const ConstRef& t) { - owned_ = t.owned_; - address_ = t.address_; - return *this; - } - const T& operator*() const { return address_ ? *address_ : owned_; } - const T& operator()() const { return address_ ? *address_ : owned_; } - const T* operator->() const { return address_ ? address_ : &owned_; } + ConstRef() = default; + ConstRef(const ConstRef&) = default; + ConstRef(const T& t) : variant_(t) {} + ConstRef(const T* t) : variant_(t) {} + + // Make a "resetable" 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: - T owned_; - const T* address_ = nullptr; + 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() {} - Ref(const T& t) : owned_(t) {} - Ref(T&& t) : owned_(std::forward(t)) {} - Ref(T* t) : owned_(), address_(t) {} - Ref(const Ref& t) : owned_(t.owned_), address_(t.address_) {} - Ref& operator=(const Ref& t) { - owned_ = t.owned_; - address_ = t.address_; - return *this; - } - T& operator*() { return address_ ? *address_ : owned_; } - T& operator()() { return address_ ? *address_ : owned_; } - T* operator->() { return address_ ? address_ : &owned_; } + Ref() = default; + Ref(const Ref&) = default; + Ref(const T& t) : variant_(t) {} + Ref(T&& t) : variant_(std::forward(t)) {} + Ref(T* t) : variant_(t) {} + + // Make a "resetable" 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: - T owned_; - T* address_ = nullptr; + 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 { +class StringRef : public Ref { public: - StringRef(std::string* ref) : address_(ref) {} - StringRef(std::string ref) : owned_(std::move(ref)) {} + using Ref::Ref; + StringRef(const wchar_t* ref) : StringRef(to_string(std::wstring(ref))) {} StringRef(const char* ref) : StringRef(std::string(ref)) {} - StringRef(const StringRef& t) : owned_(t.owned_), address_(t.address_) {} - StringRef& operator=(const StringRef& t) { - owned_ = t.owned_; - address_ = t.address_; - return *this; - } - std::string& operator*() { return address_ ? *address_ : owned_; } - std::string& operator()() { return address_ ? *address_ : owned_; } - std::string* operator->() { return address_ ? address_ : &owned_; } - - private: - std::string owned_; - std::string* address_ = nullptr; }; /// @brief An adapter. Own or reference a constant string. For convenience, this /// class convert multiple immutable string toward a shared representation. -class ConstStringRef { +class ConstStringRef : public ConstRef { public: - ConstStringRef(const std::string* ref) : address_(ref) {} - ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {} - ConstStringRef(std::string ref) : owned_(std::move(ref)) {} - ConstStringRef(std::wstring ref) : ConstStringRef(to_string(ref)) {} - ConstStringRef(const wchar_t* ref) : ConstStringRef(std::wstring(ref)) {} - ConstStringRef(const char* ref) - : ConstStringRef(to_wstring(std::string(ref))) {} - ConstStringRef(const ConstStringRef& t) - : owned_(t.owned_), address_(t.address_) {} - ConstStringRef& operator=(const ConstStringRef& t) { - owned_ = t.owned_; - address_ = t.address_; - return *this; - } - ConstStringRef& operator=(ConstStringRef&& t) { - owned_ = std::move(t.owned_); - address_ = t.address_; - return *this; - } - const std::string& operator()() const { - return address_ ? *address_ : owned_; - } - const std::string& operator*() const { return address_ ? *address_ : owned_; } - const std::string* operator->() const { - return address_ ? address_ : &owned_; - } + using ConstRef::ConstRef; - private: - std::string owned_; - const std::string* address_ = nullptr; + ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {} + ConstStringRef(const std::wstring ref) : ConstStringRef(to_string(ref)) {} + ConstStringRef(const wchar_t* ref) + : ConstStringRef(to_string(std::wstring(ref))) {} + ConstStringRef(const char* ref) : ConstStringRef(std::string(ref)) {} + + ConstStringRef& operator=(const ConstStringRef&) = default; }; /// @brief An adapter. Reference a list of strings. diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 0f32946..cd5b070 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -568,7 +568,7 @@ Component Input(InputOption option) { /// placeholder /// ``` Component Input(StringRef content, InputOption option) { - option.content = content; + option.content = std::move(content); return Make(std::move(option)); } @@ -594,8 +594,8 @@ Component Input(StringRef content, InputOption option) { /// placeholder /// ``` Component Input(StringRef content, StringRef placeholder, InputOption option) { - option.content = content; - option.placeholder = placeholder; + option.content = std::move(content); + option.placeholder = std::move(placeholder); return Make(std::move(option)); } diff --git a/src/ftxui/dom/canvas.cpp b/src/ftxui/dom/canvas.cpp index db8a699..f42efb6 100644 --- a/src/ftxui/dom/canvas.cpp +++ b/src/ftxui/dom/canvas.cpp @@ -849,15 +849,14 @@ class CanvasNodeBase : public Node { Element canvas(ConstRef canvas) { class Impl : public CanvasNodeBase { public: - // NOLINTNEXTLINE - explicit Impl(ConstRef canvas) : canvas_(std::move(canvas)) { + explicit Impl(ConstRef canvas) : canvas_(canvas) { requirement_.min_x = (canvas_->width() + 1) / 2; requirement_.min_y = (canvas_->height() + 3) / 4; } const Canvas& canvas() final { return *canvas_; } ConstRef canvas_; }; - return std::make_shared(std::move(canvas)); + return std::make_shared(canvas); } /// @brief Produce an element drawing a canvas of requested size.