#include "value.h" #include "config.h" #include #include #include #include #include #include #include using namespace NConfig; namespace { template class TValue: public IValue { public: inline TValue(const T& t) : T_(t) { } bool IsA(const std::type_info& info) const override { return info == typeid(T); } TString TypeName() const override { return ::TypeName(); } void* Ptr() const override { return (void*)&T_; } void ToJson(IOutputStream& out) const override { out << AsString(); } bool AsBool() const override { return (bool)AsDouble(); } protected: T T_; }; class TNullValue: public TValue { public: inline TNullValue() : TValue(TNull()) { Ref(); } double AsDouble() const override { return 0; } ui64 AsUInt() const override { return 0; } i64 AsInt() const override { return 0; } TString AsString() const override { return TString(); } void ToJson(IOutputStream& out) const override { out << "null"; } TString TypeName() const override { return "null"; } }; template class TNumericValue: public TValue { public: inline TNumericValue(const T& t) : TValue(t) { } double AsDouble() const override { return this->T_; } ui64 AsUInt() const override { return this->T_; } i64 AsInt() const override { return this->T_; } }; class TBoolValue: public TNumericValue { public: inline TBoolValue(bool v) : TNumericValue(v) { } TString AsString() const override { return T_ ? "true" : "false"; } }; template class TArithmeticValue: public TNumericValue { public: inline TArithmeticValue(T v) : TNumericValue(v) { } TString AsString() const override { return ToString(this->T_); } }; class TStringValue: public TValue { public: inline TStringValue(const TString& v) : TValue(v) { } template inline T AsT() const { const TStringBuf s = StripString(TStringBuf(T_)); if (IsTrue(s)) { return true; } if (IsFalse(s)) { return false; } return FromString(s); } double AsDouble() const override { return AsT(); } ui64 AsUInt() const override { return AsT(); } i64 AsInt() const override { return AsT(); } TString AsString() const override { return T_; } void ToJson(IOutputStream& out) const override { NEscJ::EscapeJ(T_, out); } TString TypeName() const override { return "string"; } }; template class TContainer: public TValue { public: inline TContainer(const T& t) : TValue(t) { } double AsDouble() const override { NCfgPrivate::ReportTypeMismatch(this->TypeName(), "double"); } ui64 AsUInt() const override { NCfgPrivate::ReportTypeMismatch(this->TypeName(), "uint"); } i64 AsInt() const override { NCfgPrivate::ReportTypeMismatch(this->TypeName(), "int"); } bool AsBool() const override { NCfgPrivate::ReportTypeMismatch(this->TypeName(), "bool"); } TString AsString() const override { NCfgPrivate::ReportTypeMismatch(this->TypeName(), "string"); } }; class TArrayValue: public TContainer { public: inline TArrayValue(const TArray& v) : TContainer(v) { } void ToJson(IOutputStream& s) const override { s << "["; for (TArray::const_iterator it = T_.begin(); it != T_.end(); ++it) { if (it != T_.begin()) { s << ","; } it->ToJson(s); } s << "]"; } TString TypeName() const override { return "array"; } }; class TDictValue: public TContainer { public: inline TDictValue(const TDict& v) : TContainer(v) { } void ToJson(IOutputStream& s) const override { s << "{"; TVector buf; buf.reserve(T_.size()); for (const auto& t : T_) { buf.push_back(t.first); } Sort(buf.begin(), buf.end()); for (TVector::const_iterator kit = buf.begin(); kit != buf.end(); ++kit) { TStringBuf key = *kit; TDict::const_iterator it = T_.find(key); if (kit != buf.begin()) { s << ","; } NEscJ::EscapeJ(key, s); s << ":"; it->second.ToJson(s); } s << "}"; } TString TypeName() const override { return "dict"; } }; } #define DECLARE(type1, type2) \ IValue* ConstructValueImpl(const type2& t) { \ return new type1(t); \ } namespace NConfig { namespace NCfgPrivate { DECLARE(TBoolValue, bool) DECLARE(TArithmeticValue, double) DECLARE(TArithmeticValue, i64) DECLARE(TArithmeticValue, ui64) DECLARE(TStringValue, TString) DECLARE(TArrayValue, TArray) DECLARE(TDictValue, TDict) } IValue* Null() { return Singleton(); } [[noreturn]] void NCfgPrivate::ReportTypeMismatch(TStringBuf realType, TStringBuf expectedType) { ythrow TTypeMismatch() << "type mismatch (real: " << realType << ", expected: " << expectedType << ')'; } }