diff --git a/doc/json.md b/doc/json.md index 4227683a..49cd7827 100644 --- a/doc/json.md +++ b/doc/json.md @@ -58,7 +58,7 @@ private: virtual void end_object() const = 0; virtual void start_array() const = 0; - virtual void end_arrary() const = 0; + virtual void end_array() const = 0; virtual void write_null() const = 0; virtual void write_string(const std::string& value) const = 0; diff --git a/include/graphqlservice/GraphQLResponse.h b/include/graphqlservice/GraphQLResponse.h index c4bd7765..9a591e33 100644 --- a/include/graphqlservice/GraphQLResponse.h +++ b/include/graphqlservice/GraphQLResponse.h @@ -500,7 +500,7 @@ class [[nodiscard("unnecessary construction")]] ValueVisitor final template ValueVisitor(std::shared_ptr writer) noexcept : _concept { std::static_pointer_cast( - std::make_shared>(std::move(writer))) } + std::make_shared>(std::move(writer))) } { } @@ -635,6 +635,8 @@ class [[nodiscard("unnecessary construction")]] ValueTokenStream final ValueTokenStream() noexcept = default; ~ValueTokenStream() = default; + GRAPHQLRESPONSE_EXPORT explicit ValueTokenStream(Value&& value); + ValueTokenStream(ValueTokenStream&&) noexcept = default; ValueTokenStream& operator=(ValueTokenStream&&) noexcept = default; @@ -662,102 +664,6 @@ class [[nodiscard("unnecessary construction")]] ValueTokenStream final std::list _tokens; }; -class [[nodiscard("unnecessary construction")]] Writer final -{ -private: - struct Concept - { - virtual ~Concept() = default; - - virtual void start_object() const = 0; - virtual void add_member(const std::string& key) const = 0; - virtual void end_object() const = 0; - - virtual void start_array() const = 0; - virtual void end_arrary() const = 0; - - virtual void write_null() const = 0; - virtual void write_string(const std::string& value) const = 0; - virtual void write_bool(bool value) const = 0; - virtual void write_int(int value) const = 0; - virtual void write_float(double value) const = 0; - }; - - template - struct Model : Concept - { - explicit Model(std::unique_ptr pimpl) noexcept - : _pimpl { std::move(pimpl) } - { - } - - void start_object() const final - { - _pimpl->start_object(); - } - - void add_member(const std::string& key) const final - { - _pimpl->add_member(key); - } - - void end_object() const final - { - _pimpl->end_object(); - } - - void start_array() const final - { - _pimpl->start_array(); - } - - void end_arrary() const final - { - _pimpl->end_arrary(); - } - - void write_null() const final - { - _pimpl->write_null(); - } - - void write_string(const std::string& value) const final - { - _pimpl->write_string(value); - } - - void write_bool(bool value) const final - { - _pimpl->write_bool(value); - } - - void write_int(int value) const final - { - _pimpl->write_int(value); - } - - void write_float(double value) const final - { - _pimpl->write_float(value); - } - - private: - std::unique_ptr _pimpl; - }; - - const std::shared_ptr _concept; - -public: - template - Writer(std::unique_ptr writer) noexcept - : _concept { std::static_pointer_cast( - std::make_shared>(std::move(writer))) } - { - } - - GRAPHQLRESPONSE_EXPORT void write(Value value) const; -}; - } // namespace graphql::response #endif // GRAPHQLRESPONSE_H diff --git a/include/graphqlservice/Response.ixx b/include/graphqlservice/Response.ixx index 4f83da5d..522a4c6e 100644 --- a/include/graphqlservice/Response.ixx +++ b/include/graphqlservice/Response.ixx @@ -31,8 +31,6 @@ using response::AwaitableValue; using response::ValueVisitor; using response::ValueToken; using response::ValueTokenStream; - -using response::Writer; // clang-format on } // namespace graphql::response diff --git a/src/GraphQLResponse.cpp b/src/GraphQLResponse.cpp index 984a2034..cb829ccb 100644 --- a/src/GraphQLResponse.cpp +++ b/src/GraphQLResponse.cpp @@ -101,9 +101,9 @@ bool IdType::operator==(const IdType& rhs) const noexcept return (std::holds_alternative(_data) ? internal::Base64::compareBase64(std::get(_data), - std::get(rhs._data)) + std::get(rhs._data)) : internal::Base64::compareBase64(std::get(rhs._data), - std::get(_data))) + std::get(_data))) == internal::Base64::Comparison::EqualTo; } @@ -146,7 +146,7 @@ bool IdType::operator<(const IdType& rhs) const noexcept return (std::holds_alternative(_data) ? (internal::Base64::compareBase64(std::get(_data), std::get(rhs._data)) - < internal::Base64::Comparison::EqualTo) + < internal::Base64::Comparison::EqualTo) : (internal::Base64::compareBase64(std::get(rhs._data), std::get(_data))) > internal::Base64::Comparison::EqualTo); @@ -1802,111 +1802,127 @@ void ValueTokenStreamVisitor::add_value(Value&& value) } } -void ValueTokenStream::append(ValueTokenStream&& other) -{ - _tokens.splice(_tokens.end(), std::move(other._tokens)); -} - -void ValueTokenStream::visit(const std::shared_ptr& visitor) && +ValueTokenStream::ValueTokenStream(Value&& value) { - for (auto& token : _tokens) - { - std::move(token).visit(visitor); - } - - visitor->complete(); -} - -Value ValueTokenStream::value() && -{ - auto visitor = std::make_shared(); - - std::move(*this).visit(std::make_shared(visitor)); - - return visitor->value(); -} - -void Writer::write(Value response) const -{ - switch (response.type()) + switch (value.type()) { case Type::Map: { - auto members = response.release(); + auto members = value.release(); - _concept->start_object(); + push_back(ValueToken::StartObject {}); + push_back(ValueToken::Reserve { members.size() }); for (auto& entry : members) { - _concept->add_member(entry.first); - write(std::move(entry.second)); + push_back(ValueToken::AddMember { std::move(entry.first) }); + append(ValueTokenStream { std::move(entry.second) }); } - _concept->end_object(); + push_back(ValueToken::EndObject {}); break; } case Type::List: { - auto elements = response.release(); + auto elements = value.release(); - _concept->start_array(); + push_back(ValueToken::StartArray {}); + push_back(ValueToken::Reserve { elements.size() }); for (auto& entry : elements) { - write(std::move(entry)); + append(ValueTokenStream { std::move(entry) }); } - _concept->end_arrary(); + push_back(ValueToken::EndArray {}); break; } case Type::String: - case Type::EnumValue: - case Type::ID: { - auto value = response.release(); + auto stringValue = value.release(); - _concept->write_string(value); + push_back(ValueToken::StringValue { std::move(stringValue) }); break; } case Type::Null: { - _concept->write_null(); + push_back(ValueToken::NullValue {}); break; } case Type::Boolean: { - _concept->write_bool(response.get()); + push_back(ValueToken::BoolValue { value.get() }); break; } case Type::Int: { - _concept->write_int(response.get()); + push_back(ValueToken::IntValue { value.get() }); break; } case Type::Float: { - _concept->write_float(response.get()); + push_back(ValueToken::FloatValue { value.get() }); + break; + } + + case Type::EnumValue: + { + auto enumValue = value.release(); + + push_back(ValueToken::EnumValue { std::move(enumValue) }); + break; + } + + case Type::ID: + { + auto idValue = value.release(); + + push_back(ValueToken::IdValue { std::move(idValue) }); break; } case Type::Scalar: { - write(response.release()); + append(ValueTokenStream { value.release() }); break; } default: { - _concept->write_null(); + push_back(ValueToken::NullValue {}); break; } } } +void ValueTokenStream::append(ValueTokenStream&& other) +{ + _tokens.splice(_tokens.end(), std::move(other._tokens)); +} + +void ValueTokenStream::visit(const std::shared_ptr& visitor) && +{ + for (auto& token : _tokens) + { + std::move(token).visit(visitor); + } + + visitor->complete(); +} + +Value ValueTokenStream::value() && +{ + auto visitor = std::make_shared(); + + std::move(*this).visit(std::make_shared(visitor)); + + return visitor->value(); +} + } // namespace graphql::response diff --git a/src/RapidJSONResponse.cpp b/src/RapidJSONResponse.cpp index e7067f61..abdcaee4 100644 --- a/src/RapidJSONResponse.cpp +++ b/src/RapidJSONResponse.cpp @@ -16,7 +16,7 @@ namespace graphql::response { -class StreamWriter +class StreamWriter : public std::enable_shared_from_this { public: StreamWriter(rapidjson::StringBuffer& buffer) @@ -24,12 +24,23 @@ class StreamWriter { } + void add_value(std::shared_ptr&& value) + { + auto writer = std::make_shared(shared_from_this()); + + ValueTokenStream(Value { *value }).visit(writer); + } + + void reserve(std::size_t /* count */) + { + } + void start_object() { _writer.StartObject(); } - void add_member(const std::string& key) + void add_member(std::string&& key) { _writer.Key(key.c_str()); } @@ -44,36 +55,50 @@ class StreamWriter _writer.StartArray(); } - void end_arrary() + void end_array() { _writer.EndArray(); } - void write_null() + void add_null() { _writer.Null(); } - void write_string(const std::string& value) + void add_string(std::string&& value) { _writer.String(value.c_str()); } - void write_bool(bool value) + void add_enum(std::string&& value) + { + add_string(std::move(value)); + } + + void add_id(IdType&& value) + { + add_string(value.release()); + } + + void add_bool(bool value) { _writer.Bool(value); } - void write_int(int value) + void add_int(int value) { _writer.Int(value); } - void write_float(double value) + void add_float(double value) { _writer.Double(value); } + void complete() + { + } + private: rapidjson::Writer _writer; }; @@ -81,9 +106,10 @@ class StreamWriter std::string toJSON(Value&& response) { rapidjson::StringBuffer buffer; - Writer writer { std::make_unique(buffer) }; + auto writer = std::make_shared(std::make_shared(buffer)); + + ValueTokenStream(std::move(response)).visit(writer); - writer.write(std::move(response)); return buffer.GetString(); } diff --git a/src/TaoCppJSONResponse.cpp b/src/TaoCppJSONResponse.cpp index 341327b8..3616d621 100644 --- a/src/TaoCppJSONResponse.cpp +++ b/src/TaoCppJSONResponse.cpp @@ -13,7 +13,7 @@ namespace graphql::response { -class StreamWriter +class StreamWriter : public std::enable_shared_from_this { public: StreamWriter(std::ostream& stream) @@ -21,13 +21,24 @@ class StreamWriter { } + void add_value(std::shared_ptr&& value) + { + auto writer = std::make_shared(shared_from_this()); + + ValueTokenStream(Value { *value }).visit(writer); + } + + void reserve(std::size_t /* count */) + { + } + void start_object() { _scopeStack.push_back(Scope::Object); _writer.begin_object(); } - void add_member(const std::string& key) + void add_member(std::string&& key) { _writer.key(key); } @@ -45,43 +56,57 @@ class StreamWriter _writer.begin_array(); } - void end_arrary() + void end_array() { _writer.end_array(); _scopeStack.pop_back(); end_value(); } - void write_null() + void add_null() { _writer.null(); end_value(); } - void write_string(const std::string& value) + void add_string(std::string&& value) { _writer.string(value); end_value(); } - void write_bool(bool value) + void add_enum(std::string&& value) + { + add_string(std::move(value)); + } + + void add_id(IdType&& value) + { + add_string(value.release()); + } + + void add_bool(bool value) { _writer.boolean(value); end_value(); } - void write_int(int value) + void add_int(int value) { _writer.number(static_cast(value)); end_value(); } - void write_float(double value) + void add_float(double value) { _writer.number(value); end_value(); } + void complete() + { + } + private: enum class Scope { @@ -115,8 +140,10 @@ class StreamWriter std::string toJSON(Value&& response) { std::ostringstream stream; - Writer writer { std::make_unique(stream) }; - writer.write(std::move(response)); + auto writer = std::make_shared(std::make_shared(stream)); + + ValueTokenStream(std::move(response)).visit(writer); + return stream.str(); }