From 6db8ce86683643eacaec85b7b957ea177c7b482c Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Mon, 20 May 2024 01:31:49 +0800 Subject: [PATCH 01/11] simplify usage of template because pointer does not need to know which type is hold at body. --- Kernel/Abstractions/sharedptr.hpp | 49 +++++++++++++++++++++++++++++++ lolly/data/string_u16.cpp | 13 ++++---- lolly/data/string_u16.hpp | 28 +++++++++--------- 3 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 Kernel/Abstractions/sharedptr.hpp diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp new file mode 100644 index 000000000..542e206f4 --- /dev/null +++ b/Kernel/Abstractions/sharedptr.hpp @@ -0,0 +1,49 @@ + +#pragma once + +#include "fast_alloc.hpp" +#include + +template struct ref_counter { + /// @brief the reference count of the object + int ref_count; + T content; + template + explicit ref_counter (Params&&... p) + : ref_count (1), content (std::forward (p)...){}; + + void inc_count () { ref_count++; } + void dec_count () { + ref_count--; + if (ref_count == 0) { + tm_delete (this); + } + } +}; + +template class counted_ptr { +protected: + using base = counted_ptr; + using counter_t= ref_counter; + counter_t* counter; + T* get () { return &(counter->content); } + const T* get () const { return &(counter->content); } + template static counter_t* make (Params&&... p) { + return tm_new (std::forward (p)...); + } + explicit counted_ptr (counter_t* c) : counter (c) {} + +public: + counted_ptr (const counted_ptr& x) : counter (x.counter) { + counter->inc_count (); + } + ~counted_ptr () { counter->dec_count (); } + counted_ptr& operator= (counted_ptr& x) { + x.counter->inc_count (); + this->counter->dec_count (); + this->counter= x.counter; + return *this; + } + T* operator->() { return &(counter->content); } + const T* operator->() const { return &(counter->content); } +}; diff --git a/lolly/data/string_u16.cpp b/lolly/data/string_u16.cpp index 2355e48b4..b6fc5e51e 100644 --- a/lolly/data/string_u16.cpp +++ b/lolly/data/string_u16.cpp @@ -81,19 +81,16 @@ string_u16_rep::reserve (int new_n) { } } -string_u16::string_u16 (char16_t c) : rep (tm_new (1)) { - rep->a[0]= c; -}; +string_u16::string_u16 (char16_t c) : base (make (1)) { get ()->a[0]= c; }; -string_u16::string_u16 (const string_u16_view& c) - : rep (tm_new (c.N)) { +string_u16::string_u16 (const string_u16_view& c) : base (make (c.N)) { for (int i= 0; i < c.N; i++) - rep->a[i]= c.a[i]; + get ()->a[i]= c.a[i]; }; -string_u16::string_u16 (char16_t c, int n) : rep (tm_new (n)) { +string_u16::string_u16 (char16_t c, int n) : base (make (n)) { for (int i= 0; i < n; i++) - rep->a[i]= c; + get ()->a[i]= c; }; string_u16 diff --git a/lolly/data/string_u16.hpp b/lolly/data/string_u16.hpp index 0dcc8fe7b..990b52785 100644 --- a/lolly/data/string_u16.hpp +++ b/lolly/data/string_u16.hpp @@ -9,8 +9,8 @@ #pragma once -#include "classdef.hpp" #include "fast_alloc.hpp" +#include "sharedptr.hpp" #include "string_view.hpp" namespace lolly { @@ -20,7 +20,7 @@ using string_u16_view= lolly::data::string_view; class string_u16; -class string_u16_rep : concrete_struct { +class string_u16_rep { int n; int a_N; char16_t* a; @@ -58,41 +58,41 @@ class string_u16_rep : concrete_struct { friend int N (string_u16 a); }; -class string_u16 { - CONCRETE (string_u16); +using string_u16_base= counted_ptr; +class string_u16 : public counted_ptr { - inline string_u16 () : rep (tm_new ()) {} - inline explicit string_u16 (int n) : rep (tm_new (n)) {} +public: + inline string_u16 () : base (make ()) {} + inline explicit string_u16 (int n) : base (make (n)) {} template - string_u16 (const char16_t (&s)[N_]) : rep (tm_new (N_ - 1)) { + string_u16 (const char16_t (&s)[N_]) : base (make (N_ - 1)) { constexpr int n= N_ - 1; for (int i= 0; i < n; i++) - rep->a[i]= s[i]; + get ()->a[i]= s[i]; }; string_u16 (char16_t c); string_u16 (char16_t c, int n); string_u16 (const string_u16_view& sv); - inline char16_t* buffer () { return rep->a; } + inline char16_t* buffer () { return get ()->a; } inline char16_t* buffer (int size) { - rep->resize (size); - return rep->a; + get ()->resize (size); + return get ()->a; } char16_t* begin () { return rep->a; } char16_t* end () { return rep->a + rep->n; } inline operator string_u16_view () { - return string_u16_view (rep->a, rep->n); + return string_u16_view (get ()->a, get ()->n); } inline string_u16_view operator() (int start, int end) { return ((string_u16_view) * this) (start, end); } - inline char16_t& operator[] (int i) { return rep->a[i]; } + inline char16_t& operator[] (int i) { return get ()->a[i]; } }; -CONCRETE_CODE (string_u16); inline int N (string_u16 a) { From b7b67fcfcd1d262400a84b8ff99c5f69a1d7f5d3 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Mon, 20 May 2024 11:03:57 +0800 Subject: [PATCH 02/11] fix perf issue introduced by get method --- lolly/data/string_u16.cpp | 6 ++++-- lolly/data/string_u16.hpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lolly/data/string_u16.cpp b/lolly/data/string_u16.cpp index b6fc5e51e..2dc12b0e3 100644 --- a/lolly/data/string_u16.cpp +++ b/lolly/data/string_u16.cpp @@ -84,13 +84,15 @@ string_u16_rep::reserve (int new_n) { string_u16::string_u16 (char16_t c) : base (make (1)) { get ()->a[0]= c; }; string_u16::string_u16 (const string_u16_view& c) : base (make (c.N)) { + char16_t* a= get ()->a; for (int i= 0; i < c.N; i++) - get ()->a[i]= c.a[i]; + a[i]= c.a[i]; }; string_u16::string_u16 (char16_t c, int n) : base (make (n)) { + char16_t* a= get ()->a; for (int i= 0; i < n; i++) - get ()->a[i]= c; + a[i]= c; }; string_u16 diff --git a/lolly/data/string_u16.hpp b/lolly/data/string_u16.hpp index 990b52785..8967bc0f5 100644 --- a/lolly/data/string_u16.hpp +++ b/lolly/data/string_u16.hpp @@ -68,8 +68,9 @@ class string_u16 : public counted_ptr { template string_u16 (const char16_t (&s)[N_]) : base (make (N_ - 1)) { constexpr int n= N_ - 1; + char16_t* a= get ()->a; for (int i= 0; i < n; i++) - get ()->a[i]= s[i]; + a[i]= s[i]; }; string_u16 (char16_t c); From 5b1529fc68e827c430e6be3dc0f97000780382d9 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Tue, 21 May 2024 01:57:07 +0800 Subject: [PATCH 03/11] add for blackbox --- Kernel/Abstractions/blackbox.hpp | 20 ++++----- Kernel/Abstractions/sharedptr.hpp | 67 ++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/Kernel/Abstractions/blackbox.hpp b/Kernel/Abstractions/blackbox.hpp index ebe05c110..bed26c69b 100644 --- a/Kernel/Abstractions/blackbox.hpp +++ b/Kernel/Abstractions/blackbox.hpp @@ -8,12 +8,13 @@ #ifndef BLACKBOX_H #define BLACKBOX_H -#include "basic.hpp" +#include "sharedptr.hpp" +#include "tm_ostream.hpp" /** * @brief A template class representing an opaque pointer. */ -class blackbox_rep : public abstract_struct { +class blackbox_rep { public: inline blackbox_rep () {} inline virtual ~blackbox_rep () {} @@ -22,11 +23,10 @@ class blackbox_rep : public abstract_struct { virtual tm_ostream& display (tm_ostream& out)= 0; }; -class blackbox { -public: - ABSTRACT_NULL (blackbox); +class blackbox : public counted_ptr_nullable { + using counted_ptr_nullable::counted_ptr_nullable; + template friend blackbox close_box (const T&); }; -ABSTRACT_NULL_CODE (blackbox); template class whitebox_rep : public blackbox_rep { public: @@ -75,7 +75,7 @@ template class whitebox_rep : public blackbox_rep { inline bool operator== (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return is_nil (bb2); - else return bb1->equal (bb2.rep); + else return bb1->equal (bb2.get()); } /** @@ -87,7 +87,7 @@ operator== (blackbox bb1, blackbox bb2) { inline bool operator!= (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return !is_nil (bb2); - else return !bb1->equal (bb2.rep); + else return !bb1->equal (bb2.get()); } /** @@ -121,7 +121,7 @@ type_box (blackbox bb) { template blackbox close_box (const T& data) { - return tm_new> (data); + return blackbox (make, blackbox_rep> (data)); } /** @@ -134,7 +134,7 @@ template T open_box (blackbox bb) { ASSERT (type_box (bb) == type_helper::id, "type mismatch"); - return ((whitebox_rep*) bb.rep)->data; + return ((whitebox_rep*) bb.get())->data; } #endif // BLACKBOX_H diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index 542e206f4..85e8169ab 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -4,7 +4,14 @@ #include "fast_alloc.hpp" #include -template struct ref_counter { +template struct ref_counter_base { + + virtual void inc_count ()= 0; + virtual void dec_count ()= 0; + virtual T* get () = 0; +}; + +template struct ref_counter : ref_counter_base { /// @brief the reference count of the object int ref_count; T content; @@ -19,6 +26,7 @@ template struct ref_counter { tm_delete (this); } } + T* get () { return &content; } }; template class counted_ptr { @@ -47,3 +55,60 @@ template class counted_ptr { T* operator->() { return &(counter->content); } const T* operator->() const { return &(counter->content); } }; + +template +static ref_counter_base* +make (Params&&... p) { + return reinterpret_cast*> ( + tm_new> (std::forward (p)...)); +} + +template class counted_ptr_nullable { +protected: + using base = counted_ptr_nullable; + using counter_t= ref_counter_base; + counter_t* counter; + explicit counted_ptr_nullable (counter_t* c) : counter (c) {} + +public: + counted_ptr_nullable () : counter (nullptr) {} + counted_ptr_nullable (const counted_ptr_nullable& x) + : counter (x.counter) { + if (counter != nullptr) { + counter->inc_count (); + } + } + ~counted_ptr_nullable () { + if (counter != nullptr) { + counter->dec_count (); + } + } + counted_ptr_nullable& operator= (counted_ptr_nullable& x) { + if (x.counter != nullptr) { + x.counter->inc_count (); + } + if (this->counter != nullptr) { + this->counter->dec_count (); + } + this->counter= x.counter; + return *this; + } + T* get () { + if (counter != nullptr) { + return counter->get (); + } + else { + return nullptr; + } + } + const T* get () const { return get (); } + T* operator->() { return get (); } + const T* operator->() const { return get (); } + bool is_nil () const { return counter == nullptr; } +}; + +template +inline bool +is_nil (const counted_ptr_nullable x) { + return x.is_nil (); +} From bf793002f898387c68a863866c15d6cc51b3cade Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Tue, 21 May 2024 11:28:25 +0800 Subject: [PATCH 04/11] merge two types --- Kernel/Abstractions/blackbox.hpp | 12 ++-- Kernel/Abstractions/sharedptr.hpp | 95 ++++++++++++++++--------------- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/Kernel/Abstractions/blackbox.hpp b/Kernel/Abstractions/blackbox.hpp index bed26c69b..7be1e136c 100644 --- a/Kernel/Abstractions/blackbox.hpp +++ b/Kernel/Abstractions/blackbox.hpp @@ -23,8 +23,8 @@ class blackbox_rep { virtual tm_ostream& display (tm_ostream& out)= 0; }; -class blackbox : public counted_ptr_nullable { - using counted_ptr_nullable::counted_ptr_nullable; +class blackbox : public counted_ptr { + using counted_ptr::counted_ptr; template friend blackbox close_box (const T&); }; @@ -75,7 +75,7 @@ template class whitebox_rep : public blackbox_rep { inline bool operator== (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return is_nil (bb2); - else return bb1->equal (bb2.get()); + else return bb1->equal (bb2.get ()); } /** @@ -87,7 +87,7 @@ operator== (blackbox bb1, blackbox bb2) { inline bool operator!= (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return !is_nil (bb2); - else return !bb1->equal (bb2.get()); + else return !bb1->equal (bb2.get ()); } /** @@ -121,7 +121,7 @@ type_box (blackbox bb) { template blackbox close_box (const T& data) { - return blackbox (make, blackbox_rep> (data)); + return blackbox (make_derived, blackbox_rep> (data)); } /** @@ -134,7 +134,7 @@ template T open_box (blackbox bb) { ASSERT (type_box (bb) == type_helper::id, "type mismatch"); - return ((whitebox_rep*) bb.get())->data; + return ((whitebox_rep*) bb.get ())->data; } #endif // BLACKBOX_H diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index 85e8169ab..067b26ccb 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -29,86 +29,89 @@ template struct ref_counter : ref_counter_base { T* get () { return &content; } }; -template class counted_ptr { -protected: - using base = counted_ptr; - using counter_t= ref_counter; - counter_t* counter; - T* get () { return &(counter->content); } - const T* get () const { return &(counter->content); } - template static counter_t* make (Params&&... p) { - return tm_new (std::forward (p)...); - } - explicit counted_ptr (counter_t* c) : counter (c) {} - -public: - counted_ptr (const counted_ptr& x) : counter (x.counter) { - counter->inc_count (); - } - ~counted_ptr () { counter->dec_count (); } - counted_ptr& operator= (counted_ptr& x) { - x.counter->inc_count (); - this->counter->dec_count (); - this->counter= x.counter; - return *this; - } - T* operator->() { return &(counter->content); } - const T* operator->() const { return &(counter->content); } -}; - template static ref_counter_base* -make (Params&&... p) { +make_derived (Params&&... p) { return reinterpret_cast*> ( tm_new> (std::forward (p)...)); } -template class counted_ptr_nullable { +template class counted_ptr { protected: - using base = counted_ptr_nullable; + using base = counted_ptr; using counter_t= ref_counter_base; counter_t* counter; - explicit counted_ptr_nullable (counter_t* c) : counter (c) {} + explicit counted_ptr (counter_t* c) : counter (c) {} + template static counter_t* make (Params&&... p) { + return make_derived (std::forward (p)...); + } public: - counted_ptr_nullable () : counter (nullptr) {} - counted_ptr_nullable (const counted_ptr_nullable& x) - : counter (x.counter) { - if (counter != nullptr) { + counted_ptr () : counter (nullptr) {} + counted_ptr (const counted_ptr& x) : counter (x.counter) { + if constexpr (nullable) { + if (counter != nullptr) { + counter->inc_count (); + } + } + else { counter->inc_count (); } } - ~counted_ptr_nullable () { - if (counter != nullptr) { + ~counted_ptr () { + if constexpr (nullable) { + if (counter != nullptr) { + counter->dec_count (); + } + } + else { counter->dec_count (); } } - counted_ptr_nullable& operator= (counted_ptr_nullable& x) { - if (x.counter != nullptr) { - x.counter->inc_count (); + counted_ptr& operator= (counted_ptr& x) { + if constexpr (nullable) { + if (x.counter != nullptr) { + x.counter->inc_count (); + } + if (this->counter != nullptr) { + this->counter->dec_count (); + } } - if (this->counter != nullptr) { + else { + x.counter->inc_count (); this->counter->dec_count (); } this->counter= x.counter; return *this; } T* get () { - if (counter != nullptr) { - return counter->get (); + if constexpr (nullable) { + if (counter != nullptr) { + return counter->get (); + } + else { + return nullptr; + } } else { - return nullptr; + return counter->get (); } } const T* get () const { return get (); } T* operator->() { return get (); } const T* operator->() const { return get (); } - bool is_nil () const { return counter == nullptr; } + bool is_nil () const { + if constexpr (nullable) { + return counter == nullptr; + } + else { + return false; + } + } }; template inline bool -is_nil (const counted_ptr_nullable x) { +is_nil (const counted_ptr x) { return x.is_nil (); } From 07719f0e423ddac24c73b903a3da98660687e956 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Tue, 21 May 2024 12:17:59 +0800 Subject: [PATCH 05/11] add cache of underlying ptr for performance fix compile error on blackbox --- Kernel/Abstractions/blackbox.hpp | 8 ++++---- Kernel/Abstractions/sharedptr.hpp | 30 +++++++++++++++++------------- lolly/data/string_u16.cpp | 6 +++--- lolly/data/string_u16.hpp | 13 ++++++------- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Kernel/Abstractions/blackbox.hpp b/Kernel/Abstractions/blackbox.hpp index 7be1e136c..f362270f5 100644 --- a/Kernel/Abstractions/blackbox.hpp +++ b/Kernel/Abstractions/blackbox.hpp @@ -9,7 +9,7 @@ #ifndef BLACKBOX_H #define BLACKBOX_H #include "sharedptr.hpp" -#include "tm_ostream.hpp" +#include "basic.hpp" /** * @brief A template class representing an opaque pointer. @@ -75,7 +75,7 @@ template class whitebox_rep : public blackbox_rep { inline bool operator== (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return is_nil (bb2); - else return bb1->equal (bb2.get ()); + else return bb1->equal (bb2.rep); } /** @@ -87,7 +87,7 @@ operator== (blackbox bb1, blackbox bb2) { inline bool operator!= (blackbox bb1, blackbox bb2) { if (is_nil (bb1)) return !is_nil (bb2); - else return !bb1->equal (bb2.get ()); + else return !bb1->equal (bb2.rep); } /** @@ -134,7 +134,7 @@ template T open_box (blackbox bb) { ASSERT (type_box (bb) == type_helper::id, "type mismatch"); - return ((whitebox_rep*) bb.get ())->data; + return ((whitebox_rep*) bb.rep)->data; } #endif // BLACKBOX_H diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index 067b26ccb..f6a580083 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -30,25 +30,30 @@ template struct ref_counter : ref_counter_base { }; template -static ref_counter_base* +inline ref_counter_base* make_derived (Params&&... p) { return reinterpret_cast*> ( tm_new> (std::forward (p)...)); } template class counted_ptr { + protected: - using base = counted_ptr; using counter_t= ref_counter_base; - counter_t* counter; - explicit counted_ptr (counter_t* c) : counter (c) {} + using base = counted_ptr; + explicit counted_ptr (counter_t* c) : counter (c), rep (c->get ()) {} template static counter_t* make (Params&&... p) { - return make_derived (std::forward (p)...); + return tm_new> (std::forward (p)...); } +private: + counter_t* counter; + public: - counted_ptr () : counter (nullptr) {} - counted_ptr (const counted_ptr& x) : counter (x.counter) { + T* rep; + counted_ptr () : counter (nullptr), rep (nullptr) {} + counted_ptr (const counted_ptr& x) + : counter (x.counter), rep (x.rep) { if constexpr (nullable) { if (counter != nullptr) { counter->inc_count (); @@ -82,24 +87,23 @@ template class counted_ptr { this->counter->dec_count (); } this->counter= x.counter; + this->rep = x.rep; return *this; } - T* get () { + T* operator->() { if constexpr (nullable) { if (counter != nullptr) { - return counter->get (); + return rep; } else { return nullptr; } } else { - return counter->get (); + return rep; } } - const T* get () const { return get (); } - T* operator->() { return get (); } - const T* operator->() const { return get (); } + const T* operator->() const { return operator->(); } bool is_nil () const { if constexpr (nullable) { return counter == nullptr; diff --git a/lolly/data/string_u16.cpp b/lolly/data/string_u16.cpp index 2dc12b0e3..7c4109c55 100644 --- a/lolly/data/string_u16.cpp +++ b/lolly/data/string_u16.cpp @@ -81,16 +81,16 @@ string_u16_rep::reserve (int new_n) { } } -string_u16::string_u16 (char16_t c) : base (make (1)) { get ()->a[0]= c; }; +string_u16::string_u16 (char16_t c) : base (make (1)) { rep->a[0]= c; }; string_u16::string_u16 (const string_u16_view& c) : base (make (c.N)) { - char16_t* a= get ()->a; + char16_t* a= rep->a; for (int i= 0; i < c.N; i++) a[i]= c.a[i]; }; string_u16::string_u16 (char16_t c, int n) : base (make (n)) { - char16_t* a= get ()->a; + char16_t* a= rep->a; for (int i= 0; i < n; i++) a[i]= c; }; diff --git a/lolly/data/string_u16.hpp b/lolly/data/string_u16.hpp index 8967bc0f5..72678257d 100644 --- a/lolly/data/string_u16.hpp +++ b/lolly/data/string_u16.hpp @@ -58,7 +58,6 @@ class string_u16_rep { friend int N (string_u16 a); }; -using string_u16_base= counted_ptr; class string_u16 : public counted_ptr { public: @@ -68,7 +67,7 @@ class string_u16 : public counted_ptr { template string_u16 (const char16_t (&s)[N_]) : base (make (N_ - 1)) { constexpr int n= N_ - 1; - char16_t* a= get ()->a; + char16_t* a= rep->a; for (int i= 0; i < n; i++) a[i]= s[i]; }; @@ -77,22 +76,22 @@ class string_u16 : public counted_ptr { string_u16 (char16_t c, int n); string_u16 (const string_u16_view& sv); - inline char16_t* buffer () { return get ()->a; } + inline char16_t* buffer () { return rep->a; } inline char16_t* buffer (int size) { - get ()->resize (size); - return get ()->a; + rep->resize (size); + return rep->a; } char16_t* begin () { return rep->a; } char16_t* end () { return rep->a + rep->n; } inline operator string_u16_view () { - return string_u16_view (get ()->a, get ()->n); + return string_u16_view (rep->a, rep->n); } inline string_u16_view operator() (int start, int end) { return ((string_u16_view) * this) (start, end); } - inline char16_t& operator[] (int i) { return get ()->a[i]; } + inline char16_t& operator[] (int i) { return rep->a[i]; } }; inline int From 9e38e22dff262ac79d66d80f2a6df696f260fa23 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Tue, 21 May 2024 16:24:29 +0800 Subject: [PATCH 06/11] add rvalue assign to avoid compile error on clang --- Kernel/Abstractions/blackbox.hpp | 2 +- Kernel/Abstractions/sharedptr.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Kernel/Abstractions/blackbox.hpp b/Kernel/Abstractions/blackbox.hpp index f362270f5..253be317c 100644 --- a/Kernel/Abstractions/blackbox.hpp +++ b/Kernel/Abstractions/blackbox.hpp @@ -8,8 +8,8 @@ #ifndef BLACKBOX_H #define BLACKBOX_H -#include "sharedptr.hpp" #include "basic.hpp" +#include "sharedptr.hpp" /** * @brief A template class representing an opaque pointer. diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index f6a580083..e32cf3b78 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -90,6 +90,11 @@ template class counted_ptr { this->rep = x.rep; return *this; } + counted_ptr& operator= (counted_ptr&& x) { + std::swap (this->counter, x.counter); + std::swap (this->rep, x.rep); + return *this; + } T* operator->() { if constexpr (nullable) { if (counter != nullptr) { From c1abf564748f7cab1ef2627d71b65f9724094d16 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Tue, 21 May 2024 23:20:48 +0800 Subject: [PATCH 07/11] simplify code --- Kernel/Abstractions/blackbox.hpp | 4 ++-- Kernel/Abstractions/sharedptr.hpp | 31 ++++++++++++------------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Kernel/Abstractions/blackbox.hpp b/Kernel/Abstractions/blackbox.hpp index 253be317c..1f9dc799c 100644 --- a/Kernel/Abstractions/blackbox.hpp +++ b/Kernel/Abstractions/blackbox.hpp @@ -24,7 +24,7 @@ class blackbox_rep { }; class blackbox : public counted_ptr { - using counted_ptr::counted_ptr; + using base::counted_ptr; template friend blackbox close_box (const T&); }; @@ -121,7 +121,7 @@ type_box (blackbox bb) { template blackbox close_box (const T& data) { - return blackbox (make_derived, blackbox_rep> (data)); + return blackbox (blackbox::make> (data)); } /** diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index e32cf3b78..660292e75 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -4,14 +4,13 @@ #include "fast_alloc.hpp" #include -template struct ref_counter_base { - - virtual void inc_count ()= 0; - virtual void dec_count ()= 0; - virtual T* get () = 0; +struct ref_counter_base { + virtual void inc_count ()= 0; + virtual void dec_count ()= 0; + virtual void* get () = 0; }; -template struct ref_counter : ref_counter_base { +template struct ref_counter : ref_counter_base { /// @brief the reference count of the object int ref_count; T content; @@ -26,24 +25,18 @@ template struct ref_counter : ref_counter_base { tm_delete (this); } } - T* get () { return &content; } + void* get () { return &content; } }; - -template -inline ref_counter_base* -make_derived (Params&&... p) { - return reinterpret_cast*> ( - tm_new> (std::forward (p)...)); -} - template class counted_ptr { protected: - using counter_t= ref_counter_base; + using counter_t= ref_counter_base; using base = counted_ptr; - explicit counted_ptr (counter_t* c) : counter (c), rep (c->get ()) {} - template static counter_t* make (Params&&... p) { - return tm_new> (std::forward (p)...); + explicit counted_ptr (counter_t* c) + : counter (c), rep (static_cast (c->get ())) {} + template + static counter_t* make (Params&&... p) { + return tm_new> (std::forward (p)...); } private: From 8b1d80f124622fa21edd965474e742492621d6c4 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Wed, 22 May 2024 00:12:55 +0800 Subject: [PATCH 08/11] add for hashtree --- Kernel/Containers/hashtree.hpp | 31 ++++++++++------------------- Kernel/Containers/hashtree.ipp | 36 ++++------------------------------ 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/Kernel/Containers/hashtree.hpp b/Kernel/Containers/hashtree.hpp index 89d949488..9db94b7ef 100644 --- a/Kernel/Containers/hashtree.hpp +++ b/Kernel/Containers/hashtree.hpp @@ -15,12 +15,13 @@ #define HASHTREE_H #include "hashmap.hpp" +#include "sharedptr.hpp" template class hashtree; template int N (hashtree tree); template bool is_nil (hashtree tree); -template class hashtree_rep : concrete_struct { +template class hashtree_rep { hashmap> children; public: @@ -75,38 +76,27 @@ template class hashtree_rep : concrete_struct { * of NULL pointers so to speak). These NULL nodes are created by passing * a boolean value to the hashtree constructor. One cannot accidentally * obtain a NULL element by e.g. accessing a child (see below). - * - * In general, I tried to imitate the TeXmacs-way of memory management - * as closely as possibly, however the workaround is not that pretty. - * As more elegant way might be to modify the hashmap class so that - * a hashmap contains only a pointer to a function that returns - * a default value instead of a instance of a value-element. - * But I didn't want to modify core TeXmacs code. ******************************************************************************/ -template class hashtree { - // CONCRETE_TEMPLATE_2(hashtree,K,V); - hashtree_rep* rep; +template +class hashtree : public counted_ptr, true> { + using base= typename counted_ptr, true>::base; // this constructor always returns a NULL element - inline hashtree (bool) : rep (NULL) {} + inline hashtree (bool) : base () {} // ensures that this hashtree has a rep void realize (); public: - inline hashtree (const hashtree&); - inline ~hashtree (); - inline hashtree& operator= (hashtree x); - // default constructor returns a non-NULL node, which does not have a value - inline hashtree () : rep (tm_new> ()) {} + inline hashtree () : base (base::make ()) {} // returns a non-NULL node, that has value - inline hashtree (V val) : rep (tm_new> (val)) {} + inline hashtree (V val) : base (base::make (val)) {} // returns this node's value - inline hashtree_rep* operator->(void); + inline hashtree_rep* operator->(); // returns this node's child with the label "key". If the node doesn't // have such a child, an error is raised. @@ -120,8 +110,7 @@ template class hashtree { inline hashtree operator[] (K key); // rw access friend class hashtree_rep; - friend bool is_nil (hashtree ht); - friend int N (hashtree ht); + friend int N (hashtree ht); }; #include "hashtree.ipp" diff --git a/Kernel/Containers/hashtree.ipp b/Kernel/Containers/hashtree.ipp index 20ed77a30..d37bba9e2 100644 --- a/Kernel/Containers/hashtree.ipp +++ b/Kernel/Containers/hashtree.ipp @@ -15,33 +15,6 @@ #define HASHTREE_C #include "hashtree.hpp" -/****************************************************************************** - * Methods normally provided by - * CONCRETE_TEMPLATE_2_CODE(hashtree,class,K,class,V); - ******************************************************************************/ - -template -inline hashtree::hashtree (const hashtree& x) : rep (x.rep) { - if (this->rep != NULL) INC_COUNT (this->rep); -} - -template inline hashtree::~hashtree () { - if (this->rep != NULL) DEC_COUNT (this->rep); -} - -template -inline hashtree& -hashtree::operator= (hashtree x) { - if (this->rep != NULL) DEC_COUNT (this->rep); - this->rep= x.rep; - if (x.rep != NULL) INC_COUNT (x.rep); - return *this; -} - -/****************************************************************************** - * Methods of hashtree_rep - ******************************************************************************/ - template inline bool hashtree_rep::contains (K key) { @@ -81,9 +54,8 @@ hashtree_rep::get_label () { template inline void hashtree::realize () { - if (rep == NULL) { - rep= tm_new> (); - INC_COUNT (rep); + if (this->is_nil ()) { + *this= hashtree (); } } @@ -96,7 +68,7 @@ inline hashtree_rep* hashtree::operator->(void) { // always make sure there is a rep! realize (); - return rep; + return this->rep; } template @@ -121,7 +93,7 @@ hashtree::operator() (K key) { template inline bool is_nil (hashtree ht) { - return ht.rep == NULL; + return ht.is_nil (); } template From e79e91f0b31a80378fc4385019f36d71a6bb99f0 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Sun, 2 Jun 2024 17:54:59 +0800 Subject: [PATCH 09/11] add for tm_ostream --- System/IO/tm_ostream.cpp | 55 ++++++++++------------------------------ System/IO/tm_ostream.hpp | 16 +++--------- 2 files changed, 17 insertions(+), 54 deletions(-) diff --git a/System/IO/tm_ostream.cpp b/System/IO/tm_ostream.cpp index ba6a4826b..988a36865 100644 --- a/System/IO/tm_ostream.cpp +++ b/System/IO/tm_ostream.cpp @@ -21,7 +21,7 @@ * Routines for abstract base class ******************************************************************************/ -tm_ostream_rep::tm_ostream_rep () : ref_count (0) {} +tm_ostream_rep::tm_ostream_rep () {} tm_ostream_rep::~tm_ostream_rep () {} void tm_ostream_rep::flush () {} @@ -116,21 +116,21 @@ std_ostream_rep::flush () { class buffered_ostream_rep : public tm_ostream_rep { public: - tm_ostream_rep* master; - string buf; + tm_ostream master; + string buf; public: - buffered_ostream_rep (tm_ostream_rep* master); + buffered_ostream_rep (tm_ostream master); ~buffered_ostream_rep (); bool is_writable () const; void write (const char*); }; -buffered_ostream_rep::buffered_ostream_rep (tm_ostream_rep* master2) +buffered_ostream_rep::buffered_ostream_rep (tm_ostream master2) : master (master2) {} -buffered_ostream_rep::~buffered_ostream_rep () { DEC_COUNT (master); } +buffered_ostream_rep::~buffered_ostream_rep () {} bool buffered_ostream_rep::is_writable () const { @@ -146,33 +146,9 @@ buffered_ostream_rep::write (const char* s) { * Abstract user interface ******************************************************************************/ -tm_ostream::tm_ostream () : rep (tm_new ()) { - INC_COUNT (this->rep); -} -tm_ostream::tm_ostream (char* s) : rep (tm_new (s)) { - INC_COUNT (this->rep); -} -tm_ostream::tm_ostream (FILE* f) : rep (tm_new (f)) { - INC_COUNT (this->rep); -} -tm_ostream::tm_ostream (const tm_ostream& x) : rep (x.rep) { - INC_COUNT (this->rep); -} -tm_ostream::tm_ostream (tm_ostream_rep* rep2) : rep (rep2) { - INC_COUNT (this->rep); -} -tm_ostream::~tm_ostream () { DEC_COUNT (this->rep); } -tm_ostream_rep* -tm_ostream::operator->() { - return rep; -} -tm_ostream& -tm_ostream::operator= (tm_ostream x) { - INC_COUNT (x.rep); - DEC_COUNT (this->rep); - this->rep= x.rep; - return *this; -} +tm_ostream::tm_ostream () : base (make ()) {} +tm_ostream::tm_ostream (char* s) : base (make (s)) {} +tm_ostream::tm_ostream (FILE* f) : base (make (f)) {} bool tm_ostream::operator== (tm_ostream& out) { return (&out == this); @@ -190,25 +166,20 @@ tm_ostream::flush () { void tm_ostream::buffer () { - rep= tm_new (rep); - INC_COUNT (rep); + *this= tm_ostream (make (*this)); } string tm_ostream::unbuffer () { buffered_ostream_rep* ptr= (buffered_ostream_rep*) rep; - rep = ptr->master; - string r = ptr->buf; - INC_COUNT (rep); - DEC_COUNT (ptr); + string r = ptr->buf; + *this = ptr->master; return r; } void tm_ostream::redirect (tm_ostream x) { - INC_COUNT (x.rep); - DEC_COUNT (this->rep); - this->rep= x.rep; + *this= x; } /****************************************************************************** diff --git a/System/IO/tm_ostream.hpp b/System/IO/tm_ostream.hpp index 7a83b5b3d..2beb43ec7 100644 --- a/System/IO/tm_ostream.hpp +++ b/System/IO/tm_ostream.hpp @@ -13,14 +13,12 @@ #define OUT_STREAM_HPP // #include "url.hpp" +#include "sharedptr.hpp" #include "string.hpp" #include class tm_ostream; class tm_ostream_rep { -public: - int ref_count; - public: tm_ostream_rep (); virtual ~tm_ostream_rep (); @@ -33,9 +31,8 @@ class tm_ostream_rep { friend class tm_ostream; }; -class tm_ostream { -public: - tm_ostream_rep* rep; +class tm_ostream : public counted_ptr { + using base::counted_ptr; public: static tm_ostream private_cout; @@ -47,12 +44,7 @@ class tm_ostream { tm_ostream (); tm_ostream (char*); tm_ostream (FILE*); - tm_ostream (const tm_ostream&); - tm_ostream (tm_ostream_rep*); - ~tm_ostream (); - tm_ostream_rep* operator->(); - tm_ostream& operator= (tm_ostream x); - bool operator== (tm_ostream&); + bool operator== (tm_ostream&); void clear (); void flush (); From 4c954ba123fc1b569d4eebee979061b55ebfac98 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Sun, 2 Jun 2024 22:01:44 +0800 Subject: [PATCH 10/11] add missing document --- Kernel/Abstractions/sharedptr.hpp | 78 ++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index 660292e75..fb7b4fe50 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -1,3 +1,10 @@ +/** \file sharedptr.hpp + * \copyright GPLv3 + * \details Defines smart pointers with reference counting. No spin lock is + * applied. + * \author jingkaimori + * \date 2024 + */ #pragma once @@ -10,15 +17,28 @@ struct ref_counter_base { virtual void* get () = 0; }; +/** + * @brief Structure representing an object with a reference count. + * @tparam T Actual type of inner object, must be a complete type + */ template struct ref_counter : ref_counter_base { /// @brief the reference count of the object int ref_count; T content; + + /** + * @brief in-place construct an object, and set its reference count to 1. + * @tparam Params types of parameters required by constructor of object + */ template explicit ref_counter (Params&&... p) : ref_count (1), content (std::forward (p)...){}; void inc_count () { ref_count++; } + /** + * @brief decrement the reference count of the object and delete it if the + * count reaches 0. + */ void dec_count () { ref_count--; if (ref_count == 0) { @@ -27,24 +47,59 @@ template struct ref_counter : ref_counter_base { } void* get () { return &content; } }; + +/** + * @brief Smart pointer with reference counting. + * @details + * To use smart pointer, counted_ptr class should be inherited publicly, and the + * type exploited to user of the smart pointer should be provided. If null + * pointer may be held inside the smart pointer, parameter nullable should be + * set to true explictly. + * + * The class derived from pointer should provide proper constructor so that user + * can instantiate pointer from arguments of other type. Operator should be + * overloaded at the derived class, rather than the type of underlying object. + * @tparam T The type which user of pointer get from indirection of the smart + * pointer. + */ template class counted_ptr { protected: using counter_t= ref_counter_base; - using base = counted_ptr; + /** + * @brief short-hand name of the class, avoiding duplicated type name of + * underlying object inside template. If the derived class is also template + * class, this declaration should be imported explictly with `using` clause. + */ + using base= counted_ptr; explicit counted_ptr (counter_t* c) : counter (c), rep (static_cast (c->get ())) {} + /** + * @tparam Stored the real type of underlying object, may differ from types + * exploits to user. This type must be complete type. + */ template static counter_t* make (Params&&... p) { return tm_new> (std::forward (p)...); } private: + /** + * @brief Opaque pointer to the counter that holds the instance of the + * underlying object + */ counter_t* counter; public: + /** + * cached pointer to the underlying object + */ T* rep; + counted_ptr () : counter (nullptr), rep (nullptr) {} + /** + * copy constructor of the smart pointer + */ counted_ptr (const counted_ptr& x) : counter (x.counter), rep (x.rep) { if constexpr (nullable) { @@ -66,6 +121,11 @@ template class counted_ptr { counter->dec_count (); } } + /** + * @brief Decrement the reference count for the old object (`*this`) and + * increments the reference count for the new object. + * @param x the new object + */ counted_ptr& operator= (counted_ptr& x) { if constexpr (nullable) { if (x.counter != nullptr) { @@ -83,11 +143,20 @@ template class counted_ptr { this->rep = x.rep; return *this; } + /** + * @brief Steal underlying reference counter from rvalue temprary object, then + * leave the old counter (`this->counter`) in the temprary object. Finally the + * temprary object will be destroyed along with old object held by `*this` + * @param x the new object + */ counted_ptr& operator= (counted_ptr&& x) { std::swap (this->counter, x.counter); std::swap (this->rep, x.rep); return *this; } + /** + * @brief pointer dereference operator + */ T* operator->() { if constexpr (nullable) { if (counter != nullptr) { @@ -101,6 +170,10 @@ template class counted_ptr { return rep; } } + /** + * @brief pointer dereference operator, call from const pointer to get const + * object + */ const T* operator->() const { return operator->(); } bool is_nil () const { if constexpr (nullable) { @@ -112,6 +185,9 @@ template class counted_ptr { } }; +/** + * @brief adapter of legacy is_nil function. + */ template inline bool is_nil (const counted_ptr x) { From 2f4066135336bdbb4fbdac41bf83c3933f90a923 Mon Sep 17 00:00:00 2001 From: jingkaimori Date: Sun, 2 Jun 2024 22:18:10 +0800 Subject: [PATCH 11/11] avoid errornous null value hold by non nullable smart pointer --- Kernel/Abstractions/sharedptr.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Kernel/Abstractions/sharedptr.hpp b/Kernel/Abstractions/sharedptr.hpp index fb7b4fe50..c1e96bc94 100644 --- a/Kernel/Abstractions/sharedptr.hpp +++ b/Kernel/Abstractions/sharedptr.hpp @@ -96,7 +96,10 @@ template class counted_ptr { */ T* rep; - counted_ptr () : counter (nullptr), rep (nullptr) {} + counted_ptr () : counter (nullptr), rep (nullptr) { + static_assert (nullable, + "null pointer is not allowed in non-null smart pointer."); + } /** * copy constructor of the smart pointer */