Created
July 10, 2024 01:38
-
-
Save alexanderchuranov/efce7b181ffce7ebbcd33d64554f534f to your computer and use it in GitHub Desktop.
The container/view in C++20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <cassert> | |
| #include <string> | |
| #include <type_traits> | |
| #include <utility> | |
| template <typename T> | |
| class View { | |
| public: | |
| View() = default; | |
| explicit View(T* p) : p_(p) { } | |
| View(View const&) = default; | |
| template <typename U> | |
| View(View<U> const& source) | |
| : p_(source.p_) { } | |
| bool empty() const { return p_ == nullptr; } | |
| T* data() const { return p_; } | |
| T& access() const { return *p_; } | |
| View& operator=(View const&) = default; | |
| bool operator==(View const& rhs) const { | |
| return *p_ == *rhs.p_; | |
| } | |
| bool operator!=(View const&) const = default; | |
| bool same_view(View const& rhs) const { | |
| return this->p_ == rhs.p_; | |
| } | |
| private: | |
| template <typename U> | |
| friend class View; | |
| T* p_ = nullptr; | |
| }; | |
| template <typename T> | |
| class Container { | |
| public: | |
| Container() = default; | |
| Container(Container const&) = default; | |
| Container(Container&& src) { | |
| std::swap(value_, src.value_); | |
| } | |
| template <typename U> | |
| Container(Container<U> const& src) : value_{src.value_} { } | |
| explicit Container(T const& value) : value_{value} { } | |
| explicit Container(View<T> const& src) : value_(src.access()) { } | |
| template <typename U> | |
| explicit Container(View<U> const& src): value_(src.access()) { } | |
| View<T> const view() { | |
| return View<T>{&value_}; | |
| } | |
| View<T const> const view() const { | |
| return View<T const>{&value_}; | |
| } | |
| Container& operator=(Container const&) = default; | |
| Container& operator=(Container&& src) { | |
| std::swap(value_, src.value_); | |
| return *this; | |
| } | |
| bool operator==(Container const&) const = default; | |
| bool operator!=(Container const& rhs) const = default; | |
| template <typename U> | |
| bool operator==(Container<U> const& src) const { | |
| return value_ == src.value_; | |
| } | |
| private: | |
| template <typename U> | |
| friend class Container; | |
| T value_; | |
| }; | |
| void view_assertions() { | |
| int a = 3; | |
| assert(View<int>{}.empty()); | |
| assert(View{&a}.access() == 3); | |
| assert(View{&a}.data() == &a); | |
| View source{&a}; | |
| View copy1{source}; | |
| View<int> copy2; | |
| copy2 = source; | |
| assert(copy1.data() == &a); | |
| assert(copy2.data() == &a); | |
| View<int> writable_source{&a}; | |
| View<int const> readable_view1{writable_source}; | |
| View<int const> readable_view2; | |
| readable_view2 = writable_source; | |
| assert(readable_view1.data() == &a); | |
| assert(readable_view2.data() == &a); | |
| View<int const> readable_source{&a}; | |
| View<int> writable_view2; | |
| // | |
| // error: cannot initialize a member subobject of type 'int *' | |
| // with an lvalue of type 'const int *const' | |
| // | |
| // View<int> writable_view1{readable_source}; | |
| // writable_view2 = readable_source; | |
| int b = 3; | |
| int c = 5; | |
| assert(View{&b} == View{&a}); | |
| assert(not View{&b}.same_view(View{&a})); | |
| assert(not(View{&b} != View{&a})); | |
| assert(View{&b} != View{&c}); | |
| assert(not(View{&b} == View{&c})); | |
| assert(View{&a}.same_view(View{&a})); | |
| int x = 10; | |
| View const writable{&x}; // View<T> const where 'T' is non-const. | |
| assert(writable.access() == 10); | |
| writable.access() = 17; | |
| assert(writable.access() == 17); | |
| int y = 11; | |
| View<int const> non_writable{&y}; // View<T const> where | |
| // 'non_writable' is non-const | |
| assert(non_writable.access() == 11); | |
| // error: cannot assign to return value because function 'access' | |
| // returns a const value | |
| // non_writable.access() = 33; | |
| } | |
| void container_assertions() { | |
| assert(Container<int>{}.view().access() == 0); | |
| Container<int> a{3}; | |
| Container<int> copy{a}; | |
| Container<int> copy2{a.view()}; | |
| assert(copy.view().access() == 3); | |
| assert(not copy.view().same_view(a.view())); | |
| assert(copy2.view().access() == 3); | |
| assert(not copy2.view().same_view(a.view())); | |
| Container<short int> b{7}; | |
| Container<int> copy3{b}; | |
| Container<int> copy4{b.view()}; | |
| assert(copy3.view().access() == 7); | |
| assert(static_cast<void*>(copy3.view().data()) | |
| != static_cast<void*>(b.view().data())); | |
| assert(copy4.view().access() == 7); | |
| assert(static_cast<void*>(copy4.view().data()) | |
| != static_cast<void*>(b.view().data())); | |
| Container<int> e; | |
| e = a; | |
| assert(e.view().access() == 3); | |
| e = b; | |
| assert(e.view().access() == 7); | |
| assert(copy == a); | |
| assert(not(copy != a)); | |
| assert(not(a == b)); | |
| assert(a != b); | |
| Container<std::string> orig1{"abcdefgijklmnopqrstuvwxyz"}; | |
| Container<std::string> receiver1{std::move(orig1)}; | |
| Container<std::string> orig2{"zyxwvutsrqponmlkjigfedcba"}; | |
| Container<std::string> receiver2; | |
| receiver2 = std::move(orig2); | |
| assert(receiver1.view().access() == "abcdefgijklmnopqrstuvwxyz"); | |
| assert(orig1.view().access() == ""); | |
| assert(orig1 != receiver1); | |
| assert(receiver2.view().access() == "zyxwvutsrqponmlkjigfedcba"); | |
| assert(orig2.view().access() == ""); | |
| assert(orig2 != receiver2); | |
| Container<int> writable{11}; | |
| assert(writable.view().access() == 11); | |
| writable.view().access() = 17; | |
| assert(writable.view().access() == 17); | |
| Container<int> const non_writable{5}; | |
| assert(non_writable.view().access() == 5); | |
| // error: cannot assign to return value because function 'access' | |
| // returns a const value | |
| // non_writable.view().access() = 33; | |
| } | |
| int main() { | |
| view_assertions(); | |
| container_assertions(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment