Repository: skyline-emu/skyline
File: app/src/main/cpp/skyline/common.h (C/C++)

Code before:

        constexpr u64 SwapEndianness(u64 in) {
            return __builtin_bswap64(in);
        }

        constexpr u32 SwapEndianness(u32 in) {
            return __builtin_bswap32(in);
        }

        constexpr u16 SwapEndianness(u16 in) {
            return __builtin_bswap16(in);
        }

        /**
         * @brief A compile-time hash function as std::hash isn't constexpr
         */
        constexpr std::size_t Hash(std::string_view view) {
            return frz::elsa<frz::string>{}(frz::string(view.data(), view.size()), 0);
        }
    }

    /**
     * @brief A custom wrapper over span that adds several useful methods to it
     * @note This class is completely transparent, it implicitly converts from and to span
     */
    template<typename T, size_t Extent = std::dynamic_extent>
    class span : public std::span<T, Extent> {
      public:
        using std::span<T, Extent>::span;
        using std::span<T, Extent>::operator=;

        typedef typename std::span<T, Extent>::element_type element_type;
        typedef typename std::span<T, Extent>::size_type size_type;

        constexpr span(const std::span<T, Extent> &spn) : std::span<T, Extent>(spn) {}

        /**
         * @brief We want to support implicitly casting from std::string_view -> span as it's just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there
         */
        template<typename Traits>
        constexpr span(const std::basic_string_view<T, Traits> &string) : std::span<T, Extent>(const_cast<T *>(string.data()), string.size()) {}

        template<typename Out>
        constexpr Out &as() {
            if (span::size_bytes() >= sizeof(Out))
                return *reinterpret_cast<Out *>(span::data());
            throw exception("Span size is less than Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
        }

        /**
         * @param nullTerminated If true and the string is null-terminated, a view of it will be returned (not including the null terminator itself), otherwise the entire span will be returned as a string view

Review comment (suggestion):
Usage of `T` here is going to be problematic since you'll have multiple `std::mt19937_64` generators based on the type. You'd want to move the `generator` outside of the function (in a `util::detail` namespace) so that you only have one generator per-thread that multiple `std::uniform_int_distribution`s can utilize.

Code after:
        }

        constexpr u64 SwapEndianness(u64 in) {
            return __builtin_bswap64(in);
        }

        constexpr u32 SwapEndianness(u32 in) {
            return __builtin_bswap32(in);
        }

        constexpr u16 SwapEndianness(u16 in) {
            return __builtin_bswap16(in);
        }

        /**
         * @brief A compile-time hash function as std::hash isn't constexpr
         */
        constexpr std::size_t Hash(std::string_view view) {
            return frz::elsa<frz::string>{}(frz::string(view.data(), view.size()), 0);
        }

        /**
         * @brief Selects the largest possible integer type for representing an object alongside providing the size of the object in terms of the underlying type
         */
        template<class T>
        struct IntegerFor {
            using type = std::conditional_t<sizeof(T) % sizeof(u64) == 0, u64,
                std::conditional_t<sizeof(T) % sizeof(u32) == 0, u32,
                    std::conditional_t<sizeof(T) % sizeof(u16) == 0, u16, u8>
                >
            >;

            static constexpr size_t count{sizeof(T) / sizeof(type)};
        };

        namespace detail {
            static thread_local std::mt19937_64 generator{GetTimeTicks()};
        }

        /**
         * @brief Fills an array with random data from a Mersenne Twister pseudo-random generator
         * @note The generator is seeded with the the current time in ticks
         */
        template<typename T> requires (std::is_integral_v<T>)
        void FillRandomBytes(std::span<T> in) {
            std::independent_bits_engine<std::mt19937_64, std::numeric_limits<T>::digits, T> gen(detail::generator);

            std::generate(in.begin(), in.end(), gen);
        }

        template<class T> requires (!std::is_integral_v<T> && std::is_trivially_copyable_v<T>)