/*	Copyright (C) 2004 Garrett A. Kajmowicz

	This file is part of the uClibc++ Library.

	This library 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 2.1 of the License, or (at your option) any later version.

	This library 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 library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#pragma once
#ifdef ARDUINO_ARCH_AVR
#include "basic_definitions"

#include "cstddef"
#include "cmath"

#pragma GCC visibility push(default)

namespace std
{

	template <class T>
	class valarray;
	class slice;
	template <class T>
	class slice_array;
	class gslice;
	template <class T>
	class gslice_array;
	template <class T>
	class mask_array;
	template <class T>
	class indirect_array;

	// Actual class definitions

	class _UCXXEXPORT slice
	{
	protected:
		size_t sta;
		size_t siz;
		size_t str;

	public:
		slice() : sta(0), siz(0), str(0) {}
		slice(size_t a, size_t b, size_t c) : sta(a), siz(b), str(c) {}
		slice(const slice &s) : sta(s.sta), siz(s.siz), str(s.str) {}
		~slice() {}
		size_t start() const
		{
			return sta;
		}
		size_t size() const
		{
			return siz;
		}
		size_t stride() const
		{
			return str;
		}
	};

	template <class T>
	class _UCXXEXPORT valarray
	{
		friend class slice_array<T>;

	protected:
		T *data;
		size_t length;

	public:
		typedef T value_type;

		valarray() : data(0), length(0) {}

		explicit valarray(size_t t) : data(0), length(t)
		{
			data = new T[length];
		}

		valarray(const T &v, size_t t) : data(0), length(t)
		{
			data = new T[length];
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = v;
			}
		}
		valarray(const T *p, size_t t) : data(0), length(t)
		{
			data = new T[length];
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = p[i];
			}
		}
		valarray(const valarray &v) : data(0), length(v.length)
		{
			data = new T[length];
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = v.data[i];
			}
		}
		valarray(const slice_array<T> &sa) : data(0), length(sa.s.size())
		{
			data = new T[length];
			for (unsigned int i = 0; i < length; ++i)
			{
				data[i] = sa.array->data[sa.s.start() + i * sa.s.stride()];
			}
		}
		valarray(const gslice_array<T> &);
		valarray(const mask_array<T> &);
		valarray(const indirect_array<T> &);
		~valarray()
		{
			delete[] data;
			data = 0;
			length = 0;
		}

		valarray<T> &operator=(const valarray<T> &v)
		{
			if (length != v.length)
			{ // DR 630
				delete[] data;
				length = v.length;
				data = new T[length];
			}
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = v.data[i];
			}
			return *this;
		}
		valarray<T> &operator=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = t;
			}
			return *this;
		}
		valarray<T> &operator=(const slice_array<T> &sa)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] = sa.data[sa.s.start() + i * sa.s.stride()];
			}
			return *this;
		}
		valarray<T> &operator=(const gslice_array<T> &);
		valarray<T> &operator=(const mask_array<T> &);
		valarray<T> &operator=(const indirect_array<T> &);

		const T &operator[](size_t t) const
		{
			return data[t];
		}
		T &operator[](size_t t)
		{
			return data[t];
		}

		valarray<T> operator[](slice s) const
		{
			valarray<T> retval(s.size());
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				retval.data[i] = data[s.start() + i * s.stride()];
			}
			return retval;
		}

		slice_array<T> operator[](slice sl)
		{
			slice_array<T> retval;
			retval.s = sl;
			retval.array = this;
			return retval;
		}

		valarray<T> operator[](const gslice &) const;
		gslice_array<T> operator[](const gslice &);
		valarray<T> operator[](const valarray<bool> &) const;
		mask_array<T> operator[](const valarray<bool> &);
		valarray<T> operator[](const valarray<size_t> &) const;
		indirect_array<T> operator[](const valarray<size_t> &);

		valarray<T> operator+() const
		{
			valarray<T> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = +data[i];
			}
			return retval;
		}
		valarray<T> operator-() const
		{
			valarray<T> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = -data[i];
			}
			return retval;
		}
		valarray<T> operator~() const
		{
			valarray<T> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = ~data[i];
			}
			return retval;
		}
		valarray<bool> operator!() const
		{
			valarray<bool> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval[i] = !data[i];
			}
			return retval;
		}
		valarray<T> &operator*=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] *= t;
			}
			return *this;
		}
		valarray<T> &operator/=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] /= t;
			}
			return *this;
		}
		valarray<T> &operator%=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] %= t;
			}
			return *this;
		}
		valarray<T> &operator+=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] += t;
			}
			return *this;
		}
		valarray<T> &operator-=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] -= t;
			}
			return *this;
		}
		valarray<T> &operator^=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] ^= t;
			}
			return *this;
		}
		valarray<T> &operator&=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] &= t;
			}
			return *this;
		}
		valarray<T> &operator|=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] |= t;
			}
			return *this;
		}
		valarray<T> &operator<<=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] <<= t;
			}
			return *this;
		}
		valarray<T> &operator>>=(const T &t)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] >>= t;
			}
			return *this;
		}
		valarray<T> &operator*=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] *= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator/=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] /= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator%=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] %= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator+=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] += a.data[i];
			}
			return *this;
		}
		valarray<T> &operator-=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] -= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator^=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] ^= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator|=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] |= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator&=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] &= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator<<=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] <<= a.data[i];
			}
			return *this;
		}
		valarray<T> &operator>>=(const valarray<T> &a)
		{
			for (size_t i = 0; i < length; ++i)
			{
				data[i] >>= a.data[i];
			}
			return *this;
		}
#if 0
		void swap(valarray& other) noexcept {
			std::swap(length, other.length);
			std::swap(data, other.data);
		}
#endif
		size_t size() const
		{
			return length;
		}

		T sum() const
		{
			T retval(data[0]);
			for (size_t i = 1; i < length; ++i)
			{
				retval += data[i];
			}
			return retval;
		}

		T min() const
		{
			T retval(data[0]);
			for (size_t i = 1; i < length; ++i)
			{
				if (data[i] < retval)
				{
					retval = data[i];
				}
			}
			return retval;
		}

		T max() const
		{
			T retval(data[0]);
			for (size_t i = 1; i < length; ++i)
			{
				if (retval < data[i])
				{
					retval = data[i];
				}
			}
			return retval;
		}

		valarray<T> shift(int n) const
		{
			valarray<T> retval(length);
			if (n < 0)
			{
				if (-size_t(n) > length)
					n = -int(length);
			}
			else
			{
				if (size_t(n) > length)
					n = int(length);
			}
			for (size_t i = 0; i < length; ++i)
			{
				if ((n + i) < length)
					retval.data[i] = data[n + i];
			}
			return retval;
		}
		valarray<T> cshift(int n) const
		{
			valarray<T> retval(length);
			if (length == 0)
				return retval;
			if (n < 0)
			{
				if (-size_t(n) > length)
					n = -int(-size_t(n) % length);
				n = length + n;
			}
			else
			{
				if (size_t(n) > length)
					n = int(size_t(n) % length);
			}
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = data[(n + i) % length];
			}
			return retval;
		}
		valarray<T> apply(T func(T)) const
		{
			valarray<T> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = func(data[i]);
			}
			return retval;
		}
		valarray<T> apply(T func(const T &)) const
		{
			valarray<T> retval(length);
			for (size_t i = 0; i < length; ++i)
			{
				retval.data[i] = func(data[i]);
			}
			return retval;
		}
		void resize(size_t sz, T c = T())
		{
			delete[] data;
			data = 0;
			if (sz > 0)
			{
				data = new T[sz];
				for (size_t i = 0; i < sz; ++i)
				{
					data[i] = c;
				}
			}
			length = sz;
		}
	};

	template <class T>
	class _UCXXEXPORT slice_array
	{
		friend class valarray<T>;

	public:
		typedef T value_type;

		void operator=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] = v[i];
			}
		}
		void operator=(const T &v)
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] = v;
			}
		}
		void fill(const T &v)
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] = v;
			}
		}
		void operator*=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] *= v[i];
			}
		}
		void operator/=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] /= v[i];
			}
		}
		void operator%=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] %= v[i];
			}
		}
		void operator+=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] += v[i];
			}
		}
		void operator-=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] -= v[i];
			}
		}
		void operator^=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] ^= v[i];
			}
		}
		void operator&=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] &= v[i];
			}
		}
		void operator|=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] |= v[i];
			}
		}
		void operator<<=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] <<= v[i];
			}
		}
		void operator>>=(const valarray<T> &v) const
		{
			for (unsigned int i = 0; i < s.size(); ++i)
			{
				array->data[s.start() + i * s.stride()] >>= v[i];
			}
		}
		~slice_array()
		{
			array = 0;
		}

	private:
		slice_array() : array(0) {}

	public:
		slice_array(const slice_array &sa) : array(sa.array), s(sa.s) {}
		slice_array &operator=(const slice_array &sa)
		{
			array = sa.array;
			s = sa.s;
			return *this;
		}

	private:
		valarray<T> *array;
		slice s;
	};

	class _UCXXEXPORT gslice
	{
	private:
		size_t sta;
		valarray<size_t> siz;
		valarray<size_t> str;

	public:
		gslice() : sta(0), siz(), str() {} // DR 543
		gslice(size_t s, const valarray<size_t> &l, const valarray<size_t> &d)
			: sta(s), siz(l), str(d) {}

		size_t start() const
		{
			return sta;
		}
		valarray<size_t> size() const
		{
			return siz;
		}
		valarray<size_t> stride() const
		{
			return str;
		}
	};

	template <class T>
	class gslice_array
	{
	private:
		friend class valarray<T>;

	public:
		~gslice_array();

		void operator=(const valarray<T> &array) const;
		void operator*=(const valarray<T> &array) const;
		void operator/=(const valarray<T> &array) const;
		void operator%=(const valarray<T> &array) const;
		void operator+=(const valarray<T> &array) const;
		void operator-=(const valarray<T> &array) const;
		void operator^=(const valarray<T> &array) const;
		void operator&=(const valarray<T> &array) const;
		void operator|=(const valarray<T> &array) const;
		void operator<<=(const valarray<T> &array) const;
		void operator>>=(const valarray<T> &array) const;

		void operator=(const T &);

	private:
		gslice_array();
		gslice_array(const gslice_array<T> &);
		gslice_array<T> &operator=(const gslice_array<T> &array);
	};

	template <class T>
	valarray<T> operator*(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval *= rhs;
		return retval;
	}

	template <class T>
	valarray<T> operator*(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval *= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator*(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(rhs);
		retval *= lhs;
		return retval;
	}
	template <class T>
	valarray<T> operator/(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval /= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator/(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval /= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator/(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval /= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator%(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval %= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator%(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval %= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator%(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval %= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator+(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval += rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator+(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval += rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator+(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval += rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator-(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval -= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator-(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval -= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator-(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval -= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator^(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval ^= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator^(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval ^= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator^(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval ^= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator&(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval &= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator&(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval &= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator&(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval &= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator|(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval |= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator|(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval |= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator|(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval |= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator<<(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval <<= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator<<(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval <<= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator<<(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval <<= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator>>(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs);
		retval >>= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator>>(const valarray<T> &lhs, const T &rhs)
	{
		valarray<T> retval(lhs);
		retval >>= rhs;
		return retval;
	}
	template <class T>
	valarray<T> operator>>(const T &lhs, const valarray<T> &rhs)
	{
		valarray<T> retval(lhs, rhs.size());
		retval >>= rhs;
		return retval;
	}

	template <class T>
	valarray<bool> operator&&(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] && rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator&&(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] && rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator&&(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs && rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator||(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] || rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator||(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] || rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator||(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs || rhs[i];
		}
		return retval;
	}

	template <class T>
	valarray<bool> operator==(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] == rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator==(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] == rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator==(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs == rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator!=(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] != rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator!=(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] != rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator!=(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs != rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] < rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] < rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs < rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] > rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] > rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs > rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<=(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] <= rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<=(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] <= rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator<=(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs <= rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>=(const valarray<T> &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] >= rhs[i];
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>=(const valarray<T> &lhs, const T &rhs)
	{
		valarray<bool> retval(lhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs[i] >= rhs;
		}
		return retval;
	}
	template <class T>
	valarray<bool> operator>=(const T &lhs, const valarray<T> &rhs)
	{
		valarray<bool> retval(rhs.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = lhs >= rhs[i];
		}
		return retval;
	}
	template <class T>
	T min(const valarray<T> &x)
	{
		T retval(x[0]);
		for (size_t i = 1; i < x.size(); ++i)
		{
			if (x[i] < retval)
			{
				retval = x[i];
			}
		}
	}
	template <class T>
	T max(const valarray<T> &x)
	{
		T retval(x[0]);
		for (size_t i = 1; i < x.size(); ++i)
		{
			if (x[i] > retval)
			{
				retval = x[i];
			}
		}
	}

	template <class T>
	valarray<T> abs(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = abs(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> acos(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = acos(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> asin(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = asin(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> atan(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = atan(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> atan2(const valarray<T> &y, const valarray<T> &x)
	{
		valarray<T> retval(y.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = atan2(y[i], x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> atan2(const valarray<T> &y, const T &x)
	{
		valarray<T> retval(y.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = atan2(y[i], x);
		}
		return retval;
	}
	template <class T>
	valarray<T> atan2(const T &y, const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = atan2(y, x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> cos(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = cos(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> cosh(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = cosh(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> exp(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = exp(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> log(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = log(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> log10(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = log10(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> pow(const valarray<T> &x, const valarray<T> &y)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = pow(x[i], y[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> pow(const valarray<T> &x, const T &y)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = pow(x[i], y);
		}
		return retval;
	}
	template <class T>
	valarray<T> pow(const T &x, const valarray<T> &y)
	{
		valarray<T> retval(y.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = pow(x, y[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> sin(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = sin(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> sinh(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = sinh(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> sqrt(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = sqrt(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> tan(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = tan(x[i]);
		}
		return retval;
	}
	template <class T>
	valarray<T> tanh(const valarray<T> &x)
	{
		valarray<T> retval(x.size());
		for (size_t i = 0; i < retval.size(); ++i)
		{
			retval[i] = tanh(x[i]);
		}
		return retval;
	}
}

#pragma GCC visibility pop
#else
#include "Cpp_Standard_Library.h"
#include _CSL_Official(valarray)
#endif