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

Code before:
        }

        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
         */
        constexpr std::string_view as_string(bool nullTerminated = false) {
            return std::string_view(reinterpret_cast<const char *>(span::data()), nullTerminated ? (std::find(span::begin(), span::end(), 0) - span::begin()) : span::size_bytes());

Review comment (suggestion):
~~Use `std::numeric_limits<T>::min()` rather than `0` here also `std::uniform_int_distribution` does not need to be `thread_local`, it can be constructed on every invocation or be `static` since it doesn't have any internal state, at least on `libcxx` which is what we care about.~~

~~I'd recommend checking if Clang ends up inlining the function entirely without `static` on [Godbolt](https://godbolt.org/), if that is the case then it should be the fastest.~~

Just directly utilize [`std::independent_bits_engine`](https://en.cppreference.com/w/cpp/numeric/random/independent_bits_engine) with the template arguments as `std::mt19937_64, std::numeric_limits<T>::digits(), T` and that should ensure you get the optimal output from the engine.

Due to the `UIntType` as defined by the C++ standard not including `char` types, you'll need to mask the result for them yourself unless you want to depend on `libcxx` here which does define it properly. I'm fine with that but I'm not sure if ByLaws would be but if you do end up going the other route I'd just recommend doing the masking yourself for everything as it would look weirder to have `u8`/`i8` specializations for this.

Code after:
            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>)
        void FillRandomBytes(T &object) {
            FillRandomBytes(std::span(reinterpret_cast<typename IntegerFor<T>::type *>(&object), IntegerFor<T>::count));
        }