32
32
#include " flexbuffer_json.h"
33
33
#include " init.h"
34
34
#include " int_id.h"
35
+ #include " json.h"
35
36
#include " mod_tracker.h"
36
37
#include " string_formatter.h"
37
38
#include " string_id.h"
@@ -1908,13 +1909,19 @@ class string_id_reader : public generic_typed_reader<string_id_reader<T>>
1908
1909
1909
1910
/* *
1910
1911
* Loads std::pair of [K = string_id, V = int/float] values from JSON -- usually into an std::map
1912
+ * It can load either an array, an object, or a single value
1911
1913
* Accepted formats for elements in an array:
1912
1914
* 1. A named key/value pair object: "addiction_type": [ { "addiction": "caffeine", "potential": 3 } ]
1913
1915
* 2. A key/value pair array: "addiction_type": [ [ "caffeine", 3 ] ]
1914
1916
* 3. A single value: "addiction_type": [ "caffeine" ]
1915
- * A single value can also be provided outside of an array, e.g. "addiction_type": "caffeine"
1917
+ * For an object, only the following format is supported
1918
+ * 4. "addiction_type": { "caffeine": 3, "alcohol": 2 }
1919
+ * A single value can be provided as follows:
1920
+ * 5. "addiction_type": "caffeine"
1916
1921
* For single values, weights are assigned default_weight
1917
1922
*/
1923
+ // TODO: format 1 is quite gross, and just accepts arbitrary keys. The only way it works is by limiting
1924
+ // the types of V, which is unfortunate
1918
1925
template <typename K, typename V>
1919
1926
class weighted_string_id_reader : public generic_typed_reader <weighted_string_id_reader<K, V>>
1920
1927
{
@@ -1966,87 +1973,86 @@ class weighted_string_id_reader : public generic_typed_reader<weighted_string_id
1966
1973
}
1967
1974
};
1968
1975
1976
+ // For loading pairs from a JSON object. { "a1": b1, "a2": b2 }, etc
1977
+ // Only supports JSON objects! Json objects are not ordered, so if you're using something where
1978
+ // the order matters, use pair_reader.
1969
1979
template <typename K, typename V>
1970
1980
class generic_map_reader : public generic_typed_reader <generic_map_reader<K, V>>
1971
1981
{
1972
1982
public:
1973
1983
static constexpr bool read_objects = true ;
1974
1984
1985
+ static_assert ( key_from_json_string<K>::valid, " Type K must have a known conversion from string" );
1986
+
1975
1987
std::pair<K, V> get_next ( const JsonValue &jv ) const {
1976
1988
const JsonMember *jm = dynamic_cast <const JsonMember *>( &jv );
1977
1989
if ( jm == nullptr ) {
1978
1990
jv.throw_error ( " not part of a JsonObject" );
1979
1991
}
1980
- K key ( jm->name () );
1992
+ K key = key_from_json_string<K>() ( jm->name () );
1981
1993
V value;
1982
1994
jv.read ( value, true );
1983
1995
return std::pair<K, V>( key, value );
1984
1996
}
1985
1997
};
1986
1998
1987
- // Support shorthand for a single value.
1988
- template <typename T>
1989
- class pair_reader : public generic_typed_reader <pair_reader<T>>
1990
- {
1991
- public:
1992
- std::pair<T, T> get_next ( const JsonValue &jv ) const {
1993
- if ( jv.test_float () ) {
1994
- T val;
1995
- jv.read ( val, true );
1996
- return std::make_pair ( val, val );
1997
- }
1998
- if ( !jv.test_array () ) {
1999
- jv.throw_error ( " bad pair" );
2000
- }
2001
- JsonArray ja = jv.get_array ();
2002
- if ( ja.size () != 2 ) {
2003
- ja.throw_error ( " Must have 2 elements" );
2004
- }
2005
- T l;
2006
- T h;
2007
- ja[0 ].read ( l, true );
2008
- ja[1 ].read ( h, true );
2009
- return std::make_pair ( l, h );
2010
- }
2011
- };
2012
-
2013
- // Reads into a vector of pairs in the format (example)
2014
- // "growth_stages": [ { "GROWTH_SEED": "23 days" }, { "GROWTH_SEEDLING": "23 days" }, { "GROWTH_MATURE": "23 days" }, { "GROWTH_HARVEST": "22 days" } ]
2015
- // OR
2016
- // "growth_stages": [ [ "GROWTH_SEED", "23 days" ], [ "GROWTH_SEEDLING", "23 days" ], [ "GROWTH_MATURE", "23 days" ], [ "GROWTH_HARVEST", "22 days" ] ]
2017
- // The key(K) of the pair object must be string constructable.
2018
- template <typename K, typename V>
2019
- class vector_pair_reader : public generic_typed_reader <vector_pair_reader<K, V>>
1999
+ // Supports three formats:
2000
+ // 1. [ a, b ]
2001
+ // 2. { "a": b }, if there exists a key_from_json_string specialization for a
2002
+ // 3. a, if T = U and a is not represented in JSON as an array or object (iff the object format is valid)
2003
+ // This would load [ "a", [ "b", "c" ], { "d": "e" } ] into three pairs:
2004
+ // ("a", "a"), ("b", "c"), ("d", "e")
2005
+ //
2006
+ // If you only need format 1, you can also use json_read_reader<std::pair<T, U>>
2007
+ //
2008
+ // TODO: constructor argument to enable/disable the shorthand format?
2009
+ template <typename T, typename U = T>
2010
+ class pair_reader : public generic_typed_reader <pair_reader<T, U>>
2020
2011
{
2021
2012
public:
2022
- std::pair<K, V> get_next ( const JsonValue &jv ) const {
2023
- if ( jv.test_object () ) {
2024
- JsonObject jo = jv.get_object ();
2025
- if ( jo.size () != 1 ) {
2026
- jv.throw_error ( string_format ( " Expected size of 1 for JsonObject, found size %d" , jo.size () ) );
2013
+ std::pair<T, U> get_next ( const JsonValue &jv ) const {
2014
+ // elements of the pair to return
2015
+ T a;
2016
+ U b;
2017
+ // [ a, b ]
2018
+ if ( jv.test_array () ) {
2019
+ JsonArray ja = jv.get_array ();
2020
+ if ( ja.size () != 2 ) {
2021
+ ja.throw_error ( " Must have 2 elements" );
2027
2022
}
2028
- for ( JsonMember jm : jo ) {
2029
- K key ( jm.name () );
2030
- V ret;
2031
- jm.read ( ret );
2032
- return std::make_pair ( key, ret );
2023
+ ja[0 ].read ( a, true );
2024
+ ja[1 ].read ( b, true );
2025
+ return std::make_pair ( a, b );
2026
+ }
2027
+ // { "a": b }
2028
+ if constexpr ( key_from_json_string<T>::valid ) {
2029
+ if ( jv.test_object () ) {
2030
+ JsonObject jo = jv.get_object ();
2031
+ if ( jo.size () != 1 ) {
2032
+ jo.throw_error ( " bad object pair, has too many elements" );
2033
+ }
2034
+ // gross - we need to get the name of the member, this just unwraps it
2035
+ for ( JsonMember jm : jo ) {
2036
+ a = key_from_json_string<T>()( jm.name () );
2037
+ jm.read ( b, true );
2038
+ return std::make_pair ( a, b );
2039
+ }
2033
2040
}
2034
2041
}
2035
- if ( !jv.test_array () ) {
2036
- jv.throw_error ( " bad pair" );
2037
- }
2038
- JsonArray ja = jv.get_array ();
2039
- if ( ja.size () != 2 ) {
2040
- ja.throw_error ( " Must have 2 elements" );
2042
+ // shorthand for a = b
2043
+ if constexpr ( std::is_same_v<T, U> ) {
2044
+ jv.read ( a, true );
2045
+ b = a;
2046
+ return std::make_pair ( a, b );
2041
2047
}
2042
- K l;
2043
- V h;
2044
- ja[0 ].read ( l, true );
2045
- ja[1 ].read ( h, true );
2046
- return std::make_pair ( l, h );
2048
+ jv.throw_error ( " bad pair" );
2049
+ return std::make_pair ( a, b );
2047
2050
}
2048
2051
};
2049
2052
2053
+ // Loads pairs as objects { key1: t1, key2: t2 }, or just t1, which uses the default for the value of t2
2054
+ // e.g. named_pair_reader<string, int>( "a", "b", 3 ) loads
2055
+ // [ "1", { "a": "3", "b": 4 } ] -> ("1", 3), ("3", 4)
2050
2056
template <typename T1, typename T2>
2051
2057
class named_pair_reader : public generic_typed_reader <named_pair_reader<T1, T2>>
2052
2058
{
@@ -2070,7 +2076,7 @@ class named_pair_reader : public generic_typed_reader<named_pair_reader<T1, T2>>
2070
2076
jo.read ( key2, ret.second , true );
2071
2077
return ret;
2072
2078
}
2073
- // TODO: support pair format?
2079
+ // TODO: support pair format? Forward to pair_reader<T1, T2>?
2074
2080
if ( jv.test_array () ) {
2075
2081
jv.throw_error ( " invalid format" );
2076
2082
}
0 commit comments