Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,13 @@
project(cppjansson)
set(SRC
jansson_handle.cpp
cppjansson.cpp
jansson_handle.hpp
cppjansson.hpp
)
omim_add_library(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME}
PUBLIC
base
jansson::jansson
)

View file

@ -0,0 +1,148 @@
#include "cppjansson.hpp"
#include <type_traits>
namespace
{
template <typename T>
std::string FromJSONToString(json_t const * root)
{
T result;
FromJSON(root, result);
// TODO(AB): Is std::to_string faster?
return strings::to_string(result);
}
} // namespace
namespace base
{
json_t * GetJSONObligatoryField(json_t * root, std::string const & field)
{
return GetJSONObligatoryField(root, field.c_str());
}
json_t * GetJSONObligatoryField(json_t * root, char const * field)
{
return const_cast<json_t *>(GetJSONObligatoryField(const_cast<json_t const *>(root), field));
}
json_t const * GetJSONObligatoryField(json_t const * root, std::string const & field)
{
return GetJSONObligatoryField(root, field.c_str());
}
json_t const * GetJSONObligatoryField(json_t const * root, char const * field)
{
auto * value = base::GetJSONOptionalField(root, field);
if (!value)
MYTHROW(base::Json::Exception, ("Obligatory field", field, "is absent."));
return value;
}
json_t * GetJSONOptionalField(json_t * root, std::string const & field)
{
return GetJSONOptionalField(root, field.c_str());
}
json_t * GetJSONOptionalField(json_t * root, char const * field)
{
return const_cast<json_t *>(GetJSONOptionalField(const_cast<json_t const *>(root), field));
}
json_t const * GetJSONOptionalField(json_t const * root, std::string const & field)
{
return GetJSONOptionalField(root, field.c_str());
}
json_t const * GetJSONOptionalField(json_t const * root, char const * field)
{
if (!json_is_object(root))
MYTHROW(base::Json::Exception, ("Bad json object while parsing", field));
return json_object_get(root, field);
}
bool JSONIsNull(json_t const * root)
{
return json_is_null(root);
}
std::string DumpToString(JSONPtr const & json, size_t flags)
{
std::string result;
size_t size = json_dumpb(json.get(), nullptr, 0, flags);
if (size == 0)
MYTHROW(base::Json::Exception, ("Zero size JSON while serializing"));
result.resize(size);
if (size != json_dumpb(json.get(), &result.front(), size, flags))
MYTHROW(base::Json::Exception, ("Wrong size JSON written while serializing"));
return result;
}
JSONPtr LoadFromString(std::string const & str)
{
json_error_t jsonError = {};
json_t * result = json_loads(str.c_str(), 0, &jsonError);
if (!result)
MYTHROW(base::Json::Exception, (jsonError.text));
return JSONPtr(result);
}
} // namespace base
void FromJSON(json_t const * root, double & result)
{
if (!json_is_number(root))
MYTHROW(base::Json::Exception, ("Object must contain a json number."));
result = json_number_value(root);
}
void FromJSON(json_t const * root, bool & result)
{
if (!json_is_true(root) && !json_is_false(root))
MYTHROW(base::Json::Exception, ("Object must contain a boolean value."));
result = json_is_true(root);
}
std::string FromJSONToString(json_t const * root)
{
if (json_is_string(root))
return FromJSONToString<std::string>(root);
if (json_is_integer(root))
return FromJSONToString<json_int_t>(root);
if (json_is_real(root))
return FromJSONToString<double>(root);
if (json_is_boolean(root))
return FromJSONToString<bool>(root);
MYTHROW(base::Json::Exception, ("Unexpected json type"));
}
namespace std
{
void FromJSON(json_t const * root, std::string & result)
{
if (!json_is_string(root))
MYTHROW(base::Json::Exception, ("The field must contain a json string."));
result = json_string_value(root);
}
} // namespace std
namespace strings
{
void FromJSON(json_t const * root, UniString & result)
{
std::string s;
FromJSON(root, s);
result = MakeUniString(s);
}
base::JSONPtr ToJSON(UniString const & s)
{
return ToJSON(ToUtf8(s));
}
} // namespace strings

View file

@ -0,0 +1,381 @@
#pragma once
#include "jansson_handle.hpp"
#include "base/exception.hpp"
#include "base/string_utils.hpp"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <jansson.h>
namespace base
{
struct JSONDecRef
{
void operator()(json_t * root) const
{
if (root)
json_decref(root);
}
};
using JSONPtr = std::unique_ptr<json_t, JSONDecRef>;
inline JSONPtr NewJSONObject()
{
return JSONPtr(json_object());
}
inline JSONPtr NewJSONArray()
{
return JSONPtr(json_array());
}
inline JSONPtr NewJSONString(std::string const & s)
{
return JSONPtr(json_string(s.c_str()));
}
inline JSONPtr NewJSONInt(json_int_t value)
{
return JSONPtr(json_integer(value));
}
inline JSONPtr NewJSONReal(double value)
{
return JSONPtr(json_real(value));
}
inline JSONPtr NewJSONBool(bool value)
{
return JSONPtr(value ? json_true() : json_false());
}
inline JSONPtr NewJSONNull()
{
return JSONPtr(json_null());
}
class Json
{
public:
DECLARE_EXCEPTION(Exception, RootException);
Json() = default;
explicit Json(std::string const & s) { ParseFrom(s); }
explicit Json(char const * s) { ParseFrom(s); }
explicit Json(JSONPtr && json) { m_handle.AttachNew(json.release()); }
Json GetDeepCopy() const
{
Json copy;
copy.m_handle.AttachNew(get_deep_copy());
return copy;
}
void ParseFrom(std::string const & s) { ParseFrom(s.c_str()); }
void ParseFrom(char const * s)
{
json_error_t jsonError;
m_handle.AttachNew(json_loads(s, 0, &jsonError));
if (!m_handle)
MYTHROW(Exception, (jsonError.line, jsonError.text));
}
json_t * get() const { return m_handle.get(); }
json_t * get_deep_copy() const { return json_deep_copy(get()); }
private:
JsonHandle m_handle;
};
JSONPtr LoadFromString(std::string const & str);
std::string DumpToString(JSONPtr const & json, size_t flags = 0);
json_t * GetJSONObligatoryField(json_t * root, std::string const & field);
json_t const * GetJSONObligatoryField(json_t const * root, std::string const & field);
json_t * GetJSONObligatoryField(json_t * root, char const * field);
json_t const * GetJSONObligatoryField(json_t const * root, char const * field);
json_t * GetJSONOptionalField(json_t * root, std::string const & field);
json_t const * GetJSONOptionalField(json_t const * root, std::string const & field);
json_t * GetJSONOptionalField(json_t * root, char const * field);
json_t const * GetJSONOptionalField(json_t const * root, char const * field);
template <class First>
inline json_t const * GetJSONObligatoryFieldByPath(json_t const * root, First && path)
{
return GetJSONObligatoryField(root, std::forward<First>(path));
}
template <class First, class... Paths>
inline json_t const * GetJSONObligatoryFieldByPath(json_t const * root, First && path, Paths &&... paths)
{
json_t const * newRoot = GetJSONObligatoryFieldByPath(root, std::forward<First>(path));
return GetJSONObligatoryFieldByPath(newRoot, std::forward<Paths>(paths)...);
}
template <class First>
inline json_t * GetJSONObligatoryFieldByPath(json_t * root, First && path)
{
return GetJSONObligatoryField(root, std::forward<First>(path));
}
template <class First, class... Paths>
inline json_t * GetJSONObligatoryFieldByPath(json_t * root, First && path, Paths &&... paths)
{
json_t * newRoot = GetJSONObligatoryFieldByPath(root, std::forward<First>(path));
return GetJSONObligatoryFieldByPath(newRoot, std::forward<Paths>(paths)...);
}
bool JSONIsNull(json_t const * root);
} // namespace base
template <typename T>
T FromJSON(json_t const * root)
{
T result{};
FromJSON(root, result);
return result;
}
inline void FromJSON(json_t * root, json_t *& value)
{
value = root;
}
inline void FromJSON(json_t const * root, json_t const *& value)
{
value = root;
}
void FromJSON(json_t const * root, double & result);
void FromJSON(json_t const * root, bool & result);
template <typename T, typename std::enable_if<std::is_integral<T>::value, void>::type * = nullptr>
void FromJSON(json_t const * root, T & result)
{
if (!json_is_number(root))
MYTHROW(base::Json::Exception, ("Object must contain a json number."));
result = static_cast<T>(json_integer_value(root));
}
std::string FromJSONToString(json_t const * root);
template <typename T>
T FromJSONObject(json_t const * root, char const * field)
{
auto const * json = base::GetJSONObligatoryField(root, field);
try
{
return FromJSON<T>(json);
}
catch (base::Json::Exception const & e)
{
MYTHROW(base::Json::Exception, ("An error occured while parsing field", field, e.Msg()));
}
}
template <typename T>
void FromJSONObject(json_t * root, std::string const & field, T & result)
{
auto * json = base::GetJSONObligatoryField(root, field);
try
{
FromJSON(json, result);
}
catch (base::Json::Exception const & e)
{
MYTHROW(base::Json::Exception, ("An error occured while parsing field", field, e.Msg()));
}
}
template <typename T>
std::optional<T> FromJSONObjectOptional(json_t const * root, char const * field)
{
auto * json = base::GetJSONOptionalField(root, field);
if (!json)
return {};
std::optional<T> result{T{}};
FromJSON(json, *result);
return result;
}
template <typename T>
void FromJSONObjectOptionalField(json_t const * root, std::string const & field, T & result)
{
auto * json = base::GetJSONOptionalField(root, field);
if (!json)
{
result = T{};
return;
}
FromJSON(json, result);
}
template <typename T, typename std::enable_if<std::is_integral<T>::value, void>::type * = nullptr>
inline base::JSONPtr ToJSON(T value)
{
return base::NewJSONInt(value);
}
inline base::JSONPtr ToJSON(double value)
{
return base::NewJSONReal(value);
}
inline base::JSONPtr ToJSON(bool value)
{
return base::NewJSONBool(value);
}
inline base::JSONPtr ToJSON(char const * s)
{
return base::NewJSONString(s);
}
template <typename T>
void ToJSONArray(json_t & root, T const & value)
{
json_array_append_new(&root, ToJSON(value).release());
}
inline void ToJSONArray(json_t & parent, base::JSONPtr & child)
{
json_array_append_new(&parent, child.release());
}
inline void ToJSONArray(json_t & parent, json_t & child)
{
json_array_append_new(&parent, &child);
}
template <typename T>
void ToJSONObject(json_t & root, char const * field, T const & value)
{
json_object_set_new(&root, field, ToJSON(value).release());
}
inline void ToJSONObject(json_t & parent, char const * field, base::JSONPtr && child)
{
json_object_set_new(&parent, field, child.release());
}
inline void ToJSONObject(json_t & parent, char const * field, base::JSONPtr & child)
{
json_object_set_new(&parent, field, child.release());
}
inline void ToJSONObject(json_t & parent, char const * field, json_t & child)
{
json_object_set_new(&parent, field, &child);
}
template <typename T>
void ToJSONObject(json_t & root, std::string const & field, T const & value)
{
ToJSONObject(root, field.c_str(), value);
}
inline void ToJSONObject(json_t & parent, std::string const & field, base::JSONPtr && child)
{
ToJSONObject(parent, field.c_str(), std::move(child));
}
inline void ToJSONObject(json_t & parent, std::string const & field, base::JSONPtr & child)
{
ToJSONObject(parent, field.c_str(), child);
}
inline void ToJSONObject(json_t & parent, std::string const & field, json_t & child)
{
ToJSONObject(parent, field.c_str(), child);
}
template <typename T>
void FromJSONObject(json_t * root, std::string const & field, std::vector<T> & result)
{
auto * arr = base::GetJSONObligatoryField(root, field);
if (!json_is_array(arr))
MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array."));
size_t sz = json_array_size(arr);
result.resize(sz);
for (size_t i = 0; i < sz; ++i)
FromJSON(json_array_get(arr, i), result[i]);
}
// The function tries to parse array of values from a value
// corresponding to |field| in a json object corresponding to |root|.
// Returns true when the value is non-null and array is successfully
// parsed. Returns false when there is no such |field| in the |root|
// or the value is null. Also, the method may throw an exception in
// case of json parsing errors.
template <typename T>
bool FromJSONObjectOptional(json_t * root, std::string const & field, std::vector<T> & result)
{
auto * arr = base::GetJSONOptionalField(root, field);
if (!arr || base::JSONIsNull(arr))
{
result.clear();
return false;
}
if (!json_is_array(arr))
MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array."));
size_t const sz = json_array_size(arr);
result.resize(sz);
for (size_t i = 0; i < sz; ++i)
FromJSON(json_array_get(arr, i), result[i]);
return true;
}
template <typename T>
void ToJSONObject(json_t & root, char const * field, std::vector<T> const & values)
{
auto arr = base::NewJSONArray();
for (auto const & value : values)
json_array_append_new(arr.get(), ToJSON(value).release());
json_object_set_new(&root, field, arr.release());
}
template <typename T>
void ToJSONObject(json_t & root, std::string const & field, std::vector<T> const & values)
{
ToJSONObject(root, field.c_str(), values);
}
template <typename T>
void FromJSONObjectOptionalField(json_t * root, std::string const & field, std::vector<T> & result)
{
FromJSONObjectOptionalField(const_cast<json_t const *>(root), field, result);
}
template <typename T>
void FromJSONObjectOptionalField(json_t const * root, std::string const & field, std::vector<T> & result)
{
json_t const * arr = base::GetJSONOptionalField(root, field);
if (!arr)
{
result.clear();
return;
}
if (!json_is_array(arr))
MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array."));
size_t sz = json_array_size(arr);
result.resize(sz);
for (size_t i = 0; i < sz; ++i)
FromJSON(json_array_get(arr, i), result[i]);
}
struct JSONFreeDeleter
{
void operator()(char * buffer) const { free(buffer); }
};
namespace std
{
void FromJSON(json_t const * root, std::string & result);
inline base::JSONPtr ToJSON(std::string const & s)
{
return base::NewJSONString(s);
}
} // namespace std
namespace strings
{
void FromJSON(json_t const * root, UniString & result);
base::JSONPtr ToJSON(UniString const & s);
} // namespace strings

View file

@ -0,0 +1,18 @@
#include "jansson_handle.hpp"
#include <jansson.h>
namespace base
{
void JsonHandle::IncRef()
{
if (m_pJson)
json_incref(m_pJson);
}
void JsonHandle::DecRef()
{
if (m_pJson)
json_decref(m_pJson);
}
} // namespace base

View file

@ -0,0 +1,47 @@
#pragma once
#include <algorithm>
struct json_t;
namespace base
{
class JsonHandle
{
void IncRef();
void DecRef();
public:
JsonHandle(json_t * pJson = 0) : m_pJson(pJson) { IncRef(); }
JsonHandle(JsonHandle const & json) : m_pJson(json.m_pJson) { IncRef(); }
~JsonHandle() { DecRef(); }
JsonHandle & operator=(JsonHandle const & json)
{
JsonHandle tmp(json);
tmp.swap(*this);
return *this;
}
void swap(JsonHandle & json) { std::swap(m_pJson, json.m_pJson); }
json_t * get() const { return m_pJson; }
json_t * operator->() const { return m_pJson; }
operator bool() const { return m_pJson != 0; }
/// Attach newly created object without incrementing ref count (it's already == 1).
void AttachNew(json_t * pJson)
{
DecRef();
m_pJson = pJson;
}
private:
json_t * m_pJson;
};
} // namespace base