//! \addtogroup Containers
//! \{
//! \~\file picontainers.h
//! \brief
//! \~english Base macros for generic containers
//! \~russian Базовые макросы для контейнеров
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/*
    PIP - Platform Independent Primitives
    Base macros 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 <algorithm>
#include <functional>
#include <initializer_list>
#include <new>
#include <string.h>
#include <type_traits>


template<typename C>
class _PIReverseWrapper {
public:
	_PIReverseWrapper(C & c): c_(c) {}
	_PIReverseWrapper(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(); }

private:
	C & c_;
};


class PIP_EXPORT _PIContainerConstantsBase {
public:
	static size_t calcMinCountPoT(size_t szof);
	static size_t calcMaxCountForPoT(size_t szof);
	static size_t calcStepAfterPoT(size_t szof);
};

template<typename T>
class _PIContainerConstants {
public:
	static size_t minCountPoT() {
		static const size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T));
		return ret;
	}
	static size_t maxCountForPoT() {
		static const size_t ret = _PIContainerConstantsBase::calcMaxCountForPoT(sizeof(T));
		return ret;
	}
	static size_t stepAfterPoT() {
		static const size_t ret = _PIContainerConstantsBase::calcStepAfterPoT(sizeof(T));
		return ret;
	}

	static size_t calcNewSize(size_t old_size, size_t new_size) {
		if (new_size == 0) return 0;
		if (new_size < maxCountForPoT()) {
			if (old_size * 2 >= new_size && old_size < new_size) {
				return old_size * 2;
			}
			ssize_t t = minCountPoT();
			new_size -= 1;
			while (new_size >> t)
				++t;
			return (1 << t);
		} else {
			size_t ret = old_size;
			while (ret < new_size)
				ret += stepAfterPoT();
			return ret;
		}
		return 0;
	}
};


template<typename C>
_PIReverseWrapper<C> PIReverseWrap(C & c) {
	return _PIReverseWrapper<C>(c);
}
template<typename C>
_PIReverseWrapper<C> PIReverseWrap(const C & c) {
	return _PIReverseWrapper<C>(c);
}


//! \brief
//! \~english Macro for short replacement of standart "for"
//! \~russian Макрос для короткой записи стандартного цикла "for"
//! \~\param c
//! \~english Iteration times in loop
//! \~russian Количество итераций цикла
#define piForTimes(c)     for (int _i##c = 0; _i##c < c; ++_i##c)


//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read/write access to each element of container.
//! Iterating in forward direction.
//! Example of using:
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
//! Перебор осуществляется в прямом порядке.
//! Пример использования:
//! \~\code
//! PIVector<int> vec;
//! vec << 1 << 2 << 3;
//! piForeach(int & i, vec) piCout << i;
//! // 1
//! // 2
//! // 3
//! piForeach(int & i, vec) i++;
//! piForeach(int & i, vec) piCout << i;
//! // 2
//! // 3
//! // 4
//! \endcode
//! \sa \a piForeachC, \a piForeachR, \a piForeachRC
#define piForeach(i, c)   for (i: c)

//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read only access to each element of container.
//! Iterating in forward direction.
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в прямом порядке.
//! \~ \sa \a piForeach, \a piForeachR, \a piForeachRC
#define piForeachC(i, c)  for (const i: c)

//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read/write access to each element of container.
//! Iterating in backward direction.
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
//! Перебор осуществляется в обратном порядке.
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachRC
#define piForeachR(i, c)  for (i: PIReverseWrap(c))

//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read only access to each element of container.
//! Iterating in backward direction. Also has alias **piForeachCR**
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в обратном порядке. Также можно писать **piForeachCR**
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachR
#define piForeachRC(i, c) for (const i: PIReverseWrap(c))
#define piForeachCR       piForeachRC


//! \~\brief
//! \~english Reshape order enum for reshape() function.
//! \~russian Порядок обхода для функции изменения размерности reshape().
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
enum ReshapeOrder {
	ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory  \~russian Обход элементов построчно, так же как они
	                находятся в памяти */
		,
	ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
};

#endif // PICONTAINERS_H
