| 1 | #pragma once
|
|---|
| 2 |
|
|---|
| 3 | #include <memory>
|
|---|
| 4 |
|
|---|
| 5 | namespace ast {
|
|---|
| 6 | class Node {
|
|---|
| 7 | public:
|
|---|
| 8 | virtual ~Node() = default;
|
|---|
| 9 |
|
|---|
| 10 | enum class ref_type {
|
|---|
| 11 | strong,
|
|---|
| 12 | weak
|
|---|
| 13 | };
|
|---|
| 14 |
|
|---|
| 15 | inline void increment(ref_type ref) const {
|
|---|
| 16 | switch (ref) {
|
|---|
| 17 | case ref_type::strong: strong_ref++; break;
|
|---|
| 18 | case ref_type::weak : weak_ref ++; break;
|
|---|
| 19 | }
|
|---|
| 20 | }
|
|---|
| 21 |
|
|---|
| 22 | inline void decrement(ref_type ref) const {
|
|---|
| 23 | switch (ref) {
|
|---|
| 24 | case ref_type::strong: strong_ref--; break;
|
|---|
| 25 | case ref_type::weak : weak_ref --; break;
|
|---|
| 26 | }
|
|---|
| 27 |
|
|---|
| 28 | if(!strong_ref && !weak_ref) {
|
|---|
| 29 | delete this;
|
|---|
| 30 | }
|
|---|
| 31 | }
|
|---|
| 32 |
|
|---|
| 33 | template<typename node_t>
|
|---|
| 34 | friend auto mutate(const node_t * node);
|
|---|
| 35 |
|
|---|
| 36 | private:
|
|---|
| 37 | mutable size_t strong_ref = 0;
|
|---|
| 38 | mutable size_t weak_ref = 0;
|
|---|
| 39 | };
|
|---|
| 40 |
|
|---|
| 41 | // Mutate a node, non-member function to avoid static type
|
|---|
| 42 | // problems and be able to use auto return
|
|---|
| 43 | template<typename node_t>
|
|---|
| 44 | auto mutate(const node_t * node) {
|
|---|
| 45 | assertf(
|
|---|
| 46 | node->strong_count >= 1,
|
|---|
| 47 | "Error: attempting to mutate a node that appears to have been linked"
|
|---|
| 48 | );
|
|---|
| 49 | if (node->strong_count == 1) {
|
|---|
| 50 | return const_cast<node_t *>(node);
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | assertf(
|
|---|
| 54 | node->weak_count == 0,
|
|---|
| 55 | "Error: mutating node with weak references to it will invalided some references"
|
|---|
| 56 | );
|
|---|
| 57 | return node->clone();
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | // Base class for the smart pointer types
|
|---|
| 61 | // should never really be used.
|
|---|
| 62 | template< typename node_t, enum Node::ref_type ref_t>
|
|---|
| 63 | class ptr_base {
|
|---|
| 64 | public:
|
|---|
| 65 | ptr_base() : node(nullptr) {}
|
|---|
| 66 | ptr_base( node_t * n ) : node(n) { if( !node ) node->increment(ref_t); }
|
|---|
| 67 | ~ptr_base() { if( node ) node->decrement(ref_t); }
|
|---|
| 68 |
|
|---|
| 69 | template< enum Node::ref_type o_ref_t >
|
|---|
| 70 | ptr_base( const ptr_base<node_t, o_ref_t> & o ) : node(o.node) {
|
|---|
| 71 | if( !node ) return;
|
|---|
| 72 | node->increment(ref_t);
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | template< enum Node::ref_type o_ref_t >
|
|---|
| 76 | ptr_base( ptr_base<node_t, o_ref_t> && o ) : node(o.node) {
|
|---|
| 77 | if( node ) node->increment(ref_t);
|
|---|
| 78 | if( node ) node->decrement(o_ref_t);
|
|---|
| 79 | }
|
|---|
| 80 |
|
|---|
| 81 | template< enum Node::ref_type o_ref_t >
|
|---|
| 82 | ptr_base & operator=( const ptr_base<node_t, o_ref_t> & o ) {
|
|---|
| 83 | assign(o.node);
|
|---|
| 84 | return *this;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | template< enum Node::ref_type o_ref_t >
|
|---|
| 88 | ptr_base & operator=( ptr_base<node_t, o_ref_t> && o ) {
|
|---|
| 89 | if(o.node == node) return *this;
|
|---|
| 90 | assign(o.node);
|
|---|
| 91 | if( node ) node->decrement(o_ref_t);
|
|---|
| 92 | return *this;
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | const node_t * get() const { return node; }
|
|---|
| 96 | const node_t * operator->() const { return node; }
|
|---|
| 97 | const node_t & operator* () const { return *node; }
|
|---|
| 98 | explicit operator bool() const { return node; }
|
|---|
| 99 | operator const node_t * const() const { return node; }
|
|---|
| 100 |
|
|---|
| 101 | using ptr = const node_t *;
|
|---|
| 102 |
|
|---|
| 103 | private:
|
|---|
| 104 | void assign(node_t * other ) {
|
|---|
| 105 | if( other ) other->increment(ref_t);
|
|---|
| 106 | if( node ) node ->decrement(ref_t);
|
|---|
| 107 | node = other;
|
|---|
| 108 | }
|
|---|
| 109 |
|
|---|
| 110 | protected:
|
|---|
| 111 | node_t * node;
|
|---|
| 112 | };
|
|---|
| 113 |
|
|---|
| 114 | template< typename node_t >
|
|---|
| 115 | using ptr = ptr_base< node_t, Node::ref_type::strong >;
|
|---|
| 116 |
|
|---|
| 117 | template< typename node_t >
|
|---|
| 118 | using readonly = ptr_base< node_t, Node::ref_type::weak >;
|
|---|
| 119 | }
|
|---|