// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp // http://stackoverflow.com/questions/687490/c0x-how-do-i-expand-a-tuple-into-variadic-template-function-arguments // Merci à Ryan "FullMetal Alchemist" Lahfa // Merci aussi à Freedom de siteduzero.com #include #include #include #include #include namespace Nz { namespace Detail { // http://www.cppsamples.com/common-tasks/apply-tuple-to-function.html template auto ApplyImplFunc(F&& fn, Tuple&& t, std::index_sequence) { return std::forward(fn)(std::get(std::forward(t))...); } template auto ApplyImplMethod(O& object, F&& fn, Tuple&& t, std::index_sequence) { return (object .* std::forward(fn))(std::get(std::forward(t))...); } NAZARA_CORE_API extern const UInt8 BitReverseTable256[256]; } /*! * \ingroup core * \brief Applies the tuple to the function (e.g. calls the function using the tuple content as arguments) * \return The result of the function * * \param fn Function * \param t Tuple of arguments for the function * * \see Apply */ template auto Apply(F&& fn, Tuple&& t) { constexpr std::size_t tSize = std::tuple_size::type>::value; return Detail::ApplyImplFunc(std::forward(fn), std::forward(t), std::make_index_sequence()); } /*! * \ingroup core * \brief Applies the tuple to the member function on an object (e.g. calls the member function using the tuple content as arguments) * \return The result of the member function called * * \param object Object of a class * \param fn Member function * \param t Tuple of arguments for the member function * * \see Apply */ template auto Apply(O& object, F&& fn, Tuple&& t) { constexpr std::size_t tSize = std::tuple_size::type>::value; return Detail::ApplyImplMethod(object, std::forward(fn), std::forward(t), std::make_index_sequence()); } /*! * \ingroup core * \brief Computes the hash of a hashable object * \return A bytearray which represents the hash * * \param hash Enumeration of type HashType * \param v Object to hash * * \remark a HashAppend specialization for type T is required * * \see ComputeHash */ template ByteArray ComputeHash(HashType hash, const T& v) { return ComputeHash(AbstractHash::Get(hash).get(), v); } /*! * \ingroup core * \brief Computes the hash of a hashable object * \return A bytearray which represents the hash * * \param hash Pointer to abstract hash * \param v Object to hash * * \remark Produce a NazaraAssert if pointer to Abstracthash is invalid * \remark a HashAppend specialization for type T is required * * \see ComputeHash */ template ByteArray ComputeHash(AbstractHash* hash, const T& v) { NazaraAssert(hash != nullptr, "Invalid abstracthash pointer"); hash->Begin(); HashAppend(hash, v); return hash->End(); } /*! * \ingroup core * \brief Returns the number of elements in a C-array * \return The number of elements * * \param name C-array * * \see CountOf */ template constexpr std::size_t CountOf(T(&name)[N]) noexcept { return N; } /*! * \ingroup core * \brief Returns the number of elements in a container * \return The number of elements * * \param c Container with the member function "size()" * * \see CountOf */ template std::size_t CountOf(const T& c) { return c.size(); } /*! * \ingroup core * \brief Combines two hash in one * * \param seed First value that will be modified (expected to be 64bits) * \param v Second value to hash */ // Algorithm from CityHash by Google // http://stackoverflow.com/questions/8513911/how-to-create-a-good-hash-combine-with-64-bit-output-inspired-by-boosthash-co template void HashCombine(std::size_t& seed, const T& v) { const UInt64 kMul = 0x9ddfea08eb382d69ULL; std::hash hasher; UInt64 a = (hasher(v) ^ seed) * kMul; a ^= (a >> 47); UInt64 b = (seed ^ a) * kMul; b ^= (b >> 47); seed = static_cast(b * kMul); } /*! * \ingroup core * \brief Reverse the bit order of the integer * \return integer with reversed bits * * \param integer Integer whose bits are to be reversed */ template T ReverseBits(T integer) { T reversed = 0; for (std::size_t i = 0; i < sizeof(T); ++i) reversed |= T(Detail::BitReverseTable256[(integer >> i * 8) & 0xFF]) << sizeof(T) * 8 - (i + 1) * 8; return reversed; } template struct PointedType {typedef T type;}; template struct PointedType {typedef T type;}; template struct PointedType {typedef T type;}; template struct PointedType {typedef T type;}; /*! * \ingroup core * \brief Serializes a boolean * \return true if serialization succedeed * * \param context Context for the serialization * \param value Boolean to serialize * * \see Serialize, Unserialize */ inline bool Serialize(SerializationContext& context, bool value) { if (context.currentBitPos == 8) { context.currentBitPos = 0; context.currentByte = 0; } if (value) context.currentByte |= 1 << context.currentBitPos; if (++context.currentBitPos >= 8) return Serialize(context, context.currentByte); else return true; } /*! * \ingroup core * \brief Serializes an arithmetic type * \return true if serialization succedeed * * \param context Context for the serialization * \param value Arithmetic type to serialize * * \see Serialize, Unserialize */ template std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value) { // Flush bits in case a writing is in progress context.FlushBits(); if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(&value, sizeof(T)); return context.stream->Write(&value, sizeof(T)) == sizeof(T); } /*! * \ingroup core * \brief Unserializes a boolean * \return true if unserialization succedeed * * \param context Context for the unserialization * \param value Pointer to boolean to unserialize * * \see Serialize, Unserialize */ inline bool Unserialize(SerializationContext& context, bool* value) { if (context.currentBitPos == 8) { if (!Unserialize(context, &context.currentByte)) return false; context.currentBitPos = 0; } if (value) *value = (context.currentByte & (1 << context.currentBitPos)) != 0; context.currentBitPos++; return true; } /*! * \ingroup core * \brief Unserializes an arithmetic type * \return true if unserialization succedeed * * \param context Context for the unserialization * \param value Pointer to arithmetic type to serialize * * \remark Produce a NazaraAssert if pointer to value is invalid * * \see Serialize, Unserialize */ template std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value) { NazaraAssert(value, "Invalid data pointer"); context.ResetBitPosition(); if (context.stream->Read(value, sizeof(T)) == sizeof(T)) { if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(value, sizeof(T)); return true; } else return false; } } #include