mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make ctl::set use 30% less memory than libcxx
This commit is contained in:
parent
6dbc3fba18
commit
135d538b1d
3 changed files with 225 additions and 112 deletions
244
ctl/set.h
244
ctl/set.h
|
@ -13,18 +13,34 @@ class set
|
||||||
{
|
{
|
||||||
struct rbtree
|
struct rbtree
|
||||||
{
|
{
|
||||||
rbtree* left;
|
uintptr_t left_;
|
||||||
rbtree* right;
|
rbtree* right;
|
||||||
rbtree* parent;
|
rbtree* parent;
|
||||||
bool is_red;
|
|
||||||
Key value;
|
Key value;
|
||||||
|
|
||||||
|
rbtree* left() const
|
||||||
|
{
|
||||||
|
return (rbtree*)(left_ & -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void left(rbtree* val)
|
||||||
|
{
|
||||||
|
left_ = (uintptr_t)val | (left_ & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_red() const
|
||||||
|
{
|
||||||
|
return left_ & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void is_red(bool val)
|
||||||
|
{
|
||||||
|
left_ &= -2;
|
||||||
|
left_ |= val;
|
||||||
|
}
|
||||||
|
|
||||||
rbtree(const Key& val)
|
rbtree(const Key& val)
|
||||||
: left(nullptr)
|
: left_(1), right(nullptr), parent(nullptr), value(val)
|
||||||
, right(nullptr)
|
|
||||||
, parent(nullptr)
|
|
||||||
, is_red(true)
|
|
||||||
, value(val)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -85,14 +101,14 @@ class set
|
||||||
{
|
{
|
||||||
if (node_ == nullptr)
|
if (node_ == nullptr)
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
if (node_->left) {
|
if (node_->left()) {
|
||||||
node_ = rightmost(node_->left);
|
node_ = rightmost(node_->left());
|
||||||
} else {
|
} else {
|
||||||
node_type* parent = node_->parent;
|
node_type* parent = node_->parent;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (parent == nullptr)
|
if (parent == nullptr)
|
||||||
break;
|
break;
|
||||||
if (node_ == parent->left) {
|
if (node_ == parent->left()) {
|
||||||
node_ = parent;
|
node_ = parent;
|
||||||
parent = parent->parent;
|
parent = parent->parent;
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,11 +177,11 @@ class set
|
||||||
|
|
||||||
reverse_iterator& operator++()
|
reverse_iterator& operator++()
|
||||||
{
|
{
|
||||||
if (node_->left) {
|
if (node_->left()) {
|
||||||
node_ = rightmost(node_->left);
|
node_ = rightmost(node_->left());
|
||||||
} else {
|
} else {
|
||||||
node_type* parent = node_->parent;
|
node_type* parent = node_->parent;
|
||||||
while (parent && node_ == parent->left) {
|
while (parent && node_ == parent->left()) {
|
||||||
node_ = parent;
|
node_ = parent;
|
||||||
parent = parent->parent;
|
parent = parent->parent;
|
||||||
}
|
}
|
||||||
|
@ -508,7 +524,7 @@ class set
|
||||||
{
|
{
|
||||||
size_type count = 0;
|
size_type count = 0;
|
||||||
if (root_ != nullptr) {
|
if (root_ != nullptr) {
|
||||||
if (root_->is_red)
|
if (root_->is_red())
|
||||||
// ILLEGAL TREE: root node must be black
|
// ILLEGAL TREE: root node must be black
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
int black_height = -1;
|
int black_height = -1;
|
||||||
|
@ -523,8 +539,8 @@ class set
|
||||||
private:
|
private:
|
||||||
static node_type* leftmost(node_type* node) noexcept
|
static node_type* leftmost(node_type* node) noexcept
|
||||||
{
|
{
|
||||||
while (node && node->left)
|
while (node && node->left())
|
||||||
node = node->left;
|
node = node->left();
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,35 +551,35 @@ class set
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearer(node_type* node) noexcept
|
static optimizesize void clearer(node_type* node) noexcept
|
||||||
{
|
{
|
||||||
node_type* right;
|
node_type* right;
|
||||||
for (; node; node = right) {
|
for (; node; node = right) {
|
||||||
right = node->right;
|
right = node->right;
|
||||||
clearer(node->left);
|
clearer(node->left());
|
||||||
delete node;
|
delete node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static node_type* copier(const node_type* node)
|
static optimizesize node_type* copier(const node_type* node)
|
||||||
{
|
{
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
node_type* new_node = new node_type(node->value);
|
node_type* new_node = new node_type(node->value);
|
||||||
new_node->left = copier(node->left);
|
new_node->left(copier(node->left()));
|
||||||
new_node->right = copier(node->right);
|
new_node->right = copier(node->right);
|
||||||
if (new_node->left)
|
if (new_node->left())
|
||||||
new_node->left->parent = new_node;
|
new_node->left()->parent = new_node;
|
||||||
if (new_node->right)
|
if (new_node->right)
|
||||||
new_node->right->parent = new_node;
|
new_node->right->parent = new_node;
|
||||||
return new_node;
|
return new_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_type tally(const node_type* node)
|
static optimizesize size_type tally(const node_type* node)
|
||||||
{
|
{
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
return 1 + tally(node->left) + tally(node->right);
|
return 1 + tally(node->left()) + tally(node->right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K>
|
template<typename K>
|
||||||
|
@ -572,7 +588,7 @@ class set
|
||||||
node_type* current = root_;
|
node_type* current = root_;
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
if (comp_(key, current->value)) {
|
if (comp_(key, current->value)) {
|
||||||
current = current->left;
|
current = current->left();
|
||||||
} else if (comp_(current->value, key)) {
|
} else if (comp_(current->value, key)) {
|
||||||
current = current->right;
|
current = current->right;
|
||||||
} else {
|
} else {
|
||||||
|
@ -590,7 +606,7 @@ class set
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
if (!comp_(current->value, key)) {
|
if (!comp_(current->value, key)) {
|
||||||
result = current;
|
result = current;
|
||||||
current = current->left;
|
current = current->left();
|
||||||
} else {
|
} else {
|
||||||
current = current->right;
|
current = current->right;
|
||||||
}
|
}
|
||||||
|
@ -606,7 +622,7 @@ class set
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
if (comp_(key, current->value)) {
|
if (comp_(key, current->value)) {
|
||||||
result = current;
|
result = current;
|
||||||
current = current->left;
|
current = current->left();
|
||||||
} else {
|
} else {
|
||||||
current = current->right;
|
current = current->right;
|
||||||
}
|
}
|
||||||
|
@ -614,11 +630,11 @@ class set
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl::pair<iterator, bool> insert_node(node_type* node)
|
optimizesize ctl::pair<iterator, bool> insert_node(node_type* node)
|
||||||
{
|
{
|
||||||
if (root_ == nullptr) {
|
if (root_ == nullptr) {
|
||||||
root_ = node;
|
root_ = node;
|
||||||
root_->is_red = false;
|
root_->is_red(false);
|
||||||
size_++;
|
size_++;
|
||||||
return { iterator(root_), true };
|
return { iterator(root_), true };
|
||||||
}
|
}
|
||||||
|
@ -627,7 +643,7 @@ class set
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
parent = current;
|
parent = current;
|
||||||
if (comp_(node->value, current->value)) {
|
if (comp_(node->value, current->value)) {
|
||||||
current = current->left;
|
current = current->left();
|
||||||
} else if (comp_(current->value, node->value)) {
|
} else if (comp_(current->value, node->value)) {
|
||||||
current = current->right;
|
current = current->right;
|
||||||
} else {
|
} else {
|
||||||
|
@ -636,7 +652,7 @@ class set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (comp_(node->value, parent->value)) {
|
if (comp_(node->value, parent->value)) {
|
||||||
parent->left = node;
|
parent->left(node);
|
||||||
} else {
|
} else {
|
||||||
parent->right = node;
|
parent->right = node;
|
||||||
}
|
}
|
||||||
|
@ -646,23 +662,23 @@ class set
|
||||||
return { iterator(node), true };
|
return { iterator(node), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase_node(node_type* node)
|
optimizesize void erase_node(node_type* node)
|
||||||
{
|
{
|
||||||
node_type* y = node;
|
node_type* y = node;
|
||||||
node_type* x = nullptr;
|
node_type* x = nullptr;
|
||||||
node_type* x_parent = nullptr;
|
node_type* x_parent = nullptr;
|
||||||
bool y_original_color = y->is_red;
|
bool y_original_color = y->is_red();
|
||||||
if (node->left == nullptr) {
|
if (node->left() == nullptr) {
|
||||||
x = node->right;
|
x = node->right;
|
||||||
transplant(node, node->right);
|
transplant(node, node->right);
|
||||||
x_parent = node->parent;
|
x_parent = node->parent;
|
||||||
} else if (node->right == nullptr) {
|
} else if (node->right == nullptr) {
|
||||||
x = node->left;
|
x = node->left();
|
||||||
transplant(node, node->left);
|
transplant(node, node->left());
|
||||||
x_parent = node->parent;
|
x_parent = node->parent;
|
||||||
} else {
|
} else {
|
||||||
y = leftmost(node->right);
|
y = leftmost(node->right);
|
||||||
y_original_color = y->is_red;
|
y_original_color = y->is_red();
|
||||||
x = y->right;
|
x = y->right;
|
||||||
if (y->parent == node) {
|
if (y->parent == node) {
|
||||||
if (x)
|
if (x)
|
||||||
|
@ -675,9 +691,9 @@ class set
|
||||||
x_parent = y->parent;
|
x_parent = y->parent;
|
||||||
}
|
}
|
||||||
transplant(node, y);
|
transplant(node, y);
|
||||||
y->left = node->left;
|
y->left(node->left());
|
||||||
y->left->parent = y;
|
y->left()->parent = y;
|
||||||
y->is_red = node->is_red;
|
y->is_red(node->is_red());
|
||||||
}
|
}
|
||||||
if (!y_original_color)
|
if (!y_original_color)
|
||||||
rebalance_after_erase(x, x_parent);
|
rebalance_after_erase(x, x_parent);
|
||||||
|
@ -685,28 +701,28 @@ class set
|
||||||
--size_;
|
--size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void left_rotate(node_type* x)
|
optimizesize void left_rotate(node_type* x)
|
||||||
{
|
{
|
||||||
node_type* y = x->right;
|
node_type* y = x->right;
|
||||||
x->right = y->left;
|
x->right = y->left();
|
||||||
if (y->left != nullptr)
|
if (y->left() != nullptr)
|
||||||
y->left->parent = x;
|
y->left()->parent = x;
|
||||||
y->parent = x->parent;
|
y->parent = x->parent;
|
||||||
if (x->parent == nullptr) {
|
if (x->parent == nullptr) {
|
||||||
root_ = y;
|
root_ = y;
|
||||||
} else if (x == x->parent->left) {
|
} else if (x == x->parent->left()) {
|
||||||
x->parent->left = y;
|
x->parent->left(y);
|
||||||
} else {
|
} else {
|
||||||
x->parent->right = y;
|
x->parent->right = y;
|
||||||
}
|
}
|
||||||
y->left = x;
|
y->left(x);
|
||||||
x->parent = y;
|
x->parent = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void right_rotate(node_type* y)
|
optimizesize void right_rotate(node_type* y)
|
||||||
{
|
{
|
||||||
node_type* x = y->left;
|
node_type* x = y->left();
|
||||||
y->left = x->right;
|
y->left(x->right);
|
||||||
if (x->right != nullptr)
|
if (x->right != nullptr)
|
||||||
x->right->parent = y;
|
x->right->parent = y;
|
||||||
x->parent = y->parent;
|
x->parent = y->parent;
|
||||||
|
@ -715,18 +731,18 @@ class set
|
||||||
} else if (y == y->parent->right) {
|
} else if (y == y->parent->right) {
|
||||||
y->parent->right = x;
|
y->parent->right = x;
|
||||||
} else {
|
} else {
|
||||||
y->parent->left = x;
|
y->parent->left(x);
|
||||||
}
|
}
|
||||||
x->right = y;
|
x->right = y;
|
||||||
y->parent = x;
|
y->parent = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transplant(node_type* u, node_type* v)
|
optimizesize void transplant(node_type* u, node_type* v)
|
||||||
{
|
{
|
||||||
if (u->parent == nullptr) {
|
if (u->parent == nullptr) {
|
||||||
root_ = v;
|
root_ = v;
|
||||||
} else if (u == u->parent->left) {
|
} else if (u == u->parent->left()) {
|
||||||
u->parent->left = v;
|
u->parent->left(v);
|
||||||
} else {
|
} else {
|
||||||
u->parent->right = v;
|
u->parent->right = v;
|
||||||
}
|
}
|
||||||
|
@ -734,10 +750,10 @@ class set
|
||||||
v->parent = u->parent;
|
v->parent = u->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void checker(const node_type* node,
|
optimizesize void checker(const node_type* node,
|
||||||
const node_type* parent,
|
const node_type* parent,
|
||||||
int black_count,
|
int black_count,
|
||||||
int& black_height) const
|
int& black_height) const
|
||||||
{
|
{
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
// Leaf nodes are considered black
|
// Leaf nodes are considered black
|
||||||
|
@ -753,117 +769,121 @@ class set
|
||||||
// ILLEGAL TREE: Parent link is incorrect
|
// ILLEGAL TREE: Parent link is incorrect
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (parent->left == node && !comp_(node->value, parent->value))
|
if (parent->left() == node && !comp_(node->value, parent->value))
|
||||||
// ILLEGAL TREE: Binary search property violated on left child
|
// ILLEGAL TREE: Binary search property violated on left child
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
if (parent->right == node && !comp_(parent->value, node->value))
|
if (parent->right == node && !comp_(parent->value, node->value))
|
||||||
// ILLEGAL TREE: Binary search property violated on right child
|
// ILLEGAL TREE: Binary search property violated on right child
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
if (!node->is_red) {
|
if (!node->is_red()) {
|
||||||
black_count++;
|
black_count++;
|
||||||
} else if (parent != nullptr && parent->is_red) {
|
} else if (parent != nullptr && parent->is_red()) {
|
||||||
// ILLEGAL TREE: Red node has red child
|
// ILLEGAL TREE: Red node has red child
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
checker(node->left, node, black_count, black_height);
|
checker(node->left(), node, black_count, black_height);
|
||||||
checker(node->right, node, black_count, black_height);
|
checker(node->right, node, black_count, black_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebalance_after_insert(node_type* node)
|
optimizesize void rebalance_after_insert(node_type* node)
|
||||||
{
|
{
|
||||||
node->is_red = true;
|
node->is_red(true);
|
||||||
while (node != root_ && node->parent->is_red) {
|
while (node != root_ && node->parent->is_red()) {
|
||||||
if (node->parent == node->parent->parent->left) {
|
if (node->parent == node->parent->parent->left()) {
|
||||||
node_type* uncle = node->parent->parent->right;
|
node_type* uncle = node->parent->parent->right;
|
||||||
if (uncle && uncle->is_red) {
|
if (uncle && uncle->is_red()) {
|
||||||
node->parent->is_red = false;
|
node->parent->is_red(false);
|
||||||
uncle->is_red = false;
|
uncle->is_red(false);
|
||||||
node->parent->parent->is_red = true;
|
node->parent->parent->is_red(true);
|
||||||
node = node->parent->parent;
|
node = node->parent->parent;
|
||||||
} else {
|
} else {
|
||||||
if (node == node->parent->right) {
|
if (node == node->parent->right) {
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
left_rotate(node);
|
left_rotate(node);
|
||||||
}
|
}
|
||||||
node->parent->is_red = false;
|
node->parent->is_red(false);
|
||||||
node->parent->parent->is_red = true;
|
node->parent->parent->is_red(true);
|
||||||
right_rotate(node->parent->parent);
|
right_rotate(node->parent->parent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node_type* uncle = node->parent->parent->left;
|
node_type* uncle = node->parent->parent->left();
|
||||||
if (uncle && uncle->is_red) {
|
if (uncle && uncle->is_red()) {
|
||||||
node->parent->is_red = false;
|
node->parent->is_red(false);
|
||||||
uncle->is_red = false;
|
uncle->is_red(false);
|
||||||
node->parent->parent->is_red = true;
|
node->parent->parent->is_red(true);
|
||||||
node = node->parent->parent;
|
node = node->parent->parent;
|
||||||
} else {
|
} else {
|
||||||
if (node == node->parent->left) {
|
if (node == node->parent->left()) {
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
right_rotate(node);
|
right_rotate(node);
|
||||||
}
|
}
|
||||||
node->parent->is_red = false;
|
node->parent->is_red(false);
|
||||||
node->parent->parent->is_red = true;
|
node->parent->parent->is_red(true);
|
||||||
left_rotate(node->parent->parent);
|
left_rotate(node->parent->parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root_->is_red = false;
|
root_->is_red(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebalance_after_erase(node_type* node, node_type* parent)
|
optimizesize void rebalance_after_erase(node_type* node, node_type* parent)
|
||||||
{
|
{
|
||||||
while (node != root_ && (node == nullptr || !node->is_red)) {
|
while (node != root_ && (node == nullptr || !node->is_red())) {
|
||||||
if (node == parent->left) {
|
if (node == parent->left()) {
|
||||||
node_type* sibling = parent->right;
|
node_type* sibling = parent->right;
|
||||||
if (sibling->is_red) {
|
if (sibling->is_red()) {
|
||||||
sibling->is_red = false;
|
sibling->is_red(false);
|
||||||
parent->is_red = true;
|
parent->is_red(true);
|
||||||
left_rotate(parent);
|
left_rotate(parent);
|
||||||
sibling = parent->right;
|
sibling = parent->right;
|
||||||
}
|
}
|
||||||
if ((sibling->left == nullptr || !sibling->left->is_red) &&
|
if ((sibling->left() == nullptr ||
|
||||||
(sibling->right == nullptr || !sibling->right->is_red)) {
|
!sibling->left()->is_red()) &&
|
||||||
sibling->is_red = true;
|
(sibling->right == nullptr || !sibling->right->is_red())) {
|
||||||
|
sibling->is_red(true);
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = node->parent;
|
parent = node->parent;
|
||||||
} else {
|
} else {
|
||||||
if (sibling->right == nullptr || !sibling->right->is_red) {
|
if (sibling->right == nullptr ||
|
||||||
sibling->left->is_red = false;
|
!sibling->right->is_red()) {
|
||||||
sibling->is_red = true;
|
sibling->left()->is_red(false);
|
||||||
|
sibling->is_red(true);
|
||||||
right_rotate(sibling);
|
right_rotate(sibling);
|
||||||
sibling = parent->right;
|
sibling = parent->right;
|
||||||
}
|
}
|
||||||
sibling->is_red = parent->is_red;
|
sibling->is_red(parent->is_red());
|
||||||
parent->is_red = false;
|
parent->is_red(false);
|
||||||
sibling->right->is_red = false;
|
sibling->right->is_red(false);
|
||||||
left_rotate(parent);
|
left_rotate(parent);
|
||||||
node = root_;
|
node = root_;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node_type* sibling = parent->left;
|
node_type* sibling = parent->left();
|
||||||
if (sibling->is_red) {
|
if (sibling->is_red()) {
|
||||||
sibling->is_red = false;
|
sibling->is_red(false);
|
||||||
parent->is_red = true;
|
parent->is_red(true);
|
||||||
right_rotate(parent);
|
right_rotate(parent);
|
||||||
sibling = parent->left;
|
sibling = parent->left();
|
||||||
}
|
}
|
||||||
if ((sibling->right == nullptr || !sibling->right->is_red) &&
|
if ((sibling->right == nullptr || !sibling->right->is_red()) &&
|
||||||
(sibling->left == nullptr || !sibling->left->is_red)) {
|
(sibling->left() == nullptr ||
|
||||||
sibling->is_red = true;
|
!sibling->left()->is_red())) {
|
||||||
|
sibling->is_red(true);
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = node->parent;
|
parent = node->parent;
|
||||||
} else {
|
} else {
|
||||||
if (sibling->left == nullptr || !sibling->left->is_red) {
|
if (sibling->left() == nullptr ||
|
||||||
sibling->right->is_red = false;
|
!sibling->left()->is_red()) {
|
||||||
sibling->is_red = true;
|
sibling->right->is_red(false);
|
||||||
|
sibling->is_red(true);
|
||||||
left_rotate(sibling);
|
left_rotate(sibling);
|
||||||
sibling = parent->left;
|
sibling = parent->left();
|
||||||
}
|
}
|
||||||
sibling->is_red = parent->is_red;
|
sibling->is_red(parent->is_red());
|
||||||
parent->is_red = false;
|
parent->is_red(false);
|
||||||
sibling->left->is_red = false;
|
sibling->left()->is_red(false);
|
||||||
right_rotate(parent);
|
right_rotate(parent);
|
||||||
node = root_;
|
node = root_;
|
||||||
break;
|
break;
|
||||||
|
@ -871,7 +891,7 @@ class set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node != nullptr)
|
if (node != nullptr)
|
||||||
node->is_red = false;
|
node->is_red(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
node_type* root_;
|
node_type* root_;
|
||||||
|
|
|
@ -18,6 +18,7 @@ TEST_CTL_DIRECTDEPS = \
|
||||||
LIBC_LOG \
|
LIBC_LOG \
|
||||||
LIBC_MEM \
|
LIBC_MEM \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_PROC \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
LIBC_THREAD \
|
LIBC_THREAD \
|
||||||
|
|
92
test/ctl/set_bench.cc
Normal file
92
test/ctl/set_bench.cc
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
|
||||||
|
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||||
|
//
|
||||||
|
// Copyright 2024 Justine Alexandra Roberts Tunney
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
// any purpose with or without fee is hereby granted, provided that the
|
||||||
|
// above copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#include "ctl/set.h"
|
||||||
|
#include "libc/calls/struct/rusage.h"
|
||||||
|
#include "libc/calls/struct/timespec.h"
|
||||||
|
#include "libc/mem/leaks.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/rusage.h"
|
||||||
|
|
||||||
|
// #include <set>
|
||||||
|
// #define ctl std
|
||||||
|
// #define check() size()
|
||||||
|
|
||||||
|
#define BENCH(ITERATIONS, WORK_PER_RUN, CODE) \
|
||||||
|
do { \
|
||||||
|
struct timespec start = timespec_real(); \
|
||||||
|
for (int __i = 0; __i < ITERATIONS; ++__i) { \
|
||||||
|
asm volatile("" ::: "memory"); \
|
||||||
|
CODE; \
|
||||||
|
} \
|
||||||
|
long long work = (WORK_PER_RUN) * (ITERATIONS); \
|
||||||
|
double nanos = \
|
||||||
|
(timespec_tonanos(timespec_sub(timespec_real(), start)) + work - \
|
||||||
|
1) / \
|
||||||
|
(double)work; \
|
||||||
|
printf("%10g ns %2dx %s\n", nanos, (ITERATIONS), #CODE); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int
|
||||||
|
rand32(void)
|
||||||
|
{
|
||||||
|
/* Knuth, D.E., "The Art of Computer Programming," Vol 2,
|
||||||
|
Seminumerical Algorithms, Third Edition, Addison-Wesley, 1998,
|
||||||
|
p. 106 (line 26) & p. 108 */
|
||||||
|
static unsigned long long lcg = 1;
|
||||||
|
lcg *= 6364136223846793005;
|
||||||
|
lcg += 1442695040888963407;
|
||||||
|
return lcg >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eat(int x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*pEat)(int) = eat;
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
|
||||||
|
{
|
||||||
|
long x = 0;
|
||||||
|
ctl::set<long> s;
|
||||||
|
BENCH(1000000, 1, s.insert(rand32() % 1000000));
|
||||||
|
// s.check();
|
||||||
|
BENCH(1000000, 1, {
|
||||||
|
auto i = s.find(rand32() % 1000000);
|
||||||
|
if (i != s.end())
|
||||||
|
x += *i;
|
||||||
|
});
|
||||||
|
BENCH(1000000, 1, {
|
||||||
|
auto i = s.lower_bound(rand32() % 1000000);
|
||||||
|
if (i != s.end())
|
||||||
|
x += *i;
|
||||||
|
});
|
||||||
|
BENCH(1000000, 1, s.erase(rand32() % 1000000));
|
||||||
|
eat(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rusage ru;
|
||||||
|
getrusage(RUSAGE_SELF, &ru);
|
||||||
|
printf("%,10d kb peak rss\n", ru.ru_maxrss);
|
||||||
|
|
||||||
|
CheckForMemoryLeaks();
|
||||||
|
}
|
Loading…
Reference in a new issue