mirror of
https://github.com/bkthomps/Containers.git
synced 2025-11-16 12:34:47 +00:00
Reduce calls to malloc in map (#101)
Reduce the number of malloc calls in map. Improves efficiency by 40%.
This commit is contained in:
@@ -75,12 +75,11 @@ unordered_map unordered_map_destroy(unordered_map me);
|
|||||||
typedef struct internal_map *map;
|
typedef struct internal_map *map;
|
||||||
|
|
||||||
/* Starting */
|
/* Starting */
|
||||||
map map_init(size_t key_size,
|
map map_init(size_t key_size, size_t value_size,
|
||||||
size_t value_size,
|
|
||||||
int (*comparator)(const void *const one, const void *const two));
|
int (*comparator)(const void *const one, const void *const two));
|
||||||
|
|
||||||
/* Capacity */
|
/* Capacity */
|
||||||
int map_size(map me);
|
size_t map_size(map me);
|
||||||
int map_is_empty(map me);
|
int map_is_empty(map me);
|
||||||
|
|
||||||
/* Accessing */
|
/* Accessing */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2019 Bailey Thompson
|
* Copyright (c) 2017-2020 Bailey Thompson
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -32,12 +32,11 @@
|
|||||||
typedef struct internal_map *map;
|
typedef struct internal_map *map;
|
||||||
|
|
||||||
/* Starting */
|
/* Starting */
|
||||||
map map_init(size_t key_size,
|
map map_init(size_t key_size, size_t value_size,
|
||||||
size_t value_size,
|
|
||||||
int (*comparator)(const void *const one, const void *const two));
|
int (*comparator)(const void *const one, const void *const two));
|
||||||
|
|
||||||
/* Capacity */
|
/* Capacity */
|
||||||
int map_size(map me);
|
size_t map_size(map me);
|
||||||
int map_is_empty(map me);
|
int map_is_empty(map me);
|
||||||
|
|
||||||
/* Accessing */
|
/* Accessing */
|
||||||
|
|||||||
522
src/map.c
522
src/map.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2019 Bailey Thompson
|
* Copyright (c) 2017-2020 Bailey Thompson
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -25,21 +25,20 @@
|
|||||||
#include "include/map.h"
|
#include "include/map.h"
|
||||||
|
|
||||||
struct internal_map {
|
struct internal_map {
|
||||||
|
size_t size;
|
||||||
size_t key_size;
|
size_t key_size;
|
||||||
size_t value_size;
|
size_t value_size;
|
||||||
int (*comparator)(const void *const one, const void *const two);
|
int (*comparator)(const void *const one, const void *const two);
|
||||||
int size;
|
char *root;
|
||||||
struct node *root;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct node {
|
static const size_t ptr_size = sizeof(char *);
|
||||||
struct node *parent;
|
/* Node balance is always the first byte (at index 0). */
|
||||||
int balance;
|
static const size_t node_parent_offset = sizeof(signed char);
|
||||||
void *key;
|
static const size_t node_left_child_offset = 1 + sizeof(char *);
|
||||||
void *value;
|
static const size_t node_right_child_offset = 1 + 2 * sizeof(char *);
|
||||||
struct node *left;
|
static const size_t node_key_offset = 1 + 3 * sizeof(char *);
|
||||||
struct node *right;
|
/* Assume the value starts right after the key ends. */
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a map.
|
* Initializes a map.
|
||||||
@@ -53,8 +52,7 @@ struct node {
|
|||||||
* initialized due to either invalid input arguments or memory
|
* initialized due to either invalid input arguments or memory
|
||||||
* allocation error
|
* allocation error
|
||||||
*/
|
*/
|
||||||
map map_init(const size_t key_size,
|
map map_init(const size_t key_size, const size_t value_size,
|
||||||
const size_t value_size,
|
|
||||||
int (*const comparator)(const void *const, const void *const))
|
int (*const comparator)(const void *const, const void *const))
|
||||||
{
|
{
|
||||||
struct internal_map *init;
|
struct internal_map *init;
|
||||||
@@ -65,10 +63,10 @@ map map_init(const size_t key_size,
|
|||||||
if (!init) {
|
if (!init) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
init->size = 0;
|
||||||
init->key_size = key_size;
|
init->key_size = key_size;
|
||||||
init->value_size = value_size;
|
init->value_size = value_size;
|
||||||
init->comparator = comparator;
|
init->comparator = comparator;
|
||||||
init->size = 0;
|
|
||||||
init->root = NULL;
|
init->root = NULL;
|
||||||
return init;
|
return init;
|
||||||
}
|
}
|
||||||
@@ -80,7 +78,7 @@ map map_init(const size_t key_size,
|
|||||||
*
|
*
|
||||||
* @return the size of the map
|
* @return the size of the map
|
||||||
*/
|
*/
|
||||||
int map_size(map me)
|
size_t map_size(map me)
|
||||||
{
|
{
|
||||||
return me->size;
|
return me->size;
|
||||||
}
|
}
|
||||||
@@ -100,70 +98,69 @@ int map_is_empty(map me)
|
|||||||
/*
|
/*
|
||||||
* Resets the parent reference.
|
* Resets the parent reference.
|
||||||
*/
|
*/
|
||||||
static void map_reference_parent(map me,
|
static void map_reference_parent(map me, char *const parent, char *const child)
|
||||||
struct node *const parent,
|
|
||||||
struct node *const child)
|
|
||||||
{
|
{
|
||||||
child->parent = parent->parent;
|
char *grand_parent;
|
||||||
if (!parent->parent) {
|
char *grand_parent_left_child;
|
||||||
|
memcpy(child + node_parent_offset, parent + node_parent_offset, ptr_size);
|
||||||
|
memcpy(&grand_parent, parent + node_parent_offset, ptr_size);
|
||||||
|
if (!grand_parent) {
|
||||||
me->root = child;
|
me->root = child;
|
||||||
} else if (parent->parent->left == parent) {
|
return;
|
||||||
parent->parent->left = child;
|
}
|
||||||
|
memcpy(&grand_parent_left_child, grand_parent + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
if (grand_parent_left_child == parent) {
|
||||||
|
memcpy(grand_parent + node_left_child_offset, &child, ptr_size);
|
||||||
} else {
|
} else {
|
||||||
parent->parent->right = child;
|
memcpy(grand_parent + node_right_child_offset, &child, ptr_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rotates the AVL tree to the left.
|
* Rotates the AVL tree to the left.
|
||||||
*/
|
*/
|
||||||
static void map_rotate_left(map me,
|
static void map_rotate_left(map me, char *const parent, char *const child)
|
||||||
struct node *const parent,
|
|
||||||
struct node *const child)
|
|
||||||
{
|
{
|
||||||
struct node *grand_child;
|
char *left_grand_child;
|
||||||
map_reference_parent(me, parent, child);
|
map_reference_parent(me, parent, child);
|
||||||
grand_child = child->left;
|
memcpy(&left_grand_child, child + node_left_child_offset, ptr_size);
|
||||||
if (grand_child) {
|
if (left_grand_child) {
|
||||||
grand_child->parent = parent;
|
memcpy(left_grand_child + node_parent_offset, &parent, ptr_size);
|
||||||
}
|
}
|
||||||
parent->parent = child;
|
memcpy(parent + node_parent_offset, &child, ptr_size);
|
||||||
parent->right = grand_child;
|
memcpy(parent + node_right_child_offset, &left_grand_child, ptr_size);
|
||||||
child->left = parent;
|
memcpy(child + node_left_child_offset, &parent, ptr_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rotates the AVL tree to the right.
|
* Rotates the AVL tree to the right.
|
||||||
*/
|
*/
|
||||||
static void map_rotate_right(map me,
|
static void map_rotate_right(map me, char *const parent, char *const child)
|
||||||
struct node *const parent,
|
|
||||||
struct node *const child)
|
|
||||||
{
|
{
|
||||||
struct node *grand_child;
|
char *right_grand_child;
|
||||||
map_reference_parent(me, parent, child);
|
map_reference_parent(me, parent, child);
|
||||||
grand_child = child->right;
|
memcpy(&right_grand_child, child + node_right_child_offset, ptr_size);
|
||||||
if (grand_child) {
|
if (right_grand_child) {
|
||||||
grand_child->parent = parent;
|
memcpy(right_grand_child + node_parent_offset, &parent, ptr_size);
|
||||||
}
|
}
|
||||||
parent->parent = child;
|
memcpy(parent + node_parent_offset, &child, ptr_size);
|
||||||
parent->left = grand_child;
|
memcpy(parent + node_left_child_offset, &right_grand_child, ptr_size);
|
||||||
child->right = parent;
|
memcpy(child + node_right_child_offset, &parent, ptr_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Performs a left repair.
|
* Performs a left repair.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair_left(map me,
|
static char *map_repair_left(map me, char *const parent, char *const child)
|
||||||
struct node *const parent,
|
|
||||||
struct node *const child)
|
|
||||||
{
|
{
|
||||||
map_rotate_left(me, parent, child);
|
map_rotate_left(me, parent, child);
|
||||||
if (child->balance == 0) {
|
if (child[0] == 0) {
|
||||||
parent->balance = 1;
|
parent[0] = 1;
|
||||||
child->balance = -1;
|
child[0] = -1;
|
||||||
} else {
|
} else {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
}
|
}
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -171,17 +168,15 @@ static struct node *map_repair_left(map me,
|
|||||||
/*
|
/*
|
||||||
* Performs a right repair.
|
* Performs a right repair.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair_right(map me,
|
static char *map_repair_right(map me, char *const parent, char *const child)
|
||||||
struct node *const parent,
|
|
||||||
struct node *const child)
|
|
||||||
{
|
{
|
||||||
map_rotate_right(me, parent, child);
|
map_rotate_right(me, parent, child);
|
||||||
if (child->balance == 0) {
|
if (child[0] == 0) {
|
||||||
parent->balance = -1;
|
parent[0] = -1;
|
||||||
child->balance = 1;
|
child[0] = 1;
|
||||||
} else {
|
} else {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
}
|
}
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -189,48 +184,44 @@ static struct node *map_repair_right(map me,
|
|||||||
/*
|
/*
|
||||||
* Performs a left-right repair.
|
* Performs a left-right repair.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair_left_right(map me,
|
static char *map_repair_left_right(map me, char *const parent,
|
||||||
struct node *const parent,
|
char *const child, char *const grand_child)
|
||||||
struct node *const child,
|
|
||||||
struct node *const grand_child)
|
|
||||||
{
|
{
|
||||||
map_rotate_left(me, child, grand_child);
|
map_rotate_left(me, child, grand_child);
|
||||||
map_rotate_right(me, parent, grand_child);
|
map_rotate_right(me, parent, grand_child);
|
||||||
if (grand_child->balance == 1) {
|
if (grand_child[0] == 1) {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = -1;
|
child[0] = -1;
|
||||||
} else if (grand_child->balance == 0) {
|
} else if (grand_child[0] == 0) {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
} else {
|
} else {
|
||||||
parent->balance = 1;
|
parent[0] = 1;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
}
|
}
|
||||||
grand_child->balance = 0;
|
grand_child[0] = 0;
|
||||||
return grand_child;
|
return grand_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Performs a right-left repair.
|
* Performs a right-left repair.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair_right_left(map me,
|
static char *map_repair_right_left(map me, char *const parent,
|
||||||
struct node *const parent,
|
char *const child, char *const grand_child)
|
||||||
struct node *const child,
|
|
||||||
struct node *const grand_child)
|
|
||||||
{
|
{
|
||||||
map_rotate_right(me, child, grand_child);
|
map_rotate_right(me, child, grand_child);
|
||||||
map_rotate_left(me, parent, grand_child);
|
map_rotate_left(me, parent, grand_child);
|
||||||
if (grand_child->balance == 1) {
|
if (grand_child[0] == 1) {
|
||||||
parent->balance = -1;
|
parent[0] = -1;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
} else if (grand_child->balance == 0) {
|
} else if (grand_child[0] == 0) {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = 0;
|
child[0] = 0;
|
||||||
} else {
|
} else {
|
||||||
parent->balance = 0;
|
parent[0] = 0;
|
||||||
child->balance = 1;
|
child[0] = 1;
|
||||||
}
|
}
|
||||||
grand_child->balance = 0;
|
grand_child[0] = 0;
|
||||||
return grand_child;
|
return grand_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,18 +229,16 @@ static struct node *map_repair_right_left(map me,
|
|||||||
* Repairs the AVL tree on insert. The only possible values of parent->balance
|
* Repairs the AVL tree on insert. The only possible values of parent->balance
|
||||||
* are {-2, 2} and the only possible values of child->balance are {-1, 0, 1}.
|
* are {-2, 2} and the only possible values of child->balance are {-1, 0, 1}.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair(map me,
|
static char *map_repair(map me, char *const parent, char *const child,
|
||||||
struct node *const parent,
|
char *const grand_child)
|
||||||
struct node *const child,
|
|
||||||
struct node *const grand_child)
|
|
||||||
{
|
{
|
||||||
if (parent->balance == 2) {
|
if (parent[0] == 2) {
|
||||||
if (child->balance == -1) {
|
if (child[0] == -1) {
|
||||||
return map_repair_right_left(me, parent, child, grand_child);
|
return map_repair_right_left(me, parent, child, grand_child);
|
||||||
}
|
}
|
||||||
return map_repair_left(me, parent, child);
|
return map_repair_left(me, parent, child);
|
||||||
}
|
}
|
||||||
if (child->balance == 1) {
|
if (child[0] == 1) {
|
||||||
return map_repair_left_right(me, parent, child, grand_child);
|
return map_repair_left_right(me, parent, child, grand_child);
|
||||||
}
|
}
|
||||||
return map_repair_right(me, parent, child);
|
return map_repair_right(me, parent, child);
|
||||||
@@ -258,62 +247,52 @@ static struct node *map_repair(map me,
|
|||||||
/*
|
/*
|
||||||
* Balances the AVL tree on insert.
|
* Balances the AVL tree on insert.
|
||||||
*/
|
*/
|
||||||
static void map_insert_balance(map me, struct node *const item)
|
static void map_insert_balance(map me, char *const item)
|
||||||
{
|
{
|
||||||
struct node *grand_child = NULL;
|
char *grand_child = NULL;
|
||||||
struct node *child = item;
|
char *child = item;
|
||||||
struct node *parent = item->parent;
|
char *parent;
|
||||||
|
memcpy(&parent, item + node_parent_offset, ptr_size);
|
||||||
while (parent) {
|
while (parent) {
|
||||||
if (parent->left == child) {
|
char *parent_left;
|
||||||
parent->balance--;
|
memcpy(&parent_left, parent + node_left_child_offset, ptr_size);
|
||||||
|
if (parent_left == child) {
|
||||||
|
parent[0]--;
|
||||||
} else {
|
} else {
|
||||||
parent->balance++;
|
parent[0]++;
|
||||||
}
|
}
|
||||||
/* If balance is zero after modification, then the tree is balanced. */
|
/* If balance is zero after modification, then the tree is balanced. */
|
||||||
if (parent->balance == 0) {
|
if (parent[0] == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Must re-balance if not in {-1, 0, 1} */
|
/* Must re-balance if not in {-1, 0, 1} */
|
||||||
if (parent->balance > 1 || parent->balance < -1) {
|
if (parent[0] > 1 || parent[0] < -1) {
|
||||||
/* After one repair, the tree is balanced. */
|
/* After one repair, the tree is balanced. */
|
||||||
map_repair(me, parent, child, grand_child);
|
map_repair(me, parent, child, grand_child);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
grand_child = child;
|
grand_child = child;
|
||||||
child = parent;
|
child = parent;
|
||||||
parent = parent->parent;
|
memcpy(&parent, parent + node_parent_offset, ptr_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates and allocates a node.
|
* Creates and allocates a node.
|
||||||
*/
|
*/
|
||||||
static struct node *map_create_node(map me,
|
static char *map_create_node(map me, const void *const key,
|
||||||
const void *const key,
|
const void *const value, char *const parent)
|
||||||
const void *const value,
|
|
||||||
struct node *const parent)
|
|
||||||
{
|
{
|
||||||
struct node *const insert = malloc(sizeof(struct node));
|
char *insert = malloc(1 + 3 * ptr_size + me->key_size + me->value_size);
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
insert->parent = parent;
|
insert[0] = 0;
|
||||||
insert->balance = 0;
|
memcpy(insert + node_parent_offset, &parent, ptr_size);
|
||||||
insert->key = malloc(me->key_size);
|
memset(insert + node_left_child_offset, 0, ptr_size);
|
||||||
if (!insert->key) {
|
memset(insert + node_right_child_offset, 0, ptr_size);
|
||||||
free(insert);
|
memcpy(insert + node_key_offset, key, me->key_size);
|
||||||
return NULL;
|
memcpy(insert + node_key_offset + me->key_size, value, me->value_size);
|
||||||
}
|
|
||||||
memcpy(insert->key, key, me->key_size);
|
|
||||||
insert->value = malloc(me->value_size);
|
|
||||||
if (!insert->value) {
|
|
||||||
free(insert->key);
|
|
||||||
free(insert);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(insert->value, value, me->value_size);
|
|
||||||
insert->left = NULL;
|
|
||||||
insert->right = NULL;
|
|
||||||
me->size++;
|
me->size++;
|
||||||
return insert;
|
return insert;
|
||||||
}
|
}
|
||||||
@@ -335,9 +314,9 @@ static struct node *map_create_node(map me,
|
|||||||
*/
|
*/
|
||||||
int map_put(map me, void *const key, void *const value)
|
int map_put(map me, void *const key, void *const value)
|
||||||
{
|
{
|
||||||
struct node *traverse;
|
char *traverse;
|
||||||
if (!me->root) {
|
if (!me->root) {
|
||||||
struct node *insert = map_create_node(me, key, value, NULL);
|
char *insert = map_create_node(me, key, value, NULL);
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -346,33 +325,39 @@ int map_put(map me, void *const key, void *const value)
|
|||||||
}
|
}
|
||||||
traverse = me->root;
|
traverse = me->root;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const int compare = me->comparator(key, traverse->key);
|
const int compare = me->comparator(key, traverse + node_key_offset);
|
||||||
if (compare < 0) {
|
if (compare < 0) {
|
||||||
if (traverse->left) {
|
char *traverse_left;
|
||||||
traverse = traverse->left;
|
memcpy(&traverse_left, traverse + node_left_child_offset, ptr_size);
|
||||||
|
if (traverse_left) {
|
||||||
|
traverse = traverse_left;
|
||||||
} else {
|
} else {
|
||||||
struct node *insert = map_create_node(me, key, value, traverse);
|
char *insert = map_create_node(me, key, value, traverse);
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
traverse->left = insert;
|
memcpy(traverse + node_left_child_offset, &insert, ptr_size);
|
||||||
map_insert_balance(me, insert);
|
map_insert_balance(me, insert);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (compare > 0) {
|
} else if (compare > 0) {
|
||||||
if (traverse->right) {
|
char *traverse_right;
|
||||||
traverse = traverse->right;
|
memcpy(&traverse_right, traverse + node_right_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
if (traverse_right) {
|
||||||
|
traverse = traverse_right;
|
||||||
} else {
|
} else {
|
||||||
struct node *insert = map_create_node(me, key, value, traverse);
|
char *insert = map_create_node(me, key, value, traverse);
|
||||||
if (!insert) {
|
if (!insert) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
traverse->right = insert;
|
memcpy(traverse + node_right_child_offset, &insert, ptr_size);
|
||||||
map_insert_balance(me, insert);
|
map_insert_balance(me, insert);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(traverse->value, value, me->value_size);
|
memcpy(traverse + node_key_offset + me->key_size, value,
|
||||||
|
me->value_size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,23 +366,28 @@ int map_put(map me, void *const key, void *const value)
|
|||||||
/*
|
/*
|
||||||
* If a match occurs, returns the match. Else, returns NULL.
|
* If a match occurs, returns the match. Else, returns NULL.
|
||||||
*/
|
*/
|
||||||
static struct node *map_equal_match(map me, const void *const key)
|
static char *map_equal_match(map me, const void *const key)
|
||||||
{
|
{
|
||||||
struct node *traverse = me->root;
|
char *traverse = me->root;
|
||||||
if (!traverse) {
|
if (!traverse) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const int compare = me->comparator(key, traverse->key);
|
const int compare = me->comparator(key, traverse + node_key_offset);
|
||||||
if (compare < 0) {
|
if (compare < 0) {
|
||||||
if (traverse->left) {
|
char *traverse_left;
|
||||||
traverse = traverse->left;
|
memcpy(&traverse_left, traverse + node_left_child_offset, ptr_size);
|
||||||
|
if (traverse_left) {
|
||||||
|
traverse = traverse_left;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (compare > 0) {
|
} else if (compare > 0) {
|
||||||
if (traverse->right) {
|
char *traverse_right;
|
||||||
traverse = traverse->right;
|
memcpy(&traverse_right, traverse + node_right_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
if (traverse_right) {
|
||||||
|
traverse = traverse_right;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -423,11 +413,11 @@ static struct node *map_equal_match(map me, const void *const key)
|
|||||||
*/
|
*/
|
||||||
int map_get(void *const value, map me, void *const key)
|
int map_get(void *const value, map me, void *const key)
|
||||||
{
|
{
|
||||||
struct node *const traverse = map_equal_match(me, key);
|
char *const traverse = map_equal_match(me, key);
|
||||||
if (!traverse) {
|
if (!traverse) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(value, traverse->value, me->value_size);
|
memcpy(value, traverse + node_key_offset + me->key_size, me->value_size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,45 +441,55 @@ int map_contains(map me, void *const key)
|
|||||||
/*
|
/*
|
||||||
* Repairs the AVL tree by pivoting on an item.
|
* Repairs the AVL tree by pivoting on an item.
|
||||||
*/
|
*/
|
||||||
static struct node *map_repair_pivot(map me,
|
static char *map_repair_pivot(map me, char *const item, const int is_left_pivot)
|
||||||
struct node *const item,
|
|
||||||
const int is_left_pivot)
|
|
||||||
{
|
{
|
||||||
struct node *const child = is_left_pivot ? item->right : item->left;
|
char *child;
|
||||||
struct node *const grand_child =
|
char *grand_child;
|
||||||
child->balance == 1 ? child->right : child->left;
|
char *item_right;
|
||||||
|
char *item_left;
|
||||||
|
char *child_right;
|
||||||
|
char *child_left;
|
||||||
|
memcpy(&item_right, item + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
|
child = is_left_pivot ? item_right : item_left;
|
||||||
|
memcpy(&child_right, child + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(&child_left, child + node_left_child_offset, ptr_size);
|
||||||
|
grand_child = child[0] == 1 ? child_right : child_left;
|
||||||
return map_repair(me, item, child, grand_child);
|
return map_repair(me, item, child, grand_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Goes back up the tree repairing it along the way.
|
* Goes back up the tree repairing it along the way.
|
||||||
*/
|
*/
|
||||||
static void map_trace_ancestors(map me, struct node *item)
|
static void map_trace_ancestors(map me, char *item)
|
||||||
{
|
{
|
||||||
struct node *child = item;
|
char *child = item;
|
||||||
struct node *parent = item->parent;
|
char *parent;
|
||||||
|
memcpy(&parent, item + node_parent_offset, ptr_size);
|
||||||
while (parent) {
|
while (parent) {
|
||||||
if (parent->left == child) {
|
char *parent_left;
|
||||||
parent->balance++;
|
memcpy(&parent_left, parent + node_left_child_offset, ptr_size);
|
||||||
|
if (parent_left == child) {
|
||||||
|
parent[0]++;
|
||||||
} else {
|
} else {
|
||||||
parent->balance--;
|
parent[0]--;
|
||||||
}
|
}
|
||||||
/* The tree is balanced if balance is -1 or +1 after modification. */
|
/* The tree is balanced if balance is -1 or +1 after modification. */
|
||||||
if (parent->balance == -1 || parent->balance == 1) {
|
if (parent[0] == -1 || parent[0] == 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Must re-balance if not in {-1, 0, 1} */
|
/* Must re-balance if not in {-1, 0, 1} */
|
||||||
if (parent->balance > 1 || parent->balance < -1) {
|
if (parent[0] > 1 || parent[0] < -1) {
|
||||||
child = map_repair_pivot(me, parent, parent->left == child);
|
child = map_repair_pivot(me, parent, parent_left == child);
|
||||||
parent = child->parent;
|
memcpy(&parent, child + node_parent_offset, ptr_size);
|
||||||
/* If balance is -1 or +1 after modification or the parent is */
|
/* If balance is -1 or +1 after modification or */
|
||||||
/* NULL, then the tree is balanced. */
|
/* the parent is NULL, then the tree is balanced. */
|
||||||
if (!parent || child->balance == -1 || child->balance == 1) {
|
if (!parent || child[0] == -1 || child[0] == 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
child = parent;
|
child = parent;
|
||||||
parent = parent->parent;
|
memcpy(&parent, parent + node_parent_offset, ptr_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,23 +497,23 @@ static void map_trace_ancestors(map me, struct node *item)
|
|||||||
/*
|
/*
|
||||||
* Balances the AVL tree on deletion.
|
* Balances the AVL tree on deletion.
|
||||||
*/
|
*/
|
||||||
static void map_delete_balance(map me,
|
static void map_delete_balance(map me, char *item, const int is_left_deleted)
|
||||||
struct node *item,
|
|
||||||
const int is_left_deleted)
|
|
||||||
{
|
{
|
||||||
if (is_left_deleted) {
|
if (is_left_deleted) {
|
||||||
item->balance++;
|
item[0]++;
|
||||||
} else {
|
} else {
|
||||||
item->balance--;
|
item[0]--;
|
||||||
}
|
}
|
||||||
/* If balance is -1 or +1 after modification, then the tree is balanced. */
|
/* If balance is -1 or +1 after modification, then the tree is balanced. */
|
||||||
if (item->balance == -1 || item->balance == 1) {
|
if (item[0] == -1 || item[0] == 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Must re-balance if not in {-1, 0, 1} */
|
/* Must re-balance if not in {-1, 0, 1} */
|
||||||
if (item->balance > 1 || item->balance < -1) {
|
if (item[0] > 1 || item[0] < -1) {
|
||||||
|
char *item_parent;
|
||||||
item = map_repair_pivot(me, item, is_left_deleted);
|
item = map_repair_pivot(me, item, is_left_deleted);
|
||||||
if (!item->parent || item->balance == -1 || item->balance == 1) {
|
memcpy(&item_parent, item + node_parent_offset, ptr_size);
|
||||||
|
if (!item_parent || item[0] == -1 || item[0] == 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,101 +523,153 @@ static void map_delete_balance(map me,
|
|||||||
/*
|
/*
|
||||||
* Removes traverse when it has no children.
|
* Removes traverse when it has no children.
|
||||||
*/
|
*/
|
||||||
static void map_remove_no_children(map me, const struct node *const traverse)
|
static void map_remove_no_children(map me, const char *const traverse)
|
||||||
{
|
{
|
||||||
struct node *const parent = traverse->parent;
|
char *traverse_parent;
|
||||||
|
char *traverse_parent_left;
|
||||||
|
memcpy(&traverse_parent, traverse + node_parent_offset, ptr_size);
|
||||||
/* If no parent and no children, then the only node is traverse. */
|
/* If no parent and no children, then the only node is traverse. */
|
||||||
if (!parent) {
|
if (!traverse_parent) {
|
||||||
me->root = NULL;
|
me->root = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
memcpy(&traverse_parent_left, traverse_parent + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
/* No re-reference needed since traverse has no children. */
|
/* No re-reference needed since traverse has no children. */
|
||||||
if (parent->left == traverse) {
|
if (traverse_parent_left == traverse) {
|
||||||
parent->left = NULL;
|
memset(traverse_parent + node_left_child_offset, 0, ptr_size);
|
||||||
map_delete_balance(me, parent, 1);
|
map_delete_balance(me, traverse_parent, 1);
|
||||||
} else {
|
} else {
|
||||||
parent->right = NULL;
|
memset(traverse_parent + node_right_child_offset, 0, ptr_size);
|
||||||
map_delete_balance(me, parent, 0);
|
map_delete_balance(me, traverse_parent, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes traverse when it has one child.
|
* Removes traverse when it has one child.
|
||||||
*/
|
*/
|
||||||
static void map_remove_one_child(map me, const struct node *const traverse)
|
static void map_remove_one_child(map me, const char *const traverse)
|
||||||
{
|
{
|
||||||
struct node *const parent = traverse->parent;
|
char *traverse_parent;
|
||||||
|
char *traverse_left;
|
||||||
|
char *traverse_right;
|
||||||
|
char *traverse_parent_left;
|
||||||
|
memcpy(&traverse_parent, traverse + node_parent_offset, ptr_size);
|
||||||
|
memcpy(&traverse_left, traverse + node_left_child_offset, ptr_size);
|
||||||
|
memcpy(&traverse_right, traverse + node_right_child_offset, ptr_size);
|
||||||
/* If no parent, make the child of traverse the new root. */
|
/* If no parent, make the child of traverse the new root. */
|
||||||
if (!parent) {
|
if (!traverse_parent) {
|
||||||
if (traverse->left) {
|
if (traverse_left) {
|
||||||
traverse->left->parent = NULL;
|
memset(traverse_left + node_parent_offset, 0, ptr_size);
|
||||||
me->root = traverse->left;
|
me->root = traverse_left;
|
||||||
} else {
|
} else {
|
||||||
traverse->right->parent = NULL;
|
memset(traverse_right + node_parent_offset, 0, ptr_size);
|
||||||
me->root = traverse->right;
|
me->root = traverse_right;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
memcpy(&traverse_parent_left, traverse_parent + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
/* The parent of traverse now references the child of traverse. */
|
/* The parent of traverse now references the child of traverse. */
|
||||||
if (parent->left == traverse) {
|
if (traverse_parent_left == traverse) {
|
||||||
if (traverse->left) {
|
if (traverse_left) {
|
||||||
parent->left = traverse->left;
|
memcpy(traverse_parent + node_left_child_offset, &traverse_left,
|
||||||
traverse->left->parent = parent;
|
ptr_size);
|
||||||
|
memcpy(traverse_left + node_parent_offset, &traverse_parent,
|
||||||
|
ptr_size);
|
||||||
} else {
|
} else {
|
||||||
parent->left = traverse->right;
|
memcpy(traverse_parent + node_left_child_offset, &traverse_right,
|
||||||
traverse->right->parent = parent;
|
ptr_size);
|
||||||
|
memcpy(traverse_right + node_parent_offset, &traverse_parent,
|
||||||
|
ptr_size);
|
||||||
}
|
}
|
||||||
map_delete_balance(me, parent, 1);
|
map_delete_balance(me, traverse_parent, 1);
|
||||||
} else {
|
} else {
|
||||||
if (traverse->left) {
|
if (traverse_left) {
|
||||||
parent->right = traverse->left;
|
memcpy(traverse_parent + node_right_child_offset, &traverse_left,
|
||||||
traverse->left->parent = parent;
|
ptr_size);
|
||||||
|
memcpy(traverse_left + node_parent_offset, &traverse_parent,
|
||||||
|
ptr_size);
|
||||||
} else {
|
} else {
|
||||||
parent->right = traverse->right;
|
memcpy(traverse_parent + node_right_child_offset, &traverse_right,
|
||||||
traverse->right->parent = parent;
|
ptr_size);
|
||||||
|
memcpy(traverse_right + node_parent_offset, &traverse_parent,
|
||||||
|
ptr_size);
|
||||||
}
|
}
|
||||||
map_delete_balance(me, parent, 0);
|
map_delete_balance(me, traverse_parent, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes traverse when it has two children.
|
* Removes traverse when it has two children.
|
||||||
*/
|
*/
|
||||||
static void map_remove_two_children(map me, const struct node *const traverse)
|
static void map_remove_two_children(map me, const char *const traverse)
|
||||||
{
|
{
|
||||||
struct node *item;
|
char *item;
|
||||||
struct node *parent;
|
char *item_parent;
|
||||||
const int is_left_deleted = traverse->right->left != NULL;
|
char *parent;
|
||||||
|
char *traverse_parent;
|
||||||
|
char *traverse_right;
|
||||||
|
char *traverse_right_left;
|
||||||
|
int is_left_deleted;
|
||||||
|
memcpy(&traverse_right, traverse + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(&traverse_right_left, traverse_right + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
is_left_deleted = traverse_right_left != NULL;
|
||||||
if (!is_left_deleted) {
|
if (!is_left_deleted) {
|
||||||
item = traverse->right;
|
char *item_left;
|
||||||
|
memcpy(&item, traverse + node_right_child_offset, ptr_size);
|
||||||
parent = item;
|
parent = item;
|
||||||
item->balance = traverse->balance;
|
item[0] = traverse[0];
|
||||||
item->parent = traverse->parent;
|
memcpy(item + node_parent_offset, traverse + node_parent_offset,
|
||||||
item->left = traverse->left;
|
ptr_size);
|
||||||
item->left->parent = item;
|
memcpy(item + node_left_child_offset, traverse + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
|
memcpy(item_left + node_parent_offset, &item, ptr_size);
|
||||||
} else {
|
} else {
|
||||||
item = traverse->right->left;
|
char *item_left;
|
||||||
while (item->left) {
|
char *item_right;
|
||||||
item = item->left;
|
item = traverse_right_left;
|
||||||
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
|
while (item_left) {
|
||||||
|
item = item_left;
|
||||||
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
}
|
}
|
||||||
parent = item->parent;
|
memcpy(&parent, item + node_parent_offset, ptr_size);
|
||||||
item->balance = traverse->balance;
|
item[0] = traverse[0];
|
||||||
item->parent->left = item->right;
|
memcpy(&item_parent, item + node_parent_offset, ptr_size);
|
||||||
if (item->right) {
|
memcpy(item_parent + node_left_child_offset,
|
||||||
item->right->parent = item->parent;
|
item + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(&item_right, item + node_right_child_offset, ptr_size);
|
||||||
|
if (item_right) {
|
||||||
|
memcpy(item_right + node_parent_offset, item + node_parent_offset,
|
||||||
|
ptr_size);
|
||||||
}
|
}
|
||||||
item->left = traverse->left;
|
memcpy(item + node_left_child_offset, traverse + node_left_child_offset,
|
||||||
item->left->parent = item;
|
ptr_size);
|
||||||
item->right = traverse->right;
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
item->right->parent = item;
|
memcpy(item_left + node_parent_offset, &item, ptr_size);
|
||||||
item->parent = traverse->parent;
|
memcpy(item + node_right_child_offset,
|
||||||
|
traverse + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(&item_right, item + node_right_child_offset, ptr_size);
|
||||||
|
memcpy(item_right + node_parent_offset, &item, ptr_size);
|
||||||
|
memcpy(item + node_parent_offset, traverse + node_parent_offset,
|
||||||
|
ptr_size);
|
||||||
}
|
}
|
||||||
if (!traverse->parent) {
|
memcpy(&traverse_parent, traverse + node_parent_offset, ptr_size);
|
||||||
|
if (!traverse_parent) {
|
||||||
me->root = item;
|
me->root = item;
|
||||||
} else if (traverse->parent->left == traverse) {
|
|
||||||
item->parent->left = item;
|
|
||||||
} else {
|
} else {
|
||||||
item->parent->right = item;
|
char *traverse_parent_left;
|
||||||
|
memcpy(&traverse_parent_left, traverse_parent + node_left_child_offset,
|
||||||
|
ptr_size);
|
||||||
|
memcpy(&item_parent, item + node_parent_offset, ptr_size);
|
||||||
|
if (traverse_parent_left == traverse) {
|
||||||
|
memcpy(item_parent + node_left_child_offset, &item, ptr_size);
|
||||||
|
} else {
|
||||||
|
memcpy(item_parent + node_right_child_offset, &item, ptr_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
map_delete_balance(me, parent, is_left_deleted);
|
map_delete_balance(me, parent, is_left_deleted);
|
||||||
}
|
}
|
||||||
@@ -625,17 +677,19 @@ static void map_remove_two_children(map me, const struct node *const traverse)
|
|||||||
/*
|
/*
|
||||||
* Removes the element from the map.
|
* Removes the element from the map.
|
||||||
*/
|
*/
|
||||||
static void map_remove_element(map me, struct node *const traverse)
|
static void map_remove_element(map me, char *const traverse)
|
||||||
{
|
{
|
||||||
if (!traverse->left && !traverse->right) {
|
char *traverse_left;
|
||||||
|
char *traverse_right;
|
||||||
|
memcpy(&traverse_left, traverse + node_left_child_offset, ptr_size);
|
||||||
|
memcpy(&traverse_right, traverse + node_right_child_offset, ptr_size);
|
||||||
|
if (!traverse_left && !traverse_right) {
|
||||||
map_remove_no_children(me, traverse);
|
map_remove_no_children(me, traverse);
|
||||||
} else if (!traverse->left || !traverse->right) {
|
} else if (!traverse_left || !traverse_right) {
|
||||||
map_remove_one_child(me, traverse);
|
map_remove_one_child(me, traverse);
|
||||||
} else {
|
} else {
|
||||||
map_remove_two_children(me, traverse);
|
map_remove_two_children(me, traverse);
|
||||||
}
|
}
|
||||||
free(traverse->key);
|
|
||||||
free(traverse->value);
|
|
||||||
free(traverse);
|
free(traverse);
|
||||||
me->size--;
|
me->size--;
|
||||||
}
|
}
|
||||||
@@ -654,7 +708,7 @@ static void map_remove_element(map me, struct node *const traverse)
|
|||||||
*/
|
*/
|
||||||
int map_remove(map me, void *const key)
|
int map_remove(map me, void *const key)
|
||||||
{
|
{
|
||||||
struct node *const traverse = map_equal_match(me, key);
|
char *const traverse = map_equal_match(me, key);
|
||||||
if (!traverse) {
|
if (!traverse) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,80 @@
|
|||||||
|
#include <memory.h>
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "../src/include/map.h"
|
#include "../src/include/map.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Include this struct to verify the tree.
|
* Include this to verify the tree.
|
||||||
*/
|
*/
|
||||||
struct internal_map {
|
struct internal_map {
|
||||||
|
size_t size;
|
||||||
size_t key_size;
|
size_t key_size;
|
||||||
size_t value_size;
|
size_t value_size;
|
||||||
int (*comparator)(const void *const one, const void *const two);
|
int (*comparator)(const void *const one, const void *const two);
|
||||||
int size;
|
char *root;
|
||||||
struct node *root;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Include this struct to verify the tree.
|
* Include this to verify the tree.
|
||||||
*/
|
*/
|
||||||
struct node {
|
static const size_t ptr_size = sizeof(char *);
|
||||||
struct node *parent;
|
/* Node balance is always the first byte (at index 0). */
|
||||||
int balance;
|
static const size_t node_parent_offset = sizeof(signed char);
|
||||||
void *key;
|
static const size_t node_left_child_offset = 1 + sizeof(char *);
|
||||||
void *value;
|
static const size_t node_right_child_offset = 1 + 2 * sizeof(char *);
|
||||||
struct node *left;
|
static const size_t node_key_offset = 1 + 3 * sizeof(char *);
|
||||||
struct node *right;
|
/* Assume the value starts right after the key ends. */
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verifies that the AVL tree rules are followed. The balance factor of an item
|
* Verifies that the AVL tree rules are followed. The balance factor of an item
|
||||||
* must be the right height minus the left height. Also, the left key must be
|
* must be the right height minus the left height. Also, the left key must be
|
||||||
* less than the right key.
|
* less than the right key.
|
||||||
*/
|
*/
|
||||||
static int map_verify_recursive(struct node *const item)
|
static int map_verify_recursive(char *const item)
|
||||||
{
|
{
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
int max;
|
int max;
|
||||||
|
char *item_left;
|
||||||
|
char *item_right;
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
left = map_verify_recursive(item->left);
|
memcpy(&item_left, item + node_left_child_offset, ptr_size);
|
||||||
right = map_verify_recursive(item->right);
|
memcpy(&item_right, item + node_right_child_offset, ptr_size);
|
||||||
|
left = map_verify_recursive(item_left);
|
||||||
|
right = map_verify_recursive(item_right);
|
||||||
max = left > right ? left : right;
|
max = left > right ? left : right;
|
||||||
assert(right - left == item->balance);
|
assert(right - left == item[0]);
|
||||||
if (item->left && item->right) {
|
if (item_left && item_right) {
|
||||||
const int left_val = *(int *) item->left->key;
|
const int left_val = *(int *) (item_left + node_key_offset);
|
||||||
const int right_val = *(int *) item->right->key;
|
const int right_val = *(int *) (item_right + node_key_offset);
|
||||||
assert(left_val < right_val);
|
assert(left_val < right_val);
|
||||||
}
|
}
|
||||||
if (item->left) {
|
if (item_left) {
|
||||||
assert(item->left->parent == item);
|
char *item_left_parent;
|
||||||
assert(item->left->parent->key == item->key);
|
memcpy(&item_left_parent, item_left + node_parent_offset, ptr_size);
|
||||||
|
assert(item_left_parent == item);
|
||||||
|
assert(item_left_parent + node_key_offset == item + node_key_offset);
|
||||||
}
|
}
|
||||||
if (item->right) {
|
if (item_right) {
|
||||||
assert(item->right->parent == item);
|
char *item_right_parent;
|
||||||
assert(item->right->parent->key == item->key);
|
memcpy(&item_right_parent, item_right + node_parent_offset, ptr_size);
|
||||||
|
assert(item_right_parent == item);
|
||||||
|
assert(item_right_parent + node_key_offset == item + node_key_offset);
|
||||||
}
|
}
|
||||||
return max + 1;
|
return max + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_compute_size(struct node *const item)
|
static size_t map_compute_size(char *const item)
|
||||||
{
|
{
|
||||||
|
char *left;
|
||||||
|
char *right;
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1 + map_compute_size(item->left) + map_compute_size(item->right);
|
memcpy(&left, item + node_left_child_offset, ptr_size);
|
||||||
|
memcpy(&right, item + node_right_child_offset, ptr_size);
|
||||||
|
return 1 + map_compute_size(left) + map_compute_size(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void map_verify(map me)
|
static void map_verify(map me)
|
||||||
@@ -89,7 +100,7 @@ static void test_invalid_init(void)
|
|||||||
static void mutation_order(map me, const int *const arr, const int size)
|
static void mutation_order(map me, const int *const arr, const int size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int actual_size = 0;
|
size_t actual_size = 0;
|
||||||
assert(map_is_empty(me));
|
assert(map_is_empty(me));
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
int num = arr[i];
|
int num = arr[i];
|
||||||
@@ -374,7 +385,7 @@ static void test_contains(void)
|
|||||||
|
|
||||||
static void test_stress_add(void)
|
static void test_stress_add(void)
|
||||||
{
|
{
|
||||||
int count = 0;
|
size_t count = 0;
|
||||||
int flip = 0;
|
int flip = 0;
|
||||||
int i;
|
int i;
|
||||||
map me = map_init(sizeof(int), sizeof(int), compare_int);
|
map me = map_init(sizeof(int), sizeof(int), compare_int);
|
||||||
@@ -506,12 +517,6 @@ static void test_put_root_out_of_memory(map me)
|
|||||||
int key = 2;
|
int key = 2;
|
||||||
fail_malloc = 1;
|
fail_malloc = 1;
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
assert(map_put(me, &key, &key) == -ENOMEM);
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 1;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 2;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -521,12 +526,6 @@ static void test_put_on_left_out_of_memory(map me)
|
|||||||
int key = 1;
|
int key = 1;
|
||||||
fail_malloc = 1;
|
fail_malloc = 1;
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
assert(map_put(me, &key, &key) == -ENOMEM);
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 1;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 2;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -536,12 +535,6 @@ static void test_put_on_right_out_of_memory(map me)
|
|||||||
int key = 3;
|
int key = 3;
|
||||||
fail_malloc = 1;
|
fail_malloc = 1;
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
assert(map_put(me, &key, &key) == -ENOMEM);
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 1;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
fail_malloc = 1;
|
|
||||||
delay_fail_malloc = 2;
|
|
||||||
assert(map_put(me, &key, &key) == -ENOMEM);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user