diff --git a/tt_metal/impl/buffers/global_circular_buffer.cpp b/tt_metal/impl/buffers/global_circular_buffer.cpp index 4d438e91fcc..2d8760f1af5 100644 --- a/tt_metal/impl/buffers/global_circular_buffer.cpp +++ b/tt_metal/impl/buffers/global_circular_buffer.cpp @@ -159,3 +159,12 @@ uint32_t GlobalCircularBuffer::size() const { return this->size_; } } // namespace v1 } // namespace tt::tt_metal + +namespace std { + +std::size_t hash::operator()( + const tt::tt_metal::v1::experimental::GlobalCircularBuffer& global_circular_buffer) const { + return tt::stl::hash::hash_objects_with_default_seed(global_circular_buffer); +} + +} // namespace std diff --git a/tt_metal/impl/buffers/global_circular_buffer.hpp b/tt_metal/impl/buffers/global_circular_buffer.hpp index c263fe47d00..d18ed91e0c4 100644 --- a/tt_metal/impl/buffers/global_circular_buffer.hpp +++ b/tt_metal/impl/buffers/global_circular_buffer.hpp @@ -76,3 +76,12 @@ class GlobalCircularBuffer { } // namespace v1 } // namespace tt::tt_metal + +namespace std { + +template <> +struct hash { + std::size_t operator()(const tt::tt_metal::v1::experimental::GlobalCircularBuffer& global_circular_buffer) const; +}; + +} // namespace std diff --git a/tt_metal/impl/buffers/global_semaphore.cpp b/tt_metal/impl/buffers/global_semaphore.cpp index 807e74a8e10..64d16beb377 100644 --- a/tt_metal/impl/buffers/global_semaphore.cpp +++ b/tt_metal/impl/buffers/global_semaphore.cpp @@ -77,3 +77,12 @@ void GlobalSemaphore::reset_semaphore_value() { } } // namespace tt::tt_metal + +namespace std { + +std::size_t hash::operator()( + const tt::tt_metal::GlobalSemaphore& global_semaphore) const { + return tt::stl::hash::hash_objects_with_default_seed(global_semaphore); +} + +} // namespace std diff --git a/tt_metal/impl/buffers/global_semaphore.hpp b/tt_metal/impl/buffers/global_semaphore.hpp index 6c2f8d17947..f6d657998f8 100644 --- a/tt_metal/impl/buffers/global_semaphore.hpp +++ b/tt_metal/impl/buffers/global_semaphore.hpp @@ -44,6 +44,9 @@ class GlobalSemaphore { void reset_semaphore_value(); + static constexpr auto attribute_names = std::forward_as_tuple("cores", "initial_value"); + const auto attribute_values() const { return std::make_tuple(this->cores_, this->initial_value_); } + private: void setup_buffer(BufferType buffer_type); @@ -59,3 +62,12 @@ class GlobalSemaphore { } // namespace v0 } // namespace tt::tt_metal + +namespace std { + +template <> +struct hash { + std::size_t operator()(const tt::tt_metal::GlobalSemaphore& global_semaphore) const; +}; + +} // namespace std diff --git a/tt_metal/tt_stl/reflection.hpp b/tt_metal/tt_stl/reflection.hpp index 42c3aecb6a4..e0c7cfd5199 100644 --- a/tt_metal/tt_stl/reflection.hpp +++ b/tt_metal/tt_stl/reflection.hpp @@ -6,7 +6,10 @@ #include +#include +#include #include +#include #include #include #include @@ -14,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -448,6 +452,32 @@ std::ostream& operator<<(std::ostream& os, const std::set& set) { return os; } +template +std::ostream& operator<<(std::ostream& os, const std::map& map) { + os << "{"; + for (auto it = map.begin(); it != map.end(); ++it) { + os << it->first << ": " << it->second; + if (it != map.end()) { + os << ", "; + } + } + os << "}"; + return os; +} + +template +std::ostream& operator<<(std::ostream& os, const std::unordered_map& map) { + os << "{"; + for (auto it = map.begin(); it != map.end(); ++it) { + os << it->first << ": " << it->second; + if (it != map.end()) { + os << ", "; + } + } + os << "}"; + return os; +} + template requires(tt::stl::concepts::Reflectable and not(std::integral or std::is_array::value)) std::ostream& operator<<(std::ostream& os, const T& object) { @@ -978,6 +1008,30 @@ struct fmt::formatter> { } }; +template +struct fmt::formatter> { + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.end(); } + + auto format(const std::map& map, format_context& ctx) const -> format_context::iterator { + using tt::stl::reflection::operator<<; + std::stringstream ss; + ss << map; + return fmt::format_to(ctx.out(), "{}", ss.str()); + } +}; + +template +struct fmt::formatter> { + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator { return ctx.end(); } + + auto format(const std::unordered_map& map, format_context& ctx) const -> format_context::iterator { + using tt::stl::reflection::operator<<; + std::stringstream ss; + ss << map; + return fmt::format_to(ctx.out(), "{}", ss.str()); + } +}; + template requires( tt::stl::concepts::Reflectable and not(std::integral or std::is_array::value or @@ -1063,7 +1117,7 @@ inline hash_t hash_object(const T& object) noexcept { fmt::print("Hashing struct {} using compile-time attributes: {}\n", get_type_name(), object); } constexpr auto num_attributes = reflection::detail::get_num_attributes(); - std::size_t hash = 0; + hash_t hash = 0; const auto attribute_values = object.attribute_values(); [&object, &hash, &attribute_values](std::index_sequence) { ( @@ -1074,11 +1128,26 @@ inline hash_t hash_object(const T& object) noexcept { ...); }(std::make_index_sequence{}); return hash; + } else if constexpr (is_specialization_v) { + if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { + fmt::print("Hashing std::tuple of type {}: {}\n", get_type_name(), object); + } + constexpr auto num_elements = std::tuple_size_v; + hash_t hash = 0; + [&object, &hash](std::index_sequence) { + ( + [&object, &hash] { + const auto& element = std::get(object); + hash = hash_objects(hash, element); + }(), + ...); + }(std::make_index_sequence{}); + return hash; } else if constexpr (is_specialization_v) { if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { fmt::print("Hashing std::vector of type {}: {}\n", get_type_name(), object); } - auto hash = 0; + hash_t hash = 0; for (const auto& element : object) { hash = hash_objects(hash, element); } @@ -1087,11 +1156,37 @@ inline hash_t hash_object(const T& object) noexcept { if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { fmt::print("Hashing std::set of type {}: {}\n", get_type_name(), object); } - auto hash = 0; + hash_t hash = 0; for (const auto& element : object) { hash = hash_objects(hash, element); } return hash; + } else if constexpr (is_specialization_v) { + if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { + fmt::print("Hashing std::map of type {}: {}\n", get_type_name(), object); + } + hash_t hash = 0; + for (const auto& [key, value] : object) { + hash = hash_objects(hash, key, value); + } + return hash; + } else if constexpr (is_specialization_v) { + if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { + fmt::print("Hashing std::unordered_map of type {}: {}\n", get_type_name(), object); + } + // Sort the unordered map by key to make the hash order invariant + std::vector iterators; + iterators.reserve(object.size()); + for (auto it = object.begin(); it != object.end(); ++it) { + iterators.push_back(it); + } + std::sort(iterators.begin(), iterators.end(), [](const auto& a, const auto& b) { return a->first < b->first; }); + + hash_t hash = 0; + for (const auto& it : iterators) { + hash = hash_objects(hash, it->first, it->second); + } + return hash; } else if constexpr (is_specialization_v) { if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { fmt::print("Hashing std::optional of type {}: {}\n", get_type_name(), object); @@ -1105,7 +1200,7 @@ inline hash_t hash_object(const T& object) noexcept { if constexpr (DEBUG_HASH_OBJECT_FUNCTION) { fmt::print("Hashing struct {} using reflect library: {}\n", get_type_name(), object); } - std::size_t hash = 0; + hash_t hash = 0; reflect::for_each([&hash, &object](auto I) { hash = hash_objects(hash, reflect::get(object)); }, object); return hash; } else { @@ -1335,7 +1430,7 @@ struct to_json_t> { nlohmann::json operator()(const std::map& object) { nlohmann::json json_object = nlohmann::json::object(); for (const auto& [key, value] : object) { - json_object[to_json(key)] = to_json(value); + json_object[to_json(key).dump()] = to_json(value); } return json_object; } @@ -1346,7 +1441,29 @@ struct from_json_t> { std::map operator()(const nlohmann::json& json_object) { std::map object; for (const auto& [key, value] : json_object.items()) { - object[from_json(key)] = from_json(value); + object[from_json(nlohmann::json::parse(key))] = from_json(value); + } + return object; + } +}; + +template +struct to_json_t> { + nlohmann::json operator()(const std::unordered_map& object) { + nlohmann::json json_object = nlohmann::json::object(); + for (const auto& [key, value] : object) { + json_object[to_json(key).dump()] = to_json(value); + } + return json_object; + } +}; + +template +struct from_json_t> { + std::map operator()(const nlohmann::json& json_object) { + std::unordered_map object; + for (const auto& [key, value] : json_object.items()) { + object[from_json(nlohmann::json::parse(key))] = from_json(value); } return object; }