NEURON
neuron::container::generic_data_handle Struct Reference

Non-template stable handle to a generic value. More...

#include <generic_data_handle.hpp>

Public Member Functions

 generic_data_handle ()=default
 Construct a null data handle. More...
 
 generic_data_handle (std::nullptr_t)
 Construct a null data handle. More...
 
template<typename T , std::enable_if_t< can_be_stored_literally_v< T >, int > = 0>
 generic_data_handle (T value)
 Construct a generic data handle that holds a small literal value. More...
 
template<typename T , std::enable_if_t< can_be_stored_literally_v< T >, int > = 0>
generic_data_handleoperator= (T value)
 Assign a small literal value to a generic data handle. More...
 
template<typename T , std::enable_if_t< std::is_pointer_v< T >, int > = 0>
generic_data_handleoperator= (T value)
 Store a pointer inside this generic data handle. More...
 
template<typename T >
 generic_data_handle (do_not_search_t dns, T *raw_ptr)
 
template<typename T , std::enable_if_t< std::is_same_v< T, void >, int > = 0>
 generic_data_handle (data_handle< T > const &handle)
 Wrap a data_handle<void> in a generic data handle. More...
 
template<typename T , std::enable_if_t<!std::is_same_v< T, void >, int > = 0>
 generic_data_handle (data_handle< T > const &handle)
 Wrap a data_handle<T != void> in a generic data handle. More...
 
template<typename T >
 operator data_handle< T > () const
 Create data_handle<T> from a generic data handle. More...
 
template<typename T >
get () const
 Explicit conversion to any T. More...
 
template<typename T >
bool holds () const
 Check if this handle refers to the specific type. More...
 
bool refers_to_a_modern_data_structure () const
 Check if this handle contains a data_handle<T> or just a literal. More...
 
std::string type_name () const
 Return the demangled name of the type this handle refers to. More...
 
template<typename T >
T & literal_value ()
 Obtain a reference to the literal value held by this handle. More...
 

Private Member Functions

void throw_error (std::string message) const
 

Private Attributes

non_owning_identifier_without_container m_offset {}
 
void * m_container {}
 
std::type_info const * m_type {}
 
int m_array_dim {1}
 
int m_array_index {}
 

Static Private Attributes

template<typename T >
static constexpr bool can_be_stored_literally_v
 

Friends

std::ostream & operator<< (std::ostream &os, generic_data_handle const &dh)
 

Detailed Description

Non-template stable handle to a generic value.

This is a type-erased version of data_handle<T>, with the additional feature that it can store values of POD types no larger than a pointer (typically int and float). It stores (at runtime) the type of the value it contains, and is therefore type-safe, but this increases sizeof(generic_data_handle) by 50% so it may be prudent to view this as useful for validation/debugging but not something to become too dependent on.

There are several states that instances of this class can be in:

  • null, no value is contained, any type can be assigned without any type mismatch error (m_type=null, m_container=null, m_offset=null)
  • wrapping an instance of a small, trivial type T (m_type=&typeid(T), m_container=the_value, m_offset=null)
  • wrapping a data handle<T> (m_type=&typeid(T*), m_container=the_container, m_offset=ptr_to_row)

    Todo:
    Consider whether this should be made more like std::any (with a maximum 2*sizeof(void*) and a promise never to allocate memory dynamically) so it actually has a data_handle<T> subobject. Presumably that would mean data_handle<T> would need to have a trivial destructor. This might make it harder in future to have some vector_of_generic_data_handle type that hoists out the pointer-to-container and typeid parts that should be the same for all rows.

Definition at line 37 of file generic_data_handle.hpp.

Constructor & Destructor Documentation

◆ generic_data_handle() [1/6]

neuron::container::generic_data_handle::generic_data_handle ( )
default

Construct a null data handle.

◆ generic_data_handle() [2/6]

neuron::container::generic_data_handle::generic_data_handle ( std::nullptr_t  )
inline

Construct a null data handle.

Definition at line 52 of file generic_data_handle.hpp.

◆ generic_data_handle() [3/6]

template<typename T , std::enable_if_t< can_be_stored_literally_v< T >, int > = 0>
neuron::container::generic_data_handle::generic_data_handle ( value)
inlineexplicit

Construct a generic data handle that holds a small literal value.

This is explicit to avoid things like operator<<(ostream&, generic_data_handle const&) being considered when printing values like size_t.

Definition at line 61 of file generic_data_handle.hpp.

◆ generic_data_handle() [4/6]

template<typename T >
neuron::container::generic_data_handle::generic_data_handle ( do_not_search_t  dns,
T *  raw_ptr 
)
inline

Definition at line 90 of file generic_data_handle.hpp.

◆ generic_data_handle() [5/6]

template<typename T , std::enable_if_t< std::is_same_v< T, void >, int > = 0>
neuron::container::generic_data_handle::generic_data_handle ( data_handle< T > const &  handle)
inline

Wrap a data_handle<void> in a generic data handle.

Note that data_handle<void> is always wrapping a raw void* and is never in "modern" mode

Definition at line 100 of file generic_data_handle.hpp.

◆ generic_data_handle() [6/6]

template<typename T , std::enable_if_t<!std::is_same_v< T, void >, int > = 0>
neuron::container::generic_data_handle::generic_data_handle ( data_handle< T > const &  handle)
inline

Wrap a data_handle<T != void> in a generic data handle.

Definition at line 110 of file generic_data_handle.hpp.

Member Function Documentation

◆ get()

template<typename T >
T neuron::container::generic_data_handle::get ( ) const
inline

Explicit conversion to any T.

It might be interesting in future to explore dropping m_type in optimised builds, in which case we should aim to avoid predicating important logic on exceptions thrown by this function.

Something like static_cast<double*>(generic_handle) will work both if the Datum holds a literal double* and if it holds a data_handle<double>.

Todo:
Consider conversion to bool and whether this means not-null or to obtain a literal, wrapped bool value

Definition at line 181 of file generic_data_handle.hpp.

◆ holds()

template<typename T >
bool neuron::container::generic_data_handle::holds ( ) const
inline

Check if this handle refers to the specific type.

This could be a small, trivial type (e.g. T=int) or a pointer type (e.g. T=double*). holds<double*>() == true could either indicate that a data_handle<double> is held or that a literal double* is held.

It might be interesting in future to explore dropping m_type in optimised builds, in which case we should aim to avoid predicating important logic on this function.

Definition at line 219 of file generic_data_handle.hpp.

◆ literal_value()

template<typename T >
T& neuron::container::generic_data_handle::literal_value ( )
inline

Obtain a reference to the literal value held by this handle.

Storing literal values is incompatible with storing data_handle<T>. If the handle stores data_handle<T> then calling this method throws an exception. If the handle is null, this sets the stored type to be T and returns a reference to it. If the handle already holds a literal value of type T then a reference to it is returned.

Note that, unlike converting to double*, literal_value<double*>() will fail if the handle contains data_handle<double>, as in that case there is no persistent double* that could be referred to.

It might be interesting in future to explore dropping m_type in optimised builds, in which case we should aim to avoid predicating important logic on exceptions thrown by this function.

Definition at line 265 of file generic_data_handle.hpp.

◆ operator data_handle< T >()

template<typename T >
neuron::container::generic_data_handle::operator data_handle< T > ( ) const
inlineexplicit

Create data_handle<T> from a generic data handle.

The conversion will succeed, yielding a null data_handle<T>, if the generic data handle is null. If the generic data handle is not null then the conversion will succeed if the generic data handle actually holds a data_handle<T> or a literal T*.

It might be interesting in future to explore dropping m_type in optimised builds, in which case we should aim to avoid predicating important logic on exceptions thrown by this function.

Definition at line 132 of file generic_data_handle.hpp.

◆ operator=() [1/2]

template<typename T , std::enable_if_t< can_be_stored_literally_v< T >, int > = 0>
generic_data_handle& neuron::container::generic_data_handle::operator= ( value)
inline

Assign a small literal value to a generic data handle.

This is important when generic_data_handle is used as the Datum type for "pointer" variables in MOD files.

Definition at line 73 of file generic_data_handle.hpp.

◆ operator=() [2/2]

template<typename T , std::enable_if_t< std::is_pointer_v< T >, int > = 0>
generic_data_handle& neuron::container::generic_data_handle::operator= ( value)
inline

Store a pointer inside this generic data handle.

Explicit handling of pointer types (with redirection via data_handle<T>) ensures that some_generic_handle = some_ptr_to_T promotes the raw T* to a modern data_handle<T> that is stable to permutation.

Definition at line 85 of file generic_data_handle.hpp.

◆ refers_to_a_modern_data_structure()

bool neuron::container::generic_data_handle::refers_to_a_modern_data_structure ( ) const
inline

Check if this handle contains a data_handle<T> or just a literal.

This should match static_cast<data_handle<T>>(generic_handle).refers_to_a_modern_data_structure() if T is correct. This will return true if we hold a data_handle that refers to a since-deleted row.

Definition at line 230 of file generic_data_handle.hpp.

◆ throw_error()

void neuron::container::generic_data_handle::throw_error ( std::string  message) const
inlineprivate

Definition at line 284 of file generic_data_handle.hpp.

◆ type_name()

std::string neuron::container::generic_data_handle::type_name ( ) const
inline

Return the demangled name of the type this handle refers to.

If the handle contains data_handle<T>, this will be T*. If a literal value or raw pointer is being wrapped, that possibly-pointer type will be returned.

It might be interesting in future to explore dropping m_type in optimised builds, in which case we should aim to avoid predicating important logic on this function.

Definition at line 244 of file generic_data_handle.hpp.

Friends And Related Function Documentation

◆ operator<<

std::ostream& operator<< ( std::ostream &  os,
generic_data_handle const &  dh 
)
friend

Definition at line 62 of file container.cpp.

Member Data Documentation

◆ can_be_stored_literally_v

template<typename T >
constexpr bool neuron::container::generic_data_handle::can_be_stored_literally_v
staticconstexprprivate
Initial value:
=
std::is_trivial_v<T> && !std::is_pointer_v<T> && sizeof(T) <= sizeof(void*)

Definition at line 42 of file generic_data_handle.hpp.

◆ m_array_dim

int neuron::container::generic_data_handle::m_array_dim {1}
private

Definition at line 298 of file generic_data_handle.hpp.

◆ m_array_index

int neuron::container::generic_data_handle::m_array_index {}
private

Definition at line 298 of file generic_data_handle.hpp.

◆ m_container

void* neuron::container::generic_data_handle::m_container {}
private

Definition at line 294 of file generic_data_handle.hpp.

◆ m_offset

non_owning_identifier_without_container neuron::container::generic_data_handle::m_offset {}
private

Definition at line 291 of file generic_data_handle.hpp.

◆ m_type

std::type_info const* neuron::container::generic_data_handle::m_type {}
private

Definition at line 296 of file generic_data_handle.hpp.


The documentation for this struct was generated from the following file: