From d563066dbaa075fc984ddb8e24ae12f8d24dd16a Mon Sep 17 00:00:00 2001 From: Martin Henselmeyer Date: Fri, 15 Dec 2023 09:40:54 +0100 Subject: [PATCH] fable: Fix excessive compilation duration --- fable/include/fable/make_schema.hpp | 100 ++++++++++++++++++++++++ fable/include/fable/schema.hpp | 25 +----- fable/include/fable/schema/array.hpp | 33 ++++---- fable/include/fable/schema/boolean.hpp | 2 +- fable/include/fable/schema/confable.hpp | 2 +- fable/include/fable/schema/duration.hpp | 4 +- fable/include/fable/schema/enum.hpp | 2 +- fable/include/fable/schema/ignore.hpp | 10 ++- fable/include/fable/schema/json.hpp | 12 +-- fable/include/fable/schema/map.hpp | 14 ++-- fable/include/fable/schema/number.hpp | 5 +- fable/include/fable/schema/optional.hpp | 8 +- fable/include/fable/schema/passthru.hpp | 4 +- fable/include/fable/schema/path.hpp | 5 +- fable/include/fable/schema/string.hpp | 2 +- fable/include/fable/schema/struct.hpp | 8 +- fable/include/fable/schema/variant.hpp | 8 +- fable/include/fable/schema/vector.hpp | 16 ++-- fable/include/fable/schema/xmagic.hpp | 2 +- 19 files changed, 176 insertions(+), 86 deletions(-) create mode 100644 fable/include/fable/make_schema.hpp diff --git a/fable/include/fable/make_schema.hpp b/fable/include/fable/make_schema.hpp new file mode 100644 index 000000000..fda42914a --- /dev/null +++ b/fable/include/fable/make_schema.hpp @@ -0,0 +1,100 @@ +/* + * Copyright 2023 Robert Bosch GmbH + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * \file fable/make_schema.hpp + * + * This file provides a facade for the make_schema function which implements + * a short-cut for the compiler which reduces the excessive resource + * consumption of the actual implementation. + */ + +#pragma once + +#include + +#include +#include // for Array<> +#include // for Boolean +#include // for FromConfable +#include // for Const<> +#include // for Duration<> +#include // for Enum<> +#include // for Ignore +#include // for Interface, Box +#include // for FromJson<> +#include // for Map<> +#include // for Number<> +#include // for Optional<> +#include // for Passthru +#include // for Path +#include // for String +#include // for Struct +#include // for Variant +#include // for Vector<> + +// It is important that this include comes after all the other ones, +// so that it has access to ALL the previous definitions. +#include // for make_prototype + +namespace fable { + +namespace schema { + +namespace details { + +/** + * Implements the make_schema function for one datatype + */ +template +struct make_schema_wrapper { + static auto make_schema(T* ptr, std::string desc) { + return ::fable::schema::make_schema_impl(ptr, desc); + } +}; + +} // namespace details + +/** + * Returns the schema for a given datum and its description + * + * \param Ptr Pointer to the datum + * \param desc Textual description of the datum + * \return Schema for the datum + */ +template +auto make_schema(T* ptr, std::string desc) { + return details::make_schema_wrapper::make_schema(ptr, desc); +} + +/** + * Returns the schema for a given datum and its description + * + * \param Ptr Pointer to the datum + * \param proto Prototype of the data-value + * \param desc Textual description of the datum + * \return Schema for the datum + * \note Those types which have a prototype, namely string & path + * do not matter for the compile-time reduction + */ +template +auto make_schema(T* ptr, T2 proto, std::string desc) { + return ::fable::schema::make_schema_impl(ptr, proto, desc); +} + +} // namespace schema +} // namespace fable diff --git a/fable/include/fable/schema.hpp b/fable/include/fable/schema.hpp index a4a1ddbd6..eec91eeab 100644 --- a/fable/include/fable/schema.hpp +++ b/fable/include/fable/schema.hpp @@ -122,29 +122,7 @@ #include // for move #include // for vector<> -#include -#include // for Array<> -#include // for Boolean -#include // for FromConfable -#include // for Const<> -#include // for Duration<> -#include // for Enum<> -#include // for Ignore -#include // for Interface, Box -#include // for FromJson<> -#include // for Map<> -#include // for Number<> -#include // for Optional<> -#include // for Passthru -#include // for Path -#include // for String -#include // for Struct -#include // for Variant -#include // for Vector<> - -// It is important that this include comes after all the other ones, -// so that it has access to ALL the previous definitions. -#include // for make_prototype +#include // for make_schema namespace fable { @@ -152,6 +130,7 @@ namespace fable { using schema::make_const_schema; using schema::make_prototype; using schema::make_schema; +using schema::make_schema_impl; /** * Define the automatically deduced schema class of a given type. diff --git a/fable/include/fable/schema/array.hpp b/fable/include/fable/schema/array.hpp index e45e1e417..b37326fcd 100644 --- a/fable/include/fable/schema/array.hpp +++ b/fable/include/fable/schema/array.hpp @@ -41,8 +41,7 @@ class Array : public Base> { using Type = std::array; using PrototypeSchema = P; - Array(Type* ptr, std::string desc) - : Array(ptr, make_prototype(), std::move(desc)) {} + Array(Type* ptr, std::string desc) : Array(ptr, make_prototype(), std::move(desc)) {} Array(Type* ptr, PrototypeSchema prototype) : Base>(), prototype_(std::move(prototype)), ptr_(ptr) {} @@ -75,7 +74,9 @@ class Array : public Base> { } public: // Overrides - [[nodiscard]] std::string type_string() const override { return "array of " + prototype_.type_string(); } + [[nodiscard]] std::string type_string() const override { + return "array of " + prototype_.type_string(); + } [[nodiscard]] Json json_schema() const override { Json j; @@ -108,12 +109,12 @@ class Array : public Base> { // If not require-all, then we can also support object notation. switch (c->type()) { - case JsonType::array: - return this->validate_array(c, err); - case JsonType::object: - return this->validate_object(c, err); - default: - return this->set_wrong_type(err, c); + case JsonType::array: + return this->validate_array(c, err); + case JsonType::object: + return this->validate_object(c, err); + default: + return this->set_wrong_type(err, c); } } @@ -266,16 +267,19 @@ class Array : public Base> { throw std::invalid_argument("invalid index key in object, require integer, got ''"); } if (s.size() > 1 && s[0] == '0') { - throw std::invalid_argument(fmt::format("invalid index key in object, require base-10 value, got '{}'", s)); + throw std::invalid_argument( + fmt::format("invalid index key in object, require base-10 value, got '{}'", s)); } for (char ch : s) { if (ch < '0' || ch > '9') { - throw std::invalid_argument(fmt::format("invalid index key in object, require integer, got '{}'", s)); + throw std::invalid_argument( + fmt::format("invalid index key in object, require integer, got '{}'", s)); } } size_t idx = std::stoul(s); if (idx >= N) { - throw std::invalid_argument(fmt::format("out-of-range index key in object, require < {}, got '{}'", N, s)); + throw std::invalid_argument( + fmt::format("out-of-range index key in object, require < {}, got '{}'", N, s)); } return idx; } @@ -317,12 +321,13 @@ class Array : public Base> { }; template -Array make_schema(std::array* ptr, P prototype, std::string desc) { +Array make_schema_impl(std::array* ptr, P prototype, std::string desc) { return Array(ptr, std::move(prototype), std::move(desc)); } template -Array())> make_schema(std::array* ptr, std::string desc) { +Array())> make_schema_impl(std::array* ptr, + std::string desc) { return Array())>(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/boolean.hpp b/fable/include/fable/schema/boolean.hpp index 61e4b9e44..18ed2c3a0 100644 --- a/fable/include/fable/schema/boolean.hpp +++ b/fable/include/fable/schema/boolean.hpp @@ -52,6 +52,6 @@ class Boolean : public Base { Type* ptr_{nullptr}; }; -inline Boolean make_schema(bool* ptr, std::string desc) { return {ptr, std::move(desc)}; } +inline Boolean make_schema_impl(bool* ptr, std::string desc) { return {ptr, std::move(desc)}; } } // namespace fable::schema diff --git a/fable/include/fable/schema/confable.hpp b/fable/include/fable/schema/confable.hpp index cae7a285e..0f9dc9099 100644 --- a/fable/include/fable/schema/confable.hpp +++ b/fable/include/fable/schema/confable.hpp @@ -102,7 +102,7 @@ class FromConfable : public Base> { }; template -FromConfable make_schema(T* ptr, std::string desc) { +FromConfable make_schema_impl(T* ptr, std::string desc) { assert(ptr != nullptr); return FromConfable(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/duration.hpp b/fable/include/fable/schema/duration.hpp index 310586480..e2f938ad3 100644 --- a/fable/include/fable/schema/duration.hpp +++ b/fable/include/fable/schema/duration.hpp @@ -188,8 +188,8 @@ class Duration : public Base> { }; template -inline Duration make_schema(std::chrono::duration* ptr, - std::string desc) { +inline Duration make_schema_impl(std::chrono::duration* ptr, + std::string desc) { return Duration(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/enum.hpp b/fable/include/fable/schema/enum.hpp index fb1f63bbc..30f44cdd0 100644 --- a/fable/include/fable/schema/enum.hpp +++ b/fable/include/fable/schema/enum.hpp @@ -107,7 +107,7 @@ class Enum : public Base> { }; template , int> = 0> -inline Enum make_schema(T* ptr, std::string desc) { +inline Enum make_schema_impl(T* ptr, std::string desc) { return Enum(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/ignore.hpp b/fable/include/fable/schema/ignore.hpp index 998b5c803..02ac526f6 100644 --- a/fable/include/fable/schema/ignore.hpp +++ b/fable/include/fable/schema/ignore.hpp @@ -54,19 +54,23 @@ class Ignore : public Base { return j; } - bool validate(const Conf& /*unused*/, std::optional& /*unused*/) const override { return true; } + bool validate(const Conf& /*unused*/, std::optional& /*unused*/) const override { + return true; + } using Interface::to_json; void to_json(Json& j) const override { j = nullptr; } void from_conf(const Conf& /*unused*/) override {} void reset_ptr() override {} - [[nodiscard]] Json serialize(const Type& /*unused*/) const { return nullptr; } // NOLINT(readability-convert-member-functions-to-static) + [[nodiscard]] Json serialize(const Type& /*unused*/) const { + return nullptr; + } // NOLINT(readability-convert-member-functions-to-static) [[nodiscard]] Type deserialize(const Conf& /*unused*/) const { return {}; } void serialize_into(Json& /*unused*/, const Type& /*unused*/) const {} void deserialize_into(const Conf& /*unused*/, Type& /*unused*/) const {} }; -inline Ignore make_schema(std::string desc, JsonType t = JsonType::object) { +inline Ignore make_schema_impl(std::string desc, JsonType t = JsonType::object) { return Ignore(std::move(desc), t); } diff --git a/fable/include/fable/schema/json.hpp b/fable/include/fable/schema/json.hpp index bfb0a57f6..111e4ce28 100644 --- a/fable/include/fable/schema/json.hpp +++ b/fable/include/fable/schema/json.hpp @@ -76,29 +76,25 @@ class FromJson : public Base> { void reset_ptr() override { ptr_ = nullptr; } - [[nodiscard]] Json serialize(const Type& x) const { - return Json(x); - } + [[nodiscard]] Json serialize(const Type& x) const { return Json(x); } void serialize_into(Json& j, const Type& x) const { ::nlohmann::adl_serializer::to_json(j, x); } - template>> + template >> [[nodiscard]] Type deserialize(const Conf& c) const { return c->get(); } - void deserialize_into(const Conf& c, Type& x) const { - c->get_to(x); - } + void deserialize_into(const Conf& c, Type& x) const { c->get_to(x); } private: Type* ptr_{nullptr}; }; template -inline FromJson make_schema(T* ptr, JsonType t, std::string desc) { +inline FromJson make_schema_impl(T* ptr, JsonType t, std::string desc) { return FromJson(ptr, t, std::move(desc)); } diff --git a/fable/include/fable/schema/map.hpp b/fable/include/fable/schema/map.hpp index 4366a659c..d65c72057 100644 --- a/fable/include/fable/schema/map.hpp +++ b/fable/include/fable/schema/map.hpp @@ -114,11 +114,13 @@ class Map : public Base> { } if (c->size() < min_properties_) { - return this->set_error(err, c, "expect at least {} properties, got {}", max_properties_, c->size()); + return this->set_error(err, c, "expect at least {} properties, got {}", max_properties_, + c->size()); } assert(required_.size() <= max_properties_); if (c->size() > max_properties_) { - return this->set_error(err, c, "expect at most {} properties, got {}", max_properties_, c->size()); + return this->set_error(err, c, "expect at most {} properties, got {}", max_properties_, + c->size()); } for (const auto& k : required_) { @@ -142,7 +144,8 @@ class Map : public Base> { return false; } if (pattern && !std::regex_match(kv.key(), *pattern)) { - return this->set_error(err, c, "expect property name to match regex '{}': {}", pattern_, kv.key()); + return this->set_error(err, c, "expect property name to match regex '{}': {}", pattern_, + kv.key()); } } return true; @@ -207,12 +210,13 @@ class Map : public Base> { }; template -Map make_schema(std::map* ptr, P prototype, std::string desc) { +Map make_schema_impl(std::map* ptr, P prototype, std::string desc) { return Map(ptr, std::move(prototype), std::move(desc)); } template -Map())> make_schema(std::map* ptr, std::string desc) { +Map())> make_schema_impl(std::map* ptr, + std::string desc) { return Map())>(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/number.hpp b/fable/include/fable/schema/number.hpp index 87aa6f545..60fc789ad 100644 --- a/fable/include/fable/schema/number.hpp +++ b/fable/include/fable/schema/number.hpp @@ -39,7 +39,8 @@ class Number : public Base> { public: // Types and Constructors using Type = T; - template && std::is_unsigned_v, int> = 0> + template && std::is_unsigned_v, int> = 0> Number(Type* ptr, std::string desc) : Base>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {} @@ -103,7 +104,7 @@ class Number : public Base> { }; template && !std::is_enum_v, int> = 0> -inline Number make_schema(T* ptr, std::string desc) { +inline Number make_schema_impl(T* ptr, std::string desc) { return Number(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/optional.hpp b/fable/include/fable/schema/optional.hpp index 1d3996723..16f70d766 100644 --- a/fable/include/fable/schema/optional.hpp +++ b/fable/include/fable/schema/optional.hpp @@ -145,15 +145,15 @@ class Optional : public Base> { Type* ptr_{nullptr}; }; -// Define make_schema only for std::optional and boost::optional. +// Define make_schema_impl only for std::optional and boost::optional. template , bool> = true> -inline Optional make_schema(T* ptr, P prototype, std::string desc) { +inline Optional make_schema_impl(T* ptr, P prototype, std::string desc) { return Optional(ptr, std::move(prototype), std::move(desc)); } template , bool> = true> -Optional())> make_schema(T* ptr, - std::string desc) { +Optional())> make_schema_impl(T* ptr, + std::string desc) { return Optional())>(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/passthru.hpp b/fable/include/fable/schema/passthru.hpp index 2728f6a60..29b7fce08 100644 --- a/fable/include/fable/schema/passthru.hpp +++ b/fable/include/fable/schema/passthru.hpp @@ -94,12 +94,12 @@ class Passthru : public Base> { Type* ptr_{nullptr}; }; -inline Passthru make_schema(Conf* ptr, std::string desc) { +inline Passthru make_schema_impl(Conf* ptr, std::string desc) { return {ptr, Ignore(), std::move(desc)}; } template -Passthru

make_schema(Conf* ptr, P prototype, std::string desc) { +Passthru

make_schema_impl(Conf* ptr, P prototype, std::string desc) { return {ptr, std::move(prototype), std::move(desc)}; } diff --git a/fable/include/fable/schema/path.hpp b/fable/include/fable/schema/path.hpp index d8df7f091..dbb3dc413 100644 --- a/fable/include/fable/schema/path.hpp +++ b/fable/include/fable/schema/path.hpp @@ -93,8 +93,7 @@ class Path : public Base> { using Type = T; using State = PathState; - Path(Type* ptr, std::string desc) - : Base>(JsonType::string, std::move(desc)), ptr_(ptr) {} + Path(Type* ptr, std::string desc) : Base>(JsonType::string, std::move(desc)), ptr_(ptr) {} public: // Special /** @@ -241,7 +240,7 @@ class Path : public Base> { }; template , bool> = true> -inline Path make_schema(T* ptr, std::string desc) { +inline Path make_schema_impl(T* ptr, std::string desc) { return Path(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/string.hpp b/fable/include/fable/schema/string.hpp index f72cebf60..39b81c7cd 100644 --- a/fable/include/fable/schema/string.hpp +++ b/fable/include/fable/schema/string.hpp @@ -259,7 +259,7 @@ class String : public Base { Type* ptr_{nullptr}; }; -inline String make_schema(std::string* ptr, std::string desc) { +inline String make_schema_impl(std::string* ptr, std::string desc) { return {ptr, std::move(desc)}; } diff --git a/fable/include/fable/schema/struct.hpp b/fable/include/fable/schema/struct.hpp index caea3e4fc..a7cabda1e 100644 --- a/fable/include/fable/schema/struct.hpp +++ b/fable/include/fable/schema/struct.hpp @@ -228,22 +228,22 @@ class Struct : public Base { }; template > -inline Struct make_schema(T&& props) { +inline Struct make_schema_impl(T&& props) { return Struct(std::forward(props)); } template > -inline Struct make_schema(std::string desc, T&& props) { +inline Struct make_schema_impl(std::string desc, T&& props) { return Struct(std::move(desc), std::forward(props)); } template > -inline Struct make_schema(std::string desc, const Box& base, T&& props) { +inline Struct make_schema_impl(std::string desc, const Box& base, T&& props) { return Struct(std::move(desc), base, std::forward(props)); } template > -inline Struct make_schema(std::string desc, const Struct& base, T&& props) { +inline Struct make_schema_impl(std::string desc, const Struct& base, T&& props) { return Struct(std::move(desc), base, std::forward(props)); } diff --git a/fable/include/fable/schema/variant.hpp b/fable/include/fable/schema/variant.hpp index 4ce088dfd..0a4e00963 100644 --- a/fable/include/fable/schema/variant.hpp +++ b/fable/include/fable/schema/variant.hpp @@ -134,13 +134,13 @@ class Variant : public Interface { bool unique_match_{false}; }; -inline Variant make_schema(std::initializer_list vec) { return {vec}; } -inline Variant make_schema(std::string desc, std::initializer_list vec) { +inline Variant make_schema_impl(std::initializer_list vec) { return {vec}; } +inline Variant make_schema_impl(std::string desc, std::initializer_list vec) { return {std::move(desc), std::vector(vec)}; } -inline Variant make_schema(std::vector&& vec) { return {std::move(vec)}; } -inline Variant make_schema(std::string desc, std::vector&& vec) { +inline Variant make_schema_impl(std::vector&& vec) { return {std::move(vec)}; } +inline Variant make_schema_impl(std::string desc, std::vector&& vec) { return {std::move(desc), std::move(vec)}; } diff --git a/fable/include/fable/schema/vector.hpp b/fable/include/fable/schema/vector.hpp index 6e7729170..a74118bce 100644 --- a/fable/include/fable/schema/vector.hpp +++ b/fable/include/fable/schema/vector.hpp @@ -23,10 +23,10 @@ #pragma once -#include // for numeric_limits<> -#include // for string -#include // for move -#include // for vector<> +#include // for numeric_limits<> +#include // for string +#include // for move +#include // for vector<> #include // for Base<>, Box @@ -85,7 +85,9 @@ class Vector : public Base> { } public: // Overrides - [[nodiscard]] std::string type_string() const override { return "array of " + prototype_.type_string(); } + [[nodiscard]] std::string type_string() const override { + return "array of " + prototype_.type_string(); + } [[nodiscard]] Json json_schema() const override { Json j{ @@ -186,12 +188,12 @@ class Vector : public Base> { }; template -Vector make_schema(std::vector* ptr, P prototype, std::string desc) { +Vector make_schema_impl(std::vector* ptr, P prototype, std::string desc) { return Vector(ptr, std::move(prototype), std::move(desc)); } template -Vector())> make_schema(std::vector* ptr, std::string desc) { +Vector())> make_schema_impl(std::vector* ptr, std::string desc) { return Vector())>(ptr, std::move(desc)); } diff --git a/fable/include/fable/schema/xmagic.hpp b/fable/include/fable/schema/xmagic.hpp index 5f6e0fd9e..4b5283a22 100644 --- a/fable/include/fable/schema/xmagic.hpp +++ b/fable/include/fable/schema/xmagic.hpp @@ -50,7 +50,7 @@ auto make_prototype(std::string desc) { template , int>> auto make_prototype(std::string desc) { - return make_schema(static_cast(nullptr), std::move(desc)); + return make_schema_impl(static_cast(nullptr), std::move(desc)); } } // namespace fable::schema