//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#pragma once

#include <cstdint> // uint8_t
#include <cstddef> // size_t
#include <fstream> // ifstream, ios
#include <iterator> // istream_iterator
#include <vector> // vector

namespace utils
{

// Some tests intentionally discard the [[nodiscard]]/JSON_HEDLEY_WARN_UNUSED_RESULT
// return value of a call they only make to exercise its side effects (e.g. checking
// that it does not throw). A plain (void) cast on the call expression does not
// suppress GCC's warning for functions using the GNU __attribute__((warn_unused_result))
// form (as opposed to the C++17 [[nodiscard]] attribute) -- passing the value into an
// ordinary function call does.
template<typename T>
inline void ignore_return_value(T&& /*unused*/) noexcept {}

// Advance i toward last (inclusive) by stride, always visiting last.
// stride 7 is coprime to 256, so every low-byte residue is still hit.
template<typename T>
T next_integer_sample(T i, T last, T stride)
{
    if (i >= last)
    {
        return static_cast<T>(last + 1);
    }
    if (stride > 0 && i > static_cast<T>(last - stride))
    {
        return last;
    }
    const T n = static_cast<T>(i + stride);
    return n < last ? n : last;
}

inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
{
    std::ifstream file(filename, std::ios::binary);
    file.unsetf(std::ios::skipws);

    file.seekg(0, std::ios::end);
    const auto size = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<std::uint8_t> byte_vector;
    byte_vector.reserve(static_cast<std::size_t>(size));
    byte_vector.insert(byte_vector.begin(), std::istream_iterator<std::uint8_t>(file), std::istream_iterator<std::uint8_t>());
    return byte_vector;
}

// sentinel for istreambuf_iterator; compares != true until EOF is reached
// lets tests read a file directly via the new iterator+sentinel overloads
// instead of buffering the whole file into a vector first.
// Only the iterator-first direction (it != sentinel) is ever evaluated by
// the library's parse loop, so no reversed-order overload is needed.
struct istreambuf_sentinel
{
    friend bool operator!=(const std::istreambuf_iterator<char>& it, const istreambuf_sentinel& /*unused*/) noexcept
    {
        return it != std::istreambuf_iterator<char>();
    }
};

} // namespace utils