summaryrefslogtreecommitdiff
path: root/src/mongo/util/immutable
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/util/immutable
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (diff)
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0' with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/util/immutable')
-rw-r--r--src/mongo/util/immutable/README.md35
-rw-r--r--src/mongo/util/immutable/SConscript29
-rw-r--r--src/mongo/util/immutable/details/map.h233
-rw-r--r--src/mongo/util/immutable/details/memory_policy.h63
-rw-r--r--src/mongo/util/immutable/details/set.h110
-rw-r--r--src/mongo/util/immutable/immutable_absl_comparison_bm.cpp168
-rw-r--r--src/mongo/util/immutable/immutable_ordered_test.cpp1336
-rw-r--r--src/mongo/util/immutable/immutable_std_comparison_bm.cpp168
-rw-r--r--src/mongo/util/immutable/immutable_unordered_test.cpp234
-rw-r--r--src/mongo/util/immutable/immutable_vector_test.cpp126
-rw-r--r--src/mongo/util/immutable/map.h358
-rw-r--r--src/mongo/util/immutable/set.h199
-rw-r--r--src/mongo/util/immutable/unordered_map.h65
-rw-r--r--src/mongo/util/immutable/unordered_set.h65
-rw-r--r--src/mongo/util/immutable/vector.h61
15 files changed, 0 insertions, 3250 deletions
diff --git a/src/mongo/util/immutable/README.md b/src/mongo/util/immutable/README.md
deleted file mode 100644
index 74f5e07259d..00000000000
--- a/src/mongo/util/immutable/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Immutable Containers
-
-This folder contains a number of _immutable_ container classes. Sometimes called _persistent data
-structures_ in the literature, these classes provide interfaces similar to STL containers with one
-key difference. Operations which "modify" the container are `const` and return a modified copy of
-the container rather than modifying it in-place. This makes the containers implicitly thread-safe to
-read and write, but external synchronization will still be needed in many cases to address isolation
-and serializability concerns (i.e.
-[MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)).
-
-## When To Use Immutable Containers
-
-If the container will be copied frequently, e.g. to support a copy-on-write pattern, consider using
-an immutable container. Otherwise, a standard container may make more sense.
-
-## Supported Containers
-
-The currently supported containers are all based on classes from the
-[`immer`](https://sinusoid.es/immer/) library.
-
- - [`immutable::map`](map.h): ordered map interface backed by `immer::flex_vector`
- - [`immutable::set`](set.h): ordered set interface backed by `immer::flex_vector`
- - [`immutable::unordered_map`](unordered_map.h): typedef for `immer:map`
- - [`immutable::unordered_set`](unordered_set.h): typedef for `immer:set`
- - [`immutable::vector`](vector.h): typedef for `immer::vector`
-
-Both ordered and unordered map and set variants support heterogeneous lookup.
-
-## A Note on Performance
-
-The internal implementations of these containers are optimized to support an internal copy-on-write
-pattern so that copies and modifications are $O(log(n))$ or even $O(1)$. However, the constants on
-these runtime guarantees, as well as those for lookups, are typically worse than those of the
-corresponding STL or Abseil containers. For this reason, they should not be considered a
-general-purpose drop-in replacement.
diff --git a/src/mongo/util/immutable/SConscript b/src/mongo/util/immutable/SConscript
deleted file mode 100644
index 72e517d93c5..00000000000
--- a/src/mongo/util/immutable/SConscript
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- mode: python -*-
-
-Import("env")
-
-env = env.Clone()
-
-env.CppUnitTest(
- target='immutable_test',
- source=[
- 'immutable_ordered_test.cpp',
- 'immutable_unordered_test.cpp',
- 'immutable_vector_test.cpp',
- ],
- LIBDEPS=[],
-)
-
-env.Benchmark(
- target='immutable_absl_comparison_bm',
- source=[
- 'immutable_absl_comparison_bm.cpp',
- ],
-)
-
-env.Benchmark(
- target='immutable_std_comparison_bm',
- source=[
- 'immutable_std_comparison_bm.cpp',
- ],
-)
diff --git a/src/mongo/util/immutable/details/map.h b/src/mongo/util/immutable/details/map.h
deleted file mode 100644
index a66db19b412..00000000000
--- a/src/mongo/util/immutable/details/map.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <algorithm>
-
-namespace mongo::immutable::details::map {
-
-template <typename map, typename SearchKey>
-bool equal(const typename map::key_type& a, const SearchKey& b) {
- return !typename map::comp{}(a, b) && !typename map::comp{}(b, a);
-}
-
-template <typename map, typename SearchKey>
-[[nodiscard]] typename map::iterator lower_bound(const typename map::storage_type& storage,
- const SearchKey& key) {
- return std::lower_bound(storage.begin(),
- storage.end(),
- key,
- [](const typename map::value_type& a, const SearchKey& b) -> bool {
- return typename map::comp{}(a.first, b);
- });
-}
-
-template <typename map, typename SearchKey>
-[[nodiscard]] typename map::iterator find(const typename map::storage_type& storage,
- const SearchKey& key) {
- auto it = lower_bound<map>(storage, key);
- if (it != storage.end() && equal<map>(it->first, key)) {
- return it;
- }
-
- return storage.end();
-}
-
-template <typename map, typename S, typename K, typename V>
-[[nodiscard]] typename map::storage_type insert(S&& storage, K&& key, V&& value) {
- auto it = lower_bound<map>(storage, key);
- if (it != storage.end() && equal<map>(it->first, key)) {
- return std::forward<S>(storage);
- }
- if (it == storage.end()) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
- return std::forward<S>(storage).insert(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
-}
-
-template <typename map, typename S, typename K, typename V>
-[[nodiscard]] typename map::storage_type insert(S&& storage,
- typename map::iterator it,
- K&& key,
- V&& value) {
- if (it != storage.end() && equal<map>(it->first, key)) {
- return std::forward<S>(storage);
- }
-
- if (it == storage.end()) {
- if (typename map::comp{}(storage[storage.size() - 1].first, key)) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
- return insert<map>(std::forward<S>(storage), std::forward<K>(key), std::forward<V>(value));
- }
-
- if (typename map::comp{}(key, it->first) &&
- (it.index() == 0 || typename map::comp{}((it - 1)->first, key))) {
- return std::forward<S>(storage).insert(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
-
- return insert<map>(std::forward<S>(storage), std::forward<K>(key), std::forward<V>(value));
-}
-
-template <typename map, typename S, typename K, typename U>
-[[nodiscard]] typename map::storage_type update(S&& storage, K&& key, U&& valueUpdate) {
- auto it = lower_bound<map>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), valueUpdate(typename map::default_value{}())));
- }
-
- if (equal<map>(it->first, key)) {
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), valueUpdate(it->second)));
- }
-
- return insert<map>(std::forward<S>(storage),
- std::forward<K>(key),
- valueUpdate(typename map::default_value{}()));
-}
-
-template <typename map, typename S, typename K, typename U>
-[[nodiscard]] typename map::storage_type update(S&& storage,
- typename map::iterator it,
- K&& key,
- U&& valueUpdate) {
- if (it == storage.end()) {
- if (typename map::comp{}(storage[storage.size() - 1].first, key)) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), valueUpdate(typename map::default_value{}())));
- }
- return update<map>(
- std::forward<S>(storage), std::forward<K>(key), std::forward<U>(valueUpdate));
- }
-
- if (equal<map>(it->first, key)) {
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), valueUpdate(it->second)));
- }
-
- if (typename map::comp{}(key, it->first) &&
- (it.index() == 0 || typename map::comp{}((it - 1)->first, key))) {
- return std::forward<S>(storage).insert(
- it.index(),
- std::make_pair(std::forward<K>(key), valueUpdate(typename map::default_value{}())));
- }
-
- return insert<map>(std::forward<S>(storage),
- std::forward<K>(key),
- valueUpdate(typename map::default_value{}()));
-}
-
-template <typename map, typename S, typename K, typename U>
-[[nodiscard]] typename map::storage_type update_if_exists(S&& storage, K&& key, U&& valueUpdate) {
- auto it = find<map>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage);
- }
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), valueUpdate(it->second)));
-}
-
-template <typename map, typename S, typename K, typename U>
-[[nodiscard]] typename map::storage_type update_if_exists(S&& storage,
- typename map::iterator it,
- K&& key,
- U&& valueUpdate) {
- if (it == storage.end() || !equal<map>(it->first, key)) {
- return update_if_exists<map>(
- std::forward<S>(storage), std::forward<K>(key), std::forward<U>(valueUpdate));
- }
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), valueUpdate(it->second)));
-}
-
-template <typename map, typename S, typename K, typename V>
-[[nodiscard]] typename map::storage_type set(S&& storage, K&& key, V&& value) {
- auto it = lower_bound<map>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- } else if (!equal<map>(it->first, key)) {
- return std::forward<S>(storage).insert(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
-}
-
-template <typename map, typename S, typename K, typename V>
-[[nodiscard]] typename map::storage_type set(S&& storage,
- typename map::iterator it,
- K&& key,
- V&& value) {
- if (it == storage.end()) {
- if (typename map::comp{}(storage[storage.size() - 1].first, key)) {
- return std::forward<S>(storage).push_back(
- std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
- return set<map>(std::forward<S>(storage), std::forward<K>(key), std::forward<V>(value));
- }
-
- if (equal<map>(it->first, key)) {
- return std::forward<S>(storage).set(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
-
- if (typename map::comp{}(key, it->first) &&
- (it.index() == 0 || typename map::comp{}((it - 1)->first, key))) {
- return std::forward<S>(storage).insert(
- it.index(), std::make_pair(std::forward<K>(key), std::forward<V>(value)));
- }
-
- return set<map>(std::forward<S>(storage), std::forward<K>(key), std::forward<V>(value));
-}
-
-template <typename map, typename S, typename K>
-[[nodiscard]] typename map::storage_type erase(S&& storage, K&& key) {
- auto it = find<map>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage);
- }
- return std::forward<S>(storage).erase(it.index());
-}
-
-template <typename map, typename S, typename K>
-[[nodiscard]] typename map::storage_type erase(S&& storage, typename map::iterator it, K&& key) {
- if (it == storage.end() || !equal<map>(it->first, key)) {
- return erase<map>(std::forward<S>(storage), std::forward<K>(key));
- }
- return std::forward<S>(storage).erase(it.index());
-}
-
-} // namespace mongo::immutable::details::map
diff --git a/src/mongo/util/immutable/details/memory_policy.h b/src/mongo/util/immutable/details/memory_policy.h
deleted file mode 100644
index 01923f032b7..00000000000
--- a/src/mongo/util/immutable/details/memory_policy.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <immer/memory_policy.hpp>
-
-namespace mongo::immutable::detail {
-
-// Memory allocations using regular new/delete operators
-using HeapPolicy = immer::heap_policy<immer::cpp_heap>;
-
-// Refcounting using atomics for thread safety
-using RefcountPolicy = immer::refcount_policy;
-
-// We are not using any features from immer that requires locking. Use 'void' as the lock type which
-// would fail compilation if locking was needed anywhere.
-using LockPolicy = void;
-
-// No transience policy (this is just used for garbage collection)
-using TransiencePolicy = immer::no_transience_policy;
-
-using MemoryPolicy = immer::memory_policy<HeapPolicy,
- RefcountPolicy,
- LockPolicy,
- TransiencePolicy,
- /*PreferFewerBiggerObjects*/ true,
- /*UseTransientRValues*/ true>;
-
-// Verify that the recommended settings for our memory policy is as expected. We need to investigate
-// if any of these fire during a library upgrade.
-static_assert(
- std::is_same<immer::get_transience_policy_t<RefcountPolicy>, TransiencePolicy>::value);
-static_assert(immer::get_prefer_fewer_bigger_objects_v<HeapPolicy> == true);
-static_assert(immer::get_use_transient_rvalues_v<RefcountPolicy> == true);
-
-} // namespace mongo::immutable::detail
diff --git a/src/mongo/util/immutable/details/set.h b/src/mongo/util/immutable/details/set.h
deleted file mode 100644
index 491412e696f..00000000000
--- a/src/mongo/util/immutable/details/set.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <algorithm>
-
-namespace mongo::immutable::details::set {
-
-template <typename set, typename SearchKey>
-bool equal(const typename set::key_type& a, const SearchKey& b) {
- return !typename set::comp{}(a, b) && !typename set::comp{}(b, a);
-}
-
-template <typename set, class SearchKey>
-[[nodiscard]] typename set::iterator lower_bound(const typename set::storage_type& storage,
- const SearchKey& key) {
- return std::lower_bound(storage.begin(), storage.end(), key, typename set::comp{});
-}
-
-template <typename set, typename SearchKey>
-[[nodiscard]] typename set::iterator find(const typename set::storage_type& storage,
- const SearchKey& key) {
- auto it = lower_bound<set>(storage, key);
- if (it != storage.end() && equal<set>(*it, key)) {
- return it;
- }
-
- return storage.end();
-}
-
-template <typename set, typename S, typename K>
-[[nodiscard]] typename set::storage_type insert(S&& storage, K&& key) {
- auto it = lower_bound<set>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage).push_back(std::forward<K>(key));
- }
-
- if (equal<set>(*it, key)) {
- return std::forward<S>(storage);
- }
-
- return std::forward<S>(storage).insert(it.index(), std::forward<K>(key));
-}
-
-template <typename set, typename S, typename K>
-[[nodiscard]] typename set::storage_type insert(S&& storage, typename set::iterator it, K&& key) {
- if (it != storage.end() && equal<set>(*it, key)) {
- return std::forward<S>(storage);
- }
-
- if (it == storage.end()) {
- if (typename set::comp{}(storage[storage.size() - 1], key)) {
- return std::forward<S>(storage).push_back(std::forward<K>(key));
- }
- return insert<set>(std::forward<S>(storage), std::forward<K>(key));
- }
-
- if (typename set::comp{}(key, *it) &&
- (it.index() == 0 || typename set::comp{}(*(it - 1), key))) {
- return std::forward<S>(storage).insert(it.index(), std::forward<K>(key));
- }
-
- return insert<set>(std::forward<S>(storage), std::forward<K>(key));
-}
-
-template <typename set, typename S, typename K>
-[[nodiscard]] typename set::storage_type erase(S&& storage, K&& key) {
- auto it = find<set>(storage, key);
- if (it == storage.end()) {
- return std::forward<S>(storage);
- }
- return std::forward<S>(storage).erase(it.index());
-}
-
-template <typename set, typename S, typename K>
-[[nodiscard]] typename set::storage_type erase(S&& storage, typename set::iterator it, K&& key) {
- if (it == storage.end() || !equal<set>(*it, key)) {
- return erase<set>(std::forward<S>(storage), std::forward<K>(key));
- }
- return std::forward<S>(storage).erase(it.index());
-}
-
-} // namespace mongo::immutable::details::set
diff --git a/src/mongo/util/immutable/immutable_absl_comparison_bm.cpp b/src/mongo/util/immutable/immutable_absl_comparison_bm.cpp
deleted file mode 100644
index 78358aae0ff..00000000000
--- a/src/mongo/util/immutable/immutable_absl_comparison_bm.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include <benchmark/benchmark.h>
-
-#include "mongo/stdx/unordered_map.h"
-#include "mongo/util/immutable/unordered_map.h"
-
-namespace mongo {
-
-static void BM_absl_insert_op(benchmark::State& state) {
- stdx::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- for (auto _ : state) {
- map[i] = i;
- i++;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_absl_copy_op(benchmark::State& state) {
- stdx::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- stdx::unordered_map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_absl_find_op(benchmark::State& state) {
- stdx::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(map.find(i - 1));
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_absl_copy_and_insert_op(benchmark::State& state) {
- stdx::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- stdx::unordered_map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- mapCopy[i] = i;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_insert_op(benchmark::State& state) {
- immutable::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- for (auto _ : state) {
- map = std::move(map).set(i, i);
- i++;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_copy_op(benchmark::State& state) {
- immutable::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- immutable::unordered_map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_find_op(benchmark::State& state) {
- immutable::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(map.find(i - 1));
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_copy_and_insert_op(benchmark::State& state) {
- immutable::unordered_map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- immutable::unordered_map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map.set(i, i);
- benchmark::ClobberMemory();
- }
-}
-
-// Run with varying container sizes: [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ].
-BENCHMARK(BM_absl_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_absl_copy_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_copy_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_absl_find_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_find_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_absl_copy_and_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_copy_and_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-} // namespace mongo
diff --git a/src/mongo/util/immutable/immutable_ordered_test.cpp b/src/mongo/util/immutable/immutable_ordered_test.cpp
deleted file mode 100644
index 2b9308d5caf..00000000000
--- a/src/mongo/util/immutable/immutable_ordered_test.cpp
+++ /dev/null
@@ -1,1336 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include "mongo/unittest/unittest.h"
-
-#include "mongo/util/immutable/map.h"
-#include "mongo/util/immutable/set.h"
-#include "mongo/util/string_map.h"
-#include <stdexcept>
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
-
-namespace mongo {
-namespace {
-
-class UserDefinedKey {
-public:
- UserDefinedKey() = default;
- explicit UserDefinedKey(int val) : a(val) {}
-
- bool operator==(const UserDefinedKey& rhs) const {
- return a == rhs.a;
- }
-
- bool operator<(const UserDefinedKey& rhs) const {
- return a < rhs.a;
- }
-
- std::string toString() const {
- return std::to_string(a);
- }
-
-private:
- int a = 0;
-};
-
-
-class Incomparable {
- friend struct CompareIncomparable;
-
-public:
- Incomparable() = default;
- explicit Incomparable(int val) : a(val) {}
-
- bool operator==(const Incomparable&) = delete;
- bool operator<(const Incomparable&) = delete;
-
- std::string toString() const {
- return std::to_string(a);
- }
-
-private:
- int a = 0;
-};
-
-struct CompareIncomparable {
- bool operator()(const Incomparable& a, const Incomparable& b) const {
- return a.a < b.a;
- }
-
- // Pair comparator needed for some testing macros to function properly for both maps and sets.
- bool operator()(const std::pair<Incomparable, int>& a,
- const std::pair<Incomparable, int>& b) const {
- return a.first.a < b.first.a;
- }
-};
-
-struct StringCompare {
- bool operator()(const std::string& a, const std::string& b) const {
- return a < b;
- }
- bool operator()(const std::string& a, const StringData& b) const {
- return a < b;
- }
- bool operator()(const StringData& a, const std::string& b) const {
- return a < b;
- }
- bool operator()(const std::string& a, const char* b) const {
- return a < b;
- }
- bool operator()(const char* a, const std::string& b) const {
- return a < b;
- }
-};
-
-template <typename C, typename L>
-void ensureContainerInvariants(const C& container, L&& less) {
- size_t visited = 0;
- for (auto it = container.begin(); it != container.end(); ++it) {
- if (++visited > 1) {
- ASSERT(less(*(it - 1), *it));
- }
- }
- ASSERT_EQ(visited, container.size());
-}
-
-
-template <typename C>
-void ensureContainerInvariants(const C& container) {
- size_t visited = 0;
- for (auto it = container.begin(); it != container.end(); ++it) {
- if (++visited > 1) {
- ASSERT(*(it - 1) < *it);
- }
- }
- ASSERT_EQ(visited, container.size());
-}
-
-template <typename C>
-void ensureContainerInvariants(const std::tuple<C, C, C, C>& containers) {
- ensureContainerInvariants(std::get<0>(containers));
- ensureContainerInvariants(std::get<1>(containers));
- ensureContainerInvariants(std::get<2>(containers));
- ensureContainerInvariants(std::get<3>(containers));
-}
-
-template <typename C>
-void ensureContainerInvariants(std::initializer_list<const C> containers) {
- for (auto& c : containers) {
- ensureContainerInvariants(c);
- }
-}
-
-template <typename K, typename V, typename M = immutable::map<K, V>>
-std::tuple<M, M, M, M> init_maps() {
- return std::make_tuple(M{}, M{}, M{}, M{});
-}
-
-template <typename K, typename S = immutable::set<K>>
-std::tuple<S, S, S, S> init_sets() {
- return std::make_tuple(S{}, S{}, S{}, S{});
-}
-
-std::ostream& operator<<(std::ostream& s, const UserDefinedKey& k) {
- return s << k.toString();
-}
-
-std::ostream& operator<<(std::ostream& s, const Incomparable& k) {
- return s << k.toString();
-}
-
-template <typename T, typename U>
-std::ostream& operator<<(std::ostream& s, const std::pair<T, U> pair) {
- return s << "(" << pair.first << "," << pair.second << ")";
-}
-
-template <typename C>
-struct ContainerWrapper {
- ContainerWrapper(const C& c) : container{c} {}
- const C& container;
-};
-template <typename T>
-std::ostream& operator<<(std::ostream& str, const ContainerWrapper<T>& wrapper) {
- str << "{";
- bool first = true;
- for (auto& el : wrapper.container) {
- if (first) {
- first = false;
- } else {
- str << ", ";
- }
- str << el;
- }
- str << "}";
- return str;
-}
-
-#define ASSERT_CONTAINS(containers, k) \
- { \
- ASSERT_TRUE(std::get<0>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_TRUE(std::get<1>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_TRUE(std::get<2>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_TRUE(std::get<3>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- }
-
-#define ASSERT_NOT_CONTAINS(containers, k) \
- { \
- ASSERT_FALSE(std::get<0>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_FALSE(std::get<1>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_FALSE(std::get<2>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- ASSERT_FALSE(std::get<3>(containers).contains(k)) \
- << ContainerWrapper{std::get<0>(containers)}; \
- }
-
-#define ASSERT_VALUE_EQ(its, v) \
- { \
- ASSERT_EQ(std::get<0>(its)->second, v); \
- ASSERT_EQ(std::get<1>(its)->second, v); \
- ASSERT_EQ(std::get<2>(its)->second, v); \
- ASSERT_EQ(std::get<3>(its)->second, v); \
- }
-
-#define MUTATE_KV(containers, fn, k, v) \
- [&]() { \
- auto _k1 = k; \
- auto _v1 = v; \
- auto _m1 = std::get<0>(containers).fn(_k1, _v1); \
- ensureContainerInvariants(_m1); \
- \
- auto _k2 = k; \
- auto _v2 = v; \
- auto _m2 = std::move(std::get<1>(containers)).fn(_k2, _v2); \
- ensureContainerInvariants(_m2); \
- \
- auto _k3 = k; \
- auto _v3 = v; \
- auto _m3 = std::get<2>(containers).fn(std::move(_k3), std::move(_v3)); \
- ensureContainerInvariants(_m3); \
- \
- auto _k4 = k; \
- auto _v4 = v; \
- auto _m4 = std::move(std::get<3>(containers)).fn(std::move(_k4), std::move(_v4)); \
- ensureContainerInvariants(_m4); \
- \
- return std::make_tuple(_m1, _m2, _m3, _m4); \
- }();
-
-#define MUTATE_K(containers, fn, k) \
- ([&]() { \
- auto _k1 = k; \
- auto _m1 = std::get<0>(containers).fn(_k1); \
- ensureContainerInvariants(_m1); \
- \
- auto _k2 = k; \
- auto _m2 = std::move(std::get<1>(containers)).fn(_k2); \
- ensureContainerInvariants(_m2); \
- \
- auto _k3 = k; \
- auto _m3 = std::get<2>(containers).fn(std::move(_k3)); \
- ensureContainerInvariants(_m3); \
- \
- auto _k4 = k; \
- auto _m4 = std::move(std::get<3>(containers)).fn(std::move(_k4)); \
- ensureContainerInvariants(_m4); \
- \
- return std::make_tuple(_m1, _m2, _m3, _m4); \
- }());
-
-#define MUTATE_IT_KV(containers, fn, its, k, v) \
- [&]() { \
- auto _k1 = k; \
- auto _v1 = v; \
- auto _m1 = std::get<0>(containers).fn(std::get<0>(its), _k1, _v1); \
- ensureContainerInvariants(_m1); \
- \
- auto _k2 = k; \
- auto _v2 = v; \
- auto _m2 = std::move(std::get<1>(containers)).fn(std::get<1>(its), _k2, _v2); \
- ensureContainerInvariants(_m2); \
- \
- auto _k3 = k; \
- auto _v3 = v; \
- auto _m3 = std::get<2>(containers).fn(std::get<2>(its), std::move(_k3), std::move(_v3)); \
- ensureContainerInvariants(_m3); \
- \
- auto _k4 = k; \
- auto _v4 = v; \
- auto _m4 = std::move(std::get<3>(containers)) \
- .fn(std::get<3>(its), std::move(_k4), std::move(_v4)); \
- ensureContainerInvariants(_m4); \
- \
- return std::make_tuple(_m1, _m2, _m3, _m4); \
- }();
-
-#define MUTATE_IT_K(containers, fn, its, k) \
- [&]() { \
- auto _k1 = k; \
- auto _m1 = std::get<0>(containers).fn(std::get<0>(its), _k1); \
- ensureContainerInvariants(_m1); \
- \
- auto _k2 = k; \
- auto _m2 = std::move(std::get<1>(containers)).fn(std::get<1>(its), _k2); \
- ensureContainerInvariants(_m2); \
- \
- auto _k3 = k; \
- auto _m3 = std::get<2>(containers).fn(std::get<2>(its), std::move(_k3)); \
- ensureContainerInvariants(_m3); \
- \
- auto _k4 = k; \
- auto _m4 = std::move(std::get<3>(containers)).fn(std::get<3>(its), std::move(_k4)); \
- ensureContainerInvariants(_m4); \
- \
- return std::make_tuple(_m1, _m2, _m3, _m4); \
- }();
-
-#define SEARCH(containers, fn, k) \
- [&]() { \
- auto _i1 = std::get<0>(containers).fn(k); \
- auto _i2 = std::get<1>(containers).fn(k); \
- auto _i3 = std::get<2>(containers).fn(k); \
- auto _i4 = std::get<3>(containers).fn(k); \
- return std::make_tuple(_i1, _i2, _i3, _i4); \
- }();
-
-#define END(containers) \
- [&]() { \
- auto _i1 = std::get<0>(containers).end(); \
- auto _i2 = std::get<1>(containers).end(); \
- auto _i3 = std::get<2>(containers).end(); \
- auto _i4 = std::get<3>(containers).end(); \
- return std::make_tuple(_i1, _i2, _i3, _i4); \
- }();
-
-TEST(ImmutableMap, Basic) {
- // Insert some values and verify that the data structure is behaving as expected
- immutable::map<int, int> v0;
- auto v1 = v0.set(1, 2);
- // Record the pointer to the value '1', verify that this doesn't change after performing more
- // inserts
- auto v1Val = v1.find(1);
-
- // Create distinct branches of the history from v1. v0 and v1 should be unaffected
- auto v2 = v1.update_if_exists(1, [](int v) { return v += 1; });
- auto v3 = v1.set(2, 3);
-
- // Verify that values are as expected
- ASSERT_EQ(v0.size(), 0);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT_TRUE(v1.contains(1));
- ASSERT_EQ(v1.find(1)->second, 2);
-
- ASSERT_EQ(v2.size(), 1);
- ASSERT_TRUE(v2.contains(1));
- ASSERT_EQ(v2.find(1)->second, 3);
- ASSERT_FALSE(v2.contains(2));
-
- ASSERT_EQ(v3.size(), 2);
- ASSERT_TRUE(v3.contains(1));
- ASSERT_EQ(v3.find(1)->second, 2);
- ASSERT_TRUE(v3.contains(2));
- ASSERT_EQ(v3.find(2)->second, 3);
-
- // Verify that v1's value did not change
- ASSERT(v1.find(1) == v1Val);
-
- // Verify that erase works as expected, and preserves history.
- auto v4 = v3.erase(1).erase(2);
- ASSERT_FALSE(v4.contains(1));
- ASSERT_FALSE(v4.contains(2));
- ASSERT_TRUE(v3.contains(1));
- ASSERT_EQ(v3.find(1)->second, 2);
- ASSERT_TRUE(v3.contains(2));
- ASSERT_EQ(v3.find(2)->second, 3);
- ASSERT_TRUE(v2.contains(1));
- ASSERT_EQ(v2.find(1)->second, 3);
- ASSERT_FALSE(v2.contains(2));
- ASSERT_TRUE(v1.contains(1));
- ASSERT_EQ(v1.find(1)->second, 2);
- ASSERT_FALSE(v1.contains(2));
-
- ensureContainerInvariants({v0, v1, v2, v3, v4});
-}
-
-TEST(ImmutableMap, UserDefinedType) {
- immutable::map<UserDefinedKey, int> v0;
- auto v1 = v0.set(UserDefinedKey(1), 2);
- ASSERT(v1.find(UserDefinedKey(1)) != v1.end());
- ASSERT_EQ(v1.find(UserDefinedKey(1))->second, 2);
-
- ensureContainerInvariants({v0, v1});
-}
-
-TEST(ImmutableMap, IncomparableType) {
- immutable::map<Incomparable, int, CompareIncomparable> v0;
- auto v1 = v0.set(Incomparable(1), 2);
- ASSERT(v1.find(Incomparable(1)) != v1.end());
- ASSERT_EQ(v1.find(Incomparable(1))->second, 2);
-
- ensureContainerInvariants(v0, CompareIncomparable{});
- ensureContainerInvariants(v1, CompareIncomparable{});
-}
-
-TEST(ImmutableMap, HeterogeneousLookup) {
- immutable::map<std::string, int, StringCompare> v0;
- auto v1 = v0.set("str", 1);
-
- // Lookup using StringData without the need to convert to string.
- ASSERT(v1.find("str"_sd) != v1.end());
-
- ensureContainerInvariants({v0, v1});
-}
-
-TEST(ImmutableMap, Accessors) {
- immutable::map<int, int> v0;
- auto v1 = v0.insert(1, 1).insert(2, 2).insert(3, 3);
-
- ASSERT_EQ(v1[1], 1);
- ASSERT_EQ(v1[2], 2);
- ASSERT_EQ(v1[3], 3);
- ASSERT_EQ(v1.at(1), 1);
- ASSERT_EQ(v1.at(2), 2);
- ASSERT_EQ(v1.at(3), 3);
-
- // Handling of missing elements
- ASSERT_EQ(v1[4], 0);
- ASSERT_THROWS(v1.at(4), std::out_of_range);
-
- ensureContainerInvariants({v0, v1});
-}
-
-TEST(ImmutableMap, Bounds) {
- immutable::map<int, int> map;
- constexpr int numKeys = 100;
- for (int i = 0; i < numKeys; ++i) {
- map = map.set(2 * i, 2 * i);
- ensureContainerInvariants(map);
- }
-
- for (int i = 0; i < numKeys - 1; ++i) {
- auto lowerExact = map.lower_bound(2 * i);
- ASSERT(lowerExact != map.end() && lowerExact->first == 2 * i);
- auto upperExact = map.upper_bound(2 * i);
- ASSERT(upperExact != map.end() && upperExact->first == 2 * (i + 1));
-
- auto lowerNear = map.lower_bound(2 * i + 1);
- ASSERT(lowerNear != map.end() && lowerNear->first == 2 * (i + 1));
- auto upperNear = map.upper_bound(2 * i + 1);
- ASSERT(upperNear != map.end() && upperNear->first == 2 * (i + 1));
- }
-}
-
-TEST(ImmutableMap, Iteration) {
- immutable::map<int, int> map;
- constexpr int numKeys = 100;
- for (int i = 0; i < numKeys; ++i) {
- map = map.set(2 * i, 2 * i);
- ensureContainerInvariants(map);
- }
-
- auto map0 = map;
- auto it0 = map0.begin();
-
- for (int i = 0; i < numKeys; ++i) {
- map = map.set(2 * i + 1, 2 * i + 1);
- ensureContainerInvariants(map);
- }
-
- auto map1 = map;
- auto it1 = map1.begin();
-
- for (int i = 0; i < numKeys; ++i) {
- ASSERT(it0 != map0.end());
- ASSERT_EQ(it0->first, 2 * i);
- ++it0;
-
- ASSERT(it1 != map1.end());
- ASSERT_EQ(it1->first, 2 * i);
- ++it1;
-
- ASSERT(it1 != map1.end());
- ASSERT_EQ(it1->first, 2 * i + 1);
- ++it1;
- }
- ASSERT(it0 == map0.end());
- ASSERT(it1 == map1.end());
-}
-
-TEST(ImmutableMap, Insert) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Insert of existing key is a noop.
- auto v5 = MUTATE_KV(v4, insert, 1, 2);
- ASSERT_CONTAINS(v5, 1);
- auto i5 = SEARCH(v5, find, 1);
- ASSERT_VALUE_EQ(i5, 1);
-
- // Insert at beginning works.
- auto v6 = MUTATE_KV(v4, insert, 0, 0);
- ASSERT_CONTAINS(v6, 0);
- auto i6 = SEARCH(v6, find, 0);
- ASSERT_VALUE_EQ(i6, 0);
-
- // Insert at end works.
- auto v7 = MUTATE_KV(v4, insert, 6, 6);
- ASSERT_CONTAINS(v7, 6);
- auto i7 = SEARCH(v7, find, 6);
- ASSERT_VALUE_EQ(i7, 6);
-
- // Insert in middle works.
- auto v8 = MUTATE_KV(v4, insert, 4, 4);
- ASSERT_CONTAINS(v8, 4);
- auto i8 = SEARCH(v8, find, 4);
- ASSERT_VALUE_EQ(i8, 4);
-}
-
-TEST(ImmutableMap, InsertViaIterator) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 6, 6);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 6);
-
- // Giving the iterator for an existing element does a noop.
-
- auto it4_2 = SEARCH(v4, find, 2);
- auto v5 = MUTATE_IT_KV(v4, insert, it4_2, 2, 5);
- auto it5_2 = SEARCH(v5, find, 2);
- ASSERT_VALUE_EQ(it5_2, 2);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end5 = END(v5);
- auto v6 = MUTATE_IT_KV(v5, insert, end5, 2, 5);
- auto it6_2 = SEARCH(v6, find, 2);
- ASSERT_VALUE_EQ(it6_2, 2);
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_KV(v6, insert, end6, 4, 4);
- ASSERT_NOT_CONTAINS(v6, 4);
- ASSERT_CONTAINS(v7, 4);
- auto it7_4 = SEARCH(v7, find, 4);
- ASSERT_VALUE_EQ(it7_4, 4);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_KV(v7, insert, end7, 7, 7);
- ASSERT_NOT_CONTAINS(v7, 7);
- ASSERT_CONTAINS(v8, 7);
- auto it8_7 = SEARCH(v8, find, 7);
- ASSERT_VALUE_EQ(it8_7, 7);
-
- // Giving hint from lower_bound works for both existing and new entries.
-
- auto lb8_2 = SEARCH(v8, lower_bound, 2);
- auto v9 = MUTATE_IT_KV(v8, insert, lb8_2, 2, 5);
- auto it9_2 = SEARCH(v9, find, 2);
- ASSERT_VALUE_EQ(it9_2, 2);
-
- auto lb9_0 = SEARCH(v9, lower_bound, 0);
- auto v10 = MUTATE_IT_KV(v9, insert, lb9_0, 0, 0);
- ASSERT_NOT_CONTAINS(v9, 0);
- ASSERT_CONTAINS(v10, 0);
- auto it10_0 = SEARCH(v10, find, 0);
- ASSERT_VALUE_EQ(it10_0, 0);
-
- auto lb10_5 = SEARCH(v10, lower_bound, 5);
- auto v11 = MUTATE_IT_KV(v10, insert, lb10_5, 5, 5);
- ASSERT_NOT_CONTAINS(v10, 5);
- ASSERT_CONTAINS(v11, 5);
- auto it11_5 = SEARCH(v11, find, 5);
- ASSERT_VALUE_EQ(it11_5, 5);
-
- auto lb11_8 = SEARCH(v11, lower_bound, 8);
- auto v12 = MUTATE_IT_KV(v11, insert, lb11_8, 8, 8);
- ASSERT_NOT_CONTAINS(v11, 8);
- ASSERT_CONTAINS(v12, 8);
- auto it12_8 = SEARCH(v12, find, 8);
- ASSERT_VALUE_EQ(it12_8, 8);
-}
-
-TEST(ImmutableMap, Set) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Set on existing key updates value.
- auto v5 = MUTATE_KV(v4, set, 1, 2);
- ASSERT_CONTAINS(v5, 1);
- auto i5 = SEARCH(v5, find, 1);
- ASSERT_VALUE_EQ(i5, 2);
-
- // Set to insert at beginning works.
- auto v6 = MUTATE_KV(v4, set, 0, 0);
- ASSERT_CONTAINS(v6, 0);
- auto i6 = SEARCH(v6, find, 0);
- ASSERT_VALUE_EQ(i6, 0);
-
- // Set to insert at end works.
- auto v7 = MUTATE_KV(v4, set, 6, 6);
- ASSERT_CONTAINS(v7, 6);
- auto i7 = SEARCH(v7, find, 6);
- ASSERT_VALUE_EQ(i7, 6);
-
- // Set to insert in middle works.
- auto v8 = MUTATE_KV(v4, set, 4, 4);
- ASSERT_CONTAINS(v8, 4);
- auto i8 = SEARCH(v8, find, 4);
- ASSERT_VALUE_EQ(i8, 4);
-}
-
-TEST(ImmutableMap, SetViaIterator) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 6, 6);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 6);
-
- // Giving the iterator for an existing element updates the value.
-
- auto it4_2 = SEARCH(v4, find, 2);
- auto v5 = MUTATE_IT_KV(v4, set, it4_2, 2, 5);
- auto it5_2 = SEARCH(v5, find, 2);
- ASSERT_VALUE_EQ(it5_2, 5);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end5 = END(v5);
- auto v6 = MUTATE_IT_KV(v5, set, end5, 2, 7);
- auto it6_2 = SEARCH(v6, find, 2);
- ASSERT_VALUE_EQ(it6_2, 7);
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_KV(v6, set, end6, 4, 4);
- ASSERT_NOT_CONTAINS(v6, 4);
- ASSERT_CONTAINS(v7, 4);
- auto it7_4 = SEARCH(v7, find, 4);
- ASSERT_VALUE_EQ(it7_4, 4);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_KV(v7, set, end7, 7, 7);
- ASSERT_NOT_CONTAINS(v7, 7);
- ASSERT_CONTAINS(v8, 7);
- auto it8_7 = SEARCH(v8, find, 7);
- ASSERT_VALUE_EQ(it8_7, 7);
-
- // Giving hint from lower_bound works for both existing and new entries.
-
- auto lb8_2 = SEARCH(v8, lower_bound, 2);
- auto v9 = MUTATE_IT_KV(v8, set, lb8_2, 2, 9);
- auto it9_2 = SEARCH(v9, find, 2);
- ASSERT_VALUE_EQ(it9_2, 9);
-
- auto lb9_0 = SEARCH(v9, lower_bound, 0);
- auto v10 = MUTATE_IT_KV(v9, set, lb9_0, 0, 0);
- ASSERT_NOT_CONTAINS(v9, 0);
- ASSERT_CONTAINS(v10, 0);
- auto it10_0 = SEARCH(v10, find, 0);
- ASSERT_VALUE_EQ(it10_0, 0);
-
- auto lb10_5 = SEARCH(v10, lower_bound, 5);
- auto v11 = MUTATE_IT_KV(v10, set, lb10_5, 5, 5);
- ASSERT_NOT_CONTAINS(v10, 5);
- ASSERT_CONTAINS(v11, 5);
- auto it11_5 = SEARCH(v11, find, 5);
- ASSERT_VALUE_EQ(it11_5, 5);
-
- auto lb11_8 = SEARCH(v11, lower_bound, 8);
- auto v12 = MUTATE_IT_KV(v11, set, lb11_8, 8, 8);
- ASSERT_NOT_CONTAINS(v11, 8);
- ASSERT_CONTAINS(v12, 8);
- auto it12_8 = SEARCH(v12, find, 8);
- ASSERT_VALUE_EQ(it12_8, 8);
-}
-
-TEST(ImmutableMap, Update) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Update on existing key updates value.
- auto v5 = MUTATE_KV(v4, update, 1, [](int x) { return x + 1; });
- ASSERT_CONTAINS(v5, 1);
- auto i5 = SEARCH(v5, find, 1);
- ASSERT_VALUE_EQ(i5, 2);
-
- // Update to insert at beginning works.
- auto v6 = MUTATE_KV(v4, update, 0, [](int x) { return x + 1; });
- ASSERT_CONTAINS(v6, 0);
- auto i6 = SEARCH(v6, find, 0);
- ASSERT_VALUE_EQ(i6, 1);
-
- // Update to insert at end works.
- auto v7 = MUTATE_KV(v4, update, 6, [](int x) { return x + 1; });
- ASSERT_CONTAINS(v7, 6);
- auto i7 = SEARCH(v7, find, 6);
- ASSERT_VALUE_EQ(i7, 1);
-
- // Update to insert in middle works.
- auto v8 = MUTATE_KV(v4, update, 4, [](int x) { return x + 1; });
- ASSERT_CONTAINS(v8, 4);
- auto i8 = SEARCH(v8, find, 4);
- ASSERT_VALUE_EQ(i8, 1);
-}
-
-TEST(ImmutableMap, UpdateViaIterator) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 6, 6);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 6);
-
- // Giving the iterator for an existing element updates the value.
-
- auto it4_2 = SEARCH(v4, find, 2);
- auto v5 = MUTATE_IT_KV(v4, update, it4_2, 2, [](int x) { return x + 1; });
- auto it5_2 = SEARCH(v5, find, 2);
- ASSERT_VALUE_EQ(it5_2, 3);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end5 = END(v5);
- auto v6 = MUTATE_IT_KV(v5, update, end5, 2, [](int x) { return x + 1; });
- auto it6_2 = SEARCH(v6, find, 2);
- ASSERT_VALUE_EQ(it6_2, 4);
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_KV(v6, update, end6, 4, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v6, 4);
- ASSERT_CONTAINS(v7, 4);
- auto it7_4 = SEARCH(v7, find, 4);
- ASSERT_VALUE_EQ(it7_4, 1);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_KV(v7, update, end7, 7, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v7, 7);
- ASSERT_CONTAINS(v8, 7);
- auto it8_7 = SEARCH(v8, find, 7);
- ASSERT_VALUE_EQ(it8_7, 1);
-
- // Giving hint from lower_bound works for both existing and new entries.
-
- auto lb8_2 = SEARCH(v8, lower_bound, 2);
- auto v9 = MUTATE_IT_KV(v8, update, lb8_2, 2, [](int x) { return x + 1; });
- auto it9_2 = SEARCH(v9, find, 2);
- ASSERT_VALUE_EQ(it9_2, 5);
-
- auto lb9_0 = SEARCH(v9, lower_bound, 0);
- auto v10 = MUTATE_IT_KV(v9, update, lb9_0, 0, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v9, 0);
- ASSERT_CONTAINS(v10, 0);
- auto it10_0 = SEARCH(v10, find, 0);
- ASSERT_VALUE_EQ(it10_0, 1);
-
- auto lb10_5 = SEARCH(v10, lower_bound, 5);
- auto v11 = MUTATE_IT_KV(v10, update, lb10_5, 5, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v10, 5);
- ASSERT_CONTAINS(v11, 5);
- auto it11_5 = SEARCH(v11, find, 5);
- ASSERT_VALUE_EQ(it11_5, 1);
-
- auto lb11_8 = SEARCH(v11, lower_bound, 8);
- auto v12 = MUTATE_IT_KV(v11, update, lb11_8, 8, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v11, 8);
- ASSERT_CONTAINS(v12, 8);
- auto it12_8 = SEARCH(v12, find, 8);
- ASSERT_VALUE_EQ(it12_8, 1);
-}
-
-TEST(ImmutableMap, UpdateIfExists) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Update on existing key updates value.
- auto v5 = MUTATE_KV(v4, update_if_exists, 1, [](int x) { return x + 1; });
- ASSERT_CONTAINS(v5, 1);
- auto i5 = SEARCH(v5, find, 1);
- ASSERT_VALUE_EQ(i5, 2);
-
- // Update to insert at beginning does nothing.
- auto v6 = MUTATE_KV(v4, update_if_exists, 0, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v6, 0);
-
- // Update to insert at end does nothing.
- auto v7 = MUTATE_KV(v4, update_if_exists, 6, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v7, 6);
-
- // Update to insert in middle does nothing.
- auto v8 = MUTATE_KV(v4, update_if_exists, 4, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v8, 4);
-}
-
-TEST(ImmutableMap, UpdateIfExistsViaIterator) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 6, 6);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 6);
-
- // Giving the iterator for an existing element updates the value.
-
- auto it4_2 = SEARCH(v4, find, 2);
- auto v5 = MUTATE_IT_KV(v4, update_if_exists, it4_2, 2, [](int x) { return x + 1; });
- auto it5_2 = SEARCH(v5, find, 2);
- ASSERT_VALUE_EQ(it5_2, 3);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end5 = END(v5);
- auto v6 = MUTATE_IT_KV(v5, update_if_exists, end5, 2, [](int x) { return x + 1; });
- auto it6_2 = SEARCH(v6, find, 2);
- ASSERT_VALUE_EQ(it6_2, 4);
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_KV(v6, update_if_exists, end6, 4, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v7, 4);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_KV(v7, update_if_exists, end7, 7, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v8, 7);
-
- // Giving hint from lower_bound works for both existing and non-existing entries.
-
- auto lb8_2 = SEARCH(v8, lower_bound, 2);
- auto v9 = MUTATE_IT_KV(v8, update_if_exists, lb8_2, 2, [](int x) { return x + 1; });
- auto it9_2 = SEARCH(v9, find, 2);
- ASSERT_VALUE_EQ(it9_2, 5);
-
- auto lb9_0 = SEARCH(v9, lower_bound, 0);
- auto v10 = MUTATE_IT_KV(v9, update_if_exists, lb9_0, 0, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v10, 0);
-
- auto lb10_5 = SEARCH(v10, lower_bound, 5);
- auto v11 = MUTATE_IT_KV(v10, update_if_exists, lb10_5, 5, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v11, 5);
-
- auto lb11_8 = SEARCH(v11, lower_bound, 8);
- auto v12 = MUTATE_IT_KV(v11, update_if_exists, lb11_8, 8, [](int x) { return x + 1; });
- ASSERT_NOT_CONTAINS(v12, 8);
-}
-
-TEST(ImmutableMap, Erase) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Erase on existing key removes value.
- auto v5 = MUTATE_K(v4, erase, 1);
- ASSERT_NOT_CONTAINS(v5, 1);
-
- // Erase on non-existent key does nothing.
- auto v6 = MUTATE_K(v5, erase, 0);
- ASSERT_NOT_CONTAINS(v6, 0);
- ASSERT_CONTAINS(v6, 2);
- ASSERT_CONTAINS(v6, 3);
- ASSERT_CONTAINS(v6, 5);
-}
-
-TEST(ImmutableMap, EraseViaIterator) {
- auto v0 = init_maps<int, int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_KV(v0, insert, 1, 1);
- auto v2 = MUTATE_KV(v1, insert, 2, 2);
- auto v3 = MUTATE_KV(v2, insert, 3, 3);
- auto v4 = MUTATE_KV(v3, insert, 5, 5);
- auto v5 = MUTATE_KV(v4, insert, 6, 6);
- ASSERT_CONTAINS(v5, 1);
- ASSERT_CONTAINS(v5, 2);
- ASSERT_CONTAINS(v5, 3);
- ASSERT_CONTAINS(v5, 5);
- ASSERT_CONTAINS(v5, 6);
-
- // Giving the iterator for an existing element erases the value.
-
- auto it5_2 = SEARCH(v5, find, 2);
- auto v6 = MUTATE_IT_K(v5, erase, it5_2, 2);
- ASSERT_NOT_CONTAINS(v6, 2);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_K(v6, erase, end6, 3);
- ASSERT_NOT_CONTAINS(v7, 3);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_K(v7, erase, end7, 4);
- ASSERT_NOT_CONTAINS(v8, 4);
-
- auto end8 = END(v8);
- auto v9 = MUTATE_IT_K(v8, erase, end8, 7);
- ASSERT_NOT_CONTAINS(v9, 7);
-
- // Giving hint from lower_bound works for both existing and non-existing entries.
-
- auto lb9_5 = SEARCH(v9, lower_bound, 5);
- auto v10 = MUTATE_IT_K(v9, erase, lb9_5, 5);
- ASSERT_NOT_CONTAINS(v10, 5);
-
- auto lb10_0 = SEARCH(v10, lower_bound, 0);
- auto v11 = MUTATE_IT_K(v10, erase, lb10_0, 0);
-
- auto lb11_4 = SEARCH(v10, lower_bound, 4);
- auto v12 = MUTATE_IT_K(v11, erase, lb11_4, 4);
-
- auto lb12_7 = SEARCH(v12, lower_bound, 7);
- auto v13 = MUTATE_IT_K(v12, erase, lb12_7, 7);
-
- ASSERT_CONTAINS(v13, 1);
- ASSERT_CONTAINS(v13, 6);
- ASSERT_NOT_CONTAINS(v13, 0);
- ASSERT_NOT_CONTAINS(v13, 2);
- ASSERT_NOT_CONTAINS(v13, 3);
- ASSERT_NOT_CONTAINS(v13, 4);
- ASSERT_NOT_CONTAINS(v13, 5);
- ASSERT_NOT_CONTAINS(v13, 7);
-}
-
-TEST(ImmutableMap, ExclusiveOwnership) {
- immutable::map<int, int> v0;
-
- auto v1 = v0.set(1, 1);
- auto v2 = v1.set(2, 2);
- auto v3 = v2.set(3, 3);
-
- ASSERT_TRUE(v1.contains(1));
- ASSERT_TRUE(v2.contains(1));
- ASSERT_TRUE(v3.contains(1));
-
- // Claiming exclusive ownership over v3 means v3 will no longer be valid after mutation, but
- // older versions should be unperturbed.
- auto v4 = std::move(v3).erase(1);
- ASSERT_TRUE(v1.contains(1));
- ASSERT_TRUE(v2.contains(1));
- ASSERT_FALSE(v4.contains(1));
-}
-
-TEST(ImmutableSet, Basic) {
- // Insert some values and verify that the data structure is behaving as expected
- immutable::set<int> v0;
- auto v1 = v0.insert(1);
- // Record the iterator for the key '1', verify that this doesn't change after performing
- // more inserts
- auto v1it = v1.find(1);
-
- // Create distinct branches of the history from v1. v0 and v1 should be unaffected
- auto v2 = v1.insert(2);
- auto v3 = v1.insert(3);
-
- // Verify that values are as expected
- ASSERT_EQ(v0.size(), 0);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT_TRUE(v1.contains(1));
- ASSERT_EQ(*v1.find(1), 1);
- ASSERT_FALSE(v1.contains(2));
- ASSERT_FALSE(v1.contains(3));
-
- ASSERT_EQ(v2.size(), 2);
- ASSERT_TRUE(v2.contains(1));
- ASSERT_EQ(*v2.find(1), 1);
- ASSERT_TRUE(v2.contains(2));
- ASSERT_EQ(*v2.find(2), 2);
- ASSERT_FALSE(v2.contains(3));
-
- ASSERT_EQ(v3.size(), 2);
- ASSERT_TRUE(v3.contains(1));
- ASSERT_EQ(*v3.find(1), 1);
- ASSERT_TRUE(v3.contains(3));
- ASSERT_EQ(*v3.find(3), 3);
- ASSERT_FALSE(v3.contains(2));
-
- // Verify that v1's iterator did not change
- ASSERT(v1.find(1) == v1it);
-
- // Verify that erase works as expected, and preserves history.
- auto v4 = v3.erase(1).erase(3);
- ASSERT_EQ(v4.size(), 0);
- ASSERT_FALSE(v4.contains(1));
- ASSERT_FALSE(v4.contains(2));
- ASSERT_FALSE(v4.contains(3));
- ASSERT_EQ(v3.size(), 2);
- ASSERT_TRUE(v3.contains(1));
- ASSERT_TRUE(v3.contains(3));
- ASSERT_EQ(v2.size(), 2);
- ASSERT_TRUE(v2.contains(1));
- ASSERT_TRUE(v2.contains(2));
- ASSERT_EQ(v1.size(), 1);
- ASSERT_TRUE(v1.contains(1));
-
- ensureContainerInvariants({v0, v1, v2, v3, v4});
-}
-
-TEST(ImmutableSet, UserDefinedType) {
- immutable::set<UserDefinedKey> v0;
- auto v1 = v0.insert(UserDefinedKey(1));
- ASSERT(v1.find(UserDefinedKey(1)) != v1.end());
- ASSERT_EQ(*v1.find(UserDefinedKey(1)), UserDefinedKey(1));
-
- ensureContainerInvariants({v0, v1});
-}
-
-TEST(ImmutableSet, IncomparableType) {
- immutable::set<Incomparable, CompareIncomparable> v0;
- auto v1 = v0.insert(Incomparable(1));
- ASSERT_TRUE(v1.contains(Incomparable(1)));
-
- ensureContainerInvariants(v0, CompareIncomparable{});
- ensureContainerInvariants(v1, CompareIncomparable{});
-}
-
-TEST(ImmutableSet, HeterogeneousLookup) {
- immutable::set<std::string, StringCompare> v0;
- auto v1 = v0.insert("str");
-
- // Lookup using StringData without the need to convert to string.
- ASSERT(v1.find("str"_sd) != v1.end());
-
- ensureContainerInvariants({v0, v1});
-}
-
-TEST(ImmutableSet, Bounds) {
- immutable::set<int> set;
- constexpr int numKeys = 100;
- for (int i = 0; i < numKeys; ++i) {
- set = set.insert(2 * i);
- ensureContainerInvariants(set);
- }
-
- for (int i = 0; i < numKeys - 1; ++i) {
- auto lowerExact = set.lower_bound(2 * i);
- ASSERT(lowerExact != set.end() && *lowerExact == 2 * i);
- auto upperExact = set.upper_bound(2 * i);
- ASSERT(upperExact != set.end() && *upperExact == 2 * (i + 1));
-
- auto lowerNear = set.lower_bound(2 * i + 1);
- ASSERT(lowerNear != set.end() && *lowerNear == 2 * (i + 1));
- auto upperNear = set.upper_bound(2 * i + 1);
- ASSERT(upperNear != set.end() && *upperNear == 2 * (i + 1));
- }
-}
-
-TEST(ImmutableSet, Iteration) {
- immutable::set<int> set;
- constexpr int numKeys = 100;
- for (int i = 0; i < numKeys; ++i) {
- set = set.insert(2 * i);
- ensureContainerInvariants(set);
- }
-
- auto set0 = set;
- auto it0 = set0.begin();
-
- for (int i = 0; i < numKeys; ++i) {
- set = set.insert(2 * i + 1);
- ensureContainerInvariants(set);
- }
-
- auto set1 = set;
- auto it1 = set1.begin();
-
- for (int i = 0; i < numKeys; ++i) {
- ASSERT(it0 != set0.end());
- ASSERT_EQ(*it0, 2 * i);
- ++it0;
-
- ASSERT(it1 != set1.end());
- ASSERT_EQ(*it1, 2 * i);
- ++it1;
-
- ASSERT(it1 != set1.end());
- ASSERT_EQ(*it1, 2 * i + 1);
- ++it1;
- }
- ASSERT(it0 == set0.end());
- ASSERT(it1 == set1.end());
-}
-
-TEST(ImmutableSet, Insert) {
- auto v0 = init_sets<int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_K(v0, insert, 1);
- auto v2 = MUTATE_K(v1, insert, 2);
- auto v3 = MUTATE_K(v2, insert, 3);
- auto v4 = MUTATE_K(v3, insert, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Insert of existing key is a noop.
- auto v5 = MUTATE_K(v4, insert, 1); // enforces no duplicates
- ASSERT_CONTAINS(v5, 1);
-
- // Insert at beginning works.
- auto v6 = MUTATE_K(v4, insert, 0);
- ASSERT_CONTAINS(v6, 0);
-
- // Insert at end works.
- auto v7 = MUTATE_K(v4, insert, 6);
- ASSERT_CONTAINS(v7, 6);
-
- // Insert in middle works.
- auto v8 = MUTATE_K(v4, insert, 4);
- ASSERT_CONTAINS(v8, 4);
-}
-
-TEST(ImmutableSet, InsertViaIterator) {
- auto v0 = init_sets<int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_K(v0, insert, 1);
- auto v2 = MUTATE_K(v1, insert, 2);
- auto v3 = MUTATE_K(v2, insert, 3);
- auto v4 = MUTATE_K(v3, insert, 6);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 6);
-
- // Giving the iterator for an existing element does a noop.
-
- auto it4_2 = SEARCH(v4, find, 2);
- auto v5 = MUTATE_IT_K(v4, insert, it4_2, 2); // enforces no duplicates
- ASSERT_CONTAINS(v5, 2);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end5 = END(v5);
- auto v6 = MUTATE_IT_K(v5, insert, end5, 2); // enforces no duplicates
- ASSERT_CONTAINS(v6, 2);
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_K(v6, insert, end6, 4);
- ASSERT_CONTAINS(v7, 4);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_K(v7, insert, end7, 7);
- ASSERT_CONTAINS(v8, 7);
-
- // Giving hint from lower_bound works for both existing and new entries.
-
- auto lb8_2 = SEARCH(v8, lower_bound, 2);
- auto v9 = MUTATE_IT_K(v8, insert, lb8_2, 2); // enforces no duplicates
- ASSERT_CONTAINS(v9, 2);
-
- auto lb9_0 = SEARCH(v9, lower_bound, 0);
- auto v10 = MUTATE_IT_K(v9, insert, lb9_0, 0);
- ASSERT_CONTAINS(v10, 0);
-
- auto lb10_5 = SEARCH(v10, lower_bound, 5);
- auto v11 = MUTATE_IT_K(v10, insert, lb10_5, 5);
- ASSERT_CONTAINS(v11, 5);
-
- auto lb11_8 = SEARCH(v11, lower_bound, 8);
- auto v12 = MUTATE_IT_K(v11, insert, lb11_8, 8);
- ASSERT_CONTAINS(v12, 8);
-}
-
-TEST(ImmutableSet, Erase) {
- auto v0 = init_sets<int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_K(v0, insert, 1);
- auto v2 = MUTATE_K(v1, insert, 2);
- auto v3 = MUTATE_K(v2, insert, 3);
- auto v4 = MUTATE_K(v3, insert, 5);
- ASSERT_CONTAINS(v4, 1);
- ASSERT_CONTAINS(v4, 2);
- ASSERT_CONTAINS(v4, 3);
- ASSERT_CONTAINS(v4, 5);
-
- // Erase on existing key removes value.
- auto v5 = MUTATE_K(v4, erase, 1);
- ASSERT_NOT_CONTAINS(v5, 1);
-
- // Erase on non-existent key does nothing.
- auto v6 = MUTATE_K(v5, erase, 0);
- ASSERT_NOT_CONTAINS(v6, 0);
- ASSERT_CONTAINS(v6, 2);
- ASSERT_CONTAINS(v6, 3);
- ASSERT_CONTAINS(v6, 5);
-}
-
-TEST(ImmutableSet, EraseViaIterator) {
- auto v0 = init_sets<int>();
-
- // Populate an initial set of values.
- auto v1 = MUTATE_K(v0, insert, 1);
- auto v2 = MUTATE_K(v1, insert, 2);
- auto v3 = MUTATE_K(v2, insert, 3);
- auto v4 = MUTATE_K(v3, insert, 5);
- auto v5 = MUTATE_K(v4, insert, 6);
- ASSERT_CONTAINS(v5, 1);
- ASSERT_CONTAINS(v5, 2);
- ASSERT_CONTAINS(v5, 3);
- ASSERT_CONTAINS(v5, 5);
- ASSERT_CONTAINS(v5, 6);
-
- // Giving the iterator for an existing element erases the value.
-
- auto it5_2 = SEARCH(v5, find, 2);
- auto v6 = MUTATE_IT_K(v5, erase, it5_2, 2);
- ASSERT_NOT_CONTAINS(v6, 2);
-
- // Giving end() as hint works appropriately whether hint is accurate or not.
-
- auto end6 = END(v6);
- auto v7 = MUTATE_IT_K(v6, erase, end6, 3);
- ASSERT_NOT_CONTAINS(v7, 3);
-
- auto end7 = END(v7);
- auto v8 = MUTATE_IT_K(v7, erase, end7, 4);
- ASSERT_NOT_CONTAINS(v8, 4);
-
- auto end8 = END(v8);
- auto v9 = MUTATE_IT_K(v8, erase, end8, 7);
- ASSERT_NOT_CONTAINS(v9, 7);
-
- // Giving hint from lower_bound works for both existing and non-existing entries.
-
- auto lb9_5 = SEARCH(v9, lower_bound, 5);
- auto v10 = MUTATE_IT_K(v9, erase, lb9_5, 5);
- ASSERT_NOT_CONTAINS(v10, 5);
-
- auto lb10_0 = SEARCH(v10, lower_bound, 0);
- auto v11 = MUTATE_IT_K(v10, erase, lb10_0, 0);
-
- auto lb11_4 = SEARCH(v10, lower_bound, 4);
- auto v12 = MUTATE_IT_K(v11, erase, lb11_4, 4);
-
- auto lb12_7 = SEARCH(v12, lower_bound, 7);
- auto v13 = MUTATE_IT_K(v12, erase, lb12_7, 7);
-
- ASSERT_CONTAINS(v13, 1);
- ASSERT_CONTAINS(v13, 6);
- ASSERT_NOT_CONTAINS(v13, 0);
- ASSERT_NOT_CONTAINS(v13, 2);
- ASSERT_NOT_CONTAINS(v13, 3);
- ASSERT_NOT_CONTAINS(v13, 4);
- ASSERT_NOT_CONTAINS(v13, 5);
- ASSERT_NOT_CONTAINS(v13, 7);
-}
-
-TEST(ImmutableSet, ExclusiveOwnership) {
- immutable::set<int> v0;
-
- auto v1 = v0.insert(1);
- auto v2 = v1.insert(2);
- auto v3 = v2.insert(3);
-
- ASSERT_TRUE(v1.contains(1));
- ASSERT_TRUE(v2.contains(1));
- ASSERT_TRUE(v3.contains(1));
-
- // Claiming exclusive ownership over v3 means v3 will no longer be valid after mutation, but
- // older versions should be unperturbed.
- auto v4 = std::move(v3).erase(1);
- ASSERT_TRUE(v1.contains(1));
- ASSERT_TRUE(v2.contains(1));
- ASSERT_FALSE(v4.contains(1));
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/util/immutable/immutable_std_comparison_bm.cpp b/src/mongo/util/immutable/immutable_std_comparison_bm.cpp
deleted file mode 100644
index 503984ca1d2..00000000000
--- a/src/mongo/util/immutable/immutable_std_comparison_bm.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include <benchmark/benchmark.h>
-
-#include "mongo/util/immutable/map.h"
-#include <map>
-
-namespace mongo {
-
-static void BM_std_insert_op(benchmark::State& state) {
- std::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- for (auto _ : state) {
- map[i] = i;
- i++;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_std_copy_op(benchmark::State& state) {
- std::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- std::map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_std_find_op(benchmark::State& state) {
- std::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(map.find(i - 1));
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_std_copy_and_insert_op(benchmark::State& state) {
- std::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map[i] = i;
- }
-
- std::map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- mapCopy[i] = i;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_insert_op(benchmark::State& state) {
- immutable::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- for (auto _ : state) {
- map = std::move(map).set(i, i);
- i++;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_copy_op(benchmark::State& state) {
- immutable::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- immutable::map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map;
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_find_op(benchmark::State& state) {
- immutable::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(map.find(i - 1));
- benchmark::ClobberMemory();
- }
-}
-
-static void BM_immutable_copy_and_insert_op(benchmark::State& state) {
- immutable::map<int, int> map;
-
- int64_t i = 0;
- for (; i < state.range(0); i++) {
- map = std::move(map).set(i, i);
- }
-
- immutable::map<int, int> mapCopy;
- for (auto _ : state) {
- mapCopy = map.set(i, i);
- benchmark::ClobberMemory();
- }
-}
-
-// Run with varying container sizes: [ 8, 16, 32, 64, 128, 256, 512, 1024, 2k, 4k, 8k ].
-BENCHMARK(BM_std_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_std_copy_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_copy_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_std_find_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_find_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-
-BENCHMARK(BM_std_copy_and_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-BENCHMARK(BM_immutable_copy_and_insert_op)->RangeMultiplier(2)->Range(8, 8 << 10);
-} // namespace mongo
diff --git a/src/mongo/util/immutable/immutable_unordered_test.cpp b/src/mongo/util/immutable/immutable_unordered_test.cpp
deleted file mode 100644
index d6e2aa055dd..00000000000
--- a/src/mongo/util/immutable/immutable_unordered_test.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include "mongo/unittest/unittest.h"
-
-#include "mongo/util/immutable/unordered_map.h"
-#include "mongo/util/immutable/unordered_set.h"
-#include "mongo/util/string_map.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
-
-namespace mongo {
-namespace {
-
-class UserDefinedKey {
-public:
- UserDefinedKey() = default;
- explicit UserDefinedKey(int val) : a(val) {}
-
- bool operator==(const UserDefinedKey& rhs) const {
- return a == rhs.a;
- }
-
- // Use the Abseil hashing framework
- template <typename H>
- friend H AbslHashValue(H h, const UserDefinedKey& obj) {
- return H::combine(std::move(h), obj.a);
- }
-
-private:
- int a = 0;
-};
-
-TEST(ImmutableUnorderedMap, Basic) {
- // Insert some values and verify that the data structure is behaving as expected
- immutable::unordered_map<int, int> v0;
- auto v1 = v0.set(1, 2);
- // Record the pointer to the value '1', verify that this doesn't change after performing more
- // inserts
- auto v1Val = v1.find(1);
-
- // Create distinct branches of the history from v1. v0 and v1 should be unaffected
- auto v2 = v1.update(1, [](int v) { return v += 1; });
- auto v3 = v1.set(2, 3);
-
- // Verify that values are as expected
- ASSERT_EQ(v0.size(), 0);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT(v1.find(1));
- ASSERT_EQ(*v1.find(1), 2);
-
- ASSERT_EQ(v2.size(), 1);
- ASSERT(v2.find(1));
- ASSERT_EQ(*v2.find(1), 3);
- ASSERT(!v2.find(2));
-
- ASSERT_EQ(v3.size(), 2);
- ASSERT(v3.find(1));
- ASSERT_EQ(*v3.find(1), 2);
- ASSERT(v3.find(2));
- ASSERT_EQ(*v3.find(2), 3);
-
- // Verify that pointer to v1's value did not change
- ASSERT_EQ(v1.find(1), v1Val);
-}
-
-TEST(ImmutableUnorderedMap, UserDefinedType) {
- immutable::unordered_map<UserDefinedKey, int> v0;
- auto v1 = v0.set(UserDefinedKey(1), 2);
- ASSERT(v1.find(UserDefinedKey(1)));
-}
-
-TEST(ImmutableUnorderedMap, HeterogeneousLookup) {
- immutable::unordered_map<std::string, int, StringMapHasher, StringMapEq> v0;
- auto v1 = v0.set("str", 1);
-
- // Lookup using StringData without the need to convert to string.
- ASSERT(v1.find("str"_sd));
-
- // Lookup using pre-hash
- StringMapHashedKey hashedKey = StringMapHasher().hashed_key("str"_sd);
- ASSERT(v1.find(hashedKey));
-}
-
-TEST(ImmutableUnorderedMap, BatchWrite) {
- immutable::unordered_map<int, int> v0;
-
- auto transient = v0.transient();
- transient.set(1, 2);
- transient.set(2, 3);
- immutable::unordered_map<int, int> v1 = transient.persistent();
-
- ASSERT(!v0.find(1));
- ASSERT(!v0.find(2));
- ASSERT(v1.find(1));
- ASSERT(v1.find(2));
-}
-
-TEST(ImmutableUnorderedMap, ExclusiveOwnership) {
- immutable::unordered_map<int, int> v0;
-
- auto v1 = v0.set(1, 1);
- auto v2 = v1.set(2, 2);
- auto v3 = v2.set(3, 3);
-
- ASSERT(v1.find(1));
- ASSERT(v2.find(1));
- ASSERT(v3.find(1));
-
- // Claiming exclusive ownership over v3 means v3 will no longer be valid after mutation, but
- // older versions should be unperturbed.
- auto v4 = std::move(v3).erase(1);
- ASSERT(v1.find(1));
- ASSERT(v2.find(1));
- ASSERT(!v4.find(1));
-}
-
-TEST(ImmutableUnorderedSet, Basic) {
- // Insert some values and verify that the data structure is behaving as expected
- immutable::unordered_set<int> v0;
- auto v1 = v0.insert(1);
- // Record the pointer to the value '1', verify that this doesn't change after performing more
- // inserts
- auto v1Val = v1.find(1);
-
- // Make more versions of the data structure, v2 and v3 are now distinct history branches from
- // v1. v0 and v1 should be unaffected
- auto v2 = v1.insert(2);
- auto v3 = v1.insert(2);
-
- // Verify that values are as expected
- ASSERT_EQ(v0.size(), 0);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT(v1.find(1));
- ASSERT_EQ(*v1.find(1), 1);
-
- ASSERT_EQ(v2.size(), 2);
- ASSERT(v2.find(1));
- ASSERT_EQ(*v2.find(1), 1);
- ASSERT(v2.find(2));
- ASSERT_EQ(*v2.find(2), 2);
-
- ASSERT_EQ(v3.size(), 2);
- ASSERT(v3.find(1));
- ASSERT_EQ(*v3.find(1), 1);
- ASSERT(v3.find(2));
- ASSERT_EQ(*v3.find(2), 2);
-
- // Verify that pointer to v1's value did not change
- ASSERT_EQ(v1.find(1), v1Val);
- // Key is stored in v2 and v3 with different addresses
- ASSERT_NE(v2.find(2), v3.find(2));
-}
-
-TEST(ImmutableUnorderedSet, UserDefinedType) {
- immutable::unordered_set<UserDefinedKey> v0;
- auto v1 = v0.insert(UserDefinedKey(1));
- ASSERT(v1.find(UserDefinedKey(1)));
-}
-
-TEST(ImmutableUnorderedSet, HeterogeneousLookup) {
- immutable::unordered_set<std::string, StringMapHasher, StringMapEq> v0;
- auto v1 = v0.insert("str");
-
- // Lookup using StringData without the need to convert to string.
- ASSERT(v1.find("str"_sd));
-
- // Lookup using pre-hash
- StringMapHashedKey hashedKey = StringMapHasher().hashed_key("str"_sd);
- ASSERT(v1.find(hashedKey));
-}
-
-TEST(ImmutableUnorderedSet, BatchWrite) {
- immutable::unordered_set<int> v0;
-
- auto transient = v0.transient();
- transient.insert(1);
- transient.insert(2);
- immutable::unordered_set<int> v1 = transient.persistent();
-
- ASSERT(!v0.find(1));
- ASSERT(!v0.find(2));
- ASSERT(v1.find(1));
- ASSERT(v1.find(2));
-}
-
-TEST(ImmutableUnorderedSet, ExclusiveOwnership) {
- immutable::unordered_set<int> v0;
-
- auto v1 = v0.insert(1);
- auto v2 = v1.insert(2);
- auto v3 = v2.insert(3);
-
- ASSERT(v1.find(1));
- ASSERT(v2.find(1));
- ASSERT(v3.find(1));
-
- auto v4 = std::move(v3).erase(1);
- ASSERT(v1.find(1));
- ASSERT(v2.find(1));
- ASSERT(!v4.find(1));
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/util/immutable/immutable_vector_test.cpp b/src/mongo/util/immutable/immutable_vector_test.cpp
deleted file mode 100644
index 60329423403..00000000000
--- a/src/mongo/util/immutable/immutable_vector_test.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include "mongo/unittest/unittest.h"
-
-#include "mongo/util/immutable/vector.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
-
-namespace mongo {
-namespace {
-
-class UserDefinedType {
-public:
- UserDefinedType() = default;
- explicit UserDefinedType(int val) : a(val) {}
-
- bool operator==(const UserDefinedType& rhs) const {
- return a == rhs.a;
- }
-
-private:
- int a = 0;
-};
-
-TEST(ImmutableUnorderedMap, Basic) {
- // Insert some values and verify that the data structure is behaving as expected
- immutable::vector<int> v0;
- auto v1 = v0.push_back(1);
- // Record the pointer to the value at index '0', verify that this doesn't change after
- // performing additional modifications
- auto* v1Val = &(*v1.begin());
-
- // Create distinct branches of the history from v1. v0 and v1 should be unaffected
- auto v2 = v1.update(0, [](int v) { return v += 1; });
- auto v3 = v1.push_back(3);
- auto v4 = v1.set(0, 4);
-
- // Verify that values are as expected
- ASSERT_EQ(v0.size(), 0);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT_EQ(v1.at(0), 1);
-
- ASSERT_EQ(v2.size(), 1);
- ASSERT_EQ(v2.at(0), 2);
-
- ASSERT_EQ(v3.size(), 2);
- ASSERT_EQ(v3.at(0), 1);
- ASSERT_EQ(v3.at(1), 3);
-
- ASSERT_EQ(v4.size(), 1);
- ASSERT_EQ(v4.at(0), 4);
-
- // Verify that pointer to v1's value did not change
- ASSERT_EQ(&(*v1.begin()), v1Val);
-}
-
-TEST(ImmutableUnorderedMap, UserDefinedType) {
- immutable::vector<UserDefinedType> v0;
- auto v1 = v0.push_back(UserDefinedType(1));
- ASSERT(v1.at(0) == UserDefinedType(1));
-}
-
-TEST(ImmutableUnorderedMap, BatchWrite) {
- immutable::vector<int> v0;
-
- auto transient = v0.transient();
- transient.push_back(1);
- transient.push_back(2);
- immutable::vector<int> v1 = transient.persistent();
-
- ASSERT_EQ(v0.size(), 0);
- ASSERT_EQ(v1.size(), 2);
- ASSERT_EQ(v1.at(0), 1);
- ASSERT_EQ(v1.at(1), 2);
-}
-
-TEST(ImmutableUnorderedMap, ExclusiveOwnership) {
- immutable::vector<int> v0;
-
- auto v1 = v0.push_back(1);
- auto v2 = v1.push_back(2);
- auto v3 = v2.push_back(3);
-
- ASSERT_EQ(v1.size(), 1);
- ASSERT_EQ(v2.size(), 2);
- ASSERT_EQ(v3.size(), 3);
-
- // Claiming exclusive ownership over v3 means v3 will no longer be valid after mutation, but
- // older versions should be unperturbed.
- auto v4 = std::move(v3).take(0);
- ASSERT_EQ(v1.size(), 1);
- ASSERT_EQ(v2.size(), 2);
- ASSERT_EQ(v4.size(), 0);
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/util/immutable/map.h b/src/mongo/util/immutable/map.h
deleted file mode 100644
index 351cfd560da..00000000000
--- a/src/mongo/util/immutable/map.h
+++ /dev/null
@@ -1,358 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <algorithm>
-
-#include <immer/flex_vector.hpp>
-
-#include "mongo/util/immutable/details/map.h"
-#include "mongo/util/immutable/details/memory_policy.h"
-
-
-namespace mongo::immutable {
-
-/**
- * Immutable ordered dictionary.
- *
- * Interfaces that "modify" the map are 'const' and return a new version of the map with the
- * modifications applied and leaves the original version untouched.
- *
- * It is optimized for efficient copies and low memory usage when multiple versions of the map exist
- * simultaneously at the expense of regular lookups not being as efficient as the regular std
- * ordered containers. Suitable for use in code that uses the copy-on-write pattern.
- *
- * Thread-safety: All methods are const, it is safe to perform modifications that result in new
- * versions from multiple threads concurrently.
- *
- * Memory management: Internal memory management is done using reference counting, memory is free'd
- * as references to different versions of the map are released.
- *
- * Built on top of 'immer::flex_vector'.
- * Documentation: 'immer/flex_vector.h' and https://sinusoid.es/immer/
- */
-template <typename Key, typename Value, typename Compare = std::less<Key>>
-class map {
-public:
- using key_type = Key;
- using mapped_type = Value;
- using value_type = std::pair<Key, Value>;
- using storage_type = immer::flex_vector<value_type, detail::MemoryPolicy>;
- using iterator = typename storage_type::iterator;
- using size_type = typename storage_type::size_type;
- using diference_type = std::ptrdiff_t;
- using reference = const value_type&;
- using const_reference = const value_type&;
- using memory_policy_type = detail::MemoryPolicy;
- using comp = Compare;
-
- map() = default;
-
- struct default_value {
- const mapped_type& operator()() const {
- static mapped_type v = mapped_type{};
- return v;
- }
- };
-
- struct error_value {
- const mapped_type& operator()() const {
- throw std::out_of_range{"key not found"};
- }
- };
-
- bool operator==(const map& other) const {
- return _storage == other._storage;
- }
-
- bool operator!=(const map& other) const {
- return !(*this == other);
- }
-
- [[nodiscard]] iterator begin() const {
- return _storage.begin();
- }
-
- [[nodiscard]] iterator end() const {
- return _storage.end();
- }
-
- size_t size() const {
- return _storage.size();
- }
-
- /**
- * Returns a reference to the value associated with 'key' if one exists, otherwise a default
- * constructed Value.
- */
- const mapped_type& operator[](const key_type& key) const {
- auto it = find(key);
- if (it == end()) {
- return default_value{}();
- }
- return it->second;
- }
-
- /**
- * Returns a reference to the value associated with 'key' if one exists, otherwise throws.
- */
- const mapped_type& at(const key_type& key) const {
- auto it = find(key);
- if (it == end()) {
- return error_value{}();
- }
- return it->second;
- }
-
- /**
- * Insert a new 'key' and 'value' pair to the map.
- *
- * Returns the modified map, or the original if 'key' was already contained.
- */
- template <typename K, typename V>
- [[nodiscard]] map insert(K&& key, V&& value) const& {
- return map{details::map::insert<map<key_type, mapped_type, comp>>(
- _storage, std::forward<K>(key), std::forward<V>(value))};
- }
- template <typename K, typename V>
- [[nodiscard]] map insert(K&& key, V&& value) && {
- return map{details::map::insert<map<key_type, mapped_type, comp>>(
- std::move(_storage), std::forward<K>(key), std::forward<V>(value))};
- }
-
- /**
- * Insert a new 'key' and 'value' pair to the map. Uses 'it' as a hint.
- *
- * Returns the modified map, or the original if 'key' was already contained.
- */
- template <typename K, typename V>
- [[nodiscard]] map insert(iterator it, K&& key, V&& value) const& {
- return map{details::map::insert<map<key_type, mapped_type, comp>>(
- _storage, it, std::forward<K>(key), std::forward<V>(value))};
- }
- template <typename K, typename V>
- [[nodiscard]] map insert(iterator it, K&& key, V&& value) && {
- return map{details::map::insert<map<key_type, mapped_type, comp>>(
- std::move(_storage), it, std::forward<K>(key), std::forward<V>(value))};
- }
-
- /**
- * Sets the value associated with 'key' to 'value', inserting the new pair if 'key' does not
- * exist.
- *
- * Returns the modified map.
- */
- template <typename K, typename V>
- [[nodiscard]] map set(K&& key, V&& value) const& {
- return map{details::map::set<map<key_type, mapped_type, comp>>(
- _storage, std::forward<K>(key), std::forward<V>(value))};
- }
- template <typename K, typename V>
- [[nodiscard]] map set(K&& key, V&& value) && {
- return map{details::map::set<map<key_type, mapped_type, comp>>(
- std::move(_storage), std::forward<K>(key), std::forward<V>(value))};
- }
-
- /**
- * Sets the value associated with 'key' to 'value', inserting the new pair if 'key' does not
- * exist. Treats 'it' as a hint.
- *
- * Returns the modified map.
- */
- template <typename K, typename V>
- [[nodiscard]] map set(iterator it, K&& key, V&& value) const& {
- return map{details::map::set<map<key_type, mapped_type, comp>>(
- _storage, it, std::forward<K>(key), std::forward<V>(value))};
- }
- template <typename K, typename V>
- [[nodiscard]] map set(iterator it, K&& key, V&& value) && {
- return map{details::map::set<map<key_type, mapped_type, comp>>(
- std::move(_storage), it, std::forward<K>(key), std::forward<V>(value))};
- }
-
- /**
- * Sets the value associated with 'key' by applying 'valueUpdate' to the existing value, or to a
- * default-constructed value if no entry for 'key' exists.
- *
- * The signature of 'valueUpdate' should be equivalent to
- * std::function<mapped_type(const mapped_type&)>. Returns the modified map.
- */
- template <typename K, typename U>
- [[nodiscard]] map update(K&& key, U&& valueUpdate) const& {
- return map{details::map::update<map<key_type, mapped_type, comp>>(
- _storage, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
- template <typename K, typename U>
- [[nodiscard]] map update(K&& key, U&& valueUpdate) && {
- return map{details::map::update<map<key_type, mapped_type, comp>>(
- std::move(_storage), std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
-
- /**
- * Updates the value associated with 'key' by applying 'valueUpdate' to the existing value, or
- * to a default-constructed value if no entry for 'key' exists. Uses 'it' as a hint.
- *
- * The signature of 'valueUpdate' should be equivalent to
- * std::function<mapped_type(const mapped_type&)>. Returns the modified map.
- */
- template <typename K, typename U>
- [[nodiscard]] map update(iterator it, K&& key, U&& valueUpdate) const& {
- return map{details::map::update<map<key_type, mapped_type, comp>>(
- _storage, it, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
- template <typename K, typename U>
- [[nodiscard]] map update(iterator it, K&& key, U&& valueUpdate) && {
- return map{details::map::update<map<key_type, mapped_type, comp>>(
- std::move(_storage), it, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
-
- /**
- * Updates the value associated with 'key' if it exists by applying 'valueUpdate' to the
- * existing value.
- *
- * The signature of 'valueUpdate' should be equivalent to
- * std::function<mapped_type(const mapped_type&)>. Returns the modified map, or the original if
- * 'key' does not exist.
- */
- template <typename K, typename U>
- [[nodiscard]] map update_if_exists(K&& key, U&& valueUpdate) const& {
- return map{details::map::update_if_exists<map<key_type, mapped_type, comp>>(
- _storage, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
- template <typename K, typename U>
- [[nodiscard]] map update_if_exists(K&& key, U&& valueUpdate) && {
- return map{details::map::update_if_exists<map<key_type, mapped_type, comp>>(
- std::move(_storage), std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
-
- /**
- * Updates the value associated with 'key' if it exists by applying 'valueUpdate' to the
- * existing value. Uses 'it' as a hint.
- *
- * The signature of 'valueUpdate' should be equivalent to
- * std::function<mapped_type(const mapped_type&)>. Returns the modified map, or the original if
- * 'key' does not exist.
- */
- template <typename K, typename U>
- [[nodiscard]] map update_if_exists(iterator it, K&& key, U&& valueUpdate) const& {
- return map{details::map::update_if_exists<map<key_type, mapped_type, comp>>(
- _storage, it, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
- template <typename K, typename U>
- [[nodiscard]] map update_if_exists(iterator it, K&& key, U&& valueUpdate) && {
- return map{details::map::update_if_exists<map<key_type, mapped_type, comp>>(
- std::move(_storage), it, std::forward<K>(key), std::forward<U>(valueUpdate))};
- }
-
- /**
- * Removes 'key' and its associated value from the map.
- *
- * Returns the modified map, or the original if 'key' does not exist.
- */
- template <typename K>
- [[nodiscard]] map erase(K&& key) const& {
- return map{
- details::map::erase<map<key_type, mapped_type, comp>>(_storage, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] map erase(K&& key) && {
- return map{details::map::erase<map<key_type, mapped_type, comp>>(std::move(_storage),
- std::forward<K>(key))};
- }
-
- /**
- * Removes entry assocated with 'it' from the map. 'it' must match 'key' or it will not be
- * erased.
- *
- * Returns the modified map, or the original if 'it' is equal to 'end()'.
- */
- template <typename K>
- [[nodiscard]] map erase(iterator it, K&& key) const& {
- return map{details::map::erase<map<key_type, mapped_type, comp>>(
- _storage, it, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] map erase(iterator it, K&& key) && {
- return map{details::map::erase<map<key_type, mapped_type, comp>>(
- std::move(_storage), it, std::forward<K>(key))};
- }
-
- /**
- * Returns an iterator to the entry for 'key' if it exists, 'end()' otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <typename SearchKey>
- [[nodiscard]] iterator find(const SearchKey& key) const {
- return details::map::find<map<key_type, mapped_type, comp>>(_storage, key);
- }
-
- /**
- * Returns true if map contains an entry for 'key'.
- *
- * Supports heterogeneous lookup.
- */
- template <typename SearchKey>
- bool contains(const SearchKey& key) const {
- return find(key) != end();
- }
-
- /**
- * Returns the first the entry greater than or equal to 'key' if one exists, 'end()' otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <typename SearchKey>
- [[nodiscard]] iterator lower_bound(const SearchKey& key) const {
- return details::map::lower_bound<map<key_type, mapped_type, comp>>(_storage, key);
- }
-
- /**
- * Returns the first the entry strictly greater than 'key' if one exists, 'end()' otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <typename SearchKey>
- [[nodiscard]] iterator upper_bound(const SearchKey& key) const {
- return std::upper_bound(
- _storage.begin(),
- _storage.end(),
- key,
- [](const SearchKey& a, const value_type& b) -> bool { return comp{}(a, b.first); });
- }
-
-private:
- template <typename S>
- explicit map(S&& s) : _storage{std::forward<S>(s)} {}
-
- storage_type _storage;
-};
-
-} // namespace mongo::immutable
diff --git a/src/mongo/util/immutable/set.h b/src/mongo/util/immutable/set.h
deleted file mode 100644
index 24e5183c34f..00000000000
--- a/src/mongo/util/immutable/set.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <algorithm>
-
-#include <immer/flex_vector.hpp>
-
-#include "mongo/util/immutable/details/memory_policy.h"
-#include "mongo/util/immutable/details/set.h"
-
-namespace mongo::immutable {
-
-/**
- * Immutable ordered set.
- *
- * Interfaces that "modify" the set are 'const' and return a new version of the set with the
- * modifications applied and leaves the original version untouched.
- *
- * It is optimized for efficient copies and low memory usage when multiple versions of the set exist
- * simultaneously at the expense of regular lookups not being as efficient as the regular std
- * ordered containers. Suitable for use in code that uses the copy-on-write pattern.
- *
- * Thread-safety: All methods are const, it is safe to perform modifications that result in new
- * versions from multiple threads concurrently.
- *
- * Memory management: Internal memory management is done using reference counting, memory is free'd
- * as references to different versions of the set are released.
- *
- * Built on top of 'immer::flex_vector'.
- * Documentation: 'immer/flex_vector.h' and https://sinusoid.es/immer/
- */
-template <typename Key, typename Compare = std::less<Key>>
-class set {
-public:
- using key_type = Key;
- using storage_type = immer::flex_vector<key_type, detail::MemoryPolicy>;
- using iterator = typename storage_type::iterator;
- using size_type = typename storage_type::size_type;
- using diference_type = std::ptrdiff_t;
- using reference = const key_type&;
- using const_reference = const key_type&;
- using memory_policy_type = detail::MemoryPolicy;
- using comp = Compare;
-
- set() = default;
-
- bool operator==(const set& other) const {
- return _storage == other._storage;
- }
-
- bool operator!=(const set& other) const {
- return !(*this == other);
- }
-
- [[nodiscard]] iterator begin() const {
- return _storage.begin();
- }
-
- [[nodiscard]] iterator end() const {
- return _storage.end();
- }
-
- size_t size() const {
- return _storage.size();
- }
-
- /**
- * Insert a new 'key' to the set.
- *
- * Returns the modified set, or the original if 'key' was already contained.
- */
- template <typename K>
- [[nodiscard]] set insert(K&& key) const& {
- return set{details::set::insert<set>(_storage, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] set insert(K&& key) && {
- return set{details::set::insert<set>(std::move(_storage), std::forward<K>(key))};
- }
-
- /**
- * Insert a new 'key' to the set. Uses 'it' as a hint.
- *
- * Returns the modified set, or the original if 'key' was already contained.
- */
- template <typename K>
- [[nodiscard]] set insert(iterator it, K&& key) const& {
- return set{details::set::insert<set>(_storage, it, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] set insert(iterator it, K&& key) && {
- return set{details::set::insert<set>(std::move(_storage), it, std::forward<K>(key))};
- }
-
- /**
- * Removes 'key' from the set.
- *
- * Returns the modified set, or the original if 'key' does not exist.
- */
- template <typename K>
- [[nodiscard]] set erase(K&& key) const& {
- return set{details::set::erase<set>(_storage, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] set erase(K&& key) && {
- return set{details::set::erase<set>(std::move(_storage), std::forward<K>(key))};
- }
-
- /**
- * Removes key associated with 'key' from the set. Uses 'it' as a hint.
- *
- * Returns the modified set, or the original if 'key' does not exist.
- */
- template <typename K>
- [[nodiscard]] set erase(iterator it, K&& key) const& {
- return set{details::set::erase<set>(_storage, it, std::forward<K>(key))};
- }
- template <typename K>
- [[nodiscard]] set erase(iterator it, K&& key) && {
- return set{details::set::erase<set>(std::move(_storage), it, std::forward<K>(key))};
- }
-
- /**
- * Returns an iterator to the element for 'key' if it exists, 'end()' otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <class SearchKey>
- [[nodiscard]] iterator find(const SearchKey& key) const {
- return details::set::find<set>(_storage, key);
- }
-
- /**
- * Returns true if set contains 'key'.
- *
- * Supports heterogeneous lookup.
- */
- template <class SearchKey>
- bool contains(const SearchKey& key) const {
- return find(key) != end();
- }
-
- /**
- * Returns the first the element greater than or equal to 'key' if one exists, 'end()'
- * otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <class SearchKey>
- [[nodiscard]] iterator lower_bound(const SearchKey& key) const {
- return details::set::lower_bound<set>(_storage, key);
- }
-
- /**
- * Returns the first the element strictly greater than 'key' if one exists, 'end()' otherwise.
- *
- * Supports heterogeneous lookup.
- */
- template <class SearchKey>
- [[nodiscard]] iterator upper_bound(const SearchKey& key) const {
- return std::upper_bound(_storage.begin(), _storage.end(), key, comp{});
- }
-
-private:
- template <typename S>
- explicit set(S&& s) : _storage{std::forward<S>(s)} {}
-
- storage_type _storage;
-};
-
-} // namespace mongo::immutable
diff --git a/src/mongo/util/immutable/unordered_map.h b/src/mongo/util/immutable/unordered_map.h
deleted file mode 100644
index b024bd5b64a..00000000000
--- a/src/mongo/util/immutable/unordered_map.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <immer/map.hpp>
-#include <immer/map_transient.hpp>
-
-#include "mongo/stdx/trusted_hasher.h"
-#include "mongo/util/immutable/details/memory_policy.h"
-
-namespace mongo::immutable {
-
-/**
- * Immutable unordered hash table.
- *
- * Interfaces that "modify" the hash table are 'const' and returns a new version of the table with
- * the modifications applied and leaves the original version untouched.
- *
- * It is optimized for efficient copies and low memory usage when multiple versions of the table
- * exist simultaneously at the expense of regular lookups not being as efficient as the regular
- * stdx unordered containers. Suitable for use in code that uses the copy-on-write pattern.
- *
- * Thread-safety: All methods are const, it is safe to perform modifications that result in new
- * versions from multiple threads concurrently.
- *
- * Memory management: Internal memory management is done using reference counting, memory is free'd
- * as references to different versions of the table are released.
- *
- * Multiple modifications can be done efficiently using the 'transient()' interface.
- *
- * Documentation: 'immer/map.h' and https://sinusoid.es/immer/
- */
-template <class K,
- class V,
- class Hasher = DefaultHasher<K>,
- class Eq = absl::container_internal::hash_default_eq<K>>
-using unordered_map = immer::map<K, V, EnsureTrustedHasher<Hasher, K>, Eq, detail::MemoryPolicy>;
-} // namespace mongo::immutable
diff --git a/src/mongo/util/immutable/unordered_set.h b/src/mongo/util/immutable/unordered_set.h
deleted file mode 100644
index c5133218007..00000000000
--- a/src/mongo/util/immutable/unordered_set.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <immer/set.hpp>
-#include <immer/set_transient.hpp>
-
-#include "mongo/stdx/trusted_hasher.h"
-#include "mongo/util/immutable/details/memory_policy.h"
-
-namespace mongo::immutable {
-
-/**
- * Immutable unordered hash set.
- *
- * Interfaces that "modify" the hash set are 'const' and returns a new version of the set with
- * the modifications applied and leaves the original version untouched.
- *
- * It is optimized for efficient copies and low memory usage when multiple versions of the set
- * exist simultaneously at the expense of regular lookups not being as efficient as the regular
- * stdx unordered containers. Suitable for use in code that uses the copy-on-write
- * pattern.
- *
- * Thread-safety: All methods are const, it is safe to perform modifications that result in new
- * versions from multiple threads concurrently.
- *
- * Memory management: Internal memory management is done using reference counting, memory is free'd
- * as references to different versions of the set are released.
- *
- * Multiple modifications can be done efficiently using the 'transient()' interface.
- *
- * Documentation: 'immer/set.h' and https://sinusoid.es/immer/
- */
-template <class T,
- class Hasher = DefaultHasher<T>,
- class Eq = absl::container_internal::hash_default_eq<T>>
-using unordered_set = immer::set<T, EnsureTrustedHasher<Hasher, T>, Eq, detail::MemoryPolicy>;
-} // namespace mongo::immutable
diff --git a/src/mongo/util/immutable/vector.h b/src/mongo/util/immutable/vector.h
deleted file mode 100644
index b9cc205575d..00000000000
--- a/src/mongo/util/immutable/vector.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <immer/vector.hpp>
-#include <immer/vector_transient.hpp>
-
-#include "mongo/util/immutable/details/memory_policy.h"
-
-namespace mongo::immutable {
-
-/**
- * Immutable vector.
- *
- * Interfaces that "modify" the vector are 'const' and return a new version of the vector with
- * the modifications applied and leave the original version untouched.
- *
- * It is optimized for efficient copies and low memory usage when multiple versions of the vector
- * exist simultaneously at the expense of regular lookups not being as efficient as the regular
- * std::vector implementation. Suitable for use in code that uses the copy-on-write pattern.
- *
- * Thread-safety: All methods are const, it is safe to perform modifications that result in new
- * versions from multiple threads concurrently.
- *
- * Memory management: Internal memory management is done using reference counting, memory is free'd
- * as references to different versions of the vector are released.
- *
- * Multiple modifications can be done efficiently using the 'transient()' interface.
- *
- * Documentation: 'immer/vector.h' and https://sinusoid.es/immer/
- */
-template <class T>
-using vector = immer::vector<T, detail::MemoryPolicy>;
-} // namespace mongo::immutable