/** * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBPANDABASE_UTILS_JSON_BUILDER_H #define LIBPANDABASE_UTILS_JSON_BUILDER_H #include #include #include #include #include #include #include #include #include namespace panda { class JsonArrayBuilder; class JsonObjectBuilder; void JsonEscape(std::ostream & /* os */, std::string_view /* string */); template class JsonBuilderBase { public: JsonBuilderBase() { ss_ << startDelimiter; } std::string Build() && { ss_ << endDelimiter; return ss_.str(); } protected: void Entry() { if (firstEntry_) { firstEntry_ = false; } else { ss_ << ','; } } template void Append(T &&value) { ss_ << (std::forward(value)); } void Stringify(std::nullptr_t) { ss_ << "null"; } void Stringify(bool boolean) { ss_ << (boolean ? "true" : "false"); } template && !std::is_same_v, int> = 0> void Stringify(T &&number) { auto value = static_cast(std::forward(number)); if (std::isfinite(value)) { ss_ << value; } else { ss_ << "null"; } } void Stringify(std::string_view string) { JsonEscape(ss_, string); } void Stringify(const char *string) { JsonEscape(ss_, string); } template , int> = 0> void Stringify(T &&array); template , int> = 0> void Stringify(T &&object); private: std::stringstream ss_; bool firstEntry_ {true}; }; class JsonArrayBuilder : public JsonBuilderBase<'[', ']'> { public: template JsonArrayBuilder &Add(T &&value) & { Entry(); Stringify(std::forward(value)); return *this; } template JsonArrayBuilder &&Add(T &&value) && { Add(std::forward(value)); return std::move(*this); } }; // Trick CodeChecker (G.FMT.03). using JsonObjectBuilderBase = JsonBuilderBase<'{', '}'>; class JsonObjectBuilder : public JsonObjectBuilderBase { public: template JsonObjectBuilder &AddProperty(const std::string_view &key, T &&value) & { Entry(); Stringify(key); Append(":"); Stringify(std::forward(value)); return *this; } template JsonObjectBuilder &&AddProperty(std::string_view key, T &&value) && { AddProperty(key, std::forward(value)); return std::move(*this); } }; template template , int>> void JsonBuilderBase::Stringify(T &&array) { JsonArrayBuilder builder; std::invoke(std::forward(array), builder); ss_ << std::move(builder).Build(); } template template , int>> void JsonBuilderBase::Stringify(T &&object) { JsonObjectBuilder builder; std::invoke(std::forward(object), builder); ss_ << std::move(builder).Build(); } } // namespace panda #endif // LIBPANDABASE_UTILS_JSON_BUILDER_H