[libc-commits] [libc] [libc] Add erase function to blockstore (PR #97641)
via libc-commits
libc-commits at lists.llvm.org
Wed Jul 3 14:28:30 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Michael Jones (michaelrj-google)
<details>
<summary>Changes</summary>
This adds the ability to erase a value from a blockstore based on an
iterator. For usability/testing purposes it also includes an addition
operator for blockstore's iterator.
---
Full diff: https://github.com/llvm/llvm-project/pull/97641.diff
2 Files Affected:
- (modified) libc/src/__support/blockstore.h (+53-2)
- (modified) libc/test/src/__support/blockstore_test.cpp (+98)
``````````diff
diff --git a/libc/src/__support/blockstore.h b/libc/src/__support/blockstore.h
index bcab7504dbd6e..e022a6ae22b0d 100644
--- a/libc/src/__support/blockstore.h
+++ b/libc/src/__support/blockstore.h
@@ -9,8 +9,10 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_BLOCKSTORE_H
#define LLVM_LIBC_SRC___SUPPORT_BLOCKSTORE_H
-#include <src/__support/CPP/new.h>
-#include <src/__support/libc_assert.h>
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/libc_assert.h"
#include <stddef.h>
#include <stdint.h>
@@ -97,6 +99,16 @@ class BlockStore {
return *reinterpret_cast<T *>(block->data + sizeof(T) * true_index);
}
+ LIBC_INLINE Iterator operator+(int i) {
+ LIBC_ASSERT(i >= 0 &&
+ "BlockStore iterators only support incrementation.");
+ auto other = *this;
+ for (int j = 0; j < i; ++j)
+ ++other;
+
+ return other;
+ }
+
LIBC_INLINE bool operator==(const Iterator &rhs) const {
return block == rhs.block && index == rhs.index;
}
@@ -175,6 +187,45 @@ class BlockStore {
else
return Iterator(current, fill_count);
}
+
+ // Removes and the element at pos, then moves all the objects after back by
+ // one to fill the hole. It's assumed that pos is a valid iterator to
+ // somewhere in this block_store.
+ LIBC_INLINE void erase(Iterator pos) {
+ const Iterator last_item = Iterator(current, fill_count);
+ if (pos == last_item) {
+ pop_back();
+ return;
+ }
+
+ if constexpr (REVERSE_ORDER) {
+ // REVERSE: Iterate from begin to pos
+ const Iterator range_end = pos;
+ Iterator cur = begin();
+ T prev_val = *cur;
+ ++cur;
+ T cur_val = *cur;
+
+ for (; cur != range_end; ++cur) {
+ cur_val = *cur;
+ *cur = prev_val;
+ prev_val = cur_val;
+ }
+ // We will always need to move at least one item (since we know that pos
+ // isn't the last item due to the check above).
+ *cur = prev_val;
+ } else {
+ // FORWARD: Iterate from pos to end
+ const Iterator range_end = end();
+ Iterator cur = pos;
+ Iterator prev = cur;
+ ++cur;
+
+ for (; cur != range_end; prev = cur, ++cur)
+ *prev = *cur;
+ }
+ pop_back();
+ }
};
template <typename T, size_t BLOCK_SIZE, bool REVERSE_ORDER>
diff --git a/libc/test/src/__support/blockstore_test.cpp b/libc/test/src/__support/blockstore_test.cpp
index 5fe8fef1b6edc..dd74ea18f2c02 100644
--- a/libc/test/src/__support/blockstore_test.cpp
+++ b/libc/test/src/__support/blockstore_test.cpp
@@ -64,6 +64,99 @@ class LlvmLibcBlockStoreTest : public LIBC_NAMESPACE::testing::Test {
}
block_store.destroy(&block_store);
}
+
+ template <bool REVERSE> void erase_test() {
+ using LIBC_NAMESPACE::BlockStore;
+ BlockStore<int, 2, REVERSE> block_store;
+ int i;
+
+ constexpr int ARR_SIZE = 6;
+
+ ASSERT_TRUE(block_store.empty());
+ for (int i = 0; i < ARR_SIZE; i++) {
+ ASSERT_TRUE(block_store.push_back(i + 1));
+ }
+
+ // block_store state should be {1,2,3,4,5,6}
+
+ block_store.erase(block_store.begin());
+
+ // FORWARD: block_store state should be {2,3,4,5,6}
+ // REVERSE: block_store state should be {1,2,3,4,5}
+
+ auto iter = block_store.begin();
+ for (i = 0; iter != block_store.end(); ++i, ++iter) {
+ if (!REVERSE) {
+ ASSERT_EQ(*iter, i + 2);
+ } else {
+ ASSERT_EQ(*iter, (ARR_SIZE - 1) - i);
+ }
+ }
+
+ // Assert that there were the correct number of elements
+ ASSERT_EQ(i, ARR_SIZE - 1);
+
+ block_store.erase(block_store.end());
+
+ // BOTH: block_store state should be {2,3,4,5}
+
+ iter = block_store.begin();
+ for (i = 0; iter != block_store.end(); ++i, ++iter) {
+ if (!REVERSE) {
+ ASSERT_EQ(*iter, i + 2);
+ } else {
+ ASSERT_EQ(*iter, (ARR_SIZE - 1) - i);
+ }
+ }
+
+ ASSERT_EQ(i, ARR_SIZE - 2);
+
+ block_store.erase(block_store.begin() + 1);
+
+ // FORWARD: block_store state should be {2,4,5}
+ // REVERSE: block_store state should be {2,3,5}
+
+ const int FORWARD_RESULTS[] = {2, 4, 5};
+ const int REVERSE_RESULTS[] = {2, 3, 5};
+
+ iter = block_store.begin();
+ for (i = 0; iter != block_store.end(); ++i, ++iter) {
+ if (!REVERSE) {
+ ASSERT_EQ(*iter, FORWARD_RESULTS[i]);
+ } else {
+ ASSERT_EQ(*iter, REVERSE_RESULTS[ARR_SIZE - 4 - i]); // reversed
+ }
+ }
+
+ ASSERT_EQ(i, ARR_SIZE - 3);
+
+ block_store.erase(block_store.begin() + 1);
+ // BOTH: block_store state should be {2,5}
+
+ iter = block_store.begin();
+ if (!REVERSE) {
+ ASSERT_EQ(*iter, 2);
+ ASSERT_EQ(*(iter + 1), 5);
+ } else {
+ ASSERT_EQ(*iter, 5);
+ ASSERT_EQ(*(iter + 1), 2);
+ }
+
+ block_store.erase(block_store.begin());
+ // FORWARD: block_store state should be {5}
+ // REVERSE: block_store state should be {2}
+ iter = block_store.begin();
+ if (!REVERSE) {
+ ASSERT_EQ(*iter, 5);
+ } else {
+ ASSERT_EQ(*iter, 2);
+ }
+
+ block_store.erase(block_store.begin());
+ // BOTH: block_store state should be {}
+
+ block_store.destroy(&block_store);
+ }
};
TEST_F(LlvmLibcBlockStoreTest, PopulateAndIterate4) {
@@ -100,3 +193,8 @@ TEST_F(LlvmLibcBlockStoreTest, Empty) {
empty_test<false>();
empty_test<true>();
}
+
+TEST_F(LlvmLibcBlockStoreTest, Erase) {
+ erase_test<false>();
+ erase_test<true>();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/97641
More information about the libc-commits
mailing list