/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2014 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef POLY_MEMORY_H_ #define POLY_MEMORY_H_ #include #include #include #include namespace poly { inline size_t hash_combine(size_t seed) { return seed; } template size_t hash_combine(size_t seed, const T& v, const Ts&... vs) { std::hash hasher; seed ^= hasher(v) + 0x9E3779B9 + (seed << 6) + (seed >> 2); return hash_combine(seed, vs...); } size_t page_size(); void copy_and_swap_16_aligned(uint16_t* dest, const uint16_t* src, size_t count, uint16_t* out_max_value = nullptr); void copy_and_swap_16_unaligned(uint16_t* dest, const uint16_t* src, size_t count, uint16_t* out_max_value = nullptr); void copy_and_swap_32_aligned(uint32_t* dest, const uint32_t* src, size_t count, uint32_t* out_max_value = nullptr); void copy_and_swap_32_unaligned(uint32_t* dest, const uint32_t* src, size_t count, uint32_t* out_max_value = nullptr); void copy_and_swap_64_aligned(uint64_t* dest, const uint64_t* src, size_t count, uint64_t* out_max_value = nullptr); void copy_and_swap_64_unaligned(uint64_t* dest, const uint64_t* src, size_t count, uint64_t* out_max_value = nullptr); template void copy_and_swap(T* dest, const T* src, size_t count) { bool is_aligned = reinterpret_cast(dest) % 32 == 0 && reinterpret_cast(src) % 32 == 0; if (sizeof(T) == 1) { std::memcpy(dest, src, count); } else if (sizeof(T) == 2) { auto ps = reinterpret_cast(src); auto pd = reinterpret_cast(dest); if (is_aligned) { copy_and_swap_16_aligned(pd, ps, count); } else { copy_and_swap_16_unaligned(pd, ps, count); } } else if (sizeof(T) == 4) { auto ps = reinterpret_cast(src); auto pd = reinterpret_cast(dest); if (is_aligned) { copy_and_swap_32_aligned(pd, ps, count); } else { copy_and_swap_32_unaligned(pd, ps, count); } } else if (sizeof(T) == 8) { auto ps = reinterpret_cast(src); auto pd = reinterpret_cast(dest); if (is_aligned) { copy_and_swap_64_aligned(pd, ps, count); } else { copy_and_swap_64_unaligned(pd, ps, count); } } else { assert_always("Invalid poly::copy_and_swap size"); } } template T load(const void* mem); template <> inline int8_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline uint8_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline int16_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline uint16_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline int32_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline uint32_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline int64_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline uint64_t load(const void* mem) { return *reinterpret_cast(mem); } template <> inline float load(const void* mem) { return *reinterpret_cast(mem); } template <> inline double load(const void* mem) { return *reinterpret_cast(mem); } template inline T load(const void* mem) { if (sizeof(T) == 1) { return static_cast(load(mem)); } else if (sizeof(T) == 2) { return static_cast(load(mem)); } else if (sizeof(T) == 4) { return static_cast(load(mem)); } else if (sizeof(T) == 8) { return static_cast(load(mem)); } else { assert_always("Invalid poly::load size"); } } template T load_and_swap(const void* mem); template <> inline int8_t load_and_swap(const void* mem) { return *reinterpret_cast(mem); } template <> inline uint8_t load_and_swap(const void* mem) { return *reinterpret_cast(mem); } template <> inline int16_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline uint16_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline int32_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline uint32_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline int64_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline uint64_t load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline float load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline double load_and_swap(const void* mem) { return byte_swap(*reinterpret_cast(mem)); } template <> inline std::string load_and_swap(const void* mem) { std::string value; for (int i = 0;; ++i) { auto c = poly::load_and_swap(reinterpret_cast(mem) + i); if (!c) { break; } value.push_back(static_cast(c)); } return value; } template <> inline std::wstring load_and_swap(const void* mem) { std::wstring value; for (int i = 0;; ++i) { auto c = poly::load_and_swap( reinterpret_cast(mem) + i); if (!c) { break; } value.push_back(static_cast(c)); } return value; } template void store(void* mem, T value); template <> inline void store(void* mem, int8_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, uint8_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, int16_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, uint16_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, int32_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, uint32_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, int64_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, uint64_t value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, float value) { *reinterpret_cast(mem) = value; } template <> inline void store(void* mem, double value) { *reinterpret_cast(mem) = value; } template inline void store(const void* mem, T value) { if (sizeof(T) == 1) { store(mem, static_cast(value)); } else if (sizeof(T) == 2) { store(mem, static_cast(value)); } else if (sizeof(T) == 4) { store(mem, static_cast(value)); } else if (sizeof(T) == 8) { store(mem, static_cast(value)); } else { assert_always("Invalid poly::store size"); } } template void store_and_swap(void* mem, T value); template <> inline void store_and_swap(void* mem, int8_t value) { *reinterpret_cast(mem) = value; } template <> inline void store_and_swap(void* mem, uint8_t value) { *reinterpret_cast(mem) = value; } template <> inline void store_and_swap(void* mem, int16_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, uint16_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, int32_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, uint32_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, int64_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, uint64_t value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, float value) { *reinterpret_cast(mem) = byte_swap(value); } template <> inline void store_and_swap(void* mem, double value) { *reinterpret_cast(mem) = byte_swap(value); } template struct be { be() = default; be(const T& src) : value(poly::byte_swap(src)) {} be(const be& other) { value = other.value; } operator T() const { return poly::byte_swap(value); } T value; }; } // namespace poly #endif // POLY_MEMORY_H_