revised adding string_view and stuct { const char * }

This commit is contained in:
Timothy Prepscius 2018-10-23 21:09:16 -04:00
parent e66a3e5242
commit b76eaabd9b
5 changed files with 365 additions and 40 deletions

View File

@ -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;

View File

@ -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;

View 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

View File

@ -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);

View File

@ -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));
}
/// @}