2014-04-17 13:32:21 +00:00
# pragma once
2014-04-18 22:12:56 +00:00
2014-04-26 17:19:59 +00:00
//#define CROW_JSON_NO_ERROR_CHECK
2021-05-13 10:30:48 +00:00
//#define CROW_JSON_USE_MAP
2014-04-17 13:32:21 +00:00
# include <string>
2021-05-12 12:45:55 +00:00
# ifdef CROW_JSON_USE_MAP
# include <map>
# else
2014-04-17 13:32:21 +00:00
# include <unordered_map>
2021-05-12 12:45:55 +00:00
# endif
2014-04-18 22:12:56 +00:00
# include <iostream>
# include <algorithm>
# include <memory>
# include <boost/lexical_cast.hpp>
# include <boost/algorithm/string/predicate.hpp>
# include <boost/operators.hpp>
2014-10-23 17:45:34 +00:00
# include <vector>
2014-04-18 22:12:56 +00:00
2016-09-21 14:11:06 +00:00
# include "crow/settings.h"
2021-01-05 14:49:10 +00:00
# include "crow/returnable.h"
2016-09-09 16:16:05 +00:00
2014-08-01 21:30:36 +00:00
# if defined(__GNUG__) || defined(__clang__)
2014-04-26 17:19:59 +00:00
# define crow_json_likely(x) __builtin_expect(x, 1)
# define crow_json_unlikely(x) __builtin_expect(x, 0)
2014-04-18 22:12:56 +00:00
# else
2014-04-26 17:19:59 +00:00
# define crow_json_likely(x) x
# define crow_json_unlikely(x) x
2014-04-18 22:12:56 +00:00
# endif
2014-04-17 13:32:21 +00:00
2014-04-26 17:19:59 +00:00
namespace crow
2014-04-17 13:32:21 +00:00
{
2014-12-11 16:38:57 +00:00
namespace mustache
{
class template_t ;
}
2014-07-30 15:50:38 +00:00
2014-04-17 13:32:21 +00:00
namespace json
{
2014-08-06 20:25:18 +00:00
inline void escape ( const std : : string & str , std : : string & ret )
2014-08-06 16:18:33 +00:00
{
ret . reserve ( ret . size ( ) + str . size ( ) + str . size ( ) / 4 ) ;
2020-10-20 09:17:00 +00:00
for ( unsigned char c : str )
2014-08-06 16:18:33 +00:00
{
switch ( c )
{
case ' " ' : ret + = " \\ \" " ; break ;
case ' \\ ' : ret + = " \\ \\ " ; break ;
case ' \n ' : ret + = " \\ n " ; break ;
case ' \b ' : ret + = " \\ b " ; break ;
case ' \f ' : ret + = " \\ f " ; break ;
case ' \r ' : ret + = " \\ r " ; break ;
case ' \t ' : ret + = " \\ t " ; break ;
default :
2020-10-20 09:17:00 +00:00
if ( c < 0x20 )
2014-08-06 16:18:33 +00:00
{
ret + = " \\ u00 " ;
auto to_hex = [ ] ( char c )
{
c = c & 0xf ;
if ( c < 10 )
return ' 0 ' + c ;
return ' a ' + c - 10 ;
} ;
ret + = to_hex ( c / 16 ) ;
ret + = to_hex ( c % 16 ) ;
}
else
ret + = c ;
break ;
}
}
}
2014-08-06 20:25:18 +00:00
inline std : : string escape ( const std : : string & str )
2014-04-18 22:12:56 +00:00
{
2014-08-06 16:18:33 +00:00
std : : string ret ;
escape ( str , ret ) ;
return ret ;
2014-04-18 22:12:56 +00:00
}
enum class type : char
2014-04-17 13:32:21 +00:00
{
Null ,
False ,
True ,
Number ,
String ,
List ,
Object ,
} ;
2016-01-12 19:43:16 +00:00
inline const char * get_type_str ( type t ) {
2015-09-27 04:36:08 +00:00
switch ( t ) {
case type : : Number : return " Number " ;
case type : : False : return " False " ;
case type : : True : return " True " ;
case type : : List : return " List " ;
case type : : String : return " String " ;
case type : : Object : return " Object " ;
default : return " Unknown " ;
}
2016-08-27 09:03:49 +00:00
}
2015-09-27 04:36:08 +00:00
2017-10-22 11:31:17 +00:00
enum class num_type : char {
Signed_integer ,
Unsigned_integer ,
Floating_point ,
Null
} ;
2014-04-18 22:12:56 +00:00
class rvalue ;
2014-04-19 20:41:53 +00:00
rvalue load ( const char * data , size_t size ) ;
2014-04-17 13:32:21 +00:00
2014-04-18 22:12:56 +00:00
namespace detail
2014-04-17 13:32:21 +00:00
{
2020-11-18 22:13:57 +00:00
/// A read string implementation with comparison functionality.
2014-04-18 22:12:56 +00:00
struct r_string
: boost : : less_than_comparable < r_string > ,
boost : : less_than_comparable < r_string , std : : string > ,
boost : : equality_comparable < r_string > ,
boost : : equality_comparable < r_string , std : : string >
{
r_string ( ) { } ;
2014-08-01 21:30:36 +00:00
r_string ( char * s , char * e )
: s_ ( s ) , e_ ( e )
2014-04-18 22:12:56 +00:00
{ } ;
~ r_string ( )
{
if ( owned_ )
delete [ ] s_ ;
}
r_string ( const r_string & r )
{
* this = r ;
}
r_string ( r_string & & r )
{
* this = r ;
}
r_string & operator = ( r_string & & r )
{
s_ = r . s_ ;
2014-08-01 21:30:36 +00:00
e_ = r . e_ ;
2014-04-18 22:12:56 +00:00
owned_ = r . owned_ ;
2016-09-04 00:33:49 +00:00
if ( r . owned_ )
r . owned_ = 0 ;
2014-04-18 22:12:56 +00:00
return * this ;
}
r_string & operator = ( const r_string & r )
{
s_ = r . s_ ;
2014-08-01 21:30:36 +00:00
e_ = r . e_ ;
2014-04-18 22:12:56 +00:00
owned_ = 0 ;
return * this ;
}
operator std : : string ( ) const
{
2014-08-01 21:30:36 +00:00
return std : : string ( s_ , e_ ) ;
2014-04-18 22:12:56 +00:00
}
const char * begin ( ) const { return s_ ; }
2014-08-01 21:30:36 +00:00
const char * end ( ) const { return e_ ; }
size_t size ( ) const { return end ( ) - begin ( ) ; }
2014-04-18 22:12:56 +00:00
using iterator = const char * ;
using const_iterator = const char * ;
2020-11-18 22:13:57 +00:00
char * s_ ; ///< Start.
mutable char * e_ ; ///< End.
2014-04-18 22:12:56 +00:00
uint8_t owned_ { 0 } ;
friend std : : ostream & operator < < ( std : : ostream & os , const r_string & s )
{
2021-02-21 00:14:30 +00:00
os < < static_cast < std : : string > ( s ) ;
2014-04-18 22:12:56 +00:00
return os ;
}
private :
2017-10-23 21:16:16 +00:00
void force ( char * s , uint32_t length )
2014-04-18 22:12:56 +00:00
{
s_ = s ;
2017-10-23 21:16:16 +00:00
e_ = s_ + length ;
2014-04-18 22:12:56 +00:00
owned_ = 1 ;
}
2014-04-26 17:19:59 +00:00
friend rvalue crow : : json : : load ( const char * data , size_t size ) ;
2014-04-18 22:12:56 +00:00
} ;
2014-08-07 16:14:27 +00:00
inline bool operator < ( const r_string & l , const r_string & r )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
return boost : : lexicographical_compare ( l , r ) ;
2014-04-17 13:32:21 +00:00
}
2014-08-07 16:14:27 +00:00
inline bool operator < ( const r_string & l , const std : : string & r )
2014-04-18 22:12:56 +00:00
{
return boost : : lexicographical_compare ( l , r ) ;
}
2014-08-07 16:14:27 +00:00
inline bool operator > ( const r_string & l , const std : : string & r )
2014-04-18 22:12:56 +00:00
{
return boost : : lexicographical_compare ( r , l ) ;
}
2014-04-17 13:32:21 +00:00
2014-08-07 16:14:27 +00:00
inline bool operator = = ( const r_string & l , const r_string & r )
2014-04-18 22:12:56 +00:00
{
return boost : : equals ( l , r ) ;
}
2014-08-07 16:14:27 +00:00
inline bool operator = = ( const r_string & l , const std : : string & r )
2014-04-18 22:12:56 +00:00
{
return boost : : equals ( l , r ) ;
}
}
2020-11-18 22:13:57 +00:00
/// JSON read value.
///
/// Value can mean any json value, including a JSON object.
/// Read means this class is used to primarily read strings into a JSON value.
2014-04-18 22:12:56 +00:00
class rvalue
2014-04-17 13:32:21 +00:00
{
2014-08-01 21:30:36 +00:00
static const int cached_bit = 2 ;
2014-04-18 22:12:56 +00:00
static const int error_bit = 4 ;
public :
2014-12-11 16:38:57 +00:00
rvalue ( ) noexcept : option_ { error_bit }
{ }
2014-04-18 22:12:56 +00:00
rvalue ( type t ) noexcept
: lsize_ { } , lremain_ { } , t_ { t }
{ }
2014-08-01 21:30:36 +00:00
rvalue ( type t , char * s , char * e ) noexcept
2014-04-18 22:12:56 +00:00
: start_ { s } ,
end_ { e } ,
t_ { t }
2017-10-22 11:31:17 +00:00
{
determine_num_type ( ) ;
}
2014-04-18 22:12:56 +00:00
rvalue ( const rvalue & r )
: start_ ( r . start_ ) ,
end_ ( r . end_ ) ,
key_ ( r . key_ ) ,
t_ ( r . t_ ) ,
2017-10-22 11:31:17 +00:00
nt_ ( r . nt_ ) ,
2014-04-18 22:12:56 +00:00
option_ ( r . option_ )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
copy_l ( r ) ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
rvalue ( rvalue & & r ) noexcept
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
* this = std : : move ( r ) ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
rvalue & operator = ( const rvalue & r )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
start_ = r . start_ ;
end_ = r . end_ ;
key_ = r . key_ ;
t_ = r . t_ ;
2017-10-22 11:31:17 +00:00
nt_ = r . nt_ ;
2014-04-18 22:12:56 +00:00
option_ = r . option_ ;
2017-10-23 21:23:10 +00:00
copy_l ( r ) ;
2014-04-18 22:12:56 +00:00
return * this ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
rvalue & operator = ( rvalue & & r ) noexcept
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
start_ = r . start_ ;
end_ = r . end_ ;
key_ = std : : move ( r . key_ ) ;
l_ = std : : move ( r . l_ ) ;
lsize_ = r . lsize_ ;
lremain_ = r . lremain_ ;
t_ = r . t_ ;
2017-10-22 11:31:17 +00:00
nt_ = r . nt_ ;
2014-04-18 22:12:56 +00:00
option_ = r . option_ ;
return * this ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
explicit operator bool ( ) const noexcept
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
return ( option_ & error_bit ) = = 0 ;
}
explicit operator int64_t ( ) const
{
return i ( ) ;
}
2016-08-27 09:12:17 +00:00
explicit operator uint64_t ( ) const
{
return u ( ) ;
}
2014-04-18 22:12:56 +00:00
explicit operator int ( ) const
{
2021-02-21 00:14:30 +00:00
return static_cast < int > ( i ( ) ) ;
2014-04-18 22:12:56 +00:00
}
2021-05-12 12:45:55 +00:00
///Return any json value (not object or list) as a string.
explicit operator std : : string ( ) const
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( t ( ) = = type : : Object | | t ( ) = = type : : List )
throw std : : runtime_error ( " json type container " ) ;
# endif
switch ( t ( ) )
{
case type : : String :
return std : : string ( s ( ) ) ;
case type : : Null :
return std : : string ( " null " ) ;
case type : : True :
return std : : string ( " true " ) ;
case type : : False :
return std : : string ( " false " ) ;
default :
return std : : string ( start_ , end_ - start_ ) ;
}
}
2020-11-18 22:13:57 +00:00
/// The type of the JSON value.
2014-04-18 22:12:56 +00:00
type t ( ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( option_ & error_bit )
{
throw std : : runtime_error ( " invalid json object " ) ;
}
# endif
return t_ ;
}
2020-11-18 22:13:57 +00:00
/// The number type of the JSON value.
2017-10-22 11:31:17 +00:00
num_type nt ( ) const
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( option_ & error_bit )
{
throw std : : runtime_error ( " invalid json object " ) ;
}
# endif
return nt_ ;
}
2020-11-18 22:13:57 +00:00
/// The integer value.
2014-04-18 22:12:56 +00:00
int64_t i ( ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2015-09-27 04:36:08 +00:00
switch ( t ( ) ) {
case type : : Number :
case type : : String :
return boost : : lexical_cast < int64_t > ( start_ , end_ - start_ ) ;
default :
2015-12-24 11:42:21 +00:00
const std : : string msg = " expected number, got: "
+ std : : string ( get_type_str ( t ( ) ) ) ;
throw std : : runtime_error ( msg ) ;
2015-09-27 04:36:08 +00:00
}
2014-04-18 22:12:56 +00:00
# endif
return boost : : lexical_cast < int64_t > ( start_ , end_ - start_ ) ;
2014-04-17 13:32:21 +00:00
}
2020-11-18 22:13:57 +00:00
/// The unsigned integer value.
2016-08-27 09:12:17 +00:00
uint64_t u ( ) const
{
# ifndef CROW_JSON_NO_ERROR_CHECK
switch ( t ( ) ) {
case type : : Number :
case type : : String :
return boost : : lexical_cast < uint64_t > ( start_ , end_ - start_ ) ;
default :
throw std : : runtime_error ( std : : string ( " expected number, got: " ) + get_type_str ( t ( ) ) ) ;
}
# endif
return boost : : lexical_cast < uint64_t > ( start_ , end_ - start_ ) ;
}
2020-11-18 22:13:57 +00:00
/// The double precision floating-point number value.
2014-04-17 13:32:21 +00:00
double d ( ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-17 13:32:21 +00:00
if ( t ( ) ! = type : : Number )
throw std : : runtime_error ( " value is not number " ) ;
2014-04-18 22:12:56 +00:00
# endif
return boost : : lexical_cast < double > ( start_ , end_ - start_ ) ;
2014-04-17 13:32:21 +00:00
}
2020-11-18 22:13:57 +00:00
/// The boolean value.
2014-11-06 14:10:38 +00:00
bool b ( ) const
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( t ( ) ! = type : : True & & t ( ) ! = type : : False )
throw std : : runtime_error ( " value is not boolean " ) ;
# endif
return t ( ) = = type : : True ;
}
2020-11-18 22:13:57 +00:00
/// The string value.
detail : : r_string s ( ) const
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( t ( ) ! = type : : String )
throw std : : runtime_error ( " value is not string " ) ;
# endif
unescape ( ) ;
return detail : : r_string { start_ , end_ } ;
}
2021-05-12 12:45:55 +00:00
///The list or object value
std : : vector < rvalue > lo ( )
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( t ( ) ! = type : : Object & & t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a container " ) ;
# endif
std : : vector < rvalue > ret ;
ret . reserve ( lsize_ ) ;
for ( uint32_t i = 0 ; i < lsize_ ; i + + )
{
ret . emplace_back ( l_ [ i ] ) ;
}
return ret ;
}
2020-11-18 22:13:57 +00:00
/// Convert escaped string character to their original form ("\\n" -> '\n').
2014-08-01 21:30:36 +00:00
void unescape ( ) const
{
if ( * ( start_ - 1 ) )
{
char * head = start_ ;
char * tail = start_ ;
while ( head ! = end_ )
{
if ( * head = = ' \\ ' )
{
switch ( * + + head )
{
case ' " ' : * tail + + = ' " ' ; break ;
case ' \\ ' : * tail + + = ' \\ ' ; break ;
case ' / ' : * tail + + = ' / ' ; break ;
case ' b ' : * tail + + = ' \b ' ; break ;
case ' f ' : * tail + + = ' \f ' ; break ;
case ' n ' : * tail + + = ' \n ' ; break ;
case ' r ' : * tail + + = ' \r ' ; break ;
case ' t ' : * tail + + = ' \t ' ; break ;
case ' u ' :
{
auto from_hex = [ ] ( char c )
{
if ( c > = ' a ' )
return c - ' a ' + 10 ;
if ( c > = ' A ' )
return c - ' A ' + 10 ;
return c - ' 0 ' ;
} ;
unsigned int code =
( from_hex ( head [ 1 ] ) < < 12 ) +
( from_hex ( head [ 2 ] ) < < 8 ) +
( from_hex ( head [ 3 ] ) < < 4 ) +
from_hex ( head [ 4 ] ) ;
if ( code > = 0x800 )
{
2015-02-20 01:54:32 +00:00
* tail + + = 0xE0 | ( code > > 12 ) ;
* tail + + = 0x80 | ( ( code > > 6 ) & 0x3F ) ;
* tail + + = 0x80 | ( code & 0x3F ) ;
2014-08-01 21:30:36 +00:00
}
else if ( code > = 0x80 )
{
2015-02-20 01:54:32 +00:00
* tail + + = 0xC0 | ( code > > 6 ) ;
* tail + + = 0x80 | ( code & 0x3F ) ;
2014-08-01 21:30:36 +00:00
}
else
{
* tail + + = code ;
}
head + = 4 ;
}
break ;
}
}
else
* tail + + = * head ;
head + + ;
}
end_ = tail ;
* end_ = 0 ;
* ( start_ - 1 ) = 0 ;
}
}
2021-05-12 12:45:55 +00:00
///Check if the json object has the passed string as a key.
2014-04-18 22:12:56 +00:00
bool has ( const char * str ) const
{
return has ( std : : string ( str ) ) ;
}
bool has ( const std : : string & str ) const
{
struct Pred
{
bool operator ( ) ( const rvalue & l , const rvalue & r ) const
{
return l . key_ < r . key_ ;
} ;
bool operator ( ) ( const rvalue & l , const std : : string & r ) const
{
return l . key_ < r ;
} ;
bool operator ( ) ( const std : : string & l , const rvalue & r ) const
{
return l < r . key_ ;
} ;
} ;
if ( ! is_cached ( ) )
{
std : : sort ( begin ( ) , end ( ) , Pred ( ) ) ;
set_cached ( ) ;
}
auto it = lower_bound ( begin ( ) , end ( ) , str , Pred ( ) ) ;
return it ! = end ( ) & & it - > key_ = = str ;
}
2014-12-11 16:38:57 +00:00
int count ( const std : : string & str )
{
return has ( str ) ? 1 : 0 ;
}
2014-07-30 15:50:38 +00:00
2014-04-18 22:12:56 +00:00
rvalue * begin ( ) const
2014-12-11 16:38:57 +00:00
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : Object & & t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a container " ) ;
# endif
2014-12-11 16:38:57 +00:00
return l_ . get ( ) ;
}
2014-04-18 22:12:56 +00:00
rvalue * end ( ) const
2014-12-11 16:38:57 +00:00
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : Object & & t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a container " ) ;
# endif
2014-12-11 16:38:57 +00:00
return l_ . get ( ) + lsize_ ;
}
2014-04-18 22:12:56 +00:00
2014-12-11 16:38:57 +00:00
const detail : : r_string & key ( ) const
{
return key_ ;
}
2014-04-18 22:12:56 +00:00
size_t size ( ) const
{
2014-08-01 21:30:36 +00:00
if ( t ( ) = = type : : String )
return s ( ) . size ( ) ;
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : Object & & t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a container " ) ;
# endif
return lsize_ ;
}
2014-12-11 16:38:57 +00:00
const rvalue & operator [ ] ( int index ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a list " ) ;
2021-02-21 00:14:30 +00:00
if ( index > = static_cast < int > ( lsize_ ) | | index < 0 )
2014-04-18 22:12:56 +00:00
throw std : : runtime_error ( " list out of bound " ) ;
# endif
2014-12-11 16:38:57 +00:00
return l_ [ index ] ;
}
2014-04-18 22:12:56 +00:00
2014-12-11 16:38:57 +00:00
const rvalue & operator [ ] ( size_t index ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : List )
throw std : : runtime_error ( " value is not a list " ) ;
2014-12-11 16:38:57 +00:00
if ( index > = lsize_ )
2014-04-18 22:12:56 +00:00
throw std : : runtime_error ( " list out of bound " ) ;
# endif
2014-12-11 16:38:57 +00:00
return l_ [ index ] ;
}
2014-04-18 22:12:56 +00:00
const rvalue & operator [ ] ( const char * str ) const
{
return this - > operator [ ] ( std : : string ( str ) ) ;
}
const rvalue & operator [ ] ( const std : : string & str ) const
{
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
if ( t ( ) ! = type : : Object )
throw std : : runtime_error ( " value is not an object " ) ;
# endif
struct Pred
{
bool operator ( ) ( const rvalue & l , const rvalue & r ) const
{
return l . key_ < r . key_ ;
} ;
bool operator ( ) ( const rvalue & l , const std : : string & r ) const
{
return l . key_ < r ;
} ;
bool operator ( ) ( const std : : string & l , const rvalue & r ) const
{
return l < r . key_ ;
} ;
} ;
if ( ! is_cached ( ) )
{
std : : sort ( begin ( ) , end ( ) , Pred ( ) ) ;
set_cached ( ) ;
}
auto it = lower_bound ( begin ( ) , end ( ) , str , Pred ( ) ) ;
if ( it ! = end ( ) & & it - > key_ = = str )
return * it ;
2014-04-26 17:19:59 +00:00
# ifndef CROW_JSON_NO_ERROR_CHECK
2014-04-18 22:12:56 +00:00
throw std : : runtime_error ( " cannot find key " ) ;
# else
static rvalue nullValue ;
return nullValue ;
# endif
}
void set_error ( )
{
option_ | = error_bit ;
}
bool error ( ) const
{
return ( option_ & error_bit ) ! = 0 ;
}
2021-05-12 12:45:55 +00:00
std : : vector < std : : string > keys ( )
{
# ifndef CROW_JSON_NO_ERROR_CHECK
if ( t ( ) ! = type : : Object )
throw std : : runtime_error ( " value is not an object " ) ;
# endif
std : : vector < std : : string > ret ;
ret . reserve ( lsize_ ) ;
for ( uint32_t i = 0 ; i < lsize_ ; i + + )
{
ret . emplace_back ( std : : string ( l_ [ i ] . key ( ) ) ) ;
}
return ret ;
}
2014-04-18 22:12:56 +00:00
private :
bool is_cached ( ) const
{
2014-08-01 21:30:36 +00:00
return ( option_ & cached_bit ) ! = 0 ;
2014-04-18 22:12:56 +00:00
}
void set_cached ( ) const
{
2014-08-01 21:30:36 +00:00
option_ | = cached_bit ;
2014-04-18 22:12:56 +00:00
}
void copy_l ( const rvalue & r )
{
2014-08-01 21:30:36 +00:00
if ( r . t ( ) ! = type : : Object & & r . t ( ) ! = type : : List )
return ;
2014-04-18 22:12:56 +00:00
lsize_ = r . lsize_ ;
lremain_ = 0 ;
l_ . reset ( new rvalue [ lsize_ ] ) ;
std : : copy ( r . begin ( ) , r . end ( ) , begin ( ) ) ;
}
void emplace_back ( rvalue & & v )
{
if ( ! lremain_ )
{
int new_size = lsize_ + lsize_ ;
if ( new_size - lsize_ > 60000 )
new_size = lsize_ + 60000 ;
if ( new_size < 4 )
new_size = 4 ;
rvalue * p = new rvalue [ new_size ] ;
rvalue * p2 = p ;
for ( auto & x : * this )
* p2 + + = std : : move ( x ) ;
l_ . reset ( p ) ;
lremain_ = new_size - lsize_ ;
}
l_ [ lsize_ + + ] = std : : move ( v ) ;
lremain_ - - ;
}
2020-11-18 22:13:57 +00:00
/// determines num_type from the string.
2017-10-22 11:31:17 +00:00
void determine_num_type ( )
{
if ( t_ ! = type : : Number )
{
nt_ = num_type : : Null ;
return ;
}
const std : : size_t len = end_ - start_ ;
const bool has_minus = std : : memchr ( start_ , ' - ' , len ) ! = nullptr ;
const bool has_e = std : : memchr ( start_ , ' e ' , len ) ! = nullptr
| | std : : memchr ( start_ , ' E ' , len ) ! = nullptr ;
const bool has_dec_sep = std : : memchr ( start_ , ' . ' , len ) ! = nullptr ;
if ( has_dec_sep | | has_e )
nt_ = num_type : : Floating_point ;
else if ( has_minus )
nt_ = num_type : : Signed_integer ;
else
nt_ = num_type : : Unsigned_integer ;
}
2014-08-01 21:30:36 +00:00
mutable char * start_ ;
mutable char * end_ ;
2014-04-18 22:12:56 +00:00
detail : : r_string key_ ;
std : : unique_ptr < rvalue [ ] > l_ ;
uint32_t lsize_ ;
uint16_t lremain_ ;
type t_ ;
2017-10-22 11:31:17 +00:00
num_type nt_ { num_type : : Null } ;
2014-04-18 22:12:56 +00:00
mutable uint8_t option_ { 0 } ;
2014-08-01 21:30:36 +00:00
friend rvalue load_nocopy_internal ( char * data , size_t size ) ;
2014-04-19 20:41:53 +00:00
friend rvalue load ( const char * data , size_t size ) ;
2014-04-18 22:12:56 +00:00
friend std : : ostream & operator < < ( std : : ostream & os , const rvalue & r )
{
switch ( r . t_ )
{
case type : : Null : os < < " null " ; break ;
case type : : False : os < < " false " ; break ;
case type : : True : os < < " true " ; break ;
2017-10-23 20:59:08 +00:00
case type : : Number :
{
switch ( r . nt ( ) )
{
case num_type : : Floating_point : os < < r . d ( ) ; break ;
case num_type : : Signed_integer : os < < r . i ( ) ; break ;
case num_type : : Unsigned_integer : os < < r . u ( ) ; break ;
case num_type : : Null : throw std : : runtime_error ( " Number with num_type Null " ) ;
}
}
break ;
2014-04-21 18:27:53 +00:00
case type : : String : os < < ' " ' < < r . s ( ) < < ' " ' ; break ;
2014-04-18 22:12:56 +00:00
case type : : List :
{
os < < ' [ ' ;
bool first = true ;
for ( auto & x : r )
{
if ( ! first )
os < < ' , ' ;
first = false ;
os < < x ;
}
os < < ' ] ' ;
}
break ;
case type : : Object :
{
os < < ' { ' ;
bool first = true ;
for ( auto & x : r )
{
if ( ! first )
os < < ' , ' ;
2014-08-01 21:30:36 +00:00
os < < ' " ' < < escape ( x . key_ ) < < " \" : " ;
2014-04-18 22:12:56 +00:00
first = false ;
os < < x ;
}
os < < ' } ' ;
}
break ;
}
return os ;
}
2014-04-17 13:32:21 +00:00
} ;
2014-08-01 21:30:36 +00:00
namespace detail {
}
2014-04-17 13:32:21 +00:00
2014-08-06 20:25:18 +00:00
inline bool operator = = ( const rvalue & l , const std : : string & r )
2014-04-18 22:12:56 +00:00
{
return l . s ( ) = = r ;
}
2014-08-06 20:25:18 +00:00
inline bool operator = = ( const std : : string & l , const rvalue & r )
2014-04-18 22:12:56 +00:00
{
return l = = r . s ( ) ;
}
2014-08-06 20:25:18 +00:00
inline bool operator ! = ( const rvalue & l , const std : : string & r )
2014-04-18 22:12:56 +00:00
{
return l . s ( ) ! = r ;
}
2014-08-06 20:25:18 +00:00
inline bool operator ! = ( const std : : string & l , const rvalue & r )
2014-04-18 22:12:56 +00:00
{
return l ! = r . s ( ) ;
}
2014-08-06 20:25:18 +00:00
inline bool operator = = ( const rvalue & l , double r )
2014-04-18 22:12:56 +00:00
{
return l . d ( ) = = r ;
}
2014-08-06 20:25:18 +00:00
inline bool operator = = ( double l , const rvalue & r )
2014-04-18 22:12:56 +00:00
{
return l = = r . d ( ) ;
}
2014-08-06 20:25:18 +00:00
inline bool operator ! = ( const rvalue & l , double r )
2014-04-18 22:12:56 +00:00
{
return l . d ( ) ! = r ;
}
2014-08-06 20:25:18 +00:00
inline bool operator ! = ( double l , const rvalue & r )
2014-04-18 22:12:56 +00:00
{
return l ! = r . d ( ) ;
}
2014-08-01 21:30:36 +00:00
inline rvalue load_nocopy_internal ( char * data , size_t size )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
//static const char* escaped = "\"\\/\b\f\n\r\t";
2014-12-11 16:38:57 +00:00
struct Parser
{
2016-08-27 09:03:49 +00:00
Parser ( char * data , size_t /*size*/ )
2014-12-11 16:38:57 +00:00
: data ( data )
{
}
bool consume ( char c )
2014-04-17 13:32:21 +00:00
{
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( * data ! = c ) )
2014-04-18 22:12:56 +00:00
return false ;
data + + ;
return true ;
}
2014-12-11 16:38:57 +00:00
void ws_skip ( )
2014-04-18 22:12:56 +00:00
{
2014-12-11 16:38:57 +00:00
while ( * data = = ' ' | | * data = = ' \t ' | | * data = = ' \r ' | | * data = = ' \n ' ) + + data ;
2014-04-17 13:32:21 +00:00
} ;
2014-04-18 22:12:56 +00:00
2014-12-11 16:38:57 +00:00
rvalue decode_string ( )
2014-04-17 13:32:21 +00:00
{
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! consume ( ' " ' ) ) )
2014-04-17 13:32:21 +00:00
return { } ;
2014-08-01 21:30:36 +00:00
char * start = data ;
2014-04-18 22:12:56 +00:00
uint8_t has_escaping = 0 ;
while ( 1 )
2014-04-17 13:32:21 +00:00
{
2014-04-26 17:19:59 +00:00
if ( crow_json_likely ( * data ! = ' " ' & & * data ! = ' \\ ' & & * data ! = ' \0 ' ) )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
data + + ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
else if ( * data = = ' " ' )
2014-04-17 13:32:21 +00:00
{
2014-08-01 21:30:36 +00:00
* data = 0 ;
* ( start - 1 ) = has_escaping ;
2014-04-18 22:12:56 +00:00
data + + ;
2014-08-01 21:30:36 +00:00
return { type : : String , start , data - 1 } ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
else if ( * data = = ' \\ ' )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
has_escaping = 1 ;
data + + ;
switch ( * data )
{
case ' u ' :
2014-08-01 21:30:36 +00:00
{
auto check = [ ] ( char c )
{
return
( ' 0 ' < = c & & c < = ' 9 ' ) | |
( ' a ' < = c & & c < = ' f ' ) | |
( ' A ' < = c & & c < = ' F ' ) ;
} ;
if ( ! ( check ( * ( data + 1 ) ) & &
check ( * ( data + 2 ) ) & &
check ( * ( data + 3 ) ) & &
check ( * ( data + 4 ) ) ) )
return { } ;
}
data + = 5 ;
2014-04-18 22:12:56 +00:00
break ;
case ' " ' :
case ' \\ ' :
case ' / ' :
case ' b ' :
case ' f ' :
case ' n ' :
case ' r ' :
case ' t ' :
data + + ;
break ;
default :
return { } ;
}
2014-04-17 13:32:21 +00:00
}
2014-04-21 18:27:53 +00:00
else
return { } ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
return { } ;
}
2014-12-11 16:38:57 +00:00
rvalue decode_list ( )
2014-04-17 13:32:21 +00:00
{
2014-12-11 16:38:57 +00:00
rvalue ret ( type : : List ) ;
if ( crow_json_unlikely ( ! consume ( ' [ ' ) ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
2014-12-11 16:38:57 +00:00
return ret ;
}
ws_skip ( ) ;
if ( crow_json_unlikely ( * data = = ' ] ' ) )
{
data + + ;
return ret ;
2014-04-18 22:12:56 +00:00
}
2014-12-11 16:38:57 +00:00
while ( 1 )
{
2014-04-18 22:12:56 +00:00
auto v = decode_value ( ) ;
2014-12-11 16:38:57 +00:00
if ( crow_json_unlikely ( ! v ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
break ;
}
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-18 22:12:56 +00:00
ret . emplace_back ( std : : move ( v ) ) ;
if ( * data = = ' ] ' )
{
data + + ;
break ;
}
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! consume ( ' , ' ) ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
break ;
}
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
}
2014-04-18 22:12:56 +00:00
return ret ;
}
2014-12-11 16:38:57 +00:00
rvalue decode_number ( )
2014-04-17 13:32:21 +00:00
{
2014-08-01 21:30:36 +00:00
char * start = data ;
2014-04-18 22:12:56 +00:00
enum NumberParsingState
{
Minus ,
AfterMinus ,
ZeroFirst ,
Digits ,
DigitsAfterPoints ,
E ,
DigitsAfterE ,
Invalid ,
} state { Minus } ;
2014-04-26 17:19:59 +00:00
while ( crow_json_likely ( state ! = Invalid ) )
2014-04-18 22:12:56 +00:00
{
switch ( * data )
{
case ' 0 ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \2 \2 \7 \3 \4 \6 \6 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
/*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus)
{
state = NumberParsingState : : ZeroFirst ;
}
else if ( state = = NumberParsingState : : Digits | |
state = = NumberParsingState : : DigitsAfterE | |
state = = NumberParsingState : : DigitsAfterPoints )
{
// ok; pass
}
else if ( state = = NumberParsingState : : E )
{
state = NumberParsingState : : DigitsAfterE ;
}
else
return { } ; */
2014-12-11 16:38:57 +00:00
break ;
2014-04-18 22:12:56 +00:00
case ' 1 ' : case ' 2 ' : case ' 3 ' :
case ' 4 ' : case ' 5 ' : case ' 6 ' :
case ' 7 ' : case ' 8 ' : case ' 9 ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \3 \3 \7 \3 \4 \6 \6 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
while ( * ( data + 1 ) > = ' 0 ' & & * ( data + 1 ) < = ' 9 ' ) data + + ;
/*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus)
{
state = NumberParsingState : : Digits ;
}
else if ( state = = NumberParsingState : : Digits | |
state = = NumberParsingState : : DigitsAfterE | |
state = = NumberParsingState : : DigitsAfterPoints )
{
// ok; pass
}
else if ( state = = NumberParsingState : : E )
{
state = NumberParsingState : : DigitsAfterE ;
}
else
return { } ; */
break ;
case ' . ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \7 \7 \4 \4 \7 \7 \7 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
/*
2014-11-08 23:47:45 +00:00
if ( state = = NumberParsingState : : Digits | | state = = NumberParsingState : : ZeroFirst )
2014-04-18 22:12:56 +00:00
{
state = NumberParsingState : : DigitsAfterPoints ;
}
else
return { } ;
*/
break ;
case ' - ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \1 \7 \7 \7 \7 \6 \7 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
/*if (state == NumberParsingState::Minus)
{
state = NumberParsingState : : AfterMinus ;
}
else if ( state = = NumberParsingState : : E )
{
state = NumberParsingState : : DigitsAfterE ;
}
else
return { } ; */
break ;
case ' + ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \7 \7 \7 \7 \7 \6 \7 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
/*if (state == NumberParsingState::E)
{
state = NumberParsingState : : DigitsAfterE ;
}
else
return { } ; */
break ;
case ' e ' : case ' E ' :
2021-02-21 00:14:30 +00:00
state = static_cast < NumberParsingState > ( " \7 \7 \7 \5 \5 \7 \7 " [ state ] ) ;
2014-04-18 22:12:56 +00:00
/*if (state == NumberParsingState::Digits ||
state = = NumberParsingState : : DigitsAfterPoints )
{
state = NumberParsingState : : E ;
}
else
return { } ; */
break ;
default :
2014-04-26 17:19:59 +00:00
if ( crow_json_likely ( state = = NumberParsingState : : ZeroFirst | |
2014-04-18 22:12:56 +00:00
state = = NumberParsingState : : Digits | |
state = = NumberParsingState : : DigitsAfterPoints | |
state = = NumberParsingState : : DigitsAfterE ) )
return { type : : Number , start , data } ;
else
return { } ;
}
data + + ;
}
return { } ;
}
2014-12-11 16:38:57 +00:00
rvalue decode_value ( )
2014-04-17 13:32:21 +00:00
{
switch ( * data )
{
2014-04-18 22:12:56 +00:00
case ' [ ' :
2014-12-11 16:38:57 +00:00
return decode_list ( ) ;
2014-04-17 13:32:21 +00:00
case ' { ' :
2014-12-11 16:38:57 +00:00
return decode_object ( ) ;
2014-04-18 22:12:56 +00:00
case ' " ' :
return decode_string ( ) ;
2014-04-17 13:32:21 +00:00
case ' t ' :
2014-04-18 22:12:56 +00:00
if ( //e-data >= 4 &&
2014-04-17 13:32:21 +00:00
data [ 1 ] = = ' r ' & &
data [ 2 ] = = ' u ' & &
data [ 3 ] = = ' e ' )
2014-04-18 22:12:56 +00:00
{
data + = 4 ;
return { type : : True } ;
}
2014-04-17 13:32:21 +00:00
else
return { } ;
case ' f ' :
2014-04-18 22:12:56 +00:00
if ( //e-data >= 5 &&
data [ 1 ] = = ' a ' & &
data [ 2 ] = = ' l ' & &
data [ 3 ] = = ' s ' & &
data [ 4 ] = = ' e ' )
{
data + = 5 ;
return { type : : False } ;
}
else
return { } ;
2014-04-17 13:32:21 +00:00
case ' n ' :
2014-04-18 22:12:56 +00:00
if ( //e-data >= 4 &&
data [ 1 ] = = ' u ' & &
data [ 2 ] = = ' l ' & &
data [ 3 ] = = ' l ' )
{
data + = 4 ;
return { type : : Null } ;
}
else
return { } ;
//case '1': case '2': case '3':
//case '4': case '5': case '6':
//case '7': case '8': case '9':
//case '0': case '-':
default :
return decode_number ( ) ;
2014-04-17 13:32:21 +00:00
}
return { } ;
2014-04-18 22:12:56 +00:00
}
2014-12-11 16:38:57 +00:00
rvalue decode_object ( )
2014-04-17 13:32:21 +00:00
{
2014-04-18 22:12:56 +00:00
rvalue ret ( type : : Object ) ;
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! consume ( ' { ' ) ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
return ret ;
}
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-18 22:12:56 +00:00
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( * data = = ' } ' ) )
2014-04-18 22:12:56 +00:00
{
data + + ;
return ret ;
}
2014-04-17 13:32:21 +00:00
while ( 1 )
{
auto t = decode_string ( ) ;
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! t ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
2014-04-17 13:32:21 +00:00
break ;
2014-04-18 22:12:56 +00:00
}
2014-04-17 13:32:21 +00:00
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! consume ( ' : ' ) ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
break ;
}
2014-04-17 13:32:21 +00:00
2014-12-11 16:38:57 +00:00
// TODO caching key to speed up (flyweight?)
2021-05-12 12:45:55 +00:00
// I have no idea how flyweight could apply here, but maybe some speedup can happen if we stopped checking type since decode_string returns a string anyway
2014-04-18 22:12:56 +00:00
auto key = t . s ( ) ;
2014-04-17 13:32:21 +00:00
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-18 22:12:56 +00:00
auto v = decode_value ( ) ;
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! v ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
break ;
2014-04-17 13:32:21 +00:00
}
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-18 22:12:56 +00:00
v . key_ = std : : move ( key ) ;
ret . emplace_back ( std : : move ( v ) ) ;
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( * data = = ' } ' ) )
2014-04-18 22:12:56 +00:00
{
data + + ;
break ;
}
2014-04-26 17:19:59 +00:00
if ( crow_json_unlikely ( ! consume ( ' , ' ) ) )
2014-04-18 22:12:56 +00:00
{
ret . set_error ( ) ;
break ;
}
2014-12-11 16:38:57 +00:00
ws_skip ( ) ;
2014-04-18 22:12:56 +00:00
}
return ret ;
2014-04-17 13:32:21 +00:00
}
2014-04-18 22:12:56 +00:00
2014-12-11 16:38:57 +00:00
rvalue parse ( )
{
ws_skip ( ) ;
auto ret = decode_value ( ) ; // or decode object?
2014-04-18 22:12:56 +00:00
ws_skip ( ) ;
2014-04-21 18:27:53 +00:00
if ( ret & & * data ! = ' \0 ' )
2014-04-18 22:12:56 +00:00
ret . set_error ( ) ;
2014-12-11 16:38:57 +00:00
return ret ;
}
2014-04-18 22:12:56 +00:00
2014-12-11 16:38:57 +00:00
char * data ;
} ;
return Parser ( data , size ) . parse ( ) ;
2014-04-18 22:12:56 +00:00
}
2014-04-19 20:41:53 +00:00
inline rvalue load ( const char * data , size_t size )
2014-04-18 22:12:56 +00:00
{
char * s = new char [ size + 1 ] ;
2014-04-21 18:27:53 +00:00
memcpy ( s , data , size ) ;
s [ size ] = 0 ;
2014-04-19 20:41:53 +00:00
auto ret = load_nocopy_internal ( s , size ) ;
2014-04-18 22:12:56 +00:00
if ( ret )
ret . key_ . force ( s , size ) ;
else
delete [ ] s ;
return ret ;
}
2014-04-19 20:41:53 +00:00
inline rvalue load ( const char * data )
2014-04-18 22:12:56 +00:00
{
2014-04-19 20:41:53 +00:00
return load ( data , strlen ( data ) ) ;
2014-04-18 22:12:56 +00:00
}
2014-04-19 20:41:53 +00:00
inline rvalue load ( const std : : string & str )
2014-04-18 22:12:56 +00:00
{
2014-04-19 20:41:53 +00:00
return load ( str . data ( ) , str . size ( ) ) ;
2014-04-18 22:12:56 +00:00
}
2020-11-18 22:13:57 +00:00
/// JSON write value.
///
/// Value can mean any json value, including a JSON object.
/// Write means this class is used to primarily assemble JSON objects using keys and values and export those into a string.
2021-01-05 14:49:10 +00:00
class wvalue : public returnable
2014-04-17 13:32:21 +00:00
{
2014-12-11 16:38:57 +00:00
friend class crow : : mustache : : template_t ;
2014-04-17 13:32:21 +00:00
public :
2014-07-30 15:50:38 +00:00
type t ( ) const { return t_ ; }
2014-04-17 13:32:21 +00:00
private :
2020-11-18 22:13:57 +00:00
type t_ { type : : Null } ; ///< The type of the value.
num_type nt { num_type : : Null } ; ///< The specific type of the number if \ref t_ is a number.
2017-10-22 11:31:17 +00:00
union {
double d ;
int64_t si ;
uint64_t ui { } ;
2020-11-18 22:13:57 +00:00
} num ; ///< Value if type is a number.
std : : string s ; ///< Value if type is a string.
std : : unique_ptr < std : : vector < wvalue > > l ; ///< Value if type is a list.
2021-05-12 12:45:55 +00:00
# ifdef CROW_JSON_USE_MAP
std : : unique_ptr < std : : map < std : : string , wvalue > > o ;
# else
2020-11-18 22:13:57 +00:00
std : : unique_ptr < std : : unordered_map < std : : string , wvalue > > o ; ///< Value if type is a JSON object.
2021-05-12 12:45:55 +00:00
# endif
2014-04-17 13:32:21 +00:00
public :
2021-01-05 14:49:10 +00:00
wvalue ( ) : returnable ( " application/json " ) { }
2021-05-12 12:45:55 +00:00
wvalue ( std : : vector < wvalue > & r ) : returnable ( " application/json " )
{
t_ = type : : List ;
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
l - > reserve ( r . size ( ) ) ;
for ( auto it = r . begin ( ) ; it ! = r . end ( ) ; + + it )
l - > emplace_back ( * it ) ;
}
2020-11-18 22:13:57 +00:00
/// Create a write value from a read value (useful for editing JSON strings).
2021-01-05 14:49:10 +00:00
wvalue ( const rvalue & r ) : returnable ( " application/json " )
2014-07-30 15:50:38 +00:00
{
t_ = r . t ( ) ;
switch ( r . t ( ) )
{
case type : : Null :
case type : : False :
case type : : True :
return ;
case type : : Number :
2017-10-22 11:31:17 +00:00
nt = r . nt ( ) ;
if ( nt = = num_type : : Floating_point )
num . d = r . d ( ) ;
else if ( nt = = num_type : : Signed_integer )
num . si = r . i ( ) ;
else
num . ui = r . u ( ) ;
2014-07-30 15:50:38 +00:00
return ;
case type : : String :
s = r . s ( ) ;
return ;
case type : : List :
2016-08-27 09:03:49 +00:00
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
2014-07-30 15:50:38 +00:00
l - > reserve ( r . size ( ) ) ;
for ( auto it = r . begin ( ) ; it ! = r . end ( ) ; + + it )
l - > emplace_back ( * it ) ;
return ;
case type : : Object :
2021-05-12 12:45:55 +00:00
# ifdef CROW_JSON_USE_MAP
o = std : : unique_ptr < std : : map < std : : string , wvalue > > ( new std : : map < std : : string , wvalue > { } ) ;
# else
o = std : : unique_ptr < std : : unordered_map < std : : string , wvalue > > ( new std : : unordered_map < std : : string , wvalue > { } ) ;
# endif
2014-07-30 15:50:38 +00:00
for ( auto it = r . begin ( ) ; it ! = r . end ( ) ; + + it )
o - > emplace ( it - > key ( ) , * it ) ;
return ;
}
}
2021-05-12 12:45:55 +00:00
wvalue ( const wvalue & r ) : returnable ( " application/json " )
{
t_ = r . t ( ) ;
switch ( r . t ( ) )
{
case type : : Null :
case type : : False :
case type : : True :
return ;
case type : : Number :
nt = r . nt ;
if ( nt = = num_type : : Floating_point )
num . d = r . num . d ;
else if ( nt = = num_type : : Signed_integer )
num . si = r . num . si ;
else
num . ui = r . num . ui ;
return ;
case type : : String :
s = r . s ;
return ;
case type : : List :
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
l - > reserve ( r . size ( ) ) ;
for ( auto it = r . l - > begin ( ) ; it ! = r . l - > end ( ) ; + + it )
l - > emplace_back ( * it ) ;
return ;
case type : : Object :
# ifdef CROW_JSON_USE_MAP
o = std : : unique_ptr < std : : map < std : : string , wvalue > > ( new std : : map < std : : string , wvalue > { } ) ;
# else
o = std : : unique_ptr < std : : unordered_map < std : : string , wvalue > > ( new std : : unordered_map < std : : string , wvalue > { } ) ;
# endif
o - > insert ( r . o - > begin ( ) , r . o - > end ( ) ) ;
return ;
}
}
2021-01-05 14:49:10 +00:00
wvalue ( wvalue & & r ) : returnable ( " application/json " )
2014-04-17 13:32:21 +00:00
{
2014-04-17 14:06:41 +00:00
* this = std : : move ( r ) ;
}
wvalue & operator = ( wvalue & & r )
{
2014-04-22 11:19:03 +00:00
t_ = r . t_ ;
2017-10-22 11:31:17 +00:00
num = r . num ;
2014-04-17 14:06:41 +00:00
s = std : : move ( r . s ) ;
l = std : : move ( r . l ) ;
o = std : : move ( r . o ) ;
return * this ;
2014-04-17 13:32:21 +00:00
}
2020-11-18 22:13:57 +00:00
/// Used for compatibility, same as \ref reset()
2014-04-17 13:32:21 +00:00
void clear ( )
{
2017-10-22 11:31:17 +00:00
reset ( ) ;
2014-04-17 13:32:21 +00:00
}
void reset ( )
{
2014-04-22 11:19:03 +00:00
t_ = type : : Null ;
2014-04-17 13:32:21 +00:00
l . reset ( ) ;
o . reset ( ) ;
}
wvalue & operator = ( std : : nullptr_t )
{
reset ( ) ;
return * this ;
}
wvalue & operator = ( bool value )
{
reset ( ) ;
if ( value )
2014-04-22 11:19:03 +00:00
t_ = type : : True ;
2014-04-17 13:32:21 +00:00
else
2014-04-22 11:19:03 +00:00
t_ = type : : False ;
2014-04-17 13:32:21 +00:00
return * this ;
}
wvalue & operator = ( double value )
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . d = value ;
nt = num_type : : Floating_point ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( unsigned short value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . ui = value ;
nt = num_type : : Unsigned_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( short value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . si = value ;
nt = num_type : : Signed_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( long long value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . si = value ;
nt = num_type : : Signed_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( long value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . si = value ;
nt = num_type : : Signed_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( int value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . si = value ;
nt = num_type : : Signed_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
2014-11-08 23:12:43 +00:00
wvalue & operator = ( unsigned long long value )
{
reset ( ) ;
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . ui = value ;
nt = num_type : : Unsigned_integer ;
2014-11-08 23:12:43 +00:00
return * this ;
}
wvalue & operator = ( unsigned long value )
{
reset ( ) ;
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . ui = value ;
nt = num_type : : Unsigned_integer ;
2014-11-08 23:12:43 +00:00
return * this ;
}
wvalue & operator = ( unsigned int value )
2014-04-17 13:32:21 +00:00
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Number ;
2017-10-22 11:31:17 +00:00
num . ui = value ;
nt = num_type : : Unsigned_integer ;
2014-04-17 13:32:21 +00:00
return * this ;
}
wvalue & operator = ( const char * str )
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : String ;
2014-04-17 13:32:21 +00:00
s = str ;
return * this ;
}
wvalue & operator = ( const std : : string & str )
{
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : String ;
2014-04-17 13:32:21 +00:00
s = str ;
return * this ;
}
2017-05-12 02:43:27 +00:00
wvalue & operator = ( std : : vector < wvalue > & & v )
{
if ( t_ ! = type : : List )
reset ( ) ;
t_ = type : : List ;
if ( ! l )
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
l - > clear ( ) ;
l - > resize ( v . size ( ) ) ;
size_t idx = 0 ;
for ( auto & x : v )
{
( * l ) [ idx + + ] = std : : move ( x ) ;
}
return * this ;
}
2014-04-18 22:12:56 +00:00
template < typename T >
2015-01-07 23:20:38 +00:00
wvalue & operator = ( const std : : vector < T > & v )
2014-04-18 22:12:56 +00:00
{
2014-04-22 11:19:03 +00:00
if ( t_ ! = type : : List )
2014-04-18 22:12:56 +00:00
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : List ;
2014-04-18 22:12:56 +00:00
if ( ! l )
2016-08-27 09:03:49 +00:00
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
2014-04-18 22:12:56 +00:00
l - > clear ( ) ;
l - > resize ( v . size ( ) ) ;
size_t idx = 0 ;
for ( auto & x : v )
{
( * l ) [ idx + + ] = x ;
}
return * this ;
}
2014-04-17 13:32:21 +00:00
wvalue & operator [ ] ( unsigned index )
{
2014-04-22 11:19:03 +00:00
if ( t_ ! = type : : List )
2014-04-17 13:32:21 +00:00
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : List ;
2014-04-17 13:32:21 +00:00
if ( ! l )
2016-08-27 09:03:49 +00:00
l = std : : unique_ptr < std : : vector < wvalue > > ( new std : : vector < wvalue > { } ) ;
2014-04-18 22:12:56 +00:00
if ( l - > size ( ) < index + 1 )
l - > resize ( index + 1 ) ;
2014-04-17 13:32:21 +00:00
return ( * l ) [ index ] ;
}
2014-12-11 16:38:57 +00:00
int count ( const std : : string & str )
{
2014-07-30 15:50:38 +00:00
if ( t_ ! = type : : Object )
2014-08-01 21:30:36 +00:00
return 0 ;
2014-07-30 15:50:38 +00:00
if ( ! o )
2014-08-01 21:30:36 +00:00
return 0 ;
2014-07-30 15:50:38 +00:00
return o - > count ( str ) ;
2014-12-11 16:38:57 +00:00
}
2014-07-30 15:50:38 +00:00
2014-04-17 13:32:21 +00:00
wvalue & operator [ ] ( const std : : string & str )
{
2014-04-22 11:19:03 +00:00
if ( t_ ! = type : : Object )
2014-04-17 13:32:21 +00:00
reset ( ) ;
2014-04-22 11:19:03 +00:00
t_ = type : : Object ;
2014-04-17 13:32:21 +00:00
if ( ! o )
2021-05-12 12:45:55 +00:00
# ifdef CROW_JSON_USE_MAP
o = std : : unique_ptr < std : : map < std : : string , wvalue > > ( new std : : map < std : : string , wvalue > { } ) ;
# else
o = std : : unique_ptr < std : : unordered_map < std : : string , wvalue > > ( new std : : unordered_map < std : : string , wvalue > { } ) ;
# endif
2014-04-17 13:32:21 +00:00
return ( * o ) [ str ] ;
}
2017-09-17 16:21:03 +00:00
std : : vector < std : : string > keys ( ) const
{
if ( t_ ! = type : : Object )
return { } ;
2016-10-09 16:05:23 +00:00
std : : vector < std : : string > result ;
2017-09-17 16:21:03 +00:00
for ( auto & kv : * o )
{
result . push_back ( kv . first ) ;
2016-10-09 16:05:23 +00:00
}
2017-09-17 16:21:03 +00:00
return result ;
2016-10-09 16:05:23 +00:00
}
2021-05-12 12:45:55 +00:00
/// If the wvalue is a list, it returns the length of the list, otherwise it returns 1.
std : : size_t size ( ) const
{
if ( t_ ! = type : : List )
return 1 ;
return l - > size ( ) ;
}
/// Returns an estimated size of the value in bytes.
2014-04-17 13:32:21 +00:00
size_t estimate_length ( ) const
{
2014-04-22 11:19:03 +00:00
switch ( t_ )
2014-04-17 13:32:21 +00:00
{
case type : : Null : return 4 ;
case type : : False : return 5 ;
case type : : True : return 4 ;
case type : : Number : return 30 ;
case type : : String : return 2 + s . size ( ) + s . size ( ) / 2 ;
case type : : List :
{
size_t sum { } ;
if ( l )
{
for ( auto & x : * l )
{
sum + = 1 ;
sum + = x . estimate_length ( ) ;
}
}
return sum + 2 ;
}
case type : : Object :
{
size_t sum { } ;
if ( o )
{
for ( auto & kv : * o )
{
sum + = 2 ;
sum + = 2 + kv . first . size ( ) + kv . first . size ( ) / 2 ;
sum + = kv . second . estimate_length ( ) ;
}
}
return sum + 2 ;
}
}
return 1 ;
}
2021-01-05 14:49:10 +00:00
private :
2014-04-17 13:32:21 +00:00
2021-05-18 16:10:39 +00:00
inline void dump_string ( const std : : string & str , std : : string & out ) const
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
out . push_back ( ' " ' ) ;
escape ( str , out ) ;
out . push_back ( ' " ' ) ;
}
2021-05-18 16:10:39 +00:00
inline void dump_internal ( const wvalue & v , std : : string & out ) const
2021-01-05 14:49:10 +00:00
{
switch ( v . t_ )
{
case type : : Null : out + = " null " ; break ;
case type : : False : out + = " false " ; break ;
case type : : True : out + = " true " ; break ;
case type : : Number :
2017-10-22 11:31:17 +00:00
{
2021-01-05 14:49:10 +00:00
if ( v . nt = = num_type : : Floating_point )
{
# ifdef _MSC_VER
# define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE))
# else
# define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE))
# endif
char outbuf [ 128 ] ;
MSC_COMPATIBLE_SPRINTF ( outbuf , " %g " , v . num . d ) ;
out + = outbuf ;
# undef MSC_COMPATIBLE_SPRINTF
}
else if ( v . nt = = num_type : : Signed_integer )
{
out + = std : : to_string ( v . num . si ) ;
}
else
{
out + = std : : to_string ( v . num . ui ) ;
}
2017-10-22 11:31:17 +00:00
}
2021-01-05 14:49:10 +00:00
break ;
case type : : String : dump_string ( v . s , out ) ; break ;
case type : : List :
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
out . push_back ( ' [ ' ) ;
if ( v . l )
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
bool first = true ;
for ( auto & x : * v . l )
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
if ( ! first )
{
out . push_back ( ' , ' ) ;
}
first = false ;
dump_internal ( x , out ) ;
2014-04-17 13:32:21 +00:00
}
}
2021-01-05 14:49:10 +00:00
out . push_back ( ' ] ' ) ;
2014-04-17 13:32:21 +00:00
}
2021-01-05 14:49:10 +00:00
break ;
case type : : Object :
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
out . push_back ( ' { ' ) ;
if ( v . o )
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
bool first = true ;
for ( auto & kv : * v . o )
2014-04-17 13:32:21 +00:00
{
2021-01-05 14:49:10 +00:00
if ( ! first )
{
out . push_back ( ' , ' ) ;
}
first = false ;
dump_string ( kv . first , out ) ;
out . push_back ( ' : ' ) ;
dump_internal ( kv . second , out ) ;
2014-04-17 13:32:21 +00:00
}
}
2021-01-05 14:49:10 +00:00
out . push_back ( ' } ' ) ;
2014-04-17 13:32:21 +00:00
}
2021-01-05 14:49:10 +00:00
break ;
}
2014-04-17 13:32:21 +00:00
}
2021-01-05 14:49:10 +00:00
public :
2021-05-18 16:10:39 +00:00
std : : string dump ( ) const
2021-01-05 14:49:10 +00:00
{
std : : string ret ;
ret . reserve ( estimate_length ( ) ) ;
dump_internal ( * this , ret ) ;
return ret ;
}
} ;
2014-04-17 13:32:21 +00:00
2014-04-18 22:12:56 +00:00
//std::vector<boost::asio::const_buffer> dump_ref(wvalue& v)
2014-04-17 13:32:21 +00:00
//{
//}
}
}
2014-04-18 22:12:56 +00:00
2014-04-26 17:19:59 +00:00
# undef crow_json_likely
# undef crow_json_unlikely