diff --git a/ttg/CMakeLists.txt b/ttg/CMakeLists.txt index c57d971186..c079c85625 100644 --- a/ttg/CMakeLists.txt +++ b/ttg/CMakeLists.txt @@ -26,6 +26,7 @@ set(ttg-base-headers ${CMAKE_CURRENT_SOURCE_DIR}/ttg/base/world.h ) set(ttg-impl-headers + ${CMAKE_CURRENT_SOURCE_DIR}/ttg/attributes.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/broadcast.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/edge.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/execution.h diff --git a/ttg/ttg/attributes.h b/ttg/ttg/attributes.h new file mode 100644 index 0000000000..2239814da6 --- /dev/null +++ b/ttg/ttg/attributes.h @@ -0,0 +1,147 @@ +#ifndef TTG_ATTRIBUTES_H +#define TTG_ATTRIBUTES_H + +namespace ttg { + + + /** + * A set of attributes supported by TTG. + */ + enum class Attribute : size_t { + PRIORITY = 0, + PROCESS, + FINAL, + SOURCE, + IMMEDIATE + }; + + + /** + * An attribute value that can store either a fixed value or a function + * to query that value based on a provided key. + */ + template + struct AttributeValue { + using value_type = std::decay_t; + using key_type = std::decay_t; + using function_type = std::function; + static constexpr const Attribute attribute_id = A; + private: + function_type fn; + value_type val; + public: + + AttributeValue() : val(value_type{}) + { } + + template + AttributeValue(Value_&& value) : val(std::forward(value)) + { } + + template>> + void set(Fn&& fn) { + this->fn = std::forward(fn); + } + + void set(value_type val) { + this->val = val; + this->fn = nullptr; + } + + value_type get(const KeyT& key) const { + return fn ? fn(key) : val; + } + + value_type operator()(const KeyT& key) const { + return get(key); + } + + }; + + + /* Overload for keys of type void */ + template + struct AttributeValue { + using value_type = std::decay_t; + using function_type = std::function; + static constexpr const Attribute attribute_id = A; + private: + function_type fn; + value_type val; + public: + + AttributeValue() : val(value_type{}) + { } + + template + AttributeValue(Value_&& value) : val(std::forward(value)) + { } + + template>> + void set(Fn&& fn) { + this->fn = std::forward(fn); + } + + void set(value_type val) { + this->val = val; + this->fn = nullptr; + } + + value_type get(void) const { + return fn ? fn() : val; + } + + value_type operator()() const { + return get(); + } + + }; + + /* Overload for keys of type ttg::Void */ + template + struct AttributeValue { + using value_type = std::decay_t; + using function_type = std::function; + static constexpr const Attribute attribute_id = A; + private: + function_type fn; + value_type val; + public: + + AttributeValue() : val(value_type{}) + { } + + template + AttributeValue(Value_&& value) : val(std::forward(value)) + { } + + template>> + void set(Fn&& fn) { + this->fn = std::forward(fn); + } + + void set(value_type val) { + this->val = val; + this->fn = nullptr; + } + + value_type get(void) const { + return fn ? fn() : val; + } + + value_type operator()() const { + return get(); + } + + }; + + template + using tt_attribute_set_t = std::tuple, + AttributeValue, + AttributeValue, + AttributeValue, + AttributeValue>; + +} // namespace ttg + +#endif // TTG_ATTRIBUTES_H diff --git a/ttg/ttg/parsec/ttg.h b/ttg/ttg/parsec/ttg.h index e261142425..615ffa5b7c 100644 --- a/ttg/ttg/parsec/ttg.h +++ b/ttg/ttg/parsec/ttg.h @@ -11,6 +11,7 @@ /* include ttg header to make symbols available in case this header is included directly */ #include "../../ttg.h" +#include "ttg/attributes.h" #include "ttg/base/keymap.h" #include "ttg/base/tt.h" #include "ttg/base/world.h" @@ -43,6 +44,7 @@ #include #include #include +#include #include #include @@ -831,8 +833,41 @@ namespace ttg_parsec { make_finalize_argstream_fcts(std::make_index_sequence{}); ttg::World world; - ttg::meta::detail::keymap_t keymap; - ttg::meta::detail::keymap_t priomap; + + ttg::tt_attribute_set_t attributes; + + // wrapper for attribute keymap + template>> + inline int keymap(KeyT&& key) const { + return get_attribute(key); + } + + inline int keymap() const { + if constexpr (ttg::meta::is_void_v) { + return get_attribute().get(); + } else { + // will never be used, but we cannot disable this function using enable_if + throw std::logic_error("UNREACHABLE!"); + } + } + + // wrapper for attribute priomap + template>> + inline + int priomap(KeyT&& key) const { + return get_attribute(key); + } + + inline + int priomap() const { + if constexpr (ttg::meta::is_void_v) { + return get_attribute().get(); + } else { + // will never be used, but we cannot disable this function using enable_if + throw std::logic_error("UNREACHABLE!"); + } + } + // For now use same type for unary/streaming input terminals, and stream reducers assigned at runtime ttg::meta::detail::input_reducers_t input_reducers; //!< Reducers for the input terminals (empty = expect single value) @@ -2314,12 +2349,15 @@ namespace ttg_parsec { ttg::World world, keymapT &&keymap_ = keymapT(), priomapT &&priomap_ = priomapT() ) : ttg::TTBase(name, numins, numouts) , world(world) - // if using default keymap, rebind to the given world - , keymap(std::is_same>::value - ? decltype(keymap)(ttg::detail::default_keymap(world)) - : decltype(keymap)(std::forward(keymap_))) - , priomap(decltype(keymap)(std::forward(priomap_))) , static_stream_goal() { + + // if using default keymap, rebind to the given world + if constexpr (std::is_same>::value) { + set_attribute(ttg::detail::default_keymap(world)); + } else { + set_attribute(keymap_); + } + // Cannot call these in base constructor since terminals not yet constructed if (innames.size() != std::tuple_size::value) throw std::logic_error("ttg_parsec::OP: #input names != #input terminals"); @@ -2539,25 +2577,47 @@ namespace ttg_parsec { ttg::TTBase::make_executable(); } - /// keymap accessor - /// @return the keymap - const decltype(keymap) &get_keymap() const { return keymap; } + /// priomap setter + /// @arg pm a function that maps a key to an integral priority value. + template + [[deprecated("Use set_attribute_map with Attribute::PRIORITY")]] + void set_priomap(Priomap &&pm) { + set_attribute(std::forward(pm)); + } /// keymap setter template + [[deprecated("Use set_attribute_map with Attribute::PROCESS")]] void set_keymap(Keymap &&km) { - keymap = km; + set_attribute(std::forward(km)); } - /// priority map accessor - /// @return the priority map - const decltype(priomap) &get_priomap() const { return priomap; } + template + void set_attribute(ValueOrFnT&& x) { + static_assert(std::tuple_element_t<(size_t)A, ttg::tt_attribute_set_t>::attribute_id == A, "Someone broke the attributes order!"); + std::get<(size_t)A>(attributes).set(std::forward(x)); + } - /// priomap setter - /// @arg pm a function that maps a key to an integral priority value. - template - void set_priomap(Priomap &&pm) { - priomap = pm; + template>> + const auto get_attribute(KeyT&& key) const { + static_assert(std::tuple_element_t<(size_t)A, ttg::tt_attribute_set_t>::attribute_id == A, "Someone broke the attributes order!"); + return std::get<(size_t)A>(attributes).get(key); + } + + template>> + const auto get_attribute() const { + static_assert(std::tuple_element_t<(size_t)A, ttg::tt_attribute_set_t>::attribute_id == A, "Someone broke the attributes order!"); + return std::get<(size_t)A>(attributes).get(); + } + + template + const auto& get_attribute(void) const { + static_assert(std::tuple_element_t<(size_t)A, ttg::tt_attribute_set_t>::attribute_id == A, "Someone broke the attributes order!"); + return std::get<(size_t)A>(attributes); + } + + inline const auto& get_keymap() const { + return get_attribute(); } // Register the static_op function to associate it to instance_id