Browse code

WIP: Add implementation

Robert Cranston authored on 18/06/2023 16:41:24
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,139 @@
1
+#ifndef CRANY_HPP_
2
+#define CRANY_HPP_
3
+
4
+
5
+#include <memory>
6
+#include <type_traits>
7
+#include <cassert>
8
+
9
+
10
+template<template<typename> class = std::is_void>
11
+class Crany;
12
+
13
+/// CranySelf
14
+template<>
15
+class Crany<>
16
+{
17
+private:
18
+    template<template<typename> class> friend class Crany;
19
+    template<typename T>
20
+    struct CranySelf
21
+    {
22
+    protected:
23
+        auto       & self()       { return *((T       *)this)->self_; }
24
+        auto const & self() const { return *((T const *)this)->self_; }
25
+        virtual ~CranySelf() = default;
26
+    };
27
+};
28
+
29
+/// Crany
30
+template<template<typename> class Concept>
31
+class Crany final : public Concept<Crany<>::CranySelf<Crany<Concept>>>
32
+{
33
+public:
34
+
35
+    /// Special member functions
36
+    template<typename Self>
37
+    Crany(Self self) : self_{new Model<Self>(std::move(self))} {}
38
+    Crany(Crany const & other) : self_(other.self_->clone()) {}
39
+    Crany & operator=(Crany const & other) { return *this = Crany(other); }
40
+    Crany(Crany && other) = default;
41
+    Crany & operator=(Crany && other) = default;
42
+
43
+private:
44
+
45
+    /// CranySelf
46
+    friend Crany<>::CranySelf<Crany<Concept>>;
47
+
48
+    /// ConceptSelf
49
+    struct ConceptSelf
50
+    {
51
+    protected:
52
+        auto       & self()       { assert(!"Crany Concept non-virtual member function called"); return *(Concept<ConceptSelf>       *)this; }
53
+        auto const & self() const { assert(!"Crany Concept non-virtual member function called"); return *(Concept<ConceptSelf> const *)this; }
54
+        virtual ~ConceptSelf() = default;
55
+    };
56
+
57
+    /// CloneConcept
58
+    struct CloneConcept : Concept<ConceptSelf>
59
+    {
60
+        virtual CloneConcept * clone() const = 0;
61
+    };
62
+
63
+    /// ModelSelf
64
+    template<typename T>
65
+    struct ModelSelf : CloneConcept
66
+    {
67
+    protected:
68
+        auto       & self()       { return ((T       *)this)->self_; }
69
+        auto const & self() const { return ((T const *)this)->self_; }
70
+    };
71
+
72
+    /// Model
73
+    template<typename Self>
74
+    struct Model final : Concept<ModelSelf<Model<Self>>>
75
+    {
76
+        Model(Self self) : self_{std::move(self)} {}
77
+        CloneConcept * clone() const { return new Model<Self>(*this); }
78
+        Self self_;
79
+    };
80
+
81
+    /// Self
82
+    std::unique_ptr<CloneConcept> self_;
83
+
84
+    /// crany_cast
85
+    template<typename T, typename Crany> friend T const * crany_cast(Crany const *  crany) noexcept;
86
+    template<typename T, typename Crany> friend T       * crany_cast(Crany       *  crany) noexcept;
87
+    template<typename T, typename Crany> friend T         crany_cast(Crany const &  crany);
88
+    template<typename T, typename Crany> friend T         crany_cast(Crany       &  crany);
89
+    template<typename T, typename Crany> friend T         crany_cast(Crany       && crany);
90
+};
91
+
92
+/// bad_crany_cast
93
+class bad_crany_cast : public std::bad_cast
94
+{
95
+};
96
+
97
+/// crany_cast
98
+template<typename T, typename Crany>
99
+T const * crany_cast(Crany const * crany) noexcept
100
+{
101
+    if (!crany)
102
+        return nullptr;
103
+    using Model = typename Crany::Model<T>;
104
+    if (auto * model = dynamic_cast<Model *>(crany->self_.get()))
105
+        return &model->self_;
106
+    return nullptr;
107
+}
108
+template<typename T, typename Crany>
109
+T * crany_cast(Crany * crany) noexcept
110
+{
111
+    return const_cast<T *>(*const_cast<T const *>(crany));
112
+}
113
+template<typename T, typename Crany>
114
+T crany_cast(Crany const & crany)
115
+{
116
+    using U = std::remove_cv_t<std::remove_reference_t<T>>;
117
+    if (auto p = crany_cast<U>(&crany))
118
+        return static_cast<T>(*p);
119
+    throw bad_crany_cast(); // TODO
120
+}
121
+template<typename T, typename Crany>
122
+T crany_cast(Crany & crany)
123
+{
124
+    using U = std::remove_cv_t<std::remove_reference_t<T>>;
125
+    if (auto p = crany_cast<U>(&crany))
126
+        return static_cast<T>(*p);
127
+    throw bad_crany_cast(); // TODO
128
+}
129
+template<typename T, typename Crany>
130
+T crany_cast(Crany && crany)
131
+{
132
+    using U = std::remove_cv_t<std::remove_reference_t<T>>;
133
+    if (auto p = crany_cast<U>(&crany))
134
+        return static_cast<T>(std::move(*p));
135
+    throw bad_crany_cast(); // TODO
136
+}
137
+
138
+
139
+#endif // CRANY_HPP_