From 2c8ceb61600bb03ac26a979d3bfec707bf23826e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pedro=20Bol=C3=ADvar=20Puente?= Date: Tue, 22 Nov 2022 21:00:30 +0100 Subject: [PATCH] Add identity API --- immer/array.hpp | 11 ++++++++++- immer/flex_vector.hpp | 11 +++++++++++ immer/map.hpp | 8 ++++++++ immer/set.hpp | 8 ++++++++ immer/vector.hpp | 11 +++++++++++ test/map/generic.ipp | 6 ++++++ test/set/generic.ipp | 4 ++++ test/vector/generic.ipp | 6 ++++++ 8 files changed, 64 insertions(+), 1 deletion(-) diff --git a/immer/array.hpp b/immer/array.hpp index d32f13fc..f71477c2 100644 --- a/immer/array.hpp +++ b/immer/array.hpp @@ -107,7 +107,8 @@ class array /*! * Returns an iterator pointing just after the last element of the - * collection. It does not allocate memory and its complexity is @f$ O(1) @f$. + * collection. It does not allocate memory and its complexity is @f$ O(1) + * @f$. */ IMMER_NODISCARD iterator end() const { return impl_.data() + impl_.size; } @@ -308,6 +309,14 @@ class array return transient_type{std::move(impl_)}; } + /*! + * Returns a value that can be used as identity for the container. If two + * values have the same identity, they are guaranteed to be equal and to + * contain the same objects. However, two equal containers are not + * guaranteed to have the same identity. + */ + void* identity() const { return impl_.ptr; } + // Semi-private const impl_t& impl() const { return impl_; } diff --git a/immer/flex_vector.hpp b/immer/flex_vector.hpp index 6ee7a320..79f29db0 100644 --- a/immer/flex_vector.hpp +++ b/immer/flex_vector.hpp @@ -503,6 +503,17 @@ class flex_vector IMMER_NODISCARD transient_type transient() const& { return impl_; } IMMER_NODISCARD transient_type transient() && { return std::move(impl_); } + /*! + * Returns a value that can be used as identity for the container. If two + * values have the same identity, they are guaranteed to be equal and to + * contain the same objects. However, two equal containers are not + * guaranteed to have the same identity. + */ + std::pair identity() const + { + return {impl_.root, impl_.tail}; + } + // Semi-private const impl_t& impl() const { return impl_; } diff --git a/immer/map.hpp b/immer/map.hpp index d13f3b48..cab8e5d5 100644 --- a/immer/map.hpp +++ b/immer/map.hpp @@ -467,6 +467,14 @@ class map return transient_type{std::move(impl_)}; } + /*! + * Returns a value that can be used as identity for the container. If two + * values have the same identity, they are guaranteed to be equal and to + * contain the same objects. However, two equal containers are not + * guaranteed to have the same identity. + */ + void* identity() const { return impl_.root; } + // Semi-private const impl_t& impl() const { return impl_; } diff --git a/immer/set.hpp b/immer/set.hpp index 73ccdcf8..df4192f5 100644 --- a/immer/set.hpp +++ b/immer/set.hpp @@ -251,6 +251,14 @@ class set return transient_type{std::move(impl_)}; } + /*! + * Returns a value that can be used as identity for the container. If two + * values have the same identity, they are guaranteed to be equal and to + * contain the same objects. However, two equal containers are not + * guaranteed to have the same identity. + */ + void* identity() const { return impl_.root; } + // Semi-private const impl_t& impl() const { return impl_; } diff --git a/immer/vector.hpp b/immer/vector.hpp index 3cf69ddb..8c8ab05d 100644 --- a/immer/vector.hpp +++ b/immer/vector.hpp @@ -340,6 +340,17 @@ class vector IMMER_NODISCARD transient_type transient() const& { return impl_; } IMMER_NODISCARD transient_type transient() && { return std::move(impl_); } + /*! + * Returns a value that can be used as identity for the container. If two + * values have the same identity, they are guaranteed to be equal and to + * contain the same objects. However, two equal containers are not + * guaranteed to have the same identity. + */ + std::pair identity() const + { + return {impl_.root, impl_.tail}; + } + // Semi-private const impl_t& impl() const { return impl_; } diff --git a/test/map/generic.ipp b/test/map/generic.ipp index ee6bbe86..2107a4bc 100644 --- a/test/map/generic.ipp +++ b/test/map/generic.ipp @@ -88,6 +88,7 @@ TEST_CASE("instantiation") { auto v = MAP_T{}; CHECK(v.size() == 0u); + CHECK(v.identity() == MAP_T{}.identity()); } } @@ -173,6 +174,11 @@ TEST_CASE("equals and setting") CHECK(v.update_if_exists(42, [](auto&& x) { return x + 1; }) == v.set(42, 43)); + CHECK(v.update_if_exists(1234, [](auto&& x) { return x + 1; }).identity() == + v.identity()); + CHECK(v.update_if_exists(42, [](auto&& x) { return x + 1; }).identity() != + v.set(42, 43).identity()); + #if IMMER_DEBUG_STATS std::cout << (v.impl().get_debug_stats() + v.impl().get_debug_stats()) .get_summary(); diff --git a/test/set/generic.ipp b/test/set/generic.ipp index 5c3cd199..9a9d35af 100644 --- a/test/set/generic.ipp +++ b/test/set/generic.ipp @@ -171,12 +171,16 @@ TEST_CASE("basic insertion") { auto v1 = SET_T{}; CHECK(v1.count(42) == 0); + CHECK(v1.identity() == SET_T{}.identity()); auto v2 = v1.insert(42); CHECK(v1.count(42) == 0); CHECK(v2.count(42) == 1); + CHECK(v1.identity() != v2.identity()); auto v3 = v2.insert(42); + // it would maybe be nice if this was not the case, but it is... + CHECK(v2.identity() != v3.identity()); CHECK(v1.count(42) == 0); CHECK(v2.count(42) == 1); CHECK(v3.count(42) == 1); diff --git a/test/vector/generic.ipp b/test/vector/generic.ipp index 5697c272..0e2dc5cb 100644 --- a/test/vector/generic.ipp +++ b/test/vector/generic.ipp @@ -127,6 +127,12 @@ TEST_CASE("push back one element") CHECK(v1.size() == 0u); CHECK(v2.size() == 1u); CHECK(v2[0] == 42); + + // basic identity rules + auto v3 = v2; + CHECK(v1.identity() != v2.identity()); + CHECK(v3.identity() == v2.identity()); + CHECK(v1.identity() == VECTOR_T{}.identity()); } SECTION("many elements")