mirror of https://github.com/GOSTSec/vanitygen
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
10 KiB
440 lines
10 KiB
12 years ago
|
/*
|
||
|
* Vanitygen, vanity bitcoin address generator
|
||
|
* Copyright (C) 2011 <samr7@cs.washington.edu>
|
||
|
*
|
||
|
* Vanitygen is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Affero General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* any later version.
|
||
|
*
|
||
|
* Vanitygen 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
|
||
|
* GNU Affero General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Affero General Public License
|
||
|
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#if !defined (__VG_AVL_H__)
|
||
|
#define __VG_AVL_H__
|
||
|
|
||
|
#include <assert.h>
|
||
|
|
||
|
/*
|
||
|
* AVL tree implementation
|
||
|
*/
|
||
|
|
||
|
typedef enum { CENT = 1, LEFT = 0, RIGHT = 2 } avl_balance_t;
|
||
|
|
||
|
typedef struct _avl_item_s {
|
||
|
struct _avl_item_s *ai_left, *ai_right, *ai_up;
|
||
|
avl_balance_t ai_balance;
|
||
|
#ifndef NDEBUG
|
||
|
int ai_indexed;
|
||
|
#endif
|
||
|
} avl_item_t;
|
||
|
|
||
|
typedef struct _avl_root_s {
|
||
|
avl_item_t *ar_root;
|
||
|
} avl_root_t;
|
||
|
|
||
|
static INLINE void
|
||
|
avl_root_init(avl_root_t *rootp)
|
||
|
{
|
||
|
rootp->ar_root = NULL;
|
||
|
}
|
||
|
|
||
|
static INLINE int
|
||
|
avl_root_empty(avl_root_t *rootp)
|
||
|
{
|
||
|
return (rootp->ar_root == NULL) ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
static INLINE void
|
||
|
avl_item_init(avl_item_t *itemp)
|
||
|
{
|
||
|
itemp->ai_left = NULL;
|
||
|
itemp->ai_right = NULL;
|
||
|
itemp->ai_up = NULL;
|
||
|
itemp->ai_balance = CENT;
|
||
|
#ifndef NDEBUG
|
||
|
itemp->ai_indexed = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#define container_of(ptr, type, member) \
|
||
|
(((type*) (((unsigned char *)ptr) - \
|
||
|
(size_t)&(((type *)((unsigned char *)0))->member))))
|
||
|
|
||
|
#define avl_item_entry(ptr, type, member) \
|
||
|
container_of(ptr, type, member)
|
||
|
|
||
|
|
||
|
|
||
|
static INLINE void
|
||
|
_avl_rotate_ll(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *tmp;
|
||
|
tmp = itemp->ai_left;
|
||
|
itemp->ai_left = tmp->ai_right;
|
||
|
if (itemp->ai_left)
|
||
|
itemp->ai_left->ai_up = itemp;
|
||
|
tmp->ai_right = itemp;
|
||
|
|
||
|
if (itemp->ai_up) {
|
||
|
if (itemp->ai_up->ai_left == itemp) {
|
||
|
itemp->ai_up->ai_left = tmp;
|
||
|
} else {
|
||
|
assert(itemp->ai_up->ai_right == itemp);
|
||
|
itemp->ai_up->ai_right = tmp;
|
||
|
}
|
||
|
} else {
|
||
|
rootp->ar_root = tmp;
|
||
|
}
|
||
|
tmp->ai_up = itemp->ai_up;
|
||
|
itemp->ai_up = tmp;
|
||
|
}
|
||
|
|
||
|
static INLINE void
|
||
|
_avl_rotate_lr(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *rcp, *rlcp;
|
||
|
rcp = itemp->ai_left;
|
||
|
rlcp = rcp->ai_right;
|
||
|
if (itemp->ai_up) {
|
||
|
if (itemp == itemp->ai_up->ai_left) {
|
||
|
itemp->ai_up->ai_left = rlcp;
|
||
|
} else {
|
||
|
assert(itemp == itemp->ai_up->ai_right);
|
||
|
itemp->ai_up->ai_right = rlcp;
|
||
|
}
|
||
|
} else {
|
||
|
rootp->ar_root = rlcp;
|
||
|
}
|
||
|
rlcp->ai_up = itemp->ai_up;
|
||
|
rcp->ai_right = rlcp->ai_left;
|
||
|
if (rcp->ai_right)
|
||
|
rcp->ai_right->ai_up = rcp;
|
||
|
itemp->ai_left = rlcp->ai_right;
|
||
|
if (itemp->ai_left)
|
||
|
itemp->ai_left->ai_up = itemp;
|
||
|
rlcp->ai_left = rcp;
|
||
|
rlcp->ai_right = itemp;
|
||
|
rcp->ai_up = rlcp;
|
||
|
itemp->ai_up = rlcp;
|
||
|
}
|
||
|
|
||
|
static INLINE void
|
||
|
_avl_rotate_rr(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *tmp;
|
||
|
tmp = itemp->ai_right;
|
||
|
itemp->ai_right = tmp->ai_left;
|
||
|
if (itemp->ai_right)
|
||
|
itemp->ai_right->ai_up = itemp;
|
||
|
tmp->ai_left = itemp;
|
||
|
|
||
|
if (itemp->ai_up) {
|
||
|
if (itemp->ai_up->ai_right == itemp) {
|
||
|
itemp->ai_up->ai_right = tmp;
|
||
|
} else {
|
||
|
assert(itemp->ai_up->ai_left == itemp);
|
||
|
itemp->ai_up->ai_left = tmp;
|
||
|
}
|
||
|
} else {
|
||
|
rootp->ar_root = tmp;
|
||
|
}
|
||
|
tmp->ai_up = itemp->ai_up;
|
||
|
itemp->ai_up = tmp;
|
||
|
}
|
||
|
|
||
|
static INLINE void
|
||
|
_avl_rotate_rl(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *rcp, *rlcp;
|
||
|
rcp = itemp->ai_right;
|
||
|
rlcp = rcp->ai_left;
|
||
|
if (itemp->ai_up) {
|
||
|
if (itemp == itemp->ai_up->ai_right) {
|
||
|
itemp->ai_up->ai_right = rlcp;
|
||
|
} else {
|
||
|
assert(itemp == itemp->ai_up->ai_left);
|
||
|
itemp->ai_up->ai_left = rlcp;
|
||
|
}
|
||
|
} else {
|
||
|
rootp->ar_root = rlcp;
|
||
|
}
|
||
|
rlcp->ai_up = itemp->ai_up;
|
||
|
rcp->ai_left = rlcp->ai_right;
|
||
|
if (rcp->ai_left)
|
||
|
rcp->ai_left->ai_up = rcp;
|
||
|
itemp->ai_right = rlcp->ai_left;
|
||
|
if (itemp->ai_right)
|
||
|
itemp->ai_right->ai_up = itemp;
|
||
|
rlcp->ai_right = rcp;
|
||
|
rlcp->ai_left = itemp;
|
||
|
rcp->ai_up = rlcp;
|
||
|
itemp->ai_up = rlcp;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
avl_delete_fix(avl_root_t *rootp, avl_item_t *itemp, avl_item_t *parentp)
|
||
|
{
|
||
|
avl_item_t *childp;
|
||
|
|
||
|
if ((parentp->ai_left == NULL) &&
|
||
|
(parentp->ai_right == NULL)) {
|
||
|
assert(itemp == NULL);
|
||
|
parentp->ai_balance = CENT;
|
||
|
itemp = parentp;
|
||
|
parentp = itemp->ai_up;
|
||
|
}
|
||
|
|
||
|
while (parentp) {
|
||
|
if (itemp == parentp->ai_right) {
|
||
|
itemp = parentp->ai_left;
|
||
|
if (parentp->ai_balance == LEFT) {
|
||
|
/* Parent was left-heavy, now worse */
|
||
|
if (itemp->ai_balance == LEFT) {
|
||
|
/* If left child is also
|
||
|
* left-heavy, LL fixes it. */
|
||
|
_avl_rotate_ll(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
parentp = itemp;
|
||
|
} else if (itemp->ai_balance == CENT) {
|
||
|
_avl_rotate_ll(rootp, parentp);
|
||
|
itemp->ai_balance = RIGHT;
|
||
|
parentp->ai_balance = LEFT;
|
||
|
break;
|
||
|
} else {
|
||
|
childp = itemp->ai_right;
|
||
|
_avl_rotate_lr(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
if (childp->ai_balance == RIGHT)
|
||
|
itemp->ai_balance = LEFT;
|
||
|
if (childp->ai_balance == LEFT)
|
||
|
parentp->ai_balance = RIGHT;
|
||
|
childp->ai_balance = CENT;
|
||
|
parentp = childp;
|
||
|
}
|
||
|
} else if (parentp->ai_balance == CENT) {
|
||
|
parentp->ai_balance = LEFT;
|
||
|
break;
|
||
|
} else {
|
||
|
parentp->ai_balance = CENT;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
itemp = parentp->ai_right;
|
||
|
if (parentp->ai_balance == RIGHT) {
|
||
|
if (itemp->ai_balance == RIGHT) {
|
||
|
_avl_rotate_rr(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
parentp = itemp;
|
||
|
} else if (itemp->ai_balance == CENT) {
|
||
|
_avl_rotate_rr(rootp, parentp);
|
||
|
itemp->ai_balance = LEFT;
|
||
|
parentp->ai_balance = RIGHT;
|
||
|
break;
|
||
|
} else {
|
||
|
childp = itemp->ai_left;
|
||
|
_avl_rotate_rl(rootp, parentp);
|
||
|
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
if (childp->ai_balance == RIGHT)
|
||
|
parentp->ai_balance = LEFT;
|
||
|
if (childp->ai_balance == LEFT)
|
||
|
itemp->ai_balance = RIGHT;
|
||
|
childp->ai_balance = CENT;
|
||
|
parentp = childp;
|
||
|
}
|
||
|
} else if (parentp->ai_balance == CENT) {
|
||
|
parentp->ai_balance = RIGHT;
|
||
|
break;
|
||
|
} else {
|
||
|
parentp->ai_balance = CENT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
itemp = parentp;
|
||
|
parentp = itemp->ai_up;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
avl_insert_fix(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *childp, *parentp = itemp->ai_up;
|
||
|
itemp->ai_left = itemp->ai_right = NULL;
|
||
|
#ifndef NDEBUG
|
||
|
assert(!itemp->ai_indexed);
|
||
|
itemp->ai_indexed = 1;
|
||
|
#endif
|
||
|
while (parentp) {
|
||
|
if (itemp == parentp->ai_left) {
|
||
|
if (parentp->ai_balance == LEFT) {
|
||
|
/* Parent was left-heavy, now worse */
|
||
|
if (itemp->ai_balance == LEFT) {
|
||
|
/* If left child is also
|
||
|
* left-heavy, LL fixes it. */
|
||
|
_avl_rotate_ll(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
break;
|
||
|
} else {
|
||
|
assert(itemp->ai_balance != CENT);
|
||
|
childp = itemp->ai_right;
|
||
|
_avl_rotate_lr(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
if (childp->ai_balance == RIGHT)
|
||
|
itemp->ai_balance = LEFT;
|
||
|
if (childp->ai_balance == LEFT)
|
||
|
parentp->ai_balance = RIGHT;
|
||
|
childp->ai_balance = CENT;
|
||
|
break;
|
||
|
}
|
||
|
} else if (parentp->ai_balance == CENT) {
|
||
|
parentp->ai_balance = LEFT;
|
||
|
} else {
|
||
|
parentp->ai_balance = CENT;
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
if (parentp->ai_balance == RIGHT) {
|
||
|
if (itemp->ai_balance == RIGHT) {
|
||
|
_avl_rotate_rr(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
break;
|
||
|
} else {
|
||
|
assert(itemp->ai_balance != CENT);
|
||
|
childp = itemp->ai_left;
|
||
|
_avl_rotate_rl(rootp, parentp);
|
||
|
itemp->ai_balance = CENT;
|
||
|
parentp->ai_balance = CENT;
|
||
|
if (childp->ai_balance == RIGHT)
|
||
|
parentp->ai_balance = LEFT;
|
||
|
if (childp->ai_balance == LEFT)
|
||
|
itemp->ai_balance = RIGHT;
|
||
|
childp->ai_balance = CENT;
|
||
|
break;
|
||
|
}
|
||
|
} else if (parentp->ai_balance == CENT) {
|
||
|
parentp->ai_balance = RIGHT;
|
||
|
} else {
|
||
|
parentp->ai_balance = CENT;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
itemp = parentp;
|
||
|
parentp = itemp->ai_up;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static INLINE avl_item_t *
|
||
|
avl_first(avl_root_t *rootp)
|
||
|
{
|
||
|
avl_item_t *itemp = rootp->ar_root;
|
||
|
if (itemp) {
|
||
|
while (itemp->ai_left)
|
||
|
itemp = itemp->ai_left;
|
||
|
}
|
||
|
return itemp;
|
||
|
}
|
||
|
|
||
|
static INLINE avl_item_t *
|
||
|
avl_next(avl_item_t *itemp)
|
||
|
{
|
||
|
if (itemp->ai_right) {
|
||
|
itemp = itemp->ai_right;
|
||
|
while (itemp->ai_left)
|
||
|
itemp = itemp->ai_left;
|
||
|
return itemp;
|
||
|
}
|
||
|
|
||
|
while (itemp->ai_up && (itemp == itemp->ai_up->ai_right))
|
||
|
itemp = itemp->ai_up;
|
||
|
|
||
|
if (!itemp->ai_up)
|
||
|
return NULL;
|
||
|
|
||
|
return itemp->ai_up;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
avl_remove(avl_root_t *rootp, avl_item_t *itemp)
|
||
|
{
|
||
|
avl_item_t *relocp, *replacep, *parentp = NULL;
|
||
|
#ifndef NDEBUG
|
||
|
assert(itemp->ai_indexed);
|
||
|
itemp->ai_indexed = 0;
|
||
|
#endif
|
||
|
/* If the item is directly replaceable, do it. */
|
||
|
if ((itemp->ai_left == NULL) || (itemp->ai_right == NULL)) {
|
||
|
parentp = itemp->ai_up;
|
||
|
replacep = itemp->ai_left;
|
||
|
if (replacep == NULL)
|
||
|
replacep = itemp->ai_right;
|
||
|
if (replacep != NULL)
|
||
|
replacep->ai_up = parentp;
|
||
|
if (parentp == NULL) {
|
||
|
rootp->ar_root = replacep;
|
||
|
} else {
|
||
|
if (itemp == parentp->ai_left)
|
||
|
parentp->ai_left = replacep;
|
||
|
else
|
||
|
parentp->ai_right = replacep;
|
||
|
|
||
|
avl_delete_fix(rootp, replacep, parentp);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Otherwise we do an indirect replacement with
|
||
|
* the item's leftmost right descendant.
|
||
|
*/
|
||
|
relocp = avl_next(itemp);
|
||
|
assert(relocp);
|
||
|
assert(relocp->ai_up != NULL);
|
||
|
assert(relocp->ai_left == NULL);
|
||
|
replacep = relocp->ai_right;
|
||
|
relocp->ai_left = itemp->ai_left;
|
||
|
if (relocp->ai_left != NULL)
|
||
|
relocp->ai_left->ai_up = relocp;
|
||
|
if (itemp->ai_up == NULL)
|
||
|
rootp->ar_root = relocp;
|
||
|
else {
|
||
|
if (itemp == itemp->ai_up->ai_left)
|
||
|
itemp->ai_up->ai_left = relocp;
|
||
|
else
|
||
|
itemp->ai_up->ai_right = relocp;
|
||
|
}
|
||
|
if (relocp == relocp->ai_up->ai_left) {
|
||
|
assert(relocp->ai_up != itemp);
|
||
|
relocp->ai_up->ai_left = replacep;
|
||
|
parentp = relocp->ai_up;
|
||
|
if (replacep != NULL)
|
||
|
replacep->ai_up = relocp->ai_up;
|
||
|
relocp->ai_right = itemp->ai_right;
|
||
|
} else {
|
||
|
assert(relocp->ai_up == itemp);
|
||
|
relocp->ai_right = replacep;
|
||
|
parentp = relocp;
|
||
|
}
|
||
|
if (relocp->ai_right != NULL)
|
||
|
relocp->ai_right->ai_up = relocp;
|
||
|
relocp->ai_up = itemp->ai_up;
|
||
|
relocp->ai_balance = itemp->ai_balance;
|
||
|
avl_delete_fix(rootp, replacep, parentp);
|
||
|
}
|
||
|
|
||
|
#endif /* !defined (__VG_AVL_H__) */
|