/*! \file picontainers.h
* \brief Base for generic containers
*
* This file declare all containers and useful macros
* to use them
*/
/*
PIP - Platform Independent Primitives
Base for generic containers
Copyright (C) 2020 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef PICONTAINERS_H
#define PICONTAINERS_H
#include "picout.h"
#include "piintrospection_containers.h"
#ifdef PIP_DEBUG
# ifdef NDEBUG
# undef NDEBUG
# endif
# include
#endif
#ifndef assert
# define assert(x)
#endif
#ifdef MAC_OS
# include
#else
# include
#endif
#include
#include
#ifndef PIP_MEMALIGN_BYTES
# define PIP_MEMALIGN_BYTES (sizeof(void*)*4)
#endif
#ifdef WINDOWS
# ifdef CC_GCC
# define amalloc(s) __mingw_aligned_malloc(s, PIP_MEMALIGN_BYTES)
# define afree(p) __mingw_aligned_free(p)
# else
# ifdef CC_VC
# define amalloc(s) _aligned_malloc(s, PIP_MEMALIGN_BYTES)
# define afree(p) _aligned_free(p)
# endif
# endif
#else
# define amalloc(s) aligned_alloc(PIP_MEMALIGN_BYTES, s)
# define afree(p) free(p)
#endif
#ifdef DOXYGEN
/*!\brief Macro for iterate any container
* \details Use this macros instead of standard "for"
* to get read/write access to each element of container.
* Pass direction is direct \n
* Example: \snippet picontainers.cpp foreach
*/
# define piForeach(i,c)
/*!\brief Macro for iterate any container only for read
* \details Use this macros instead of standard "for"
* to get read access to each element of container.
* Pass direction is direct \n
* Example: \snippet picontainers.cpp foreachC
*/
# define piForeachC(i,c)
/*!\brief Macro for iterate any container with reverse direction
* \details Use this macros instead of standard "for"
* to get read/write access to each element of container.
* Pass direction is reverse \n
* Example: \snippet picontainers.cpp foreachR
*/
# define piForeachR(i,c)
/*!\brief Macro for iterate any container only for read with reverse direction
* \details Use this macros instead of standard "for"
* to get read access to each element of container.
* Pass direction is reverse \n
* Example: \snippet picontainers.cpp foreachCR
*/
# define piForeachCR(i,c)
/*!\brief Macro for break from any piForeach* loop
* \details \warning C++ ordinary "break" doesn`t work inside piForeach*
* loops! Always use "piBreak" instead!
*/
# define piBreak
#else
# define piBreak {_for._end = true; break;}
# define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
#ifdef CC_GCC
template
class _PIForeach {
public:
_PIForeach(Type & t): _t(t), _break(false), _end(false) {_it = _t.begin();}
typename Type::value_type _var;
typename Type::iterator _it;
Type & _t;
bool _break, _end;
inline bool isEnd() {return _it == _t.end();}
inline void operator ++() {if (_end) _it = _t.end(); else _it++; _break = false;}
};
template
class _PIForeachR {
public:
_PIForeachR(Type & t): _t(t), _break(false), _end(false) {_rit = _t.rbegin();}
typename Type::value_type _var;
typename Type::reverse_iterator _rit;
Type & _t;
bool _break, _end;
inline bool isEnd() {return _rit == _t.rend();}
inline void operator ++() {if (_end) _rit = _t.rend(); else _rit++; _break = false;}
};
template
class _PIForeachC {
public:
_PIForeachC(const Type & t): _t(t), _break(false), _end(false) {_it = _t.begin();}
typename Type::value_type _var;
typename Type::const_iterator _it;
const Type & _t;
bool _break, _end;
inline bool isEnd() {return _it == _t.end();}
inline void operator ++() {if (_end) _it = _t.end(); else _it++; _break = false;}
};
template
class _PIForeachCR {
public:
_PIForeachCR(const Type & t): _t(t), _break(false), _end(false) {_rit = _t.rbegin();}
typename Type::value_type _var;
typename Type::const_reverse_iterator _rit;
const Type & _t;
bool _break, _end;
inline bool isEnd() {return _rit == _t.rend();}
inline void operator ++() {if (_end) _rit = _t.rend(); else _rit++; _break = false;}
};
#define piForeach(i,c) for(_PIForeach _for(c); !_for.isEnd(); ++_for) \
for(i(*_for._it); !_for._break; _for._break = true)
#define piForeachR(i,c) for(_PIForeachR _for(c); !_for.isEnd(); ++_for) \
for(i(*_for._rit); !_for._break; _for._break = true)
#define piForeachA(i,c) for(_PIForeach _for(c); !_for.isEnd(); ++_for) \
for(typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
#define piForeachAR(i,c) for(_PIForeachR _for(c); !_for.isEnd(); ++_for) \
for(typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
#define piForeachC(i,c) for(_PIForeachC _for(c); !_for.isEnd(); ++_for) \
for(const i(*_for._it); !_for._break; _for._break = true)
#define piForeachCR(i,c) for(_PIForeachCR _for(c); !_for.isEnd(); ++_for) \
for(const i(*_for._rit); !_for._break; _for._break = true)
#define piForeachCA(i,c) for(_PIForeachC _for(c); !_for.isEnd(); ++_for) \
for(const typeof(_for._var) & i(*_for._it); !_for._break; _for._break = true)
#define piForeachCAR(i,c) for(_PIForeachCR _for(c); !_for.isEnd(); ++_for) \
for(const typeof(_for._var) & i(*_for._rit); !_for._break; _for._break = true)
#define piForeachRA piForeachAR
#define piForeachAC piForeachCA
#define piForeachCRA piForeachCAR
#define piForeachARC piForeachCAR
#define piForeachACR piForeachCAR
#define piForeachRCA piForeachCAR
#define piForeachRAC piForeachCAR
#else
class _PIForeachBase {public: mutable bool _break, _end; };
template
class _PIForeach: public _PIForeachBase {
public:
_PIForeach(Type & t, bool i = false): _t(t), _inv(i) {_break = _end = false; if (_inv) _rit = _t.rbegin(); else _it = _t.begin();}
mutable typename Type::value_type _var;
mutable typename Type::iterator _it;
mutable typename Type::reverse_iterator _rit;
Type & _t;
bool _inv;
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
void operator ++() {if (_inv) {if (_end) _rit = _t.rend(); else _rit++;} else {if (_end) _it = _t.end(); else _it++;} _break = false;}
};
template
class _PIForeachC: public _PIForeachBase {
public:
_PIForeachC(const Type & t, bool i = false): _t(t), _inv(i) {_break = _end = false; if (_inv) _rit = _t.rbegin(); else _it = _t.begin();}
mutable typename Type::value_type _var;
mutable typename Type::const_iterator _it;
mutable typename Type::const_reverse_iterator _rit;
const Type & _t;
bool _inv;
bool isEnd() {if (_inv) return _rit == _t.rend(); else return _it == _t.end();}
void operator ++() {if (_inv) {if (_end) _rit = _t.rend(); else _rit++;} else {if (_end) _it = _t.end(); else _it++;} _break = false;}
};
template inline _PIForeach _PIForeachNew(T & t, bool i = false) {return _PIForeach(t, i);}
template inline _PIForeach * _PIForeachCast(_PIForeachBase & c, T & ) {return static_cast<_PIForeach * >(&c);}
template inline _PIForeachC _PIForeachNewC(const T & t, bool i = false) {return _PIForeachC(t, i);}
template inline _PIForeachC * _PIForeachCastC(_PIForeachBase & c, const T & ) {return static_cast<_PIForeachC * >(&c);}
#define piForeach(i,c) for(_PIForeachBase & _for = _PIForeachNew(c); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
for(i = *(_PIForeachCast(_for, c)->_it); !_for._break; _for._break = true)
#define piForeachR(i,c) for(_PIForeachBase & _for = _PIForeachNew(c, true); !_PIForeachCast(_for, c)->isEnd(); ++(*_PIForeachCast(_for, c))) \
for(i = *(_PIForeachCast(_for, c)->_rit); !_for._break; _for._break = true)
#define piForeachC(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
for(const i = *(_PIForeachCastC(_for, c)->_it); !_for._break; _for._break = true)
#define piForeachCR(i,c) for(_PIForeachBase & _for = _PIForeachNewC(c, false); !_PIForeachCastC(_for, c)->isEnd(); ++(*_PIForeachCastC(_for, c))) \
for(const i = *(_PIForeachCastC(_for, c)->_rit); !_for._break; _for._break = true)
#endif
#define piForeachRC piForeachCR
#endif // DOXYGEN
#endif // PICONTAINERS_H