Lumiera  0.pre.03
»edit your freedom«
meta/util.hpp File Reference

Go to the source code of this file.

Description

Simple and lightweight helpers for metaprogramming and type detection.

This header is a collection of very basic type detection and metaprogramming utilities.

Warning
indirectly, this header gets included into the majority of compilation units. Avoid anything here which increases compilation times or adds much debugging info.
See also
MetaUtils_test
trait.hpp
typelist.hpp

Definition in file meta/util.hpp.

#include "lib/integral.hpp"
#include <typeinfo>
#include <string>

Classes

class  _DetectNested_TypeResult< TY >
 
struct  _ExtractFirst<... >
 
struct  _ExtractFirst< X, XS... >
 
struct  can_convertToString< X >
 detect possibility of a conversion to string. More...
 
struct  enable_if_c< B, T >
 
struct  enable_if_c< false, T >
 
class  has_FunctionOperator< FUN >
 Trait template to detect presence of a simple function call operator. More...
 
struct  has_TypeResult< X >
 helper to check if another metafunction produced a result type More...
 
class  is_Typelist< TY >
 Trait template for detecting a typelist type. More...
 
struct  Marked< BAS, m >
 Metaprogramming helper to mark some arbitrary base type by subclassing. More...
 
struct  No_t
 
struct  has_FunctionOperator< FUN >::Probe< FF, SEL >
 
struct  can_convertToString< X >::Probe< XX, i >
 
class  shared_ptr< X >
 
struct  StringConv< X, COND >
 failsafe invocation of custom string conversion. More...
 
struct  StringConv< X *, lib::meta::disable_if< std::__or_< std::is_same< std::remove_cv_t< X >, char >, std::is_same< std::remove_cv_t< X >, void > > > >
 specialisation to allow rendering pointers to string-convertible types. More...
 
struct  StringConv< X, lib::meta::enable_CustomStringConversion< X > >
 
class  unique_ptr< T >
 STL class.
 

Typedefs

template<class Cond , class T = void>
using disable_if = typename enable_if_c< not Cond::value, T >::type
 
template<class SELF , typename ... ARGS>
using disable_if_self = disable_if< std::is_same< std::remove_cv_t< std::remove_reference_t< extractFirst_t< ARGS... > >>, SELF > >
 helper to prevent a template constructor from shadowing inherited copy ctors
 
template<typename X >
using enable_CustomStringConversion = enable_if< can_convertToString< X > >
 toggle for explicit specialisations
 
template<class Cond , class T = void>
using enable_if = typename enable_if_c< Cond::value, T >::type
 SFINAE helper to control the visibility of specialisations and overloads. More...
 
template<typename... XS>
using extractFirst_t = typename _ExtractFirst< XS... >::Type
 helper to extract the first argument from a variadic arg pack, if any
 
typedef char Yes_t
 helper types to detect the overload resolution chosen by the compiler
 

Functions

string demangleCxx (Literal rawName)
 Fallback type-ID: More...
 
string humanReadableTypeID (lib::Literal)
 pretty-print an internal C++ type representation More...
 
unsigned long long operator""_GiB (unsigned long long const siz)
 
uint operator""_KiB (unsigned long long const siz)
 
uint operator""_MiB (unsigned long long const siz)
 
string primaryTypeComponent (lib::Literal)
 extract core name component from a raw type spec More...
 
string sanitisedFullTypeName (lib::Literal)
 build a sanitised ID from full type name
 
string sanitisedSymbol (std::string const &)
 condense a string and retain only valid identifiers More...
 
string showAddr (void const *addr) noexcept
 pretty-print an address as hex-suffix
 
template<typename X >
std::string showAddr (X &elm) noexcept
 
std::string showBool (bool yes) noexcept
 human readable display of boolean values More...
 
string showComplete (double) noexcept
 show enough decimal digits to represent every distinct value
 
string showComplete (float val) noexcept
 
string showComplete (f128 val) noexcept
 
string showDecimal (double) noexcept
 show maximum reproducible decimal representation
 
string showDecimal (float val) noexcept
 
string showDecimal (f128 val) noexcept
 
string showDouble (double) noexcept
 pretty-print a double in (rounded) fixed-point format More...
 
string showFloat (float val) noexcept
 
template<typename X >
std::string showPtr (X *ptr=nullptr)
 diagnostics helper for explicitly indicating pointers
 
string showSize (size_t val) noexcept
 
template<typename SP >
std::string showSmartPtr (SP const &smPtr, std::string label="smP")
 
template<typename TY >
std::string typeStr (TY const *obj=nullptr) noexcept
 failsafe human readable type display More...
 
template<typename TY >
disable_if< std::is_pointer< TY >, std::string > typeStr (TY const &ref) noexcept
 
std::string typeStr (void const *) noexcept
 
template<typename TY >
std::string typeSymbol (TY const *obj=nullptr)
 simple expressive symbol to designate a type More...
 
template<typename TY >
disable_if< std::is_pointer< TY >, std::string > typeSymbol (TY const &ref)
 

Namespaces

 lib
 Implementation namespace for support and library code.
 

Typedef Documentation

◆ enable_if

using enable_if = typename enable_if_c<Cond::value, T>::type

SFINAE helper to control the visibility of specialisations and overloads.

explanation
This template needs to be interspersed somehow into a type expression, which is driven by an external, primary type parameter. Thus, it is possible to use it on an extraneous, possibly default template parameter, or when forming the return type of a function. The purpose is to remove a given definition from sight, unless a boolean condition Cond::value holds true. In the typical usage, this condition is suppled by a metafunction, i.e. a template, which detects some feature or other circumstantial condition with the types involved.
Remarks
this is a widely used facility, available both from boost and from the standard library. For the most common case, we roll our own variant here, which is slightly stripped down and a tiny bit more concise than the boost variant. This way, we can avoid a lot of boost inclusions, which always bear some weight.
See also
std::enable_if

Definition at line 92 of file meta/util.hpp.


Class Documentation

◆ lib::meta::anonymous_namespace{util.hpp}::_ExtractFirst

struct lib::meta::anonymous_namespace{util.hpp}::_ExtractFirst
Class Members
typedef void Type
+ Collaboration diagram for _ExtractFirst<... >:

◆ lib::meta::anonymous_namespace{util.hpp}::_ExtractFirst< X, XS... >

struct lib::meta::anonymous_namespace{util.hpp}::_ExtractFirst< X, XS... >
Class Members
typedef X Type
+ Collaboration diagram for _ExtractFirst< X, XS... >:

◆ lib::meta::has_FunctionOperator::Probe

struct lib::meta::has_FunctionOperator::Probe
+ Collaboration diagram for has_FunctionOperator< FUN >::Probe< FF, SEL >:

◆ lib::meta::can_convertToString::Probe

struct lib::meta::can_convertToString::Probe
+ Collaboration diagram for can_convertToString< X >::Probe< XX, i >:

Function Documentation

◆ humanReadableTypeID()

std::string humanReadableTypeID ( Literal  rawType)

pretty-print an internal C++ type representation

implementation notes
  • we do not strip type adornments like const, & or *, however, the typical usage from within util::typeStr() is arranged in a way to absorb these adornments by the way the template signatures are defined
  • we do simplify the type display and strip some obnoxious namespace prefixes with the help of std::regex_replace
  • we perform those simplifying rewrites in place thus overwriting the result string. This exploits the fact that the replacements are always shorter than what is being replaced (beware).
  • standard regular expressions can be assumed to be threadsafe. Thus, we're able to build an embedded shared static variable on demand and use the performance optimisation offered by the standard library
  • performance wise we'll assume the transformation happens within the cache, so it doesn't make much of a difference if we scan the same comparatively short string multiple times
See also
format-obj.cpp implementation
Examples:
/Werk/devel/lumi/src/lib/test/test-helper.hpp.

Definition at line 199 of file format-obj.cpp.

References lib::meta::demangleCxx(), and lib::meta::humanReadableTypeID().

Referenced by lib::meta::humanReadableTypeID(), and lib::meta::sanitisedFullTypeName().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ primaryTypeComponent()

std::string primaryTypeComponent ( Literal  rawType)

extract core name component from a raw type spec

implementation notes
We want to get at the name of the most relevant type entity. This in itself is a heuristic. But we can work on the assumption, that we get a sequence of nested namespaces and type names, and we'll be interested in the last, the innermost of these types. In the most general case, each type could be templated, and thus will be followed by parameter specs enclosed in angle braces. Behind this spec, only type adornments will follow. Thus we'll inspect the string from the back side, skipping over all type parameter contents, until we reach brace level zero again. From this point, we have to search backwards to the first namespace separator ::
Warning
we acknowledge this function can fail in various ways, some of which will be indicated by returning the string "void". But it may well happen that the returned string contains whitespace, superfluous punctuation or even the whole demangled type specification as is.
Returns
simple identifier possibly "the" type
Warning
implemented lexically, not necessarily correct!

Definition at line 270 of file format-obj.cpp.

References lib::meta::demangleCxx(), lib::meta::primaryTypeComponent(), and lib::meta::typeStr().

Referenced by lib::meta::primaryTypeComponent().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sanitisedSymbol()

std::string sanitisedSymbol ( std::string const &  )

condense a string and retain only valid identifiers

Returns
string starting with letter, followed by letters, digits and underscore

Definition at line 315 of file format-obj.cpp.

References lib::meta::sanitisedSymbol().

Referenced by lib::meta::sanitisedSymbol().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ demangleCxx()

std::string demangleCxx ( Literal  rawName)

Fallback type-ID:

reverse the effect of C++ name mangling.

Returns
unaltered internal type-ID
string in language-level form of a C++ type or object name, or a string with the original input if demangling fails.
Warning
implementation relies on the cross vendor C++ ABI in use by GCC and compatible compilers, so portability is limited. The implementation is accessed through libStdC++ Name representation in emitted object code and type IDs is essentially an implementation detail and subject to change.
Examples:
/Werk/devel/lumi/src/lib/test/test-helper.hpp.

Definition at line 168 of file format-obj.cpp.

References lib::meta::demangleCxx().

Referenced by lib::meta::demangleCxx(), lib::meta::humanReadableTypeID(), and lib::meta::primaryTypeComponent().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ typeStr()

std::string lib::meta::typeStr ( TY const *  obj = nullptr)
inlinenoexcept

failsafe human readable type display

Returns
string representing the C++ type.
Remarks
the purpose of this function is diagnostics and unit-testing. When possible, RTTI is exposed, otherwise the implementation falls back on the static type as seen by the compiler on usage site. An attempt is made to de-mangle and further simplify the type string, leaving out some common (hard wired) namespace prefixes, and stripping typical adornments like const, * and &
almost all calls will enter through the const& variant of this function, since C++ considers this best match in template substitution. Thus, we deliberately force calls with pointer to enter here, since we do want the pointer itself (and not a pointer to the pointer). We then pass the "object" as so called "glvalue" to the typeid() function, so to get the evaluation of RTTI, when applicable.
Warning
this function does string transformations behind the scene, and thus should not be used in performance critical context. Moreover, the returned type string is not necessarily exact and re-parsable.
Examples:
/Werk/devel/lumi/src/lib/test/test-helper.hpp.

Definition at line 325 of file meta/util.hpp.

Referenced by lib::meta::primaryTypeComponent().

+ Here is the caller graph for this function:

◆ typeSymbol()

std::string lib::meta::typeSymbol ( TY const *  obj = nullptr)
inline

simple expressive symbol to designate a type

Returns
single word identifier, derived from the full type name, not necessarily correct or unique

Definition at line 357 of file meta/util.hpp.

◆ showBool()

std::string util::showBool ( bool  yes)
inlinenoexcept

human readable display of boolean values

Returns
"`true`" or "`false`"

Definition at line 444 of file meta/util.hpp.

References util::showBool().

Referenced by util::showBool().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ showDouble()

std::string showDouble ( double  val)
noexcept

pretty-print a double in (rounded) fixed-point format

Returns
fixed point string representation, never empty
Note
we set an explicit precision, since this is a diagnostic facility
Remarks
typically do not want to see all digits, but, for test code, we do want a predictable string representation of simple fractional values like 0.1 (which can not be represented as binary floats)

Definition at line 362 of file format-obj.cpp.

References util::showDouble().

Referenced by util::showDouble().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: