#pragma once
#include <stdint.h>
#include <stddef.h>
#include <array>
#include <algorithm>

#if __cplusplus <= 201703L
namespace _hidden{
	enum class endian
	{
	#ifdef _WIN32
		little = 0,
		big    = 1,
		native = little
	#else
		little = __ORDER_LITTLE_ENDIAN__,
		big    = __ORDER_BIG_ENDIAN__,
		native = __BYTE_ORDER__
	#endif
	};
}
namespace bitops{
	using endian = _hidden::endian;
} 
#else
#include <type_traits>
namespace bitops{
	using endian = std::endian;
} 
#endif

namespace bitops{

	template<typename T, size_t sz = sizeof(T)>
	constexpr std::array<uint8_t,sizeof(T)> swap_if_little_raw(T xsz)
	{
		std::array<uint8_t,sizeof(T)> ret = {0};

		auto abstract = (std::array<uint8_t,sizeof(T)>*)&xsz;
		if constexpr (endian::native == endian::little)
		{
			std::copy(abstract->rbegin(), abstract->rend(), ret.begin());
		}
		else
		{
			std::copy(abstract->begin(), abstract->end(), ret.begin());
		}
		return ret;
	}

	template<typename T, size_t sz = sizeof(T)>
	constexpr T swap_if_little(T xsz)
	{
		auto tmp = swap_if_little_raw(xsz);
		return *(T*)&tmp;
	}

	template<typename T>
	struct [[gnu::packed]] regulated{
		T internal = 0;

		constexpr regulated(T value)
		: internal{swap_if_little(value)}
		{ }

		constexpr void operator=(T value)
		{
			internal = swap_if_little(value);
		}

		constexpr void operator+=(const int& v)
		{
			internal = swap_if_little(T(*this)+v);
		}

		constexpr operator T() const {
			return swap_if_little(internal);
		}
	};
}