Skip to content

Commit

Permalink
fable: Fix excessive compilation duration
Browse files Browse the repository at this point in the history
  • Loading branch information
clsim committed Dec 18, 2023
1 parent 54877b8 commit d563066
Show file tree
Hide file tree
Showing 19 changed files with 176 additions and 86 deletions.
100 changes: 100 additions & 0 deletions fable/include/fable/make_schema.hpp
Original file line number Diff line number Diff line change
@@ -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 <string>

#include <fable/fable_fwd.hpp>
#include <fable/schema/array.hpp> // for Array<>
#include <fable/schema/boolean.hpp> // for Boolean
#include <fable/schema/confable.hpp> // for FromConfable
#include <fable/schema/const.hpp> // for Const<>
#include <fable/schema/duration.hpp> // for Duration<>
#include <fable/schema/enum.hpp> // for Enum<>
#include <fable/schema/ignore.hpp> // for Ignore
#include <fable/schema/interface.hpp> // for Interface, Box
#include <fable/schema/json.hpp> // for FromJson<>
#include <fable/schema/map.hpp> // for Map<>
#include <fable/schema/number.hpp> // for Number<>
#include <fable/schema/optional.hpp> // for Optional<>
#include <fable/schema/passthru.hpp> // for Passthru
#include <fable/schema/path.hpp> // for Path
#include <fable/schema/string.hpp> // for String
#include <fable/schema/struct.hpp> // for Struct
#include <fable/schema/variant.hpp> // for Variant
#include <fable/schema/vector.hpp> // 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 <fable/schema/xmagic.hpp> // for make_prototype

namespace fable {

namespace schema {

namespace details {

/**
* Implements the make_schema function for one datatype
*/
template <typename T>
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 <typename T>
auto make_schema(T* ptr, std::string desc) {
return details::make_schema_wrapper<T>::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 <typename T, typename T2>
auto make_schema(T* ptr, T2 proto, std::string desc) {
return ::fable::schema::make_schema_impl(ptr, proto, desc);
}

} // namespace schema
} // namespace fable
25 changes: 2 additions & 23 deletions fable/include/fable/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,36 +122,15 @@
#include <utility> // for move
#include <vector> // for vector<>

#include <fable/fable_fwd.hpp>
#include <fable/schema/array.hpp> // for Array<>
#include <fable/schema/boolean.hpp> // for Boolean
#include <fable/schema/confable.hpp> // for FromConfable
#include <fable/schema/const.hpp> // for Const<>
#include <fable/schema/duration.hpp> // for Duration<>
#include <fable/schema/enum.hpp> // for Enum<>
#include <fable/schema/ignore.hpp> // for Ignore
#include <fable/schema/interface.hpp> // for Interface, Box
#include <fable/schema/json.hpp> // for FromJson<>
#include <fable/schema/map.hpp> // for Map<>
#include <fable/schema/number.hpp> // for Number<>
#include <fable/schema/optional.hpp> // for Optional<>
#include <fable/schema/passthru.hpp> // for Passthru
#include <fable/schema/path.hpp> // for Path
#include <fable/schema/string.hpp> // for String
#include <fable/schema/struct.hpp> // for Struct
#include <fable/schema/variant.hpp> // for Variant
#include <fable/schema/vector.hpp> // 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 <fable/schema/xmagic.hpp> // for make_prototype
#include <fable/make_schema.hpp> // for make_schema

namespace fable {

// Bring all make_* functions into the fable namespace.
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.
Expand Down
33 changes: 19 additions & 14 deletions fable/include/fable/schema/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ class Array : public Base<Array<T, N, P>> {
using Type = std::array<T, N>;
using PrototypeSchema = P;

Array(Type* ptr, std::string desc)
: Array<T, N, P>(ptr, make_prototype<T>(), std::move(desc)) {}
Array(Type* ptr, std::string desc) : Array<T, N, P>(ptr, make_prototype<T>(), std::move(desc)) {}

Array(Type* ptr, PrototypeSchema prototype)
: Base<Array<T, N, P>>(), prototype_(std::move(prototype)), ptr_(ptr) {}
Expand Down Expand Up @@ -75,7 +74,9 @@ class Array : public Base<Array<T, N, P>> {
}

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;
Expand Down Expand Up @@ -108,12 +109,12 @@ class Array : public Base<Array<T, N, P>> {

// 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);
}
}

Expand Down Expand Up @@ -266,16 +267,19 @@ class Array : public Base<Array<T, N, P>> {
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;
}
Expand Down Expand Up @@ -317,12 +321,13 @@ class Array : public Base<Array<T, N, P>> {
};

template <typename T, typename P, size_t N>
Array<T, N, P> make_schema(std::array<T, N>* ptr, P prototype, std::string desc) {
Array<T, N, P> make_schema_impl(std::array<T, N>* ptr, P prototype, std::string desc) {
return Array<T, N, P>(ptr, std::move(prototype), std::move(desc));
}

template <typename T, size_t N>
Array<T, N, decltype(make_prototype<T>())> make_schema(std::array<T, N>* ptr, std::string desc) {
Array<T, N, decltype(make_prototype<T>())> make_schema_impl(std::array<T, N>* ptr,
std::string desc) {
return Array<T, N, decltype(make_prototype<T>())>(ptr, std::move(desc));
}

Expand Down
2 changes: 1 addition & 1 deletion fable/include/fable/schema/boolean.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ class Boolean : public Base<Boolean> {
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
2 changes: 1 addition & 1 deletion fable/include/fable/schema/confable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class FromConfable : public Base<FromConfable<T>> {
};

template <typename T>
FromConfable<T> make_schema(T* ptr, std::string desc) {
FromConfable<T> make_schema_impl(T* ptr, std::string desc) {
assert(ptr != nullptr);
return FromConfable<T>(ptr, std::move(desc));
}
Expand Down
4 changes: 2 additions & 2 deletions fable/include/fable/schema/duration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ class Duration : public Base<Duration<T, Period>> {
};

template <typename Rep, typename Period>
inline Duration<Rep, Period> make_schema(std::chrono::duration<Rep, Period>* ptr,
std::string desc) {
inline Duration<Rep, Period> make_schema_impl(std::chrono::duration<Rep, Period>* ptr,
std::string desc) {
return Duration<Rep, Period>(ptr, std::move(desc));
}

Expand Down
2 changes: 1 addition & 1 deletion fable/include/fable/schema/enum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class Enum : public Base<Enum<T>> {
};

template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
inline Enum<T> make_schema(T* ptr, std::string desc) {
inline Enum<T> make_schema_impl(T* ptr, std::string desc) {
return Enum<T>(ptr, std::move(desc));
}

Expand Down
10 changes: 7 additions & 3 deletions fable/include/fable/schema/ignore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,23 @@ class Ignore : public Base<Ignore> {
return j;
}

bool validate(const Conf& /*unused*/, std::optional<SchemaError>& /*unused*/) const override { return true; }
bool validate(const Conf& /*unused*/, std::optional<SchemaError>& /*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);
}

Expand Down
12 changes: 4 additions & 8 deletions fable/include/fable/schema/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,29 +76,25 @@ class FromJson : public Base<FromJson<T>> {

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<Type>::to_json(j, x);
}

template<typename = std::enable_if<std::is_default_constructible_v<Type>>>
template <typename = std::enable_if<std::is_default_constructible_v<Type>>>
[[nodiscard]] Type deserialize(const Conf& c) const {
return c->get<Type>();
}

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 <typename T>
inline FromJson<T> make_schema(T* ptr, JsonType t, std::string desc) {
inline FromJson<T> make_schema_impl(T* ptr, JsonType t, std::string desc) {
return FromJson<T>(ptr, t, std::move(desc));
}

Expand Down
14 changes: 9 additions & 5 deletions fable/include/fable/schema/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ class Map : public Base<Map<T, P>> {
}

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_) {
Expand All @@ -142,7 +144,8 @@ class Map : public Base<Map<T, P>> {
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;
Expand Down Expand Up @@ -207,12 +210,13 @@ class Map : public Base<Map<T, P>> {
};

template <typename T, typename P>
Map<T, P> make_schema(std::map<std::string, T>* ptr, P prototype, std::string desc) {
Map<T, P> make_schema_impl(std::map<std::string, T>* ptr, P prototype, std::string desc) {
return Map<T, P>(ptr, std::move(prototype), std::move(desc));
}

template <typename T>
Map<T, decltype(make_prototype<T>())> make_schema(std::map<std::string, T>* ptr, std::string desc) {
Map<T, decltype(make_prototype<T>())> make_schema_impl(std::map<std::string, T>* ptr,
std::string desc) {
return Map<T, decltype(make_prototype<T>())>(ptr, std::move(desc));
}

Expand Down
5 changes: 3 additions & 2 deletions fable/include/fable/schema/number.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class Number : public Base<Number<T>> {
public: // Types and Constructors
using Type = T;

template <typename X = T, std::enable_if_t<std::is_integral_v<X> && std::is_unsigned_v<X>, int> = 0>
template <typename X = T,
std::enable_if_t<std::is_integral_v<X> && std::is_unsigned_v<X>, int> = 0>
Number(Type* ptr, std::string desc)
: Base<Number<T>>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {}

Expand Down Expand Up @@ -103,7 +104,7 @@ class Number : public Base<Number<T>> {
};

template <typename T, std::enable_if_t<std::is_arithmetic_v<T> && !std::is_enum_v<T>, int> = 0>
inline Number<T> make_schema(T* ptr, std::string desc) {
inline Number<T> make_schema_impl(T* ptr, std::string desc) {
return Number<T>(ptr, std::move(desc));
}

Expand Down
8 changes: 4 additions & 4 deletions fable/include/fable/schema/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,15 @@ class Optional : public Base<Optional<T, P>> {
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 <typename T, typename P, std::enable_if_t<is_optional_v<T>, bool> = true>
inline Optional<T, P> make_schema(T* ptr, P prototype, std::string desc) {
inline Optional<T, P> make_schema_impl(T* ptr, P prototype, std::string desc) {
return Optional<T, P>(ptr, std::move(prototype), std::move(desc));
}

template <typename T, std::enable_if_t<is_optional_v<T>, bool> = true>
Optional<T, decltype(make_prototype<typename T::value_type>())> make_schema(T* ptr,
std::string desc) {
Optional<T, decltype(make_prototype<typename T::value_type>())> make_schema_impl(T* ptr,
std::string desc) {
return Optional<T, decltype(make_prototype<typename T::value_type>())>(ptr, std::move(desc));
}

Expand Down
Loading

0 comments on commit d563066

Please sign in to comment.