22#include < string>
33#include < format>
44#include < type_traits>
5+ #include < utility>
56#include < vector>
67#include < meta>
8+ #include < atomic>
79
8- #include < print>
910
1011#include < rsl/serialize>
1112#include < rsl/repr>
1213
1314#include < kwargs.h>
1415
1516namespace rsl ::logging {
16- namespace _impl {
17- template <typename T>
18- struct Impl {
19- static std::string to_string (void const * p) {
20- return std::format (" {}" , *static_cast <const T*>(p));
21- }
22- static std::string to_repr (void const * p) { return rsl::repr (*static_cast <const T*>(p)); }
23- static std::string to_json (void const * p) { return " " ; }
17+ class Field {
18+ template <typename T>
19+ struct Impl {
20+ struct RefCounted {
21+ mutable std::atomic_unsigned_lock_free references;
22+ T data;
23+ std::string name;
24+
25+ RefCounted (T obj, std::string_view name) : references(0 ), data(std::move(obj)), name(name) {}
26+ ~RefCounted () = default ;
27+ RefCounted (RefCounted const &) = delete ;
28+ RefCounted (RefCounted&&) = delete ;
29+ RefCounted& operator =(RefCounted const &) = delete ;
30+ RefCounted& operator =(RefCounted&&) = delete ;
31+ };
32+
33+ static std::string to_string (Field const * field) { return std::format (" {}" , *get (field)); }
34+ static std::string to_repr (Field const * field) { return rsl::repr (*get (field)); }
35+ static std::string to_json (Field const * field) { return " " ; }
36+
37+ static T* get (Field* field) {
38+ if (field->vtable ->destroy != nullptr ) {
39+ return &static_cast <RefCounted*>(field->ptr )->data ;
40+ } else {
41+ return static_cast <T*>(field->ptr );
42+ }
43+ }
2444
25- static void * clone (void const * p) { return new T (*static_cast <T const *>(p)); }
26- static void destroy (void * p) { delete static_cast <T*>(p); }
27- };
45+ static T const * get (Field const * field) { return get (const_cast <Field*>(field)); }
2846
29- struct VTable {
30- std::string (*type_name)(void const *);
31- std::string (*to_string)(void const *);
32- std::string (*to_repr)(void const *);
33- std::string (*to_json)(void const *);
34- void * (*clone)(void const *);
35- void (*destroy)(void * p);
36- };
47+ static Field transition (Field const * field) {
48+ RefCounted* ref = new RefCounted (*static_cast <T const *>(field->ptr ), field->name );
49+ return Field (ref, make_vtable<T, true >(), ref->name );
50+ }
3751
38- template <typename T>
39- constexpr VTable const * make_vtable () {
40- static constexpr VTable table{.to_string = &Impl<T>::to_string,
41- .to_repr = &Impl<T>::to_repr,
42- .to_json = &Impl<T>::to_json,
43- .clone = &Impl<T>::clone,
44- .destroy = &Impl<T>::destroy};
45- return &table;
46- }
47- } // namespace _impl
52+ static Field clone (Field const * field) {
53+ auto const & control_block = *static_cast <RefCounted const *>(field->ptr );
54+ // control_block.references++;
55+ auto val = control_block.references .fetch_add (1 );
56+ return Field (field->ptr , field->vtable , field->name );
57+ }
4858
49- class Field {
50- void * ptr = nullptr ;
51- _impl::VTable const * vtable = nullptr ;
59+ static void destroy (void * p) {
60+ auto * control_block = static_cast <RefCounted*>(p);
61+ auto val = control_block->references .fetch_sub (1 );
62+ if (val == 0 ) {
63+ delete control_block;
64+ }
65+ }
66+ };
67+
68+ struct VTable {
69+ std::string_view type_name;
70+
71+ std::string (*to_string)(Field const *);
72+ std::string (*to_repr)(Field const *);
73+ std::string (*to_json)(Field const *);
74+ Field (*clone)(Field const *);
75+ void (*destroy)(void * p);
76+
77+ bool is_owning () const { return destroy != nullptr ; }
78+ };
79+
80+ template <typename T, bool Heap>
81+ constexpr static VTable const * make_vtable () {
82+ static constexpr VTable table{.type_name = rsl::type_name<T>,
83+ .to_string = &Impl<T>::to_string,
84+ .to_repr = &Impl<T>::to_repr,
85+ .to_json = &Impl<T>::to_json,
86+ .clone = Heap ? &Impl<T>::clone : &Impl<T>::transition,
87+ .destroy = Heap ? &Impl<T>::destroy : nullptr };
88+ return &table;
89+ }
5290
53- // TODO maybe count references in owning mode?
54- bool owning = false ;
91+ void * ptr = nullptr ;
92+ VTable const * vtable = nullptr ;
5593
5694 void destroy () {
57- if (owning ) {
95+ if (vtable != nullptr && vtable-> is_owning () ) {
5896 vtable->destroy (ptr);
5997 }
6098 ptr = nullptr ;
61- owning = false ;
99+ vtable = nullptr ;
62100 }
63101
64- Field (void * ptr, _impl::VTable const * vtable, bool owning, std::string_view name, std::string_view type_name)
65- : ptr(ptr)
66- , vtable(vtable)
67- , owning(owning)
68- , name(name)
69- , type_name(type_name) {}
102+ Field (void * ptr, VTable const * vtable, std::string_view name)
103+ : ptr(ptr)
104+ , vtable(vtable)
105+ , name(name) {}
106+
107+ static Field copy_from (Field const & other) {
108+ if (other.vtable ->destroy != nullptr ) {
109+ return other.vtable ->clone (&other);
110+ } else {
111+ return {other.ptr , other.vtable , other.name };
112+ }
113+ }
70114
71115public:
72116 std::string_view name;
73- std::string_view type_name;
74117
75118 Field () = default ;
76-
77- Field (const Field& other)
78- : ptr(other.owning ? other.vtable->clone (other.ptr) : other.ptr)
79- , vtable(other.vtable)
80- , owning(other.owning)
81- , name(other.name)
82- , type_name(other.type_name) {}
119+ Field (const Field& other) : Field(copy_from(other)) {}
83120
84121 // move constructor
85122 Field (Field&& other) noexcept
86123 : ptr(other.ptr)
87124 , vtable(other.vtable)
88- , owning(other.owning)
89- , name(other.name)
90- , type_name(other.type_name) {
125+ , name(other.name) {
91126 other.ptr = nullptr ;
92- other.owning = false ;
127+ other.vtable = nullptr ;
93128 }
94129
95130 // copy assignment
96131 Field& operator =(const Field& other) {
97132 if (this != &other) {
98133 destroy ();
99- ptr = other.owning ? other.vtable ->clone (other.ptr ) : other.ptr ;
100- vtable = other.vtable ;
101- owning = other.owning ;
102- name = other.name ;
103- type_name = other.type_name ;
134+ *this = copy_from (other);
104135 }
105136 return *this ;
106137 }
@@ -109,45 +140,40 @@ class Field {
109140 Field& operator =(Field&& other) noexcept {
110141 if (this != &other) {
111142 destroy ();
112- ptr = other.ptr ;
113- vtable = other.vtable ;
114- owning = other.owning ;
115- name = other.name ;
116- type_name = other.type_name ;
117- other.ptr = nullptr ;
118- other.owning = false ;
143+ ptr = std::exchange (other.ptr , nullptr );
144+ vtable = std::exchange (other.vtable , nullptr );
145+ name = other.name ;
119146 }
120147 return *this ;
121148 }
122149
123150 template <typename T>
124151 requires (not std::same_as<T, void >)
125- Field (std::string_view name, T* value, bool needs_cleanup = false )
126- : name(name)
127- , type_name(rsl::type_name<T>)
128- , ptr(value)
129- , vtable(_impl::make_vtable<T>())
130- , owning(needs_cleanup) {}
131-
132- ~Field () noexcept {
133- destroy ();
134- }
152+ Field (std::string_view name, T* value)
153+ : ptr(value)
154+ , vtable(make_vtable<T, false >())
155+ , name(name) {}
156+
157+ ~Field () noexcept { destroy (); }
135158
136159 [[nodiscard]] Field clone () const {
137- return Field (ptr ? vtable->clone (ptr) : nullptr , vtable, true , name, type_name);
160+ if (vtable == nullptr || ptr == nullptr ) {
161+ return {};
162+ }
163+ return vtable->clone (this );
138164 }
139165
140166 template <class T >
141- friend T* any_cast (Field* other ) noexcept {
142- if (!other || !other ->ptr ) {
167+ friend T* any_cast (Field* field ) noexcept {
168+ if (!field || !field ->ptr ) {
143169 return nullptr ;
144170 }
145171
146172 // checking one function in the table is sufficient to determine equality
147- if (other ->vtable ->to_string != &_impl:: Impl<T>::to_string) {
173+ if (field ->vtable ->to_string != &Impl<T>::to_string) {
148174 return nullptr ;
149175 }
150- return static_cast <T*>(other-> ptr );
176+ return Impl<T>:: get (field );
151177 }
152178
153179 template <typename T, typename U>
@@ -160,16 +186,18 @@ class Field {
160186 }
161187 }
162188
163- [[nodiscard]] std::string to_string () const { return vtable->to_string (ptr); }
164- [[nodiscard]] std::string to_json () const { return vtable->to_json (ptr); }
165- [[nodiscard]] std::string to_repr () const { return vtable->to_repr (ptr); }
189+ [[nodiscard]] std::string_view type_name () const { return vtable->type_name ; }
190+ [[nodiscard]] std::string to_string () const { return vtable->to_string (this ); }
191+ [[nodiscard]] std::string to_json () const { return vtable->to_json (this ); }
192+ [[nodiscard]] std::string to_repr () const { return vtable->to_repr (this ); }
166193};
167194
168195struct ExtraFields {
196+ // TODO this could be a span that views memory on the stack and transitions to heap if its elts do
169197 std::vector<Field> fields;
170198
171199 ExtraFields () = default ;
172- explicit (false ) ExtraFields(std::vector<Field> fields) : fields(fields) {}
200+ explicit (false ) ExtraFields(std::vector<Field> fields) : fields(std::move( fields) ) {}
173201 template <typename T>
174202 requires is_kwargs<std::remove_cvref_t <T>>
175203 explicit (false ) ExtraFields(T&& kwargs) {
@@ -215,4 +243,4 @@ struct ExtraFields {
215243 }
216244};
217245
218- } // namespace rsl::_log_impl
246+ } // namespace rsl::logging
0 commit comments