diff --git a/include/xgboost/json.h b/include/xgboost/json.h deleted file mode 100644 index 97dc2e11d396..000000000000 --- a/include/xgboost/json.h +++ /dev/null @@ -1,555 +0,0 @@ -/*! - * Copyright (c) by Contributors 2019 - */ -#ifndef XGBOOST_JSON_H_ -#define XGBOOST_JSON_H_ - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace xgboost { - -class Json; -class JsonReader; -class JsonWriter; - -class Value { - public: - /*!\brief Simplified implementation of LLVM RTTI. */ - enum class ValueKind { - String, - Number, - Integer, - Object, // std::map - Array, // std::vector - Boolean, - Null - }; - - explicit Value(ValueKind _kind) : kind_{_kind} {} - - ValueKind Type() const { return kind_; } - virtual ~Value() = default; - - virtual void Save(JsonWriter* writer) = 0; - - virtual Json& operator[](std::string const & key) = 0; - virtual Json& operator[](int ind) = 0; - - virtual bool operator==(Value const& rhs) const = 0; - virtual Value& operator=(Value const& rhs) = 0; - - std::string TypeStr() const; - - private: - ValueKind kind_; -}; - -template -bool IsA(Value const* value) { - return T::isClassOf(value); -} - -template -T* Cast(U* value) { - if (IsA(value)) { - return dynamic_cast(value); - } else { - LOG(FATAL) << "Invalid cast, from " + value->TypeStr() + " to " + T().TypeStr(); - } - return dynamic_cast(value); // supress compiler warning. -} - -class JsonString : public Value { - std::string str_; - public: - JsonString() : Value(ValueKind::String) {} - JsonString(std::string const& str) : // NOLINT - Value(ValueKind::String), str_{str} {} - JsonString(std::string&& str) : // NOLINT - Value(ValueKind::String), str_{std::move(str)} {} - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - std::string const& getString() && { return str_; } - std::string const& getString() const & { return str_; } - std::string& getString() & { return str_; } - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::String; - } -}; - -class JsonArray : public Value { - std::vector vec_; - - public: - JsonArray() : Value(ValueKind::Array) {} - JsonArray(std::vector&& arr) : // NOLINT - Value(ValueKind::Array), vec_{std::move(arr)} {} - JsonArray(std::vector const& arr) : // NOLINT - Value(ValueKind::Array), vec_{arr} {} - JsonArray(JsonArray const& that) = delete; - JsonArray(JsonArray && that); - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - std::vector const& getArray() && { return vec_; } - std::vector const& getArray() const & { return vec_; } - std::vector& getArray() & { return vec_; } - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Array; - } -}; - -class JsonObject : public Value { - std::map object_; - - public: - JsonObject() : Value(ValueKind::Object) {} - JsonObject(std::map&& object); // NOLINT - JsonObject(JsonObject const& that) = delete; - JsonObject(JsonObject && that); - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - std::map const& getObject() && { return object_; } - std::map const& getObject() const & { return object_; } - std::map & getObject() & { return object_; } - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Object; - } - virtual ~JsonObject() = default; -}; - -class JsonNumber : public Value { - public: - using Float = float; - - private: - Float number_; - - public: - JsonNumber() : Value(ValueKind::Number) {} - template ::value>::type* = nullptr> - JsonNumber(FloatT value) : Value(ValueKind::Number) { // NOLINT - number_ = value; - } - template ::value>::type* = nullptr> - JsonNumber(FloatT value) : Value{ValueKind::Number}, // NOLINT - number_{static_cast(value)} {} - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - Float const& getNumber() && { return number_; } - Float const& getNumber() const & { return number_; } - Float& getNumber() & { return number_; } - - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Number; - } -}; - -class JsonInteger : public Value { - public: - using Int = int64_t; - - private: - Int integer_; - - public: - JsonInteger() : Value(ValueKind::Integer), integer_{0} {} // NOLINT - template ::value>::type* = nullptr> - JsonInteger(IntT value) : Value(ValueKind::Integer), integer_{value} {} // NOLINT - template ::value>::type* = nullptr> - JsonInteger(IntT value) : Value(ValueKind::Integer), // NOLINT - integer_{static_cast(value)} {} - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - Int const& getInteger() && { return integer_; } - Int const& getInteger() const & { return integer_; } - Int& getInteger() & { return integer_; } - void Save(JsonWriter* writer) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Integer; - } -}; - -class JsonNull : public Value { - public: - JsonNull() : Value(ValueKind::Null) {} - JsonNull(std::nullptr_t) : Value(ValueKind::Null) {} // NOLINT - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Null; - } -}; - -/*! \brief Describes both true and false. */ -class JsonBoolean : public Value { - bool boolean_; - - public: - JsonBoolean() : Value(ValueKind::Boolean) {} // NOLINT - // Ambigious with JsonNumber. - template ::value || - std::is_same::value>::type* = nullptr> - JsonBoolean(Bool value) : // NOLINT - Value(ValueKind::Boolean), boolean_{value} {} - - void Save(JsonWriter* writer) override; - - Json& operator[](std::string const & key) override; - Json& operator[](int ind) override; - - bool const& getBoolean() && { return boolean_; } - bool const& getBoolean() const & { return boolean_; } - bool& getBoolean() & { return boolean_; } - - bool operator==(Value const& rhs) const override; - Value& operator=(Value const& rhs) override; - - static bool isClassOf(Value const* value) { - return value->Type() == ValueKind::Boolean; - } -}; - -struct StringView { - using CharT = char; // unsigned char - CharT const* str_; - size_t size_; - - public: - StringView() = default; - StringView(CharT const* str, size_t size) : str_{str}, size_{size} {} - - CharT const& operator[](size_t p) const { return str_[p]; } - CharT const& at(size_t p) const { // NOLINT - CHECK_LT(p, size_); - return str_[p]; - } - size_t size() const { return size_; } // NOLINT - // Copies a portion of string. Since we don't have std::from_chars and friends here, so - // copying substring is necessary for appending `\0`. It's not too bad since string by - // default has small vector optimization, which is enabled by most if not all modern - // compilers for numeric values. - std::string substr(size_t beg, size_t n) const { // NOLINT - CHECK_LE(beg, size_); - return std::string {str_ + beg, n < (size_ - beg) ? n : (size_ - beg)}; - } - char const* c_str() const { return str_; } // NOLINT -}; - -/*! - * \brief Data structure representing JSON format. - * - * Limitation: UTF-8 is not properly supported. Code points above ASCII are - * invalid. - * - * Examples: - * - * \code - * // Create a JSON object. - * Json object { Object() }; - * // Assign key "key" with a JSON string "Value"; - * object["key"] = String("Value"); - * // Assign key "arr" with a empty JSON Array; - * object["arr"] = Array(); - * \endcode - */ -class Json { - friend JsonWriter; - - public: - /*! \brief Load a Json object from string. */ - static Json Load(StringView str); - /*! \brief Pass your own JsonReader. */ - static Json Load(JsonReader* reader); - /*! \brief Dump json into stream. */ - static void Dump(Json json, std::ostream* stream, - bool pretty = ConsoleLogger::ShouldLog( - ConsoleLogger::LogVerbosity::kDebug)); - static void Dump(Json json, std::string* out, - bool pretty = ConsoleLogger::ShouldLog( - ConsoleLogger::LogVerbosity::kDebug)); - - Json() : ptr_{new JsonNull} {} - - // number - explicit Json(JsonNumber number) : ptr_{new JsonNumber(number)} {} - Json& operator=(JsonNumber number) { - ptr_.reset(new JsonNumber(std::move(number))); - return *this; - } - - // integer - explicit Json(JsonInteger integer) : ptr_{new JsonInteger(integer)} {} - Json& operator=(JsonInteger integer) { - ptr_.reset(new JsonInteger(std::move(integer))); - return *this; - } - - // array - explicit Json(JsonArray list) : - ptr_ {new JsonArray(std::move(list))} {} - Json& operator=(JsonArray array) { - ptr_.reset(new JsonArray(std::move(array))); - return *this; - } - - // object - explicit Json(JsonObject object) : - ptr_{new JsonObject(std::move(object))} {} - Json& operator=(JsonObject object) { - ptr_.reset(new JsonObject(std::move(object))); - return *this; - } - // string - explicit Json(JsonString str) : - ptr_{new JsonString(std::move(str))} {} - Json& operator=(JsonString str) { - ptr_.reset(new JsonString(std::move(str))); - return *this; - } - // bool - explicit Json(JsonBoolean boolean) : - ptr_{new JsonBoolean(std::move(boolean))} {} - Json& operator=(JsonBoolean boolean) { - ptr_.reset(new JsonBoolean(std::move(boolean))); - return *this; - } - // null - explicit Json(JsonNull null) : - ptr_{new JsonNull(std::move(null))} {} - Json& operator=(JsonNull null) { - ptr_.reset(new JsonNull(std::move(null))); - return *this; - } - - // copy - Json(Json const& other) : ptr_{other.ptr_} {} - Json& operator=(Json const& other); - // move - Json(Json&& other) : ptr_{std::move(other.ptr_)} {} - Json& operator=(Json&& other) { - ptr_ = std::move(other.ptr_); - return *this; - } - - /*! \brief Index Json object with a std::string, used for Json Object. */ - Json& operator[](std::string const & key) const { return (*ptr_)[key]; } - /*! \brief Index Json object with int, used for Json Array. */ - Json& operator[](int ind) const { return (*ptr_)[ind]; } - - /*! \Brief Return the reference to stored Json value. */ - Value const& GetValue() const & { return *ptr_; } - Value const& GetValue() && { return *ptr_; } - Value& GetValue() & { return *ptr_; } - - bool operator==(Json const& rhs) const { - return *ptr_ == *(rhs.ptr_); - } - - friend std::ostream& operator<<(std::ostream& os, Json const& j) { - std::string str; - Json::Dump(j, &str); - os << str; - return os; - } - - private: - std::shared_ptr ptr_; -}; - -template -bool IsA(Json const j) { - auto const& v = j.GetValue(); - return IsA(&v); -} - -namespace detail { - -// Number -template ::value>::type* = nullptr> -JsonNumber::Float& GetImpl(T& val) { // NOLINT - return val.getNumber(); -} -template ::value>::type* = nullptr> -JsonNumber::Float const& GetImpl(T& val) { // NOLINT - return val.getNumber(); -} - -// Integer -template ::value>::type* = nullptr> -JsonInteger::Int& GetImpl(T& val) { // NOLINT - return val.getInteger(); -} -template ::value>::type* = nullptr> -JsonInteger::Int const& GetImpl(T& val) { // NOLINT - return val.getInteger(); -} - -// String -template ::value>::type* = nullptr> -std::string& GetImpl(T& val) { // NOLINT - return val.getString(); -} -template ::value>::type* = nullptr> -std::string const& GetImpl(T& val) { // NOLINT - return val.getString(); -} - -// Boolean -template ::value>::type* = nullptr> -bool& GetImpl(T& val) { // NOLINT - return val.getBoolean(); -} -template ::value>::type* = nullptr> -bool const& GetImpl(T& val) { // NOLINT - return val.getBoolean(); -} - -// Array -template ::value>::type* = nullptr> -std::vector& GetImpl(T& val) { // NOLINT - return val.getArray(); -} -template ::value>::type* = nullptr> -std::vector const& GetImpl(T& val) { // NOLINT - return val.getArray(); -} - -// Object -template ::value>::type* = nullptr> -std::map& GetImpl(T& val) { // NOLINT - return val.getObject(); -} -template ::value>::type* = nullptr> -std::map const& GetImpl(T& val) { // NOLINT - return val.getObject(); -} - -} // namespace detail - -/*! - * \brief Get Json value. - * - * \tparam T One of the Json value type. - * - * \param json - * \return Value contained in Json object of type T. - */ -template -auto get(U& json) -> decltype(detail::GetImpl(*Cast(&json.GetValue())))& { // NOLINT - auto& value = *Cast(&json.GetValue()); - return detail::GetImpl(value); -} - -using Object = JsonObject; -using Array = JsonArray; -using Number = JsonNumber; -using Integer = JsonInteger; -using Boolean = JsonBoolean; -using String = JsonString; -using Null = JsonNull; - -// Utils tailored for XGBoost. - -template -Object toJson(XGBoostParameter const& param) { - Object obj; - for (auto const& kv : param.__DICT__()) { - obj[kv.first] = kv.second; - } - return obj; -} - -template -void fromJson(Json const& obj, XGBoostParameter* param) { - auto const& j_param = get(obj); - std::map m; - for (auto const& kv : j_param) { - m[kv.first] = get(kv.second); - } - param->UpdateAllowUnknown(m); -} -} // namespace xgboost -#endif // XGBOOST_JSON_H_ diff --git a/include/xgboost/json_io.h b/include/xgboost/json_io.h deleted file mode 100644 index deaacf8c6dbd..000000000000 --- a/include/xgboost/json_io.h +++ /dev/null @@ -1,165 +0,0 @@ -/*! - * Copyright (c) by Contributors 2019 - */ -#ifndef XGBOOST_JSON_IO_H_ -#define XGBOOST_JSON_IO_H_ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace xgboost { - -template -class FixedPrecisionStreamContainer : public std::basic_stringstream< - char, std::char_traits, Allocator> { - public: - FixedPrecisionStreamContainer() { - this->precision(std::numeric_limits::max_digits10); - this->imbue(std::locale("C")); - this->setf(std::ios::scientific); - } -}; - -using FixedPrecisionStream = FixedPrecisionStreamContainer>; - -/* - * \brief A json reader, currently error checking and utf-8 is not fully supported. - */ -class JsonReader { - protected: - size_t constexpr static kMaxNumLength = - std::numeric_limits::max_digits10 + 1; - - struct SourceLocation { - size_t pos_; // current position in raw_str_ - - public: - SourceLocation() : pos_(0) {} - size_t Pos() const { return pos_; } - - SourceLocation& Forward() { - pos_++; - return *this; - } - SourceLocation& Forward(uint32_t n) { - pos_ += n; - return *this; - } - } cursor_; - - StringView raw_str_; - - protected: - void SkipSpaces(); - - char GetNextChar() { - if (cursor_.Pos() == raw_str_.size()) { - return -1; - } - char ch = raw_str_[cursor_.Pos()]; - cursor_.Forward(); - return ch; - } - - char PeekNextChar() { - if (cursor_.Pos() == raw_str_.size()) { - return -1; - } - char ch = raw_str_[cursor_.Pos()]; - return ch; - } - - char GetNextNonSpaceChar() { - SkipSpaces(); - return GetNextChar(); - } - - char GetChar(char c) { - char result = GetNextNonSpaceChar(); - if (result != c) { Expect(c, result); } - return result; - } - - void Error(std::string msg) const; - - // Report expected character - void Expect(char c, char got) { - std::string msg = "Expecting: \""; - msg += c; - msg += "\", got: \""; - msg += std::string {got} + " \""; - Error(msg); - } - - virtual Json ParseString(); - virtual Json ParseObject(); - virtual Json ParseArray(); - virtual Json ParseNumber(); - virtual Json ParseBoolean(); - virtual Json ParseNull(); - - Json Parse(); - - public: - explicit JsonReader(StringView str) : - raw_str_{str} {} - - virtual ~JsonReader() = default; - - Json Load(); -}; - -class JsonWriter { - static constexpr size_t kIndentSize = 2; - FixedPrecisionStream convertor_; - - size_t n_spaces_; - std::ostream* stream_; - bool pretty_; - - public: - JsonWriter(std::ostream* stream, bool pretty) : - n_spaces_{0}, stream_{stream}, pretty_{pretty} {} - - virtual ~JsonWriter() = default; - - void NewLine() { - if (pretty_) { - *stream_ << u8"\n" << std::string(n_spaces_, ' '); - } - } - - void BeginIndent() { - n_spaces_ += kIndentSize; - } - void EndIndent() { - n_spaces_ -= kIndentSize; - } - - void Write(std::string str) { - *stream_ << str; - } - void Write(StringView str) { - stream_->write(str.c_str(), str.size()); - } - - void Save(Json json); - - virtual void Visit(JsonArray const* arr); - virtual void Visit(JsonObject const* obj); - virtual void Visit(JsonNumber const* num); - virtual void Visit(JsonInteger const* num); - virtual void Visit(JsonNull const* null); - virtual void Visit(JsonString const* str); - virtual void Visit(JsonBoolean const* boolean); -}; -} // namespace xgboost - -#endif // XGBOOST_JSON_IO_H_ diff --git a/plugin/example/custom_obj.cc b/plugin/example/custom_obj.cc index a574c151a522..653d5d681ab7 100644 --- a/plugin/example/custom_obj.cc +++ b/plugin/example/custom_obj.cc @@ -7,7 +7,6 @@ #include #include #include -#include #include "../../src/common/json_experimental.h" // FIXME(trivialfis): Put json in public header. namespace xgboost { diff --git a/src/common/json.cc b/src/common/json.cc deleted file mode 100644 index 2c8000787c45..000000000000 --- a/src/common/json.cc +++ /dev/null @@ -1,730 +0,0 @@ -/*! - * Copyright (c) by Contributors 2019 - */ -#include -#include -#include - -#include "xgboost/base.h" -#include "xgboost/logging.h" -#include "xgboost/json.h" -#include "xgboost/json_io.h" - -namespace xgboost { - -void JsonWriter::Save(Json json) { - json.ptr_->Save(this); -} - -void JsonWriter::Visit(JsonArray const* arr) { - this->Write("["); - auto const& vec = arr->getArray(); - size_t size = vec.size(); - for (size_t i = 0; i < size; ++i) { - auto const& value = vec[i]; - this->Save(value); - if (i != size-1) { Write(", "); } - } - this->Write("]"); -} - -void JsonWriter::Visit(JsonObject const* obj) { - this->Write("{"); - this->BeginIndent(); - this->NewLine(); - - size_t i = 0; - size_t size = obj->getObject().size(); - - for (auto& value : obj->getObject()) { - this->Write("\"" + value.first + "\": "); - this->Save(value.second); - - if (i != size-1) { - this->Write(","); - this->NewLine(); - } - i++; - } - this->EndIndent(); - this->NewLine(); - this->Write("}"); -} - -void JsonWriter::Visit(JsonNumber const* num) { - convertor_ << num->getNumber(); - auto const& str = convertor_.str(); - this->Write(StringView{str.c_str(), str.size()}); - convertor_.str(""); -} - -void JsonWriter::Visit(JsonInteger const* num) { - convertor_ << num->getInteger(); - auto const& str = convertor_.str(); - this->Write(StringView{str.c_str(), str.size()}); - convertor_.str(""); -} - -void JsonWriter::Visit(JsonNull const* null) { - this->Write("null"); -} - -void JsonWriter::Visit(JsonString const* str) { - std::string buffer; - buffer += '"'; - auto const& string = str->getString(); - for (size_t i = 0; i < string.length(); i++) { - const char ch = string[i]; - if (ch == '\\') { - if (i < string.size() && string[i+1] == 'u') { - buffer += "\\"; - } else { - buffer += "\\\\"; - } - } else if (ch == '"') { - buffer += "\\\""; - } else if (ch == '\b') { - buffer += "\\b"; - } else if (ch == '\f') { - buffer += "\\f"; - } else if (ch == '\n') { - buffer += "\\n"; - } else if (ch == '\r') { - buffer += "\\r"; - } else if (ch == '\t') { - buffer += "\\t"; - } else if (static_cast(ch) <= 0x1f) { - // Unit separator - char buf[8]; - snprintf(buf, sizeof buf, "\\u%04x", ch); - buffer += buf; - } else { - buffer += ch; - } - } - buffer += '"'; - this->Write(buffer); -} - -void JsonWriter::Visit(JsonBoolean const* boolean) { - bool val = boolean->getBoolean(); - if (val) { - this->Write(u8"true"); - } else { - this->Write(u8"false"); - } -} - -// Value -std::string Value::TypeStr() const { - switch (kind_) { - case ValueKind::String: return "String"; break; - case ValueKind::Number: return "Number"; break; - case ValueKind::Object: return "Object"; break; - case ValueKind::Array: return "Array"; break; - case ValueKind::Boolean: return "Boolean"; break; - case ValueKind::Null: return "Null"; break; - case ValueKind::Integer: return "Integer"; break; - } - return ""; -} - -// Only used for keeping old compilers happy about non-reaching return -// statement. -Json& DummyJsonObject() { - static Json obj; - return obj; -} - -// Json Object -JsonObject::JsonObject(JsonObject && that) : - Value(ValueKind::Object), object_{std::move(that.object_)} {} - -JsonObject::JsonObject(std::map&& object) - : Value(ValueKind::Object), object_{std::move(object)} {} - -Json& JsonObject::operator[](std::string const & key) { - return object_[key]; -} - -Json& JsonObject::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer."; - return DummyJsonObject(); -} - -bool JsonObject::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return object_ == Cast(&rhs)->getObject(); -} - -Value& JsonObject::operator=(Value const &rhs) { - JsonObject const* casted = Cast(&rhs); - object_ = casted->getObject(); - return *this; -} - -void JsonObject::Save(JsonWriter* writer) { - writer->Visit(this); -} - -// Json String -Json& JsonString::operator[](std::string const & key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonString::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer." - << " Please try obtaining std::string first."; - return DummyJsonObject(); -} - -bool JsonString::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return Cast(&rhs)->getString() == str_; -} - -Value & JsonString::operator=(Value const &rhs) { - JsonString const* casted = Cast(&rhs); - str_ = casted->getString(); - return *this; -} - -// FIXME: UTF-8 parsing support. -void JsonString::Save(JsonWriter* writer) { - writer->Visit(this); -} - -// Json Array -JsonArray::JsonArray(JsonArray && that) : - Value(ValueKind::Array), vec_{std::move(that.vec_)} {} - -Json& JsonArray::operator[](std::string const & key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonArray::operator[](int ind) { - return vec_.at(ind); -} - -bool JsonArray::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - auto& arr = Cast(&rhs)->getArray(); - return std::equal(arr.cbegin(), arr.cend(), vec_.cbegin()); -} - -Value & JsonArray::operator=(Value const &rhs) { - JsonArray const* casted = Cast(&rhs); - vec_ = casted->getArray(); - return *this; -} - -void JsonArray::Save(JsonWriter* writer) { - writer->Visit(this); -} - -// Json Number -Json& JsonNumber::operator[](std::string const & key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonNumber::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer."; - return DummyJsonObject(); -} - -bool JsonNumber::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return number_ == Cast(&rhs)->getNumber(); -} - -Value & JsonNumber::operator=(Value const &rhs) { - JsonNumber const* casted = Cast(&rhs); - number_ = casted->getNumber(); - return *this; -} - -void JsonNumber::Save(JsonWriter* writer) { - writer->Visit(this); -} - -// Json Integer -Json& JsonInteger::operator[](std::string const& key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonInteger::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer."; - return DummyJsonObject(); -} - -bool JsonInteger::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return integer_ == Cast(&rhs)->getInteger(); -} - -Value & JsonInteger::operator=(Value const &rhs) { - JsonInteger const* casted = Cast(&rhs); - integer_ = casted->getInteger(); - return *this; -} - -void JsonInteger::Save(JsonWriter* writer) { - writer->Visit(this); -} - -// Json Null -Json& JsonNull::operator[](std::string const & key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonNull::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer."; - return DummyJsonObject(); -} - -bool JsonNull::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return true; -} - -Value & JsonNull::operator=(Value const &rhs) { - Cast(&rhs); // Checking only. - return *this; -} - -void JsonNull::Save(JsonWriter* writer) { - writer->Write("null"); -} - -// Json Boolean -Json& JsonBoolean::operator[](std::string const & key) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by string."; - return DummyJsonObject(); -} - -Json& JsonBoolean::operator[](int ind) { - LOG(FATAL) << "Object of type " - << Value::TypeStr() << " can not be indexed by Integer."; - return DummyJsonObject(); -} - -bool JsonBoolean::operator==(Value const& rhs) const { - if (!IsA(&rhs)) { return false; } - return boolean_ == Cast(&rhs)->getBoolean(); -} - -Value & JsonBoolean::operator=(Value const &rhs) { - JsonBoolean const* casted = Cast(&rhs); - boolean_ = casted->getBoolean(); - return *this; -} - -void JsonBoolean::Save(JsonWriter *writer) { - writer->Visit(this); -} - -size_t constexpr JsonReader::kMaxNumLength; - -Json JsonReader::Parse() { - while (true) { - SkipSpaces(); - char c = PeekNextChar(); - if (c == -1) { break; } - - if (c == '{') { - return ParseObject(); - } else if ( c == '[' ) { - return ParseArray(); - } else if ( c == '-' || std::isdigit(c) ) { - return ParseNumber(); - } else if ( c == '\"' ) { - return ParseString(); - } else if ( c == 't' || c == 'f' ) { - return ParseBoolean(); - } else if (c == 'n') { - return ParseNull(); - } else { - Error("Unknown construct"); - } - } - return Json(); -} - -Json JsonReader::Load() { - Json result = Parse(); - return result; -} - -void JsonReader::Error(std::string msg) const { - // just copy it. - std::istringstream str_s(raw_str_.substr(0, raw_str_.size())); - - msg += ", around character: " + std::to_string(cursor_.Pos()); - msg += '\n'; - - constexpr size_t kExtend = 8; - auto beg = static_cast(cursor_.Pos()) - - static_cast(kExtend) < 0 ? 0 : cursor_.Pos() - kExtend; - auto end = cursor_.Pos() + kExtend >= raw_str_.size() ? - raw_str_.size() : cursor_.Pos() + kExtend; - - std::string const& raw_portion = raw_str_.substr(beg, end - beg); - std::string portion; - for (auto c : raw_portion) { - if (c == '\n') { - portion += "\\n"; - } else { - portion += c; - } - } - - msg += " "; - msg += portion; - msg += '\n'; - - msg += " "; - for (size_t i = beg; i < cursor_.Pos() - 1; ++i) { - msg += '~'; - } - msg += '^'; - for (size_t i = cursor_.Pos(); i < end; ++i) { - msg += '~'; - } - LOG(FATAL) << msg; -} - -// Json class -void JsonReader::SkipSpaces() { - while (cursor_.Pos() < raw_str_.size()) { - char c = raw_str_[cursor_.Pos()]; - if (std::isspace(c)) { - cursor_.Forward(); - } else { - break; - } - } -} - -void ParseStr(std::string const& str) { - size_t end = 0; - for (size_t i = 0; i < str.size(); ++i) { - if (str[i] == '"' && i > 0 && str[i-1] != '\\') { - end = i; - break; - } - } - std::string result; - result.resize(end); -} - -Json JsonReader::ParseString() { - char ch { GetChar('\"') }; // NOLINT - std::ostringstream output; - std::string str; - while (true) { - ch = GetNextChar(); - if (ch == '\\') { - char next = static_cast(GetNextChar()); - switch (next) { - case 'r': str += u8"\r"; break; - case 'n': str += u8"\n"; break; - case '\\': str += u8"\\"; break; - case 't': str += u8"\t"; break; - case '\"': str += u8"\""; break; - case 'u': - str += ch; - str += 'u'; - break; - default: Error("Unknown escape"); - } - } else { - if (ch == '\"') break; - str += ch; - } - if (ch == EOF || ch == '\r' || ch == '\n') { - Expect('\"', ch); - } - } - return Json(std::move(str)); -} - -Json JsonReader::ParseNull() { - char ch = GetNextNonSpaceChar(); - std::string buffer{ch}; - for (size_t i = 0; i < 3; ++i) { - buffer.push_back(GetNextChar()); - } - if (buffer != "null") { - Error("Expecting null value \"null\""); - } - return Json{JsonNull()}; -} - -Json JsonReader::ParseArray() { - std::vector data; - - char ch { GetChar('[') }; // NOLINT - while (true) { - if (PeekNextChar() == ']') { - GetChar(']'); - return Json(std::move(data)); - } - auto obj = Parse(); - data.push_back(obj); - ch = GetNextNonSpaceChar(); - if (ch == ']') break; - if (ch != ',') { - Expect(',', ch); - } - } - - return Json(std::move(data)); -} - -Json JsonReader::ParseObject() { - GetChar('{'); - - std::map data; - SkipSpaces(); - char ch = PeekNextChar(); - - if (ch == '}') return Json(std::move(data)); - - while (true) { - SkipSpaces(); - ch = PeekNextChar(); - CHECK_NE(ch, -1) << "cursor_.Pos(): " << cursor_.Pos() << ", " - << "raw_str_.size():" << raw_str_.size(); - if (ch != '"') { - Expect('"', ch); - } - Json key = ParseString(); - - ch = GetNextNonSpaceChar(); - - if (ch != ':') { - Expect(':', ch); - } - - Json value { Parse() }; - - data[get(key)] = std::move(value); - - ch = GetNextNonSpaceChar(); - - if (ch == '}') break; - if (ch != ',') { - Expect(',', ch); - } - } - - return Json(std::move(data)); -} - -Json JsonReader::ParseNumber() { - // Adopted from sajson with some simplifications and small optimizations. - char const* p = raw_str_.c_str() + cursor_.Pos(); - char const* const beg = p; // keep track of current pointer - - // TODO(trivialfis): Add back all the checks for number - bool negative = false; - if ('-' == *p) { - ++p; - negative = true; - } - - bool is_float = false; - - using ExpInt = std::remove_const< - decltype(std::numeric_limits::max_exponent)>::type; - constexpr auto kExpMax = std::numeric_limits::max(); - constexpr auto kExpMin = std::numeric_limits::min(); - - JsonInteger::Int i = 0; - double f = 0.0; // Use double to maintain accuracy - - if (*p == '0') { - ++p; - } else { - char c = *p; - do { - ++p; - char digit = c - '0'; - i = 10 * i + digit; - c = *p; - } while (std::isdigit(c)); - } - - ExpInt exponent = 0; - const char *const dot_position = p; - if ('.' == *p) { - is_float = true; - f = i; - ++p; - char c = *p; - - do { - ++p; - f = f * 10 + (c - '0'); - c = *p; - } while (std::isdigit(c)); - } - if (is_float) { - exponent = dot_position - p + 1; - } - - char e = *p; - if ('e' == e || 'E' == e) { - if (!is_float) { - is_float = true; - f = i; - } - ++p; - - bool negative_exponent = false; - if ('-' == *p) { - negative_exponent = true; - ++p; - } else if ('+' == *p) { - ++p; - } - - ExpInt exp = 0; - - char c = *p; - while (std::isdigit(c)) { - unsigned char digit = c - '0'; - if (XGBOOST_EXPECT(exp > (kExpMax - digit) / 10, false)) { - CHECK_GT(exp, (kExpMax - digit) / 10) << "Overflow"; - } - exp = 10 * exp + digit; - ++p; - c = *p; - } - static_assert(-kExpMax >= kExpMin, "exp can be negated without loss or UB"); - exponent += (negative_exponent ? -exp : exp); - } - - if (exponent) { - CHECK(is_float); - // If d is zero but the exponent is huge, don't - // multiply zero by inf which gives nan. - if (f != 0.0) { - // Only use exp10 from libc on gcc+linux -#if !defined(__GNUC__) || defined(_WIN32) || defined(__APPLE__) -#define exp10(val) std::pow(10, (val)) -#endif // !defined(__GNUC__) || defined(_WIN32) || defined(__APPLE__) - f *= exp10(exponent); -#if !defined(__GNUC__) || defined(_WIN32) || defined(__APPLE__) -#undef exp10 -#endif // !defined(__GNUC__) || defined(_WIN32) || defined(__APPLE__) - } - } - - if (negative) { - f = -f; - i = -i; - } - - auto moved = std::distance(beg, p); - this->cursor_.Forward(moved); - - if (is_float) { - return Json(static_cast(f)); - } else { - return Json(JsonInteger(i)); - } -} - -Json JsonReader::ParseBoolean() { - bool result = false; - char ch = GetNextNonSpaceChar(); - std::string const t_value = u8"true"; - std::string const f_value = u8"false"; - std::string buffer; - - if (ch == 't') { - for (size_t i = 0; i < 3; ++i) { - buffer.push_back(GetNextNonSpaceChar()); - } - if (buffer != u8"rue") { - Error("Expecting boolean value \"true\"."); - } - result = true; - } else { - for (size_t i = 0; i < 4; ++i) { - buffer.push_back(GetNextNonSpaceChar()); - } - if (buffer != u8"alse") { - Error("Expecting boolean value \"false\"."); - } - result = false; - } - return Json{JsonBoolean{result}}; -} - -// This is an ad-hoc solution for writing numeric value in standard way. We need to add -// a locale independent way of writing stream like `std::{from, to}_chars' from C++-17. -// FIXME(trivialfis): Remove this. -class GlobalCLocale { - std::locale ori_; - - public: - GlobalCLocale() : ori_{std::locale()} { - std::string const name {"C"}; - try { - std::locale::global(std::locale(name.c_str())); - } catch (std::runtime_error const& e) { - LOG(FATAL) << "Failed to set locale: " << name; - } - } - ~GlobalCLocale() { - std::locale::global(ori_); - } -}; - -Json Json::Load(StringView str) { - GlobalCLocale guard; - JsonReader reader(str); - Json json{reader.Load()}; - return json; -} - -Json Json::Load(JsonReader* reader) { - GlobalCLocale guard; - Json json{reader->Load()}; - return json; -} - -void Json::Dump(Json json, std::ostream *stream, bool pretty) { - GlobalCLocale guard; - JsonWriter writer(stream, pretty); - writer.Save(json); -} - -void Json::Dump(Json json, std::string* str, bool pretty) { - GlobalCLocale guard; - std::stringstream ss; - JsonWriter writer(&ss, pretty); - writer.Save(json); - *str = ss.str(); -} - -Json& Json::operator=(Json const &other) = default; -} // namespace xgboost diff --git a/src/common/timer.cc b/src/common/timer.cc index d4cfbfcc73fe..9a6348e548fa 100644 --- a/src/common/timer.cc +++ b/src/common/timer.cc @@ -7,8 +7,11 @@ #include #include #include + #include "timer.h" -#include "xgboost/json.h" +#include "json_experimental.h" +#include "json_reader_experimental.h" +#include "json_writer_experimental.h" namespace xgboost { namespace common { @@ -35,22 +38,22 @@ std::vector Monitor::CollectFromOtherRanks() const { // It's much easier to work with rabit if we have a string serialization. So we go with // json. - Json j_statistic { Object() }; - j_statistic["rank"] = Integer(rank); - j_statistic["statistic"] = Object(); + experimental::Document j_statistic; + j_statistic.GetValue().CreateMember("rank") = static_cast(rank); + auto statistic = j_statistic.CreateMember("statistic"); + statistic.SetObject(); - auto& statistic = j_statistic["statistic"]; for (auto const& kv : statistics_map) { - statistic[kv.first] = Object(); - auto& j_pair = statistic[kv.first]; - j_pair["count"] = Integer(kv.second.count); - j_pair["elapsed"] = Integer(std::chrono::duration_cast( - kv.second.timer.elapsed).count()); + // statistic[kv.first] = Object(); + auto prop = statistic.CreateMember(kv.first); + prop.SetObject(); + prop.CreateMember("count").SetInteger(kv.second.count); + prop.CreateMember("elapsed").SetInteger( + std::chrono::duration_cast( + kv.second.timer.elapsed).count()); } - std::stringstream ss; - Json::Dump(j_statistic, &ss); - std::string const str { ss.str() }; + std::string str = j_statistic.Dump(); size_t str_size = str.size(); rabit::Allreduce(&str_size, 1); @@ -64,17 +67,17 @@ std::vector Monitor::CollectFromOtherRanks() const { for (size_t i = 0; i < world_size; ++i) { std::copy(str.cbegin(), str.cend(), buffer.begin()); rabit::Broadcast(&buffer, i); - auto j_other = Json::Load(StringView{buffer.c_str(), buffer.size()}); + auto j_other = experimental::Document::Load(experimental::StringRef{buffer}); auto& other = world[i]; - auto const& j_statistic = get(j_other["statistic"]); + auto const& j_statistic = *j_other.GetValue().FindMemberByKey("statistic"); - for (auto const& kv : j_statistic) { - std::string const& timer_name = kv.first; - auto const& pair = kv.second; - other[timer_name] = {get(pair["count"]), get(pair["elapsed"])}; + for (auto it = j_statistic.cbegin(); it != j_statistic.cend(); ++it) { + auto const& timer_name = it.Key(); + auto pair = *it; + other[timer_name.Copy()] = {(*pair.FindMemberByKey("count")).GetInt(), + (*pair.FindMemberByKey("elapsed")).GetInt()}; } - // FIXME(trivialfis): How to ask rabit to block here? } diff --git a/src/common/version.cc b/src/common/version.cc index 49b7358d9221..58f05e664aa7 100644 --- a/src/common/version.cc +++ b/src/common/version.cc @@ -8,7 +8,6 @@ #include #include "xgboost/logging.h" -#include "xgboost/json.h" #include "xgboost/version_config.h" #include "version.h" #include "json_experimental.h" @@ -21,7 +20,7 @@ Version::TripletT Version::Load(experimental::Json const& in, bool check) { if (in.FindMemberByKey("version") == in.cend()) { return kInvalid; } - Integer::Int major {0}, minor {0}, patch {0}; + int64_t major {0}, minor {0}, patch {0}; try { auto j_version = *in.FindMemberByKey("version"); major = j_version.GetArrayElem(0).GetInt(); @@ -57,7 +56,7 @@ Version::TripletT Version::Load(dmlc::Stream* fi) { } void Version::Save(experimental::Json* out) { - Integer::Int major, minor, patch; + int64_t major, minor, patch; std::tie(major, minor, patch)= Self(); auto j_version = out->CreateMember("version"); j_version.SetArray(3); @@ -78,7 +77,7 @@ void Version::Save(dmlc::Stream* fo) { std::string Version::String(TripletT const& version) { std::stringstream ss; - ss << std::get<0>(version) << "." << get<1>(version) << "." << get<2>(version); + ss << std::get<0>(version) << "." << std::get<1>(version) << "." << std::get<2>(version); return ss.str(); } diff --git a/src/data/data.cu b/src/data/data.cu index cb51a7555121..9ea289eaad94 100644 --- a/src/data/data.cu +++ b/src/data/data.cu @@ -6,7 +6,7 @@ */ #include "xgboost/data.h" #include "xgboost/logging.h" -#include "xgboost/json.h" + #include "columnar.h" #include "../common/device_helpers.cuh" #include "../common/json_experimental.h" diff --git a/src/data/simple_csr_source.cc b/src/data/simple_csr_source.cc index 25836f2c2238..4e2c44de4540 100644 --- a/src/data/simple_csr_source.cc +++ b/src/data/simple_csr_source.cc @@ -4,7 +4,6 @@ */ #include #include -#include #include #include "simple_csr_source.h" diff --git a/tests/cpp/common/test_json.cc b/tests/cpp/common/test_json.cc deleted file mode 100644 index 94e87bcac462..000000000000 --- a/tests/cpp/common/test_json.cc +++ /dev/null @@ -1,431 +0,0 @@ -/*! - * Copyright (c) by Contributors 2019 - */ -#include -#include -#include -#include - -#include "xgboost/json.h" -#include "xgboost/logging.h" -#include "xgboost/json_io.h" -#include "../../../src/common/io.h" - -namespace xgboost { - -std::string GetModelStr() { - std::string model_json = R"json( -{ - "model_parameter": { - "base_score": "0.5", - "num_class": "0", - "num_feature": "10" - }, - "train_parameter": { - "debug_verbose": "0", - "disable_default_eval_metric": "0", - "dsplit": "auto", - "nthread": "0", - "seed": "0", - "seed_per_iteration": "0", - "test_flag": "", - "tree_method": "gpu_hist" - }, - "configuration": { - "booster": "gbtree", - "gpu_id": "0", - "num_class": "0", - "num_feature": "10", - "objective": "reg:linear", - "predictor": "gpu_predictor", - "tree_method": "gpu_hist", - "updater": "grow_gpu_hist" - }, - "objective": "reg:linear", - "booster": "gbtree", - "gbm": { - "GBTreeModelParam": { - "num_feature": "10", - "num_output_group": "1", - "num_roots": "1", - "size_leaf_vector": "0" - }, - "trees": [{ - "TreeParam": { - "num_feature": "10", - "num_roots": "1", - "size_leaf_vector": "0" - }, - "num_nodes": "9", - "nodes": [ - { - "depth": 0, - "gain": 31.8892, - "hess": 10, - "left": 1, - "missing": 1, - "nodeid": 0, - "right": 2, - "split_condition": 0.580717, - "split_index": 2 - }, - { - "depth": 1, - "gain": 1.5625, - "hess": 3, - "left": 5, - "missing": 5, - "nodeid": 2, - "right": 6, - "split_condition": 0.160345, - "split_index": 0 - }, - { - "depth": 2, - "gain": 0.25, - "hess": 2, - "left": 7, - "missing": 7, - "nodeid": 6, - "right": 8, - "split_condition": 0.62788, - "split_index": 0 - }, - { - "hess": 1, - "leaf": 0.375, - "nodeid": 8 - }, - { - "hess": 1, - "leaf": 0.075, - "nodeid": 7 - }, - { - "hess": 1, - "leaf": -0.075, - "nodeid": 5 - }, - { - "depth": 3, - "gain": 10.4866, - "hess": 7, - "left": 3, - "missing": 3, - "nodeid": 1, - "right": 4, - "split_condition": 0.238748, - "split_index": 1 - }, - { - "hess": 6, - "leaf": 1.54286, - "nodeid": 4 - }, - { - "hess": 1, - "leaf": 0.225, - "nodeid": 3 - } - ], - "leaf_vector": [] - }], - "tree_info": [0] - } -} -)json"; - return model_json; -} - -TEST(Json, TestParseObject) { - std::string str = R"obj({"TreeParam" : {"num_feature": "10"}})obj"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); -} - -TEST(Json, ParseNumber) { - { - std::string str = "31.8892"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); - ASSERT_NEAR(get(json), 31.8892f, kRtEps); - } - { - std::string str = "-31.8892"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); - ASSERT_NEAR(get(json), -31.8892f, kRtEps); - } - { - std::string str = "2e4"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); - ASSERT_NEAR(get(json), 2e4f, kRtEps); - } - { - std::string str = "2e-4"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); - ASSERT_NEAR(get(json), 2e-4f, kRtEps); - } -} - -TEST(Json, ParseArray) { - std::string str = R"json( -{ - "nodes": [ - { - "depth": 3, - "gain": 10.4866, - "hess": 7, - "left": 3, - "missing": 3, - "nodeid": 1, - "right": 4, - "split_condition": 0.238748, - "split_index": 1 - }, - { - "hess": 6, - "leaf": 1.54286, - "nodeid": 4 - }, - { - "hess": 1, - "leaf": 0.225, - "nodeid": 3 - } - ] -} -)json"; - auto json = Json::Load(StringView{str.c_str(), str.size()}); - json = json["nodes"]; - std::vector arr = get(json); - ASSERT_EQ(arr.size(), 3); - Json v0 = arr[0]; - ASSERT_EQ(get(v0["depth"]), 3); - ASSERT_NEAR(get(v0["gain"]), 10.4866, kRtEps); -} - -TEST(Json, Null) { - Json json {JsonNull()}; - std::stringstream ss; - Json::Dump(json, &ss); - ASSERT_EQ(ss.str(), "null"); - - std::string null_input {R"null({"key": null })null"}; - - json = Json::Load({null_input.c_str(), null_input.size()}); - ASSERT_TRUE(IsA(json["key"])); -} - -TEST(Json, EmptyObject) { - std::string str = R"json( -{ - "rank": 1, - "statistic": { - - } -} -)json"; - std::stringstream iss(str); - auto json = Json::Load(StringView{str.c_str(), str.size()}); - ASSERT_TRUE(IsA(json["statistic"])); -} - -TEST(Json, EmptyArray) { - std::string str = R"json( -{ - "leaf_vector": [] -} -)json"; - std::istringstream iss(str); - auto json = Json::Load(StringView{str.c_str(), str.size()}); - auto arr = get(json["leaf_vector"]); - ASSERT_EQ(arr.size(), 0); -} - -TEST(Json, Boolean) { - std::string str = R"json( -{ - "left_child": true, - "right_child": false -} -)json"; - Json j {Json::Load(StringView{str.c_str(), str.size()})}; - ASSERT_EQ(get(j["left_child"]), true); - ASSERT_EQ(get(j["right_child"]), false); -} - -TEST(Json, Indexing) { - auto str = GetModelStr(); - JsonReader reader(StringView{str.c_str(), str.size()}); - Json j {Json::Load(&reader)}; - auto& value_1 = j["model_parameter"]; - auto& value = value_1["base_score"]; - std::string result = Cast(&value.GetValue())->getString(); - - ASSERT_EQ(result, "0.5"); -} - -TEST(Json, AssigningObjects) { - { - Json json; - json = JsonObject(); - json["Okay"] = JsonArray(); - ASSERT_EQ(get(json["Okay"]).size(), 0); - } - - { - std::map objects; - Json json_objects { JsonObject() }; - std::vector arr_0 (1, Json(3.3f)); - json_objects["tree_parameters"] = JsonArray(arr_0); - std::vector json_arr = get(json_objects["tree_parameters"]); - ASSERT_NEAR(get(json_arr[0]), 3.3f, kRtEps); - } - - { - Json json_object { JsonObject() }; - auto str = JsonString("1"); - auto& k = json_object["1"]; - k = str; - auto& m = json_object["1"]; - std::string value = get(m); - ASSERT_EQ(value, "1"); - ASSERT_EQ(get(json_object["1"]), "1"); - } -} - -TEST(Json, AssigningArray) { - Json json; - json = JsonArray(); - std::vector tmp_0 {Json(Number(1.0f)), Json(Number(2.0f))}; - json = tmp_0; - std::vector tmp_1 {Json(Number(3.0f))}; - get(json) = tmp_1; - std::vector res = get(json); - ASSERT_EQ(get(res[0]), 3); -} - -TEST(Json, AssigningNumber) { - { - // right value - Json json = Json{ Number(4.0f) }; - get(json) = 15; - ASSERT_EQ(get(json), 15); - } - - { - // left value ref - Json json = Json{ Number(4.0f) }; - Number::Float& ref = get(json); - ref = 15; - ASSERT_EQ(get(json), 15); - } - - { - // left value - Json json = Json{ Number(4.0f) }; - double value = get(json); - ASSERT_EQ(value, 4); - value = 15; // NOLINT - ASSERT_EQ(get(json), 4); - } -} - -TEST(Json, AssigningString) { - { - // right value - Json json = Json{ String("str") }; - get(json) = "modified"; - ASSERT_EQ(get(json), "modified"); - } - - { - // left value ref - Json json = Json{ String("str") }; - std::string& ref = get(json); - ref = "modified"; - ASSERT_EQ(get(json), "modified"); - } - - { - // left value - Json json = Json{ String("str") }; - std::string value = get(json); - value = "modified"; - ASSERT_EQ(get(json), "str"); - } -} - -TEST(Json, LoadDump) { - std::string ori_buffer = GetModelStr(); - Json origin {Json::Load(StringView{ori_buffer.c_str(), ori_buffer.size()})}; - - dmlc::TemporaryDirectory tempdir; - auto const& path = tempdir.path + "test_model_dump"; - - std::ofstream fout (path); - Json::Dump(origin, &fout); - fout.close(); - - std::string new_buffer = common::LoadSequentialFile(path); - Json load_back {Json::Load(StringView(new_buffer.c_str(), new_buffer.size()))}; - - ASSERT_EQ(load_back, origin) << ori_buffer << "\n\n---------------\n\n" - << new_buffer; -} - -// For now Json is quite ignorance about unicode. -TEST(Json, CopyUnicode) { - std::string json_str = R"json( -{"m": ["\ud834\udd1e", "\u20ac", "\u0416", "\u00f6"]} -)json"; - Json loaded {Json::Load(StringView{json_str.c_str(), json_str.size()})}; - - std::stringstream ss_1; - Json::Dump(loaded, &ss_1); - - std::string dumped_string = ss_1.str(); - ASSERT_NE(dumped_string.find("\\u20ac"), std::string::npos); -} - -TEST(Json, WrongCasts) { - { - Json json = Json{ String{"str"} }; - ASSERT_ANY_THROW(get(json)); - } - { - Json json = Json{ Array{ std::vector{ Json{ Number{1.0f} } } } }; - ASSERT_ANY_THROW(get(json)); - } - { - Json json = Json{ Object{std::map{ - {"key", Json{String{"value"}}}} } }; - ASSERT_ANY_THROW(get(json)); - } -} - -TEST(Json, Int_vs_Float) { - // If integer is parsed as float, calling `get()' will throw. - { - std::string str = R"json( -{ - "number": 123.4, - "integer": 123 -})json"; - - Json obj = Json::Load({str.c_str(), str.size()}); - JsonNumber::Float number = get(obj["number"]); - ASSERT_NEAR(number, 123.4f, kRtEps); - JsonInteger::Int integer = get(obj["integer"]); - ASSERT_EQ(integer, 123); - } - - { - std::string str = R"json( -{"data": [2503595760, false], "shape": [10]} -)json"; - Json obj = Json::Load({str.c_str(), str.size()}); - auto array = get(obj["data"]); - auto ptr = get(array[0]); - ASSERT_EQ(ptr, 2503595760); - } -} -} // namespace xgboost diff --git a/tests/cpp/common/test_version.cc b/tests/cpp/common/test_version.cc index bab054b77044..c4fe8c99d917 100644 --- a/tests/cpp/common/test_version.cc +++ b/tests/cpp/common/test_version.cc @@ -7,12 +7,12 @@ #include #include -#include #include #include #include "../../../src/common/version.h" +#include "../../../src/common/json_experimental.h" namespace xgboost { TEST(Version, Basic) { diff --git a/tests/cpp/data/test_metainfo.cu b/tests/cpp/data/test_metainfo.cu index 82e434e78284..7fc619262d51 100644 --- a/tests/cpp/data/test_metainfo.cu +++ b/tests/cpp/data/test_metainfo.cu @@ -2,85 +2,84 @@ #include #include -#include #include #include "../../../src/common/device_helpers.cuh" namespace xgboost { -template -std::string PrepareData(std::string typestr, thrust::device_vector* out) { - constexpr size_t kRows = 16; - out->resize(kRows); - auto& d_data = *out; - - for (size_t i = 0; i < d_data.size(); ++i) { - d_data[i] = i * 2.0; - } - - Json column { Object() }; - - std::vector j_shape {Json(Integer(static_cast(kRows)))}; - column["shape"] = Array(j_shape); - column["strides"] = Array(std::vector{Json(Integer(static_cast(4)))}); - column["version"] = Integer(static_cast(1)); - column["typestr"] = String(typestr); - - auto p_d_data = dh::Raw(d_data); - std::vector j_data { - Json(Integer(reinterpret_cast(p_d_data))), - Json(Boolean(false))}; - column["data"] = j_data; - Json array(std::vector{column}); - - std::stringstream ss; - Json::Dump(array, &ss); - std::string str = ss.str(); - - return str; -} - -TEST(MetaInfo, FromInterface) { - cudaSetDevice(0); - thrust::device_vector d_data; - - std::string str = PrepareData(" d_data; - std::string str = PrepareData(" +// std::string PrepareData(std::string typestr, thrust::device_vector* out) { +// constexpr size_t kRows = 16; +// out->resize(kRows); +// auto& d_data = *out; + +// for (size_t i = 0; i < d_data.size(); ++i) { +// d_data[i] = i * 2.0; +// } + +// Json column { Object() }; + +// std::vector j_shape {Json(Integer(static_cast(kRows)))}; +// column["shape"] = Array(j_shape); +// column["strides"] = Array(std::vector{Json(Integer(static_cast(4)))}); +// column["version"] = Integer(static_cast(1)); +// column["typestr"] = String(typestr); + +// auto p_d_data = dh::Raw(d_data); +// std::vector j_data { +// Json(Integer(reinterpret_cast(p_d_data))), +// Json(Boolean(false))}; +// column["data"] = j_data; +// Json array(std::vector{column}); + +// std::stringstream ss; +// Json::Dump(array, &ss); +// std::string str = ss.str(); + +// return str; +// } + +// TEST(MetaInfo, FromInterface) { +// cudaSetDevice(0); +// thrust::device_vector d_data; + +// std::string str = PrepareData(" d_data; +// std::string str = PrepareData(" #include -#include #include "../../../src/data/simple_csr_source.h" #include "../helpers.h" diff --git a/tests/cpp/helpers.cc b/tests/cpp/helpers.cc index 16a2154eb595..2e56f4999751 100644 --- a/tests/cpp/helpers.cc +++ b/tests/cpp/helpers.cc @@ -3,7 +3,6 @@ */ #include #include -#include #include diff --git a/tests/cpp/helpers.h b/tests/cpp/helpers.h index e7d546e8a44d..fdcab506fb17 100644 --- a/tests/cpp/helpers.h +++ b/tests/cpp/helpers.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/tests/cpp/objective/test_multiclass_obj.cc b/tests/cpp/objective/test_multiclass_obj.cc index de53dee6a1ad..d79372f24c07 100644 --- a/tests/cpp/objective/test_multiclass_obj.cc +++ b/tests/cpp/objective/test_multiclass_obj.cc @@ -3,7 +3,9 @@ */ #include #include + #include "../../src/common/common.h" +#include "../../src/common/json_experimental.h" #include "../helpers.h" namespace xgboost { diff --git a/tests/cpp/objective/test_ranking_obj.cc b/tests/cpp/objective/test_ranking_obj.cc index 53b4de24942b..081fe6da4890 100644 --- a/tests/cpp/objective/test_ranking_obj.cc +++ b/tests/cpp/objective/test_ranking_obj.cc @@ -3,7 +3,6 @@ #include #include "../helpers.h" #include "../../src/common/json_experimental.h" -#include namespace xgboost { diff --git a/tests/cpp/objective/test_regression_obj.cc b/tests/cpp/objective/test_regression_obj.cc index 2ead20e76ef7..d2e18d7ddbce 100644 --- a/tests/cpp/objective/test_regression_obj.cc +++ b/tests/cpp/objective/test_regression_obj.cc @@ -4,8 +4,10 @@ #include #include #include -#include + +#include "../../src/common/json_experimental.h" #include "../helpers.h" + namespace xgboost { TEST(Objective, DeclareUnifiedTest(LinearRegressionGPair)) {