Algorithms - Visitor implementation
This commit is contained in:
parent
46fa84d967
commit
0bc11d32d7
2 changed files with 178 additions and 0 deletions
95
include/ebcl/Algorithms.hh
Normal file
95
include/ebcl/Algorithms.hh
Normal file
|
@ -0,0 +1,95 @@
|
|||
/******************************************************************************/
|
||||
/* VARIOUS ALGORITHMS *********************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_ALGORITHMS
|
||||
#define _H_EBCL_ALGORITHMS
|
||||
#include <ebcl/Types.hh>
|
||||
#include <ebcl/Arrays.hh>
|
||||
namespace ebcl {
|
||||
|
||||
|
||||
/*= VISITOR ==================================================================*/
|
||||
|
||||
|
||||
/* Helper for the visitor algorithm. Provides the various types used internally
|
||||
* as well as means to create and dereference values for the stack.
|
||||
*
|
||||
* The template's default implementation are not functional. It is specialised
|
||||
* later for references and non-references.
|
||||
*/
|
||||
template<
|
||||
typename T_Ref ,
|
||||
bool IsRef = std::is_reference< T_Ref >::value
|
||||
> struct T_VisitorHelper_
|
||||
{
|
||||
using T_Opt = void; // Optional value type
|
||||
using T_StackRef = void; // Stack reference type
|
||||
|
||||
static T_StackRef mkext( T_Ref ) noexcept; // Create stack reference
|
||||
static T_Ref deref( T_StackRef ) noexcept; // Dereference stack entry
|
||||
};
|
||||
|
||||
|
||||
template<
|
||||
// Node type
|
||||
typename T_Node ,
|
||||
// Node reference type; by default, use values for arithmetic types and
|
||||
// pointers, and references for other types
|
||||
typename R_Node = std::conditional_t<
|
||||
std::is_arithmetic< T_Node >::value || std::is_pointer< T_Node >::value ,
|
||||
T_Node , T_Node& >
|
||||
> class T_Visitor
|
||||
{
|
||||
private:
|
||||
using Helper_ = T_VisitorHelper_< R_Node >;
|
||||
|
||||
public:
|
||||
// Optional value
|
||||
using T_OptNode = typename Helper_::T_Opt;
|
||||
|
||||
// Node browser. Returns the Nth child of the specified node, or null
|
||||
// if there are no children left.
|
||||
using F_NodeBrowser = std::function< T_OptNode( R_Node , uint32_t ) >;
|
||||
|
||||
// Node action. Second parameter indicates whether the action is
|
||||
// being called before (false) or after (true) visiting the children.
|
||||
using F_NodeAction = std::function< bool( R_Node , bool ) >;
|
||||
|
||||
private:
|
||||
using T_StackRef_ = typename Helper_::T_StackRef;
|
||||
|
||||
// State of a stack entry
|
||||
enum E_State_ {
|
||||
BEFORE , // Must enter the node
|
||||
CHILDREN , // Going through children
|
||||
AFTER // Must exit the node
|
||||
};
|
||||
struct T_NodeRef_ {
|
||||
T_StackRef_ node;
|
||||
uint32_t child;
|
||||
E_State_ state{ BEFORE };
|
||||
|
||||
explicit T_NodeRef_( R_Node node ) noexcept
|
||||
: node( Helper_::mkext( node ) ) , child( 0 ) {}
|
||||
explicit T_NodeRef_( R_Node node , uint32_t child ) noexcept
|
||||
: node( Helper_::mkext( node ) ) , child( child ) {}
|
||||
};
|
||||
|
||||
F_NodeBrowser nodeBrowser_;
|
||||
T_AutoArray< T_NodeRef_ , 8 > stack_;
|
||||
|
||||
public:
|
||||
T_Visitor( ) = delete;
|
||||
T_Visitor( T_Visitor const& ) = default;
|
||||
T_Visitor( T_Visitor&& ) noexcept = default;
|
||||
|
||||
explicit T_Visitor( F_NodeBrowser browser ) noexcept;
|
||||
|
||||
void visit( R_Node root , F_NodeAction action );
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_EBCL_ALGORITHMS
|
||||
#include <ebcl/inline/Algorithms.hh>
|
83
include/ebcl/inline/Algorithms.hh
Normal file
83
include/ebcl/inline/Algorithms.hh
Normal file
|
@ -0,0 +1,83 @@
|
|||
/******************************************************************************/
|
||||
/* ALGORITHMS - INLINE CODE ***************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef _H_EBCL_INLINE_ALGORITHMS
|
||||
#define _H_EBCL_INLINE_ALGORITHMS
|
||||
#include <ebcl/Algorithms.hh>
|
||||
namespace ebcl {
|
||||
|
||||
|
||||
/*= VISITOR ==================================================================*/
|
||||
|
||||
// Specialization of the visitor helper for references
|
||||
template< typename R >
|
||||
struct T_VisitorHelper_< R , true >
|
||||
{
|
||||
using T_Base = typename std::remove_reference< R >::type;
|
||||
using T_Opt = T_Base*;
|
||||
using T_StackRef = T_Base*;
|
||||
|
||||
static T_StackRef mkext( R value ) noexcept { return &value; }
|
||||
static R deref( T_StackRef ref ) noexcept { return *ref; }
|
||||
};
|
||||
|
||||
// Specialization of the visitor helper for values
|
||||
template< typename R >
|
||||
struct T_VisitorHelper_< R , false >
|
||||
{
|
||||
using T_Base = typename std::remove_const< R >::type;
|
||||
using T_Opt = T_Optional< T_Base >;
|
||||
using T_StackRef = T_Base;
|
||||
|
||||
static T_StackRef mkext( R value ) noexcept { return value; }
|
||||
static R deref( T_StackRef ref ) noexcept { return ref; }
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
template< typename T , typename R >
|
||||
inline T_Visitor< T , R >::T_Visitor(
|
||||
F_NodeBrowser browser ) noexcept
|
||||
: nodeBrowser_( std::move( browser ) )
|
||||
{ }
|
||||
|
||||
template< typename T , typename R >
|
||||
inline void T_Visitor< T , R >::visit(
|
||||
R root ,
|
||||
F_NodeAction action )
|
||||
{
|
||||
stack_.addNew( root , 0 );
|
||||
|
||||
while ( !stack_.empty( ) ) {
|
||||
auto& n( stack_.last( ) );
|
||||
switch ( n.state ) {
|
||||
case BEFORE:
|
||||
n.state = action( Helper_::deref( n.node ) , false )
|
||||
? CHILDREN : AFTER;
|
||||
break;
|
||||
|
||||
case CHILDREN: {
|
||||
const T_OptNode child{
|
||||
nodeBrowser_( Helper_::deref( n.node ) , n.child ++ ) };
|
||||
if ( child ) {
|
||||
stack_.addNew( *child , 0 );
|
||||
} else {
|
||||
n.state = AFTER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AFTER:
|
||||
action( Helper_::deref( n.node ) , true );
|
||||
stack_.removeLast( );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_EBCL_INLINE_ALGORITHMS
|
Loading…
Reference in a new issue