2026-02-13 19:15:05 +01:00
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
2026-04-17 21:00:35 +02:00
// | | |__ | | | | | | version 3.12.0
2026-02-13 19:15:05 +01:00
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
2026-04-17 21:00:35 +02:00
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
2026-02-13 19:15:05 +01:00
// SPDX-License-Identifier: MIT
#pragma once
#include <array> // array
#include <cstddef> // size_t
#include <cstring> // strlen
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
#include <memory> // shared_ptr, make_shared, addressof
#include <numeric> // accumulate
#include <string> // string, char_traits
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
#include <utility> // pair, declval
#ifndef JSON_NO_IO
#include <cstdio> // FILE *
#include <istream> // istream
#endif // JSON_NO_IO
2026-04-17 21:00:35 +02:00
#include <nlohmann/detail/exceptions.hpp>
2026-02-13 19:15:05 +01:00
#include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
/// the supported input formats
enum class input_format_t { json , cbor , msgpack , ubjson , bson , bjdata };
////////////////////
// input adapters //
////////////////////
#ifndef JSON_NO_IO
/*!
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
buffer. This adapter is a very low level adapter.
*/
class file_input_adapter
{
public :
using char_type = char ;
JSON_HEDLEY_NON_NULL ( 2 )
explicit file_input_adapter ( std :: FILE * f ) noexcept
: m_file ( f )
{
JSON_ASSERT ( m_file != nullptr );
}
// make class move-only
file_input_adapter ( const file_input_adapter & ) = delete ;
file_input_adapter ( file_input_adapter && ) noexcept = default ;
file_input_adapter & operator = ( const file_input_adapter & ) = delete ;
file_input_adapter & operator = ( file_input_adapter && ) = delete ;
~ file_input_adapter () = default ;
std :: char_traits < char >:: int_type get_character () noexcept
{
return std :: fgetc ( m_file );
}
2026-04-17 21:00:35 +02:00
// returns the number of characters successfully read
template < class T >
std :: size_t get_elements ( T * dest , std :: size_t count = 1 )
{
return fread ( dest , 1 , sizeof ( T ) * count , m_file );
}
2026-02-13 19:15:05 +01:00
private :
/// the file pointer to read from
std :: FILE * m_file ;
};
/*!
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
beginning of input. Does not support changing the underlying std::streambuf
in mid-input. Maintains underlying std::istream and std::streambuf to support
subsequent use of standard std::istream operations to process any input
characters following those used in parsing the JSON input. Clears the
std::istream flags; any input errors (e.g., EOF) will be detected by the first
subsequent call for input from the std::istream.
*/
class input_stream_adapter
{
public :
using char_type = char ;
~ input_stream_adapter ()
{
// clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags, except eof
if ( is != nullptr )
{
is -> clear ( is -> rdstate () & std :: ios :: eofbit );
}
}
explicit input_stream_adapter ( std :: istream & i )
: is ( & i ), sb ( i . rdbuf ())
{}
// delete because of pointer members
input_stream_adapter ( const input_stream_adapter & ) = delete ;
input_stream_adapter & operator = ( input_stream_adapter & ) = delete ;
input_stream_adapter & operator = ( input_stream_adapter && ) = delete ;
input_stream_adapter ( input_stream_adapter && rhs ) noexcept
: is ( rhs . is ), sb ( rhs . sb )
{
rhs . is = nullptr ;
rhs . sb = nullptr ;
}
// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
// ensure that std::char_traits<char>::eof() and the character 0xFF do not
// end up as the same value, e.g. 0xFFFFFFFF.
std :: char_traits < char >:: int_type get_character ()
{
auto res = sb -> sbumpc ();
// set eof manually, as we don't use the istream interface.
if ( JSON_HEDLEY_UNLIKELY ( res == std :: char_traits < char >:: eof ()))
{
is -> clear ( is -> rdstate () | std :: ios :: eofbit );
}
return res ;
}
2026-04-17 21:00:35 +02:00
template < class T >
std :: size_t get_elements ( T * dest , std :: size_t count = 1 )
{
auto res = static_cast < std :: size_t > ( sb -> sgetn ( reinterpret_cast < char *> ( dest ), static_cast < std :: streamsize > ( count * sizeof ( T ))));
if ( JSON_HEDLEY_UNLIKELY ( res < count * sizeof ( T )))
{
is -> clear ( is -> rdstate () | std :: ios :: eofbit );
}
return res ;
}
2026-02-13 19:15:05 +01:00
private :
/// the associated input stream
std :: istream * is = nullptr ;
std :: streambuf * sb = nullptr ;
};
#endif // JSON_NO_IO
// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
template < typename IteratorType >
class iterator_input_adapter
{
public :
using char_type = typename std :: iterator_traits < IteratorType >:: value_type ;
iterator_input_adapter ( IteratorType first , IteratorType last )
: current ( std :: move ( first )), end ( std :: move ( last ))
{}
typename char_traits < char_type >:: int_type get_character ()
{
if ( JSON_HEDLEY_LIKELY ( current != end ))
{
auto result = char_traits < char_type >:: to_int_type ( * current );
std :: advance ( current , 1 );
return result ;
}
return char_traits < char_type >:: eof ();
}
2026-04-17 21:00:35 +02:00
// for general iterators, we cannot really do something better than falling back to processing the range one-by-one
template < class T >
std :: size_t get_elements ( T * dest , std :: size_t count = 1 )
{
auto * ptr = reinterpret_cast < char *> ( dest );
for ( std :: size_t read_index = 0 ; read_index < count * sizeof ( T ); ++ read_index )
{
if ( JSON_HEDLEY_LIKELY ( current != end ))
{
ptr [ read_index ] = static_cast < char > ( * current );
std :: advance ( current , 1 );
}
else
{
return read_index ;
}
}
return count * sizeof ( T );
}
2026-02-13 19:15:05 +01:00
private :
IteratorType current ;
IteratorType end ;
template < typename BaseInputAdapter , size_t T >
friend struct wide_string_input_helper ;
bool empty () const
{
return current == end ;
}
};
template < typename BaseInputAdapter , size_t T >
struct wide_string_input_helper ;
template < typename BaseInputAdapter >
struct wide_string_input_helper < BaseInputAdapter , 4 >
{
// UTF-32
static void fill_buffer ( BaseInputAdapter & input ,
std :: array < std :: char_traits < char >:: int_type , 4 >& utf8_bytes ,
size_t & utf8_bytes_index ,
size_t & utf8_bytes_filled )
{
utf8_bytes_index = 0 ;
if ( JSON_HEDLEY_UNLIKELY ( input . empty ()))
{
utf8_bytes [ 0 ] = std :: char_traits < char >:: eof ();
utf8_bytes_filled = 1 ;
}
else
{
// get the current character
const auto wc = input . get_character ();
// UTF-32 to UTF-8 encoding
if ( wc < 0x80 )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( wc );
utf8_bytes_filled = 1 ;
}
else if ( wc <= 0x7FF )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xC0u | (( static_cast < unsigned int > ( wc ) >> 6u ) & 0x1Fu ));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( static_cast < unsigned int > ( wc ) & 0x3Fu ));
utf8_bytes_filled = 2 ;
}
else if ( wc <= 0xFFFF )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xE0u | (( static_cast < unsigned int > ( wc ) >> 12u ) & 0x0Fu ));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( static_cast < unsigned int > ( wc ) >> 6u ) & 0x3Fu ));
utf8_bytes [ 2 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( static_cast < unsigned int > ( wc ) & 0x3Fu ));
utf8_bytes_filled = 3 ;
}
else if ( wc <= 0x10FFFF )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xF0u | (( static_cast < unsigned int > ( wc ) >> 18u ) & 0x07u ));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( static_cast < unsigned int > ( wc ) >> 12u ) & 0x3Fu ));
utf8_bytes [ 2 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( static_cast < unsigned int > ( wc ) >> 6u ) & 0x3Fu ));
utf8_bytes [ 3 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( static_cast < unsigned int > ( wc ) & 0x3Fu ));
utf8_bytes_filled = 4 ;
}
else
{
// unknown character
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( wc );
utf8_bytes_filled = 1 ;
}
}
}
};
template < typename BaseInputAdapter >
struct wide_string_input_helper < BaseInputAdapter , 2 >
{
// UTF-16
static void fill_buffer ( BaseInputAdapter & input ,
std :: array < std :: char_traits < char >:: int_type , 4 >& utf8_bytes ,
size_t & utf8_bytes_index ,
size_t & utf8_bytes_filled )
{
utf8_bytes_index = 0 ;
if ( JSON_HEDLEY_UNLIKELY ( input . empty ()))
{
utf8_bytes [ 0 ] = std :: char_traits < char >:: eof ();
utf8_bytes_filled = 1 ;
}
else
{
// get the current character
const auto wc = input . get_character ();
// UTF-16 to UTF-8 encoding
if ( wc < 0x80 )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( wc );
utf8_bytes_filled = 1 ;
}
else if ( wc <= 0x7FF )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xC0u | (( static_cast < unsigned int > ( wc ) >> 6u )));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( static_cast < unsigned int > ( wc ) & 0x3Fu ));
utf8_bytes_filled = 2 ;
}
else if ( 0xD800 > wc || wc >= 0xE000 )
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xE0u | (( static_cast < unsigned int > ( wc ) >> 12u )));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( static_cast < unsigned int > ( wc ) >> 6u ) & 0x3Fu ));
utf8_bytes [ 2 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( static_cast < unsigned int > ( wc ) & 0x3Fu ));
utf8_bytes_filled = 3 ;
}
else
{
if ( JSON_HEDLEY_UNLIKELY ( ! input . empty ()))
{
const auto wc2 = static_cast < unsigned int > ( input . get_character ());
const auto charcode = 0x10000u + ((( static_cast < unsigned int > ( wc ) & 0x3FFu ) << 10u ) | ( wc2 & 0x3FFu ));
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( 0xF0u | ( charcode >> 18u ));
utf8_bytes [ 1 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( charcode >> 12u ) & 0x3Fu ));
utf8_bytes [ 2 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | (( charcode >> 6u ) & 0x3Fu ));
utf8_bytes [ 3 ] = static_cast < std :: char_traits < char >:: int_type > ( 0x80u | ( charcode & 0x3Fu ));
utf8_bytes_filled = 4 ;
}
else
{
utf8_bytes [ 0 ] = static_cast < std :: char_traits < char >:: int_type > ( wc );
utf8_bytes_filled = 1 ;
}
}
}
}
};
// Wraps another input adapter to convert wide character types into individual bytes.
template < typename BaseInputAdapter , typename WideCharType >
class wide_string_input_adapter
{
public :
using char_type = char ;
wide_string_input_adapter ( BaseInputAdapter base )
: base_adapter ( base ) {}
typename std :: char_traits < char >:: int_type get_character () noexcept
{
// check if buffer needs to be filled
if ( utf8_bytes_index == utf8_bytes_filled )
{
fill_buffer < sizeof ( WideCharType ) > ();
JSON_ASSERT ( utf8_bytes_filled > 0 );
JSON_ASSERT ( utf8_bytes_index == 0 );
}
// use buffer
JSON_ASSERT ( utf8_bytes_filled > 0 );
JSON_ASSERT ( utf8_bytes_index < utf8_bytes_filled );
return utf8_bytes [ utf8_bytes_index ++ ];
}
2026-04-17 21:00:35 +02:00
// parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here
template < class T >
std :: size_t get_elements ( T * /*dest*/ , std :: size_t /*count*/ = 1 )
{
JSON_THROW ( parse_error :: create ( 112 , 1 , "wide string type cannot be interpreted as binary data" , nullptr ));
}
2026-02-13 19:15:05 +01:00
private :
BaseInputAdapter base_adapter ;
template < size_t T >
void fill_buffer ()
{
wide_string_input_helper < BaseInputAdapter , T >:: fill_buffer ( base_adapter , utf8_bytes , utf8_bytes_index , utf8_bytes_filled );
}
/// a buffer for UTF-8 bytes
std :: array < std :: char_traits < char >:: int_type , 4 > utf8_bytes = {{ 0 , 0 , 0 , 0 }};
/// index to the utf8_codes array for the next valid byte
std :: size_t utf8_bytes_index = 0 ;
/// number of valid bytes in the utf8_codes array
std :: size_t utf8_bytes_filled = 0 ;
};
template < typename IteratorType , typename Enable = void >
struct iterator_input_adapter_factory
{
using iterator_type = IteratorType ;
using char_type = typename std :: iterator_traits < iterator_type >:: value_type ;
using adapter_type = iterator_input_adapter < iterator_type > ;
static adapter_type create ( IteratorType first , IteratorType last )
{
return adapter_type ( std :: move ( first ), std :: move ( last ));
}
};
template < typename T >
struct is_iterator_of_multibyte
{
using value_type = typename std :: iterator_traits < T >:: value_type ;
enum
{
value = sizeof ( value_type ) > 1
};
};
template < typename IteratorType >
struct iterator_input_adapter_factory < IteratorType , enable_if_t < is_iterator_of_multibyte < IteratorType >:: value >>
{
using iterator_type = IteratorType ;
using char_type = typename std :: iterator_traits < iterator_type >:: value_type ;
using base_adapter_type = iterator_input_adapter < iterator_type > ;
using adapter_type = wide_string_input_adapter < base_adapter_type , char_type > ;
static adapter_type create ( IteratorType first , IteratorType last )
{
return adapter_type ( base_adapter_type ( std :: move ( first ), std :: move ( last )));
}
};
// General purpose iterator-based input
template < typename IteratorType >
typename iterator_input_adapter_factory < IteratorType >:: adapter_type input_adapter ( IteratorType first , IteratorType last )
{
using factory_type = iterator_input_adapter_factory < IteratorType > ;
return factory_type :: create ( first , last );
}
// Convenience shorthand from container to iterator
// Enables ADL on begin(container) and end(container)
// Encloses the using declarations in namespace for not to leak them to outside scope
namespace container_input_adapter_factory_impl
{
using std :: begin ;
using std :: end ;
template < typename ContainerType , typename Enable = void >
struct container_input_adapter_factory {};
template < typename ContainerType >
struct container_input_adapter_factory < ContainerType ,
void_t < decltype ( begin ( std :: declval < ContainerType > ()), end ( std :: declval < ContainerType > ())) >>
{
using adapter_type = decltype ( input_adapter ( begin ( std :: declval < ContainerType > ()), end ( std :: declval < ContainerType > ())));
static adapter_type create ( const ContainerType & container )
{
return input_adapter ( begin ( container ), end ( container ));
}
};
} // namespace container_input_adapter_factory_impl
template < typename ContainerType >
typename container_input_adapter_factory_impl :: container_input_adapter_factory < ContainerType >:: adapter_type input_adapter ( const ContainerType & container )
{
return container_input_adapter_factory_impl :: container_input_adapter_factory < ContainerType >:: create ( container );
}
2026-04-17 21:00:35 +02:00
// specialization for std::string
using string_input_adapter_type = decltype ( input_adapter ( std :: declval < std :: string > ()));
2026-02-13 19:15:05 +01:00
#ifndef JSON_NO_IO
// Special cases with fast paths
inline file_input_adapter input_adapter ( std :: FILE * file )
{
2026-04-17 21:00:35 +02:00
if ( file == nullptr )
{
JSON_THROW ( parse_error :: create ( 101 , 0 , "attempting to parse an empty input; check that your input string or stream contains the expected JSON" , nullptr ));
}
2026-02-13 19:15:05 +01:00
return file_input_adapter ( file );
}
inline input_stream_adapter input_adapter ( std :: istream & stream )
{
return input_stream_adapter ( stream );
}
inline input_stream_adapter input_adapter ( std :: istream && stream )
{
return input_stream_adapter ( stream );
}
#endif // JSON_NO_IO
using contiguous_bytes_input_adapter = decltype ( input_adapter ( std :: declval < const char *> (), std :: declval < const char *> ()));
// Null-delimited strings, and the like.
template < typename CharT ,
typename std :: enable_if <
std :: is_pointer < CharT >:: value &&
! std :: is_array < CharT >:: value &&
std :: is_integral < typename std :: remove_pointer < CharT >:: type >:: value &&
sizeof ( typename std :: remove_pointer < CharT >:: type ) == 1 ,
int >:: type = 0 >
contiguous_bytes_input_adapter input_adapter ( CharT b )
{
2026-04-17 21:00:35 +02:00
if ( b == nullptr )
{
JSON_THROW ( parse_error :: create ( 101 , 0 , "attempting to parse an empty input; check that your input string or stream contains the expected JSON" , nullptr ));
}
2026-02-13 19:15:05 +01:00
auto length = std :: strlen ( reinterpret_cast < const char *> ( b ));
const auto * ptr = reinterpret_cast < const char *> ( b );
2026-04-17 21:00:35 +02:00
return input_adapter ( ptr , ptr + length ); // cppcheck-suppress[nullPointerArithmeticRedundantCheck]
2026-02-13 19:15:05 +01:00
}
template < typename T , std :: size_t N >
auto input_adapter ( T ( & array )[ N ]) -> decltype ( input_adapter ( array , array + N )) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{
return input_adapter ( array , array + N );
}
// This class only handles inputs of input_buffer_adapter type.
// It's required so that expressions like {ptr, len} can be implicitly cast
// to the correct adapter.
class span_input_adapter
{
public :
template < typename CharT ,
typename std :: enable_if <
std :: is_pointer < CharT >:: value &&
std :: is_integral < typename std :: remove_pointer < CharT >:: type >:: value &&
sizeof ( typename std :: remove_pointer < CharT >:: type ) == 1 ,
int >:: type = 0 >
span_input_adapter ( CharT b , std :: size_t l )
: ia ( reinterpret_cast < const char *> ( b ), reinterpret_cast < const char *> ( b ) + l ) {}
template < class IteratorType ,
typename std :: enable_if <
std :: is_same < typename iterator_traits < IteratorType >:: iterator_category , std :: random_access_iterator_tag >:: value ,
int >:: type = 0 >
span_input_adapter ( IteratorType first , IteratorType last )
: ia ( input_adapter ( first , last )) {}
contiguous_bytes_input_adapter && get ()
{
return std :: move ( ia ); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
}
private :
contiguous_bytes_input_adapter ia ;
};
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END