// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // Node.hpp -- // // Author : Thierry Delisle // Created On : Wed May 8 10:27:04 2019 // Last Modified By : Aaron B. Moss // Last Modified On : Wed May 8 11:00:00 2019 // Update Count : 2 // #pragma once #include #include namespace ast { class Visitor; /// Base class for all AST nodes. /// Keeps both strong and weak reference counts. class Node { public: // override defaults to ensure assignment doesn't // change/share reference counts Node() = default; Node(const Node&) : strong_count(0), weak_count(0) {} Node(Node&&) : strong_count(0), weak_count(0) {} Node& operator= (const Node&) = delete; Node& operator= (Node&&) = delete; virtual ~Node() = default; virtual const Node * accept( Visitor & v ) const = 0; /// Types of node references enum class ref_type { strong, weak }; inline void increment(ref_type ref) const { switch (ref) { case ref_type::strong: strong_count++; break; case ref_type::weak : weak_count ++; break; } } inline void decrement(ref_type ref) const { switch (ref) { case ref_type::strong: strong_count--; break; case ref_type::weak : weak_count --; break; } if(!strong_count && !weak_count) { delete this; } } private: /// Make a copy of this node; should be overridden in subclass with more precise return type virtual const Node * clone() const = 0; /// Must be copied in ALL derived classes template friend auto mutate(const node_t * node); mutable size_t strong_count = 0; mutable size_t weak_count = 0; }; // Mutate a node, non-member function to avoid static type // problems and be able to use auto return template auto mutate(const node_t * node) { assertf( node->strong_count >= 1, "Error: attempting to mutate a node that appears to have been linked" ); if (node->strong_count == 1) { return const_cast(node); } assertf( node->weak_count == 0, "Error: mutating node with weak references to it will invalided some references" ); return node->clone(); } std::ostream& operator<< ( std::ostream& out, const Node* node ); // Base class for the smart pointer types // should never really be used. template< typename node_t, enum Node::ref_type ref_t> class ptr_base { public: ptr_base() : node(nullptr) {} ptr_base( const node_t * n ) : node(n) { if( !node ) increment(node, ref_t); } ~ptr_base() { if( node ) decrement(node, ref_t); } template< enum Node::ref_type o_ref_t > ptr_base( const ptr_base & o ) : node(o.node) { if( !node ) return; increment(node, ref_t); } template< enum Node::ref_type o_ref_t > ptr_base( ptr_base && o ) : node(o.node) { if( node ) increment(node, ref_t); } template ptr_base & operator=( const o_node_t * node ) { assign(strict_dynamic_cast(node)); return *this; } template< enum Node::ref_type o_ref_t > ptr_base & operator=( const ptr_base & o ) { assign(o.node); return *this; } template< enum Node::ref_type o_ref_t > ptr_base & operator=( ptr_base && o ) { if(o.node == node) return *this; assign(o.node); return *this; } const node_t * get() const { return node; } const node_t * operator->() const { return node; } const node_t & operator* () const { return *node; } explicit operator bool() const { return node; } operator const node_t * const() const { return node; } using ptr = const node_t *; private: void assign(const node_t * other ) { if( other ) increment(other, ref_t); if( node ) decrement(node , ref_t); node = other; } protected: const node_t * node; }; /// Owning pointer to node template< typename node_t > using ptr = ptr_base< node_t, Node::ref_type::strong >; /// Observing pointer to node template< typename node_t > using readonly = ptr_base< node_t, Node::ref_type::weak >; } // Local Variables: // // tab-width: 4 // // mode: c++ // // compile-command: "make install" // // End: //