Files
Extern/C3d/Include/generic_utility.h
SaraP 525666c31c Extern :
- C3d aggiornamento delle librerie ( 117968).
2023-11-30 14:51:23 +01:00

1245 lines
43 KiB
C++

//////////////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Шаблонные утилиты.
\en Template utilities. \~
*/
/////////////////////////////////////////////////////////////////////////////// C3D API///
#ifndef __GENERIC_UTILITY_H
#define __GENERIC_UTILITY_H
#include <memory.h>
//
#include <templ_sptr.h>
//
#include <assert.h>
#include <mb_variables.h>
#include <new>
#include <utility>
#include <functional>
#include <vector>
//----------------------------------------------------------------------------------------
/// \ru Пустой тип данных. \en Empty data type.
//---
struct null_type
{
static const null_type value() { return null_type(); }
};
//----------------------------------------------------------------------------------------
/** \brief \ru Шаблон для получения индексного типа (для статического сопоставления типов на этапе компиляции)
\en Template to generate an indexed type (for static type-matching in compile-time)
*/
//---
template<size_t>
struct index_tag
{
index_tag() {} // Constructor under GCC compiler
};
//----------------------------------------------------------------------------------------
/// \ru Цветовая маркировка (применяется для графов) \en Color marking (used for graphs)
//---
enum color_code: char
{
white_color = 0
, gray_color = 1
, green_color = 2
, black_color = 3
, red_color
, orange_color
, visited_color
};
//----------------------------------------------------------------------------------------
// Constant valued function
//---
template<bool boolVal>
bool boolFunc() { return boolVal; }
/*
//----------------------------------------------------------------------------------------
/// \ru Цветовая маркировка, например, для графовых объектов \en Color marking, for example: for graph objects
//---
template<typename ColorValue = color_code >
struct color_traits
{
static color_code white() { return white_color; }
static color_code gray() { return gray_color; }
static color_code green() { return green_color; }
static color_code red() { return red_color; }
static color_code black() { return black_color; }
};
template<>
struct color_traits<char>
{
static char white() { return 0; }
static char gray() { return 1; }
static char green() { return 2; }
static char red() { return 3; }
static char black() { return 4; }
};
*/
//----------------------------------------------------------------------------------------
/// \ru Графовые характеристики типов. \en Graph datatype traits.
//---
template< class Graph >
struct graph_traits
{
/*
Ассоциативные типы данных концепции графа.
Associative datatypes of the graph concept.
*/
typedef typename Graph::vertex vertex; // Тип, интерпретируемый, как вершина графа.
typedef typename Graph::edge edge; // Тип, интерпретируемый, как ребро графа
typedef typename Graph::vertex_iterator vertex_iterator; // Обход всех вершин графа
typedef typename Graph::adjacency_iterator adjacency_iterator; // Обход смежных вершин некоторой вершины
typedef typename Graph::vertices_size_t vertices_size_t; // Целочисленный тип размера графа
typedef typename Graph::degree_size_t degree_size_t; // Целочисленный тип вершинной степени
typedef typename Graph::edge_iterator edge_iterator; // Итератор обхода исходящих ребер [или неориентированных ребер]
};
//----------------------------------------------------------------------------------------
/// \ru Наибольшее из двух. \en Maximum of two.
// ---
template<class T>
inline const T & max_of( const T & elem1, const T & elem2 )
{
if ( elem2 < elem1 )
return elem1;
return elem2;
}
//----------------------------------------------------------------------------------------
/// \ru Наибольшее из двух. \en Maximum of two.
// ---
template<class T>
inline const T & min_of( const T & elem1, const T & elem2 )
{
if ( elem1 < elem2 )
return elem1;
return elem2;
}
//----------------------------------------------------------------------------------------
/// \ru Поменять местами значения. \en Swap the values.
// ---
template<class T>
inline void swap_vals( T & elem1, T & elem2 )
{
T tmp = elem1;
elem1 = elem2;
elem2 = tmp;
}
//----------------------------------------------------------------------------------------
/// \ru Поменять местами значения указателей. \en Swap the values of pointers.
// ---
template<class T>
inline void swap_ptrs( T* & elem1, T* & elem2 )
{
T * tmp = elem1;
elem1 = elem2;
elem2 = tmp;
}
//----------------------------------------------------------------------------------------
/// \ru Поменять местами значения указателей. \en Swap the values of pointers.
//---
template<class Type>
inline void swap_ptrs( SPtr<Type> & p1, SPtr<Type> & p2 )
{
SPtr<Type> t = p1;
p1 = p2;
p2 = t;
}
//----------------------------------------------------------------------------------------
// \ru Равенство пары указателей \en Equality of pointer pair
//---
template< class Type1, class Type2 >
bool equal_ptrs( const Type1 * ptr1, const Type2 * ptr2 )
{
return static_cast<const Type2*>(ptr1) == ptr2;
}
//----------------------------------------------------------------------------------------
// \ru Равенство пары указателей \en Equality of pointer pair
//---
template< class Type1, class Type2 >
bool equal_ptrs( SPtr<Type1> ptr1, const Type2 * ptr2 )
{
return static_cast<const Type2*>(ptr1.get()) == ptr2;
}
//----------------------------------------------------------------------------------------
// \ru Равенство пары двухмерных векторов или точек \en Equality of 2D points or vectors
//---
template< class XY1, class XY2 >
bool equal_xy( const XY1 & v1, const XY2 & v2, double eps )
{
if ( fabs(v1.x-v2.x) > eps )
return false;
if ( fabs(v1.y-v2.y) > eps )
return false;
return true;
}
//----------------------------------------------------------------------------------------
// \ru Наименьший общий делитель \en The lowest common denominator
// ---
template < typename Integer >
Integer euclid_algo ( Integer a, Integer b )
{
Integer const zero = static_cast<Integer>( 0 );
bool goOn = true;
while ( goOn )
{
if ( a == zero ) {
goOn = false;
return b;
}
b %= a;
if ( b == zero ) {
goOn = false;
return a;
}
a %= b;
}
return zero;
}
//----------------------------------------------------------------------------------------
/// \ru Получить НОД для пары целых чисел \en Get GCD for a pair of integers
// ---
template < typename IntegerType >
inline IntegerType gcd( IntegerType a, IntegerType b )
{
IntegerType const zero = static_cast<IntegerType>( 0 );
IntegerType const result = ::euclid_algo( a, b );
return ( result < zero ) ? -result : result;
}
//----------------------------------------------------------------------------------------
// \ru Функциональный объект - коллектор \en The functional object - collector
/*\ru Играет роль посетителя foreach-алгоритмов, осуществляющий накачку STL-совместимых контейнеров
\en Serves as a visitor of foreach-algorithms exercising pumping of STL-compatible containers \~
*/
//---
template<class _Cont>
struct collector
{
typedef typename _Cont::value_type value_type;
_Cont & container; // \ru STL-совместимый контейнер \en STL-compatible container
collector( _Cont & arr )
: container( arr ) {}
collector( const collector & c ) : container( c.container ) {}
void operator () ( const value_type & elem ) const
{
container.push_back( elem );
}
private: // \ru не реализовано \en not implemented
collector & operator = ( const collector & );
};
//----------------------------------------------------------------------------------------
/** \brief \ru Статический вектор.
\en Static vector.
\note \ru Требуется, что бы элементы вектора имели конструктор по умолчанию,
конструктор копирования и оператор присвоения.
\en Required that the vector elements have a default constructor,
copy constructor and assignment operator. \~
*/
//---
template<class Elem, size_t arrSize>
class static_array
{
public:
typedef Elem value_type; // \ru ассоциативный тип элемента массива \en associative type of array element
private:
value_type arr[arrSize]; // \ru статическое выделение памяти под массив \en static allocation for the array
public:
/// \ru Инициализация одним элементом. \en Initialization of one element.
explicit static_array( const Elem & val )
{
fill( val );
}
/// \ru Инициализация парой элементов. \en Initialization of a pair of elements.
static_array( const Elem & e1, const Elem & e2 )
{
PRECONDITION( arrSize == 2 );
arr[0] = e1;
arr[1] = e2;
}
/// \ru Конструктор по тройке. \en Constructs as a triplet.
static_array( const Elem & e1, const Elem & e2, const Elem & e3 )
{
PRECONDITION( arrSize == 3 );
arr[0] = e1;
arr[1] = e2;
arr[2] = e3;
}
explicit static_array( const static_array & vec )
{
_Assign( vec );
}
template<class _Vector>
static_array( const _Vector & vec )
{
_Assign( vec );
}
/// \ru Инициализация одним элементом. \en Initialization of one element.
static_array & fill( const Elem & val )
{
for( size_t idx = 0; idx<arrSize; ++idx )
{
arr[idx] = val;
}
return *this;
}
template<class _Iter>
static_array & assign( _Iter iter, _Iter last )
{
for ( value_type * myIter = arr ; iter!=last; ++iter, ++myIter )
{
PRECONDITION( myIter < arr+arrSize );
*myIter = *iter;
}
return *this;
}
inline value_type & operator[] ( size_t idx )
{
PRECONDITION( idx < arrSize );
return arr[idx];
}
inline const value_type & operator[] ( size_t idx ) const
{
PRECONDITION( idx < arrSize );
return arr[idx];
}
template<class _Vector>
static_array & operator = ( const _Vector & vec )
{
_Assign( vec );
return *this;
}
/// \ru Равенство. \en Equality.
template<class _Vector>
bool operator == ( const _Vector & vec ) const
{
if ( arrSize != vec.size() )
{
return false;
}
for( size_t idx = 0; idx<arrSize; ++idx )
{
if ( arr[idx] != vec[idx] )
{
return false;
}
}
return true;
}
inline const Elem * c_arr() const { return arr; }
inline Elem * c_arr() { return arr; }
inline size_t size() const { return arrSize; }
inline value_type & front() { return *arr; }
inline value_type & back() { PRECONDITION(arrSize>0); return arr[arrSize-1]; }
inline const value_type & front() const { return *arr; }
inline const value_type & back() const { PRECONDITION(arrSize>0); return arr[arrSize-1]; }
private:
template< class _Vector >
void _Assign( const _Vector & vec )
{
PRECONDITION( vec.size() == size() );
for ( size_t idx = ::min_of( arrSize, vec.size() ); idx > 0; )
{
idx--;
arr[idx] = vec[idx];
}
}
};
// \ru (!) Запретить пустые статические массивы \en (!) Prevent empty static arrays
template<class Elem> class static_array<Elem,0> {};
//----------------------------------------------------------------------------------------
/// \ru Статический вектор двух элементов (пара). \en Static vector of two elements (pair).
//---
template<class Elem>
struct static_pair: public static_array<Elem,2>
{
typedef static_array<Elem,2> parent_type;
// static_pair(): parent_type() {}
explicit static_pair( const Elem & el ): parent_type( el ) {}
static_pair( const Elem & el1, const Elem & el2 ): parent_type( el1, el2 ) {}
explicit static_pair( const static_pair & pair ) : parent_type( pair ) {}
static_pair & operator = ( const static_pair & vec )
{
parent_type::operator=( vec );
return *this;
}
};
//----------------------------------------------------------------------------------------
/**
\brief \ru Динамический контейнер для хранения элементов упорядоченного множества.
\en Dynamic container for storing elements of an ordered set.
\details
\ru Тип элемента контейнера должен иметь операторы порядка. Не стоит путать этот
тип контейнера с set или map. Он вовсе не обязан всегда поддерживаться в отсортированном
состоянии, а только тогда, когда это закажут (с кэшированием алгоритма сортировки).
Гарантируется, что вектор отсортирован сразу после вызова функций get_sorted или sort.
Константные методы, а также метод erase не нарушают сортировки.\n
\en Type of container element must have order operators. Do not confuse this
type of container with a set or map. It is not obliged always be supported in a sorted
state, and only when it is needed (with caching of sorting algorithm). It is guaranteed
that the vector is sorted immediately after the function call get_sorted or sort.
Const methods and the erase method does not break sorting. \n \~
\par \ru Про эффективность
Часто сортированный вектор оказывается более эффективным, чем std::map или std::set,
особенно если добавление/удаление элементов массива осуществляется серийно и достаточно
редко перемежаются, с запросами быстрого (бинарного) поиска элемента или его места по
порядку. В отличие от map или set минимально дефрагментируется память и не требуется
избыточной информации для хранения указателей (может занимать в 4 раза меньше памяти).
Для быстрых запросов можно применять стандартные алгоритмы, такие
как std::binary_search, std::lower_bound и т.п.
\en About efficiency
Often sorted vector is more effective than
std::map or std::set especially when adding/removing elements
of the array is standard and is rarely interspersed
with queries quickly (binary) search of element or its place by
the order. In contrast to the map or set minimal defragmented
memory and does not require excess information for storage of pointers
(can occupy memory in less than 4 times).
For fast queries, can use standard algorithms such
as std::binary_search, std::lower_bound etc. \~
*/
//---
template<class KeyType, class _Pr = std::less<KeyType> > // \ru KeyType - тип элемента с операторами порядка "<" \en KeyType - the element type with the operators of order "<"
class sorting_array
{
public:
typedef std::vector<KeyType> container_type;
typedef typename container_type::value_type value_type;
typedef typename container_type::size_type size_type;
typedef typename container_type::const_iterator iterator;
typedef typename container_type::iterator _iterator;
typedef std::pair<iterator,iterator> iter_range;
typedef _Pr key_compare; // \ru отношение порядка (предикат) \en order relation (predicate)
public:
sorting_array() : m_vector(), m_sorted( true ) {}
public:
iter_range get_sorted() { sort(); return iter_range(m_vector.begin(), m_vector.end()); }
iter_range range() const { return iter_range(m_vector.begin(), m_vector.end()); }
const KeyType & sorted_back() { sort(); return m_vector.back(); }
bool empty() const { return m_vector.empty(); }
iterator begin() const { return m_vector.begin(); }
iterator end() const { return m_vector.end(); }
_iterator _begin() { return m_vector.begin(); }
_iterator _end() { return m_vector.end(); }
const KeyType & front() const { return m_vector.front(); }
const KeyType & back() const { return m_vector.back(); }
void erase( iterator );
void erase( iterator f, iterator l );
bool is_sorted() const { return m_sorted; }
iterator insert( iterator _whereItr, const KeyType & val ); // \ru вставить элемент перед позицией whereItr \en insert element before position whereItr
template <class InputIterator>
void insert( iterator position, InputIterator first, InputIterator last )
{
m_vector.insert( position, first, last );
m_sorted = false;
}
template <class InputIterator>
void assign ( InputIterator first, InputIterator last )
{
m_vector.assign( first, last );
m_sorted = false;
}
void resize( size_t n, const KeyType & val );
void reserve ( size_t n ) { m_vector.reserve( n ); }
void push_back( const KeyType & val );
void sort()
{
if ( !m_sorted )
{
std::sort( m_vector.begin(), m_vector.end(), _Pr() );
m_sorted = true;
}
}
void clear() { m_vector.clear(); }
size_t size() const { return m_vector.size(); }
KeyType & operator[] ( size_t n ) { PRECONDITION( n < m_vector.size() ); return m_vector[n]; }
const KeyType & operator[] ( size_t n ) const { PRECONDITION( n < m_vector.size() ); return m_vector[n]; }
private:
container_type m_vector;
bool m_sorted;
private:
sorting_array( const sorting_array & ); // \ru реализовать по необходимости \en implement if necessary
sorting_array & operator = ( const sorting_array & ); // \ru реализовать по необходимости \en implement if necessary
};
//----------------------------------------------------------------------------------------
//
// ---
template<class KeyType, class _Pr >
void sorting_array<KeyType,_Pr>::push_back( const KeyType & val )
{
m_sorted = m_vector.empty() ? true : m_sorted && _Pr()( m_vector.back(), val );
m_vector.push_back( val );
}
//----------------------------------------------------------------------------------------
//
//---
template<class KeyType, class _Pr >
void sorting_array<KeyType,_Pr>::erase( iterator ersItr )
{
m_vector.erase( m_vector.begin() + (ersItr - begin()) );
}
//----------------------------------------------------------------------------------------
//
//---
template<class KeyType, class _Pr >
void sorting_array<KeyType,_Pr>::erase( iterator f, iterator l )
{
typename container_type::iterator first, last;
first = last = m_vector.begin();
std::advance( first, std::distance(begin(),f) ); // convert from const-iterator to non-const
std::advance( last, std::distance(begin(),l) );
m_vector.erase( first, last );
}
//----------------------------------------------------------------------------------------
// \ru Вставить элемент перед позицией whereItr \en Insert element before position whereItr
//---
template<class KeyType, class _Pr >
typename sorting_array<KeyType,_Pr>::iterator
sorting_array<KeyType,_Pr>::insert( iterator _whereItr, const KeyType & val )
{
typename container_type::iterator whereItr = m_vector.begin();
std::advance( whereItr, std::distance(begin(),_whereItr) ); // \ru перевод из конст-итератора в неконст \en convert from const-iterator to non-const
// \ru Далее проверяем не нарушает ли новая вставка упорядоченности массива \en Next, whether new insert does not break ordering of the array
if ( m_sorted && (_whereItr != m_vector.end()) )
{
m_sorted = ! key_compare()( *_whereItr, val );
if ( m_sorted ) // val <= _where
{
m_sorted = ( _whereItr == m_vector.begin() ) || !key_compare()( val, *(--_whereItr) );
}
}
// \ru Вставка \en Insert
return m_vector.insert( whereItr, val );
}
//----------------------------------------------------------------------------------------
//
//---
template<class KeyType, class _Pr >
void sorting_array<KeyType,_Pr>::resize( size_t n, const KeyType & val )
{
if ( m_sorted && (m_vector.size() < n) && !m_vector.empty() )
{
m_sorted = !key_compare()( val, m_vector.back() ); // m_vector.back() <= val
}
m_vector.resize( n, val );
}
//----------------------------------------------------------------------------------------
/// \ru Проверка упорядоченности массива \en Check for ordering array
//---
template<class SortedArray>
bool check_ordering( const SortedArray & arr )
{
if ( arr.is_sorted() && !arr.empty() )
{
typename SortedArray::value_type prev( *arr.begin() );
typename SortedArray::iterator first = arr.begin()+1;
typename SortedArray::iterator last = arr.end();
for( ; first!=last; ++first )
{
if ( (*first) < prev )
{
return false; // \ru нарушен порядок следования \en order has been broken
}
prev = *first;
}
}
return true;
}
//----------------------------------------------------------------------------------------
/// \ru Обнулить структуру данных (использовать осторожно!). \en Reset the data structure (use with caution!).
//---
template< class DataSt >
inline DataSt null_struct()
{
DataSt data;
::memset( &data, 0, sizeof(DataSt) );
return data;
}
//----------------------------------------------------------------------------------------
/// \ru Отладочный инспектор union-контейнера (НЕдоделан!). \en Debug Inspector of union-container (NOT completed yet!).
//---
template<class _PairUnion>
struct dbg_inspector
{
union data_t
{
typename _PairUnion::value_type * first;
};
data_t data;
dbg_inspector() { data.first = 0; }
void init( const _PairUnion & ) {}
};
//----------------------------------------------------------------------------------------
/// \ru Хвостовой элемент для рекурсивного определения типа recursive_union<T1,T2>. \en Tail element for recursive determination of type recursive_union<T1,T2>.
//---
struct empty_variant
{
static const size_t dataSize = 0;
static const size_t power = 0;
struct value_type {};
bool empty() { return true; }
};
//----------------------------------------------------------------------------------------
/// \ru Получить номер типа из списка union-контейнера. \en Get type index from the list of union-container.
//---
template<class _PairUnion, class _Type>
struct which_type
{
static const int value = 1 + which_type<typename _PairUnion::tail_type,_Type>::value;
};
// \ru Специализация 1 \en Specialization 1
template<class _PairUnion>
struct which_type<_PairUnion,typename _PairUnion::value_type>
{
static const int value = 0;
};
// \ru Специализация 2 \en Specialization 2
template<class _Type>
struct which_type<empty_variant,_Type>
{
static const int value = -1;
};
//----------------------------------------------------------------------------------------
/// \ru Получить тип варианта с заданным номером. \en Get variant type with a given index.
//---
template<class T, int idx >
struct type_which
{
typedef typename T::tail_type tail_t;
typedef typename type_which<tail_t,idx-1>::value_t value_t;
};
template<class T>
struct type_which<T,0>
{
typedef typename T::value_type value_t;
};
template<class T>
struct type_which<T,-1>
{
private:
typedef null_type value_t;
};
//----------------------------------------------------------------------------------------
/// \ru Проводник посетителя для рекурсивно-заданного контейнера. \en Conductor of visitor for recursively given container.
//---
template<class _PairUnion, int typeNb, int power >
struct union_conductor
{
typedef typename type_which<_PairUnion,typeNb>::value_t _Type;
/// \ru Статическое приведение типа. \en Static cast of type.
template<class U, class T>
static T * unsafe_cast( U & u ) { return u.template unsafe_cast<T>(); }
/// \ru Статическое приведение типа. \en Static cast of type.
template<class U, class T>
static const T * unsafe_cast( const U & u ) { return u.template unsafe_cast<T>(); }
/// \ru Применить функтор. \en Apply the functor.
template<class _Visitor>
static inline void apply( const _Visitor & vis, _PairUnion & oper )
{
if ( oper.which() == typeNb )
{
vis( *unsafe_cast<_PairUnion,_Type>(oper) );
}
else
{
union_conductor<_PairUnion,typeNb+1,power>::apply( vis, oper );
}
}
};
//----------------------------------------------------------------------------------------
// \ru Вызвать деструктор для указателя, если его тип попадает в диапазон от t до power. \en Call the destructor for the pointer if its type is within the range from t to power.
//---
template<class _PairUnion, int power >
struct union_conductor<_PairUnion,power,power>
{
template<class _Visitor>
static inline void apply( const _Visitor & , _PairUnion & ) {}
};
//----------------------------------------------------------------------------------------
/**
\brief \ru Рекурсивное определение класса "union-контейнер".
\en Recursive definition of class "union-container".
\details \ru Контейнер, который может хранить элемент типа "value_type" или один из типов
хвостового контейнера.
\en Container which can store the element of type "value_type" or one of types
of tail container. \~
*/
//---
template<class Type, class Tail = empty_variant >
class recursive_union
{
typedef recursive_union<Type,Tail> _Myt;
public: // \ru доступные ассоциативные типы и константы \en available associative types and constants
static const size_t dataSize = sizeof(Type) > Tail::dataSize ? sizeof(Type) : Tail::dataSize;
static const size_t power = 1 + Tail::power; // \ru Количество типов, которое может обеспечить вариант \en The count of types which can provide a variant
typedef Type value_type;
typedef Tail tail_type;
public:
recursive_union() : m_typeNb(-1) { ::memset(m_data, 0, dataSize); }
recursive_union( const Type & );
#ifndef __DEBUG_MEMORY_ALLOCATE_FREE_
template<class _Type>
recursive_union( const _Type & elem )
: m_typeNb( which_type<_Myt,_Type>::value )
, dbg_data()
{
if ( m_typeNb >= 0 )
{
new ( (void*)m_data ) _Type( elem );
}
}
#else // __DEBUG_MEMORY_ALLOCATE_FREE_
template<class _Type>
recursive_union( const _Type & )
: m_typeNb( which_type<_Myt,_Type>::value )
, dbg_data()
{
// (!) The placement form of operator new is required.
C3D_ASSERT_UNCONDITIONAL( false );
}
#endif //__DEBUG_MEMORY_ALLOCATE_FREE_
~recursive_union();
private: // \ru вспомогательные объекты \en assisting objects
// \ru Посетитель для вызова конструктора типа, которым занят union-контейнер \en The visitor to call the type constructor which is occupied by union-container
struct assigner
{
assigner( _Myt & d ) : lOper(&d) {}
template<class _Type>
void operator() ( const _Type & elem ) const
{
C3D_ASSERT( lOper );
*lOper = elem;
}
private:
mutable _Myt * lOper; // \ru Левый операнд присвоения \en The left operand of assignment
private:
assigner & operator = ( const assigner & );
};
// \ru Посетитель для вызова деcтруктора типа, которым занят union-контейнер \en The visitor to call the type destructor which is occupied by union-container
struct destroyer
{
template<class _Type>
static void ignore(const _Type & ) {} // \ru для подавления сообщений \en for suppression of messages
template<class _Type>
void operator() (const _Type & elem ) const
{
ignore( elem );
elem.~_Type();
}
};
// \ru Проверка на равенство \en The check for equality
struct comparer
{
const _Myt & data;
mutable bool result;
comparer( const _Myt & d ) : data( d ), result(false) {}
template<class _Type>
void operator() ( const _Type & elem ) const
{
result = (data == elem);
}
private:
comparer & operator = ( const comparer & );
};
struct conductor: public union_conductor<_Myt,0,power> {};
struct const_conductor: public union_conductor<const _Myt,0,power> {};
public:
int which() const { return m_typeNb; }
// \ru Проверить пустой ли контейнер \en Check whether the container is empty
bool empty() const { return m_typeNb < 0; }
// \ru Безопасное динамическое приведение типа \en Secure dynamic cast of type
template<class _Type>
_Type * safe_cast()
{
if ( which_type<_Myt,_Type>::value == m_typeNb )
{
return (_Type*)m_data;
}
return 0;
}
// \ru Безопасное динамическое приведение типа \en Secure dynamic cast of type
template<class _Type>
const _Type * safe_cast() const
{
if ( which_type<_Myt,_Type>::value == m_typeNb )
{
return (const _Type*)m_data;
}
return 0;
}
// \ru Статическое приведение типа \en Static cast of type
template<class _Type>
_Type * unsafe_cast()
{
assert( (which_type<_Myt,_Type>::value == m_typeNb) );
return (_Type*)m_data;
}
// \ru Статическое приведение типа \en Static cast of type
/*
template<int _typeNb> typename type_which<_Myt,_typeNb>::value_t &
unsafe_get();
*/
/*
{
assert( (which_type<_Myt,_Type>::value == m_typeNb) );
return (type_which<_Myt,_typeNb>::value_t*)m_data;
}
*/
// \ru Статическое приведение типа \en Static cast of type
template<class _Type>
const _Type * unsafe_cast() const
{
assert( (which_type<_Myt,_Type>::value == m_typeNb) );
return reinterpret_cast<const _Type*>( m_data );
}
void release()
{
accept( destroyer() );
m_typeNb = -1;
}
/*
template<class _Type>
void release()
{
if ( which_type<_Myt,_Type>::value == m_typeNb )
{
((_Type*)m_data)->~_Type();
m_typeNb = -1;
}
}
*/
// \ru Присвоение другого union-контейнера \en Assignment of another union-container
_Myt & operator = ( const _Myt & v )
{
release();
v.accept( assigner(*this) );
C3D_ASSERT( m_typeNb == v.m_typeNb );
return *this;
}
// \ru Присвоение произвольного типа \en Assignment of arbitrary type
/*
template<class _Type>
_Myt & operator = ( const _Type & elem )
{
m_typeNb = which_type<_Myt,_Type>::value;
if ( m_typeNb >= 0 )
{
new ( (void*)m_data ) _Type( elem );
}
return *this;
}
*/
// \ru Равенство \en Equality
bool operator == ( const _Myt & v ) const
{
if ( m_typeNb == v.m_typeNb )
{
comparer cmp( *this );
v.accept( cmp );
return cmp.result;
}
return false;
}
// \ru Равенство \en Equality
template<class _Type>
bool operator == ( const _Type & elem ) const
{
if ( m_typeNb == which_type<_Myt,_Type>::value )
{
return elem == *unsafe_cast<_Type>();
}
return false;
}
// \ru Доступ посетителя \en Visitor access
template<class _Visitor>
void accept( const _Visitor & vis ) const
{
const_conductor::apply( vis, *this );
}
// \ru Доступ посетителя \en Visitor access
template<class _Visitor>
void accept( const _Visitor & vis )
{
conductor::apply( vis, *this );
}
private: // \ru данные \en data
char m_data[dataSize];
int m_typeNb;
dbg_inspector<_Myt> dbg_data;
};
//----------------------------------------------------------------------------------------
//
//---
template<class Type, class Tail>
recursive_union<Type,Tail>::recursive_union( const Type & elem )
: m_typeNb( 0 )
, dbg_data()
{
dbg_data.init( *this );
new ( (void*)m_data ) Type( elem );
}
//----------------------------------------------------------------------------------------
//
//---
template<class Type, class Tail>
recursive_union<Type,Tail>::~recursive_union()
{
release();
}
template<class T, class Tail >
struct def_pair_union // \ru определитель рекурсивного контейнера для пары типов \en determinant of a recursive container for a pair of types
{
typedef recursive_union<T,Tail> value_t;
};
template<class T>
struct def_pair_union<T,empty_variant>
{
typedef recursive_union<T,empty_variant> value_t;
};
template<>
struct def_pair_union<null_type,empty_variant>
{
typedef empty_variant value_t;
};
//----------------------------------------------------------------------------------------
/** \brief \ru union-контейнер для экземпляра типа из определенного набора типов.
\en union-container for instance of type from a specific set of types.
\details \ru Позволяет создать тип, принимающий значения из некоторого набора разнородных
типов.
\en Allows to create a type which takes values ??from a set of heterogeneous
types. \~
*/
//---
template<
class T0
, class T1
, class T2 = null_type
, class T3 = null_type
, class T4 = null_type
, class T5 = null_type>
class aligned_union
{
typedef empty_variant _Tail6;
typedef typename def_pair_union<T5,_Tail6>::value_t _Tail5;
typedef typename def_pair_union<T4,_Tail5>::value_t _Tail4;
typedef typename def_pair_union<T3,_Tail4>::value_t _Tail3;
typedef typename def_pair_union<T2,_Tail3>::value_t _Tail2;
typedef typename def_pair_union<T1,_Tail2>::value_t _Tail1;
typedef typename def_pair_union<T0,_Tail1>::value_t _Variant;
typedef aligned_union<T0,T1,T2,T3,T4,T5> _Myt;
public:
aligned_union(): m_data() {}
template<class T>
aligned_union( const T & elem ) : m_data( elem ) {}
public:
/// \ru Выдать номер текущего типа, которым занят контейнер \en Get a index of the current type which is occupied container
int which() const { return m_data.which(); }
/// \ru Проверить пустой ли контейнер \en Check whether the container is empty
bool empty() const { return m_data.empty(); }
/// \ru Применить функтор (посетитель) \en Apply the functor (visitor)
template<class _Vis>
void accept( const _Vis & vis ) const { m_data.accept( vis ); }
/// \ru Применить функтор (посетитель) \en Apply the functor (visitor)
template<class _Vis>
void accept( const _Vis & vis ) { m_data.accept( vis ); }
/// \ru Сделать контейнер пустым \en Make an empty container
void clear() { m_data.release(); }
/// \ru Операция присвоения \en Assignment operation
_Myt & operator = ( const _Myt & elem ) { m_data = elem.m_data; return *this; }
template<class T >
_Myt & operator = ( const T & elem ) { m_data = elem; return *this; }
// \ru Операция сравнения \en Compare operation
bool operator == ( const _Myt & elem ) const { return m_data == elem.m_data; }
template<class T >
bool operator == ( const T & elem ) const { return m_data == elem; }
/// \ru Безопасно преобразовать тип контейнера к указателю \en Safely convert type of container to a pointer
template<class T >
T * safe_cast() { return m_data.template safe_cast<T>(); }
template<class T >
const T * safe_cast() const { return m_data.template safe_cast<T>(); }
template<class T >
bool get( T & val ) const
{
if ( const T * ptr = m_data.template safe_cast<T>() )
{
val = *ptr;
return true;
}
return false;
}
private:
_Variant m_data;
};
//----------------------------------------------------------------------------------------
//
// ---
template<class _Iterator, class _Element>
constexpr bool is_exist( _Iterator begIt, _Iterator endIt, const _Element & elem )
{
return std::find( begIt, endIt, elem ) != endIt;
}
//----------------------------------------------------------------------------------------
//
// ---
template<class _Iterator, class UnaryPredicate>
constexpr bool is_exist_if( _Iterator begIt, _Iterator endIt, UnaryPredicate _Pred )
{
return std::find_if( begIt, endIt, _Pred ) != endIt;
}
namespace c3d
{
struct color_label
{
color_code val;
color_label() : val( white_color ) {}
bool operator == ( color_code col ) const { return col == val; }
color_label & operator = ( color_code col ) { val = col; return *this; }
};
//----------------------------------------------------------------------------------------
//
//---
template <typename Iterator>
struct _IterTraits
{
typedef typename Iterator::value_type value_type;
typedef typename Iterator::reference reference;
};
template <typename T>
struct _IterTraits<T*>
{
typedef T value_type;
typedef T& reference;
};
//----------------------------------------------------------------------------------------
// Диапазон итераторов.
//---
template<class Iterator>
struct range : public std::pair<Iterator, Iterator>
{
typedef std::pair<Iterator, Iterator> _Pair;
//typedef std::iterator_traits<Iterator> _IterTraits; // Стандартный пока не действует на итераторы графа.
typedef typename _IterTraits<Iterator>::value_type value_type;
typedef typename _IterTraits<Iterator>::reference reference;
range( const Iterator & iter, const Iterator & last ) : _Pair( iter, last ) {}
range( Iterator && iter, Iterator && last ) : _Pair( iter, last ) {}
range( const _Pair & other ) : _Pair( other ) {}
range() : _Pair() {}
Iterator begin() const { return _Pair::first; }
Iterator end() const { return _Pair::second; }
bool empty() const { return _Pair::first == _Pair::second; }
size_t size() const { return (size_t)std::distance( _Pair::first, _Pair::second ); }
void clear() { _Pair::first = _Pair::second; }
range & move_front() { ++_Pair::first; return *this; }
range & drop_front() { ++_Pair::first; return *this; }
range & drop_back() { --_Pair::second; return *this; }
const reference front() const { return *_Pair::first; }
const reference back() const { return *(_Pair::second - 1); }
};
//----------------------------------------------------------------------------------------
// Get a range of the STL-container
//---
template<class _Cont>
inline range<typename _Cont::const_iterator> range_of( const _Cont & list )
{
return {list.begin(), list.end()};
}
template<class _Cont>
inline range<typename _Cont::iterator> range_of( _Cont & list )
{
return {list.begin(), list.end()};
}
//----------------------------------------------------------------------------------------
// Get a range of iterators
//---
template<class _Iterator>
inline range<_Iterator> make_range( _Iterator first, _Iterator last )
{
return {first, last};
}
//----------------------------------------------------------------------------------------
/// \ru Пара ссылок. \en A pair of references.
//---
template<class _Ty1, class _Ty2>
struct ref_pair
{
_Ty1 & first;
_Ty2 & second;
ref_pair( _Ty1 & val1, _Ty2 & val2 )
: first(val1), second(val2)
{}
ref_pair( const ref_pair & other )
: first(other.first), second(other.second)
{}
template<class _Other1, class _Other2>
ref_pair( const std::pair<_Other1, _Other2> & right )
: first(right.first), second(right.second)
{}
template<class _Other1, class _Other2>
ref_pair & operator = ( const std::pair<_Other1, _Other2> & right )
{
first = right.first;
second = right.second;
return *this;
}
private:
ref_pair & operator = ( const ref_pair & ); // \ru не реализуемо \en not implemented
};
//----------------------------------------------------------------------------------------
/// \ru Выдать ссылки одной связкой. \en Get references as one bunch.
//---
template<typename Type1, typename Type2 >
inline ref_pair<Type1,Type2>
tie( Type1 & iter1, Type2 & iter2 )
{
return ref_pair<Type1,Type2> ( iter1, iter2 );
}
//----------------------------------------------------------------------------------------
//
// ---
template< class InputIt, class UnaryPredicate >
inline bool all_of( InputIt iter, InputIt last, UnaryPredicate Pred )
{
for ( ; iter != last; ++iter )
{
if ( !Pred(*iter) )
{
return false;
}
}
return true;
}
}; // namespace c3d
#endif // __GENERIC_UTILITY_H
// eof