revised adding string_view and stuct { const char * }
This commit is contained in:
parent
e66a3e5242
commit
b76eaabd9b
@ -6,6 +6,7 @@
|
||||
|
||||
#include <nlohmann/detail/input/parser.hpp>
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/json_string_view.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
@ -21,6 +22,7 @@ input.
|
||||
template<typename BasicJsonType>
|
||||
struct json_sax
|
||||
{
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
/// type for (signed) integers
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
/// type for unsigned integers
|
||||
@ -143,6 +145,7 @@ template<typename BasicJsonType>
|
||||
class json_sax_dom_parser
|
||||
{
|
||||
public:
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
@ -209,7 +212,7 @@ class json_sax_dom_parser
|
||||
bool key(string_t& val)
|
||||
{
|
||||
// add null at given key and store the reference for later
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](val));
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](to_map_key<typename object_t::key_type>(val)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -318,6 +321,7 @@ template<typename BasicJsonType>
|
||||
class json_sax_dom_callback_parser
|
||||
{
|
||||
public:
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
@ -402,7 +406,7 @@ class json_sax_dom_callback_parser
|
||||
// add discarded value at given key and store the reference for later
|
||||
if (keep and ref_stack.back())
|
||||
{
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
|
||||
object_element = &(ref_stack.back()->m_value.object->operator[](to_map_key<typename object_t::key_type>(val)) = discarded);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include <nlohmann/detail/input/json_sax.hpp>
|
||||
#include <nlohmann/detail/input/lexer.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
#include <nlohmann/detail/json_string_view.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
@ -31,6 +32,7 @@ This class implements a recursive decent parser.
|
||||
template<typename BasicJsonType>
|
||||
class parser
|
||||
{
|
||||
using object_t = typename BasicJsonType::object_t;
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
|
||||
257
include/nlohmann/detail/json_string_view.hpp
Normal file
257
include/nlohmann/detail/json_string_view.hpp
Normal file
@ -0,0 +1,257 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// This header, and the associated changes in json.hpp enable string_view and struct { const char * } as a map_key type.
|
||||
//
|
||||
// Why would you want this? In my case, I am using millions of json objects, each one uses the same keys.
|
||||
// Why use objects at all? This is a question for another time.
|
||||
//
|
||||
// In any case, since my keys are known, and finite, I would rather there be a key look-up table, so as to no have a billion copies
|
||||
// of "transform" lying around. I would rather just have one.
|
||||
//
|
||||
// The differences of string_view and const char * are simple.
|
||||
// string_view uses a strcmp in it's core of the map lookup, so there is no performance increase.
|
||||
// struct { const char * } uses a pure pointer comparison, so map operations are super fast, and as well, the map should probably be changed
|
||||
// into a hash map using the pointers.
|
||||
//
|
||||
// The draw back of the struct { const char * }, is that, for the full performance, you must cache the correct to_map_key("my_key_value")
|
||||
// and use that (so it doesn't need to look up the correct pointer first). This is trivial to do however, so, the performance increase
|
||||
// is great.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef USE_EXPERIMENTAL_STRINGVIEW
|
||||
#include <experimental/string_view>
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
|
||||
#ifdef USE_EXPERIMENTAL_STRINGVIEW
|
||||
using json_string_view = std::experimental::string_view;
|
||||
#else
|
||||
|
||||
// a minimum implementation of string_view
|
||||
struct json_string_view
|
||||
{
|
||||
const char *data_;
|
||||
size_t size_;
|
||||
|
||||
json_string_view(const char *data, size_t size) :
|
||||
data_(data), size_(size)
|
||||
{}
|
||||
|
||||
json_string_view(const std::string &s) :
|
||||
data_(s.c_str()), size_(s.size())
|
||||
{
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return std::string(data_, size_);
|
||||
}
|
||||
|
||||
const char *begin() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const char *end () const
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
} ;
|
||||
|
||||
inline
|
||||
bool operator ==(const json_string_view &l, const json_string_view &r)
|
||||
{
|
||||
if (l.data_ == r.data_ && l.size_ == r.size_)
|
||||
return true;
|
||||
|
||||
return l.size_ == r.size_ && strncmp(l.data_, r.data_, l.size_) == 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator !=(const json_string_view &l, const json_string_view &r)
|
||||
{
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator <(const json_string_view &l, const json_string_view &r)
|
||||
{
|
||||
// will implement, i need to look up proper way to do this
|
||||
std::string ls(l);
|
||||
std::string rs(r);
|
||||
return ls < rs;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------
|
||||
|
||||
struct json_const_char_star {
|
||||
const char *data;
|
||||
} ;
|
||||
|
||||
inline
|
||||
bool operator ==(const json_const_char_star &l, const json_const_char_star &r)
|
||||
{
|
||||
return (l.data == r.data);
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator !=(const json_const_char_star &l, const json_const_char_star &r)
|
||||
{
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator <(const json_const_char_star &l, const json_const_char_star &r)
|
||||
{
|
||||
// pure pointer compare
|
||||
return l.data < r.data;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
// why am I having trouble getting rid of this? it must be too late
|
||||
typedef const char *__stupid_const_char_typedef;
|
||||
|
||||
template<typename R> inline R to_map_key(const __stupid_const_char_typedef &s);
|
||||
template<typename R> inline R to_map_key(const json_string_view &s);
|
||||
template<typename R> inline R to_map_key(const std::string &s);
|
||||
template<typename R> inline R to_map_key(const json_const_char_star &s);
|
||||
|
||||
template<typename R> inline R to_lookup_key(const __stupid_const_char_typedef &s);
|
||||
template<typename R> inline R to_lookup_key(const json_string_view &s);
|
||||
template<typename R> inline R to_lookup_key(const std::string &s);
|
||||
template<typename R> inline R to_lookup_key(const json_const_char_star &s);
|
||||
|
||||
template<typename T, typename R=std::string>
|
||||
inline R to_concatable_string(const T &t)
|
||||
{
|
||||
return R(t);
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
template<>
|
||||
inline json_string_view to_map_key(const json_string_view &s)
|
||||
{
|
||||
static std::set<std::string> strings;
|
||||
static std::set<json_string_view> internals;
|
||||
|
||||
auto i = internals.find(s);
|
||||
if (i == internals.end())
|
||||
{
|
||||
std::string str(s.begin(), s.end());
|
||||
strings.insert(str);
|
||||
|
||||
auto sv = json_string_view(*strings.find(str));
|
||||
|
||||
internals.insert(sv);
|
||||
return sv;
|
||||
}
|
||||
|
||||
return *i;
|
||||
} ;
|
||||
|
||||
template<>
|
||||
inline json_string_view to_map_key(const std::string &s)
|
||||
{
|
||||
return to_map_key<json_string_view>(json_string_view(s));
|
||||
} ;
|
||||
|
||||
template<>
|
||||
inline json_string_view to_map_key(const __stupid_const_char_typedef &s)
|
||||
{
|
||||
return to_map_key<json_string_view>(json_string_view(s, strlen(s)));
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
|
||||
template<>
|
||||
inline json_string_view to_lookup_key(const json_string_view &s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline json_string_view to_lookup_key(const std::string &s)
|
||||
{
|
||||
return json_string_view(s);
|
||||
} ;
|
||||
|
||||
template<>
|
||||
inline json_string_view to_lookup_key(const __stupid_const_char_typedef &s)
|
||||
{
|
||||
return json_string_view(s, strlen(s));
|
||||
} ;
|
||||
|
||||
// -----------------------
|
||||
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_map_key(const std::string &s)
|
||||
{
|
||||
static std::set<std::string> strings;
|
||||
|
||||
auto i = strings.find(s);
|
||||
if (i == strings.end())
|
||||
{
|
||||
std::string str(s);
|
||||
strings.insert(str);
|
||||
|
||||
i = strings.find(str);
|
||||
}
|
||||
|
||||
return { i->c_str() };
|
||||
} ;
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_map_key(const __stupid_const_char_typedef &s)
|
||||
{
|
||||
return to_map_key<json_const_char_star>(std::string(s));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_map_key(const json_const_char_star &s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_lookup_key(const std::string &s)
|
||||
{
|
||||
return to_map_key<json_const_char_star>(s);
|
||||
} ;
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_lookup_key(const __stupid_const_char_typedef &s)
|
||||
{
|
||||
return to_map_key<json_const_char_star>(s);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline json_const_char_star to_lookup_key(const json_const_char_star &s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
std::string to_concatable_string(const json_const_char_star &t)
|
||||
{
|
||||
return std::string(t.data);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
@ -106,7 +106,7 @@ class serializer
|
||||
{
|
||||
o->write_characters(indent_string.c_str(), new_indent);
|
||||
o->write_character('\"');
|
||||
dump_escaped(i->first, ensure_ascii);
|
||||
dump_escaped(to_concatable_string(i->first), ensure_ascii);
|
||||
o->write_characters("\": ", 3);
|
||||
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
||||
o->write_characters(",\n", 2);
|
||||
@ -117,7 +117,7 @@ class serializer
|
||||
assert(std::next(i) == val.m_value.object->cend());
|
||||
o->write_characters(indent_string.c_str(), new_indent);
|
||||
o->write_character('\"');
|
||||
dump_escaped(i->first, ensure_ascii);
|
||||
dump_escaped(to_concatable_string(i->first), ensure_ascii);
|
||||
o->write_characters("\": ", 3);
|
||||
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
||||
|
||||
@ -134,7 +134,7 @@ class serializer
|
||||
for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
|
||||
{
|
||||
o->write_character('\"');
|
||||
dump_escaped(i->first, ensure_ascii);
|
||||
dump_escaped(to_concatable_string(i->first), ensure_ascii);
|
||||
o->write_characters("\":", 2);
|
||||
dump(i->second, false, ensure_ascii, indent_step, current_indent);
|
||||
o->write_character(',');
|
||||
@ -144,7 +144,7 @@ class serializer
|
||||
assert(i != val.m_value.object->cend());
|
||||
assert(std::next(i) == val.m_value.object->cend());
|
||||
o->write_character('\"');
|
||||
dump_escaped(i->first, ensure_ascii);
|
||||
dump_escaped(to_concatable_string(i->first), ensure_ascii);
|
||||
o->write_characters("\":", 2);
|
||||
dump(i->second, false, ensure_ascii, indent_step, current_indent);
|
||||
|
||||
|
||||
@ -68,6 +68,7 @@ SOFTWARE.
|
||||
#include <nlohmann/detail/output/serializer.hpp>
|
||||
#include <nlohmann/detail/json_ref.hpp>
|
||||
#include <nlohmann/detail/json_pointer.hpp>
|
||||
#include <nlohmann/detail/json_string_view.hpp>
|
||||
#include <nlohmann/adl_serializer.hpp>
|
||||
|
||||
/*!
|
||||
@ -162,6 +163,10 @@ Format](http://rfc7159.net/rfc7159)
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
class basic_json
|
||||
{
|
||||
public:
|
||||
// these definitions should come
|
||||
typedef json_string_view map_key_type;
|
||||
|
||||
private:
|
||||
template<detail::value_t> friend struct detail::external_constructor;
|
||||
friend ::nlohmann::json_pointer<basic_json>;
|
||||
@ -471,7 +476,7 @@ class basic_json
|
||||
7159](http://rfc7159.net/rfc7159), because any order implements the
|
||||
specified "unordered" nature of JSON objects.
|
||||
*/
|
||||
using object_t = ObjectType<StringType,
|
||||
using object_t = ObjectType<map_key_type,
|
||||
basic_json,
|
||||
object_comparator_t,
|
||||
AllocatorType<std::pair<const StringType,
|
||||
@ -1436,7 +1441,7 @@ class basic_json
|
||||
{
|
||||
auto element = element_ref.moved_or_copied();
|
||||
m_value.object->emplace(
|
||||
std::move(*((*element.m_value.array)[0].m_value.string)),
|
||||
std::move(to_map_key<typename object_t::key_type>(*((*element.m_value.array)[0].m_value.string))),
|
||||
std::move((*element.m_value.array)[1]));
|
||||
});
|
||||
}
|
||||
@ -3006,7 +3011,7 @@ class basic_json
|
||||
JSON_CATCH (std::out_of_range&)
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
|
||||
JSON_THROW(out_of_range::create(403, "key '" + to_concatable_string(key) + "' not found"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3014,6 +3019,13 @@ class basic_json
|
||||
JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
reference at(const T& key_)
|
||||
{
|
||||
auto key = to_lookup_key<typename object_t::key_type>(key_);
|
||||
return at(key);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief access specified object element with bounds checking
|
||||
@ -3045,7 +3057,7 @@ class basic_json
|
||||
`at()`. It also demonstrates the different exceptions that can be thrown.,
|
||||
at__object_t_key_type_const}
|
||||
*/
|
||||
const_reference at(const typename object_t::key_type& key) const
|
||||
const_reference at(const typename object_t::key_type & key) const
|
||||
{
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@ -3057,7 +3069,7 @@ class basic_json
|
||||
JSON_CATCH (std::out_of_range&)
|
||||
{
|
||||
// create better exception explanation
|
||||
JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
|
||||
JSON_THROW(out_of_range::create(403, "key '" + to_concatable_string(key) + "' not found"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3066,6 +3078,13 @@ class basic_json
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const_reference at(const T& key_) const
|
||||
{
|
||||
auto key = to_lookup_key<typename object_t::key_type>(key_);
|
||||
return at(key);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief access specified array element
|
||||
|
||||
@ -3117,6 +3136,12 @@ class basic_json
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
|
||||
}
|
||||
|
||||
reference operator[](int idx)
|
||||
{
|
||||
return operator[](size_t(idx));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@brief access specified array element
|
||||
@ -3148,6 +3173,11 @@ class basic_json
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
|
||||
}
|
||||
|
||||
const_reference operator[](int idx) const
|
||||
{
|
||||
return operator[](size_t(idx));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief access specified object element
|
||||
|
||||
@ -3175,7 +3205,7 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
reference operator[](const typename object_t::key_type& key)
|
||||
reference operator[](const typename object_t::key_type& key_)
|
||||
{
|
||||
// implicitly convert null value to an empty object
|
||||
if (is_null())
|
||||
@ -3188,6 +3218,11 @@ class basic_json
|
||||
// operator[] only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
{
|
||||
auto i = m_value.object->find(key_);
|
||||
if (i != m_value.object->end())
|
||||
return i->second;
|
||||
|
||||
auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
return m_value.object->operator[](key);
|
||||
}
|
||||
|
||||
@ -3263,26 +3298,25 @@ class basic_json
|
||||
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
reference operator[](T* key)
|
||||
template<typename T>
|
||||
reference operator[](const T &key_)
|
||||
{
|
||||
// implicitly convert null to object
|
||||
if (is_null())
|
||||
{
|
||||
m_type = value_t::object;
|
||||
m_value = value_t::object;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
{
|
||||
return m_value.object->operator[](key);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
|
||||
auto key = to_lookup_key<typename object_t::key_type>(key_);
|
||||
return operator[](key);
|
||||
}
|
||||
|
||||
// reference operator[](const std::string &key_)
|
||||
// {
|
||||
// auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
// return operator[](key);
|
||||
// }
|
||||
//
|
||||
// reference operator[](const char *key_)
|
||||
// {
|
||||
// auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
// return operator[](key);
|
||||
// }
|
||||
|
||||
/*!
|
||||
@brief read-only access specified object element
|
||||
|
||||
@ -3313,19 +3347,25 @@ class basic_json
|
||||
|
||||
@since version 1.1.0
|
||||
*/
|
||||
template<typename T>
|
||||
const_reference operator[](T* key) const
|
||||
template<typename T>
|
||||
const_reference operator[](const T &key_) const
|
||||
{
|
||||
// at only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
{
|
||||
assert(m_value.object->find(key) != m_value.object->end());
|
||||
return m_value.object->find(key)->second;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
|
||||
auto key = to_lookup_key<typename object_t::key_type>(key_);
|
||||
return operator[](key);
|
||||
}
|
||||
|
||||
// const_reference operator[](const std::string &key_) const
|
||||
// {
|
||||
// auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
// return operator[](key);
|
||||
// }
|
||||
//
|
||||
// const_reference operator[](const char *key_) const
|
||||
// {
|
||||
// auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
// return operator[](key);
|
||||
// }
|
||||
|
||||
/*!
|
||||
@brief access specified object element with default value
|
||||
|
||||
@ -3802,7 +3842,7 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
size_type erase(const typename object_t::key_type& key)
|
||||
size_type erase(const typename object_t::key_type & key)
|
||||
{
|
||||
// this erase only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
@ -3813,6 +3853,24 @@ class basic_json
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_type erase(const T& key_)
|
||||
{
|
||||
auto key = to_map_key<typename object_t::key_type>(key_);
|
||||
return erase(key);
|
||||
}
|
||||
|
||||
void erase(const iterator &key)
|
||||
{
|
||||
// this erase only works for objects
|
||||
if (JSON_LIKELY(is_object()))
|
||||
{
|
||||
m_value.object->erase(key.m_it.object_iterator);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief remove element from a JSON array given an index
|
||||
|
||||
@ -3855,6 +3913,10 @@ class basic_json
|
||||
}
|
||||
}
|
||||
|
||||
void erase(int idx)
|
||||
{
|
||||
erase(static_cast<size_t>(idx));
|
||||
}
|
||||
/// @}
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user