/*! \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
	Ivan Pelipenko peri4ko@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PICONTAINERS_H
#define PICONTAINERS_H

#include "picout.h"
#include "piintrospection_containers.h"
#ifdef MAC_OS
#  include <stdlib.h>
#else
#  include <malloc.h>
#endif
#include <initializer_list>
#include <type_traits>
#include <string.h>
#include <new>
#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)

#else


template <typename C>
struct _reverse_wrapper {
	C & c_;
	_reverse_wrapper(C & c): c_(c) {}
	_reverse_wrapper(const C & c): c_(const_cast<C&>(c)) {}
	typename C::reverse_iterator begin() {return c_.rbegin();}
	typename C::reverse_iterator end() {return c_.rend(); }
	typename C::const_reverse_iterator begin() const {return c_.rbegin();}
	typename C::const_reverse_iterator end() const {return c_.rend(); }
};

template <typename C> _reverse_wrapper<C> _reverse_wrap(C & c) {return _reverse_wrapper<C>(c);}
template <typename C> _reverse_wrapper<C> _reverse_wrap(const C & c) {return _reverse_wrapper<C>(c);}


#  define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)

#  define piForeach(i,c) for(i : c)
#  define piForeachC(i,c) for(const i : c)
#  define piForeachR(i,c) for(i : _reverse_wrap(c))
#  define piForeachRC(i,c) for(const i : _reverse_wrap(c))

#  define piForeachCR piForeachRC

#endif // DOXYGEN


#endif // PICONTAINERS_H
