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

Code before:
     * @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());
        }

        template<typename Out, size_t OutExtent = std::dynamic_extent>
        constexpr span<Out> cast() {
            if (util::IsAligned(span::size_bytes(), sizeof(Out)))
                return span<Out, OutExtent>(reinterpret_cast<Out *>(span::data()), span::size_bytes() / sizeof(Out));
            throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
        }

        /**
         * @brief Copies data from the supplied span into this one
         * @param amount The amount of elements that need to be copied (in terms of the supplied span), 0 will try to copy the entirety of the other span
         */
        template<typename In, size_t InExtent>
        constexpr void copy_from(const span<In, InExtent> spn, size_type amount = 0) {
            auto size{amount ? amount * sizeof(In) : spn.size_bytes()};
            if (span::size_bytes() < size)
                throw exception("Data being copied is larger than this span");
            std::memmove(span::data(), spn.data(), size);
        }

Review comment (suggestion):
Do one that is `requires (!std::is_integral_v<T>)` with just `void FillRandomBytes(T object)` and calls `FillRandomBytes(std::span(reinterpret_cast<PointerFor<T>::type>(&object), PointerFor<T>::count))` which should handle the case for non-integral types then utilize this for the UUIDs. Alternatively, you can make a `T CreateRandomObject()` which takes nothing but returns an object filled with random bytes of whatever the supplied template type is.

Code after:
         */
        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));
        }
    }

    /**
     * @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
         */