356 lines
9.2 KiB
C++
356 lines
9.2 KiB
C++
/*
|
|
* art.h
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2020 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
#include <stdint.h>
|
|
#include "flow/Arena.h"
|
|
#include "flow/Platform.h"
|
|
|
|
#ifndef ART_H
|
|
#define ART_H
|
|
|
|
|
|
struct art_iterator;
|
|
|
|
struct art_tree {
|
|
enum ART_NODE_TYPE : uint8_t{
|
|
ART_LEAF = 0, ART_NODE4 = 1, ART_NODE16 = 2, ART_NODE48 = 3, ART_NODE256 = 4,
|
|
ART_NODE4_KV = 5, ART_NODE16_KV = 6, ART_NODE48_KV = 7, ART_NODE256_KV = 8
|
|
};
|
|
#define ART_MIN_LEAF_UNSET 1UL
|
|
#define ART_LEAF_MATCH_KEY 1
|
|
#define ART_LEAF_SMALLER_KEY 2
|
|
#define ART_LEAF_LARGER_KEY 3
|
|
#define ART_I_FOUND 2
|
|
#define ART_I_DEPTH 3
|
|
#define ART_I_BACKTRACK 4
|
|
|
|
#define ART_NEXT 1
|
|
#define ART_PREV -1
|
|
#define ART_NEITHER 0
|
|
|
|
|
|
#define ART_IS_LEAF(x) ( (*((ART_NODE_TYPE*)x) == ART_LEAF))
|
|
|
|
#define ART_LEAF_RAW(x) ((art_leaf*)(x))
|
|
|
|
#define ART_LEAF_DISPL(x) fat_leaf_offset[(x)->type]
|
|
#define ART_FAT_NODE_LEAF(node_ptr) (*((art_leaf**) (((char*)(node_ptr))+ART_LEAF_DISPL(node_ptr))))
|
|
|
|
//In Bytes
|
|
//This is needed so that we can pre-allocate a static stack to perform efficient backtracking in iterative_bound
|
|
#define ART_MAX_KEY_LEN 10000
|
|
|
|
#define _mm_cmpge_epu8(a, b) \
|
|
_mm_cmpeq_epi8(_mm_max_epu8(a, b), a)
|
|
|
|
#define _mm_cmple_epu8(a, b) _mm_cmpge_epu8(b, a)
|
|
|
|
#define _mm_cmpgt_epu8(a, b) \
|
|
_mm_xor_si128(_mm_cmple_epu8(a, b), _mm_set1_epi8(-1))
|
|
|
|
#define _mm_cmplt_epu8(a, b) _mm_cmpgt_epu8(b, a)
|
|
|
|
#define ART_MAX_PREFIX_LEN 10
|
|
|
|
|
|
/**
|
|
* This struct is included as part
|
|
* of all the various node sizes
|
|
*/
|
|
struct art_node {
|
|
ART_NODE_TYPE type;
|
|
uint8_t num_children;
|
|
uint32_t partial_len;
|
|
unsigned char partial[ART_MAX_PREFIX_LEN];
|
|
};
|
|
|
|
/**
|
|
* Represents a leaf. These are
|
|
* of arbitrary size, as they include the key.
|
|
* Note that the first two fields must be the same as in art_node
|
|
*/
|
|
struct art_leaf {
|
|
ART_NODE_TYPE type;
|
|
void *value;
|
|
art_leaf *prev = nullptr;
|
|
art_leaf *next = nullptr;
|
|
KeyRef key;
|
|
|
|
art_leaf(const KeyRef &k, void *v) : type(ART_LEAF), value(v), key(k.begin(), k.size()) {
|
|
}
|
|
|
|
art_leaf(const uint8_t *ptr, int len, void *v) : type(ART_LEAF), value(v), key(ptr, len) {}
|
|
|
|
};
|
|
|
|
/**
|
|
* Small node with only 4 children
|
|
*/
|
|
struct art_node4 {
|
|
art_node n;
|
|
unsigned char keys[4];
|
|
art_node *children[4];
|
|
};
|
|
|
|
/**
|
|
* Node with 16 children
|
|
*/
|
|
struct art_node16 {
|
|
art_node n;
|
|
unsigned char keys[16];
|
|
art_node *children[16];
|
|
};
|
|
|
|
/**
|
|
* Node with 48 children, but
|
|
* a full 256 byte field.
|
|
*/
|
|
struct art_node48 {
|
|
art_node n;
|
|
unsigned char keys[256];
|
|
art_node *children[48];
|
|
};
|
|
|
|
/**
|
|
* Full node with 256 children
|
|
*/
|
|
struct art_node256 {
|
|
art_node n;
|
|
art_node *children[256];
|
|
};
|
|
|
|
/**
|
|
* Small node with only 4 children
|
|
*/
|
|
struct art_node4_kv {
|
|
art_node4 n;
|
|
art_leaf *leaf;
|
|
};
|
|
|
|
/**
|
|
* Node with 16 children
|
|
*/
|
|
struct art_node16_kv {
|
|
art_node16 n;
|
|
art_leaf *leaf;
|
|
};
|
|
|
|
/**
|
|
* Node with 48 children, but
|
|
* a full 256 byte field.
|
|
*/
|
|
struct art_node48_kv {
|
|
art_node48 n;
|
|
art_leaf *leaf;
|
|
};
|
|
|
|
/**
|
|
* Full node with 256 children
|
|
*/
|
|
struct art_node256_kv {
|
|
art_node256 n;
|
|
art_leaf *leaf;
|
|
};
|
|
|
|
|
|
private:
|
|
art_node *root;
|
|
uint64_t size;
|
|
Arena *arena;
|
|
static int fat_leaf_offset[9];
|
|
static int node_sizes[9];
|
|
|
|
static int check_bound_node(art_node *n, const KeyRef &k, int *depth_p, art_leaf **result, bool strict);
|
|
|
|
static int art_bound_leaf(art_node *n, const KeyRef &k, int depth, art_leaf **result);
|
|
|
|
static art_leaf *minimum(art_node *n);
|
|
|
|
static art_leaf *maximum(art_node *n);
|
|
|
|
static int leaf_matches_signed(art_leaf *n, const KeyRef &k, int depth);
|
|
|
|
static int leaf_matches(const art_leaf *n, const KeyRef &k, int depth);
|
|
|
|
static int signed_prefix_mismatch(art_node *n, const KeyRef &k, int depth, art_leaf **min_leaf, bool find_min);
|
|
|
|
static int prefix_mismatch(art_node *n, KeyRef &k, int depth, art_leaf **minout);
|
|
|
|
static art_leaf *minimum_kv(art_node *n);
|
|
|
|
static art_node **find_child(art_node *n, unsigned char c);
|
|
|
|
static void find_next(art_node *n, unsigned char c, art_node **out);
|
|
|
|
static void find_prev(art_node *n, unsigned char c, art_node **out);
|
|
|
|
static int art_next_prev(art_node *n, unsigned char c, art_node **out);
|
|
|
|
void art_bound_iterative(art_node *n, const KeyRef &k, int depth, art_leaf **result, bool strict);
|
|
|
|
static inline int min(int a, int b) {
|
|
return (a < b) ? a : b;
|
|
}
|
|
|
|
static inline void *SET_LEAF(void *x) {
|
|
(*((uint8_t *) x) = 0);
|
|
return x;
|
|
}
|
|
|
|
static int check_prefix(const art_node *n, const KeyRef &k, int depth);
|
|
|
|
void recursive_delete_binary(art_node *n, art_node **ref, const KeyRef &k, int depth);
|
|
|
|
void remove_child(art_node *n, art_node **ref, unsigned char c, art_node **l, int depth);
|
|
|
|
//needs this pointer to do allocation
|
|
art_node *alloc_node(ART_NODE_TYPE type);
|
|
|
|
art_node *alloc_kv_node(ART_NODE_TYPE type);
|
|
|
|
art_leaf *make_leaf(const KeyRef &k, void *value);
|
|
|
|
static void remove_fat_child(art_node *n, art_node **ref, int depth);
|
|
|
|
static void remove_fat_child4(art_node4_kv *n, art_node **ref, int depth);
|
|
|
|
static void remove_child4(art_node4 *n, art_node **ref, art_node **l, int depth);
|
|
|
|
static void remove_fat_child16(art_node16_kv *n, art_node **ref);
|
|
|
|
void remove_child16(art_node16 *n, art_node **ref, art_node **l);
|
|
|
|
static void remove_fat_child48(art_node48_kv *n, art_node **ref);
|
|
|
|
void remove_child48(art_node48 *n, art_node **ref, unsigned char c);
|
|
|
|
static void remove_fat_child256(art_node256_kv *n, art_node **ref);
|
|
|
|
void remove_child256(art_node256 *n, art_node **ref, unsigned char c);
|
|
|
|
static void copy_header(art_node *dest, art_node *src);
|
|
|
|
art_leaf *iterative_insert(art_node *root, art_node **root_ptr, KeyRef &k, void *value,
|
|
int depth, int *old, int replace_existing);
|
|
|
|
art_leaf *insert_leaf(art_node *n, art_node **ref, const KeyRef &k, void *value, int depth,
|
|
int *old, int replace_existing);
|
|
|
|
art_leaf *insert_fat_node(art_node *n, art_node **ref, const KeyRef &k, void *value, int depth,
|
|
int *old, art_leaf *min_of_n, int replace_existing);
|
|
|
|
art_leaf *insert_internal_node(art_node *n, art_node **ref, const KeyRef &k, void *value, int depth,
|
|
int *old, art_leaf *min_of_n, int prefix_diff, int replace_existing);
|
|
|
|
art_leaf *insert_child(art_node *n, art_node **ref, const KeyRef &k, void *value, int depth,
|
|
int *old, int replace_existing);
|
|
|
|
static inline int longest_common_prefix(const KeyRef &k1, const KeyRef &k2, int depth);
|
|
|
|
static void insert_after(art_leaf *l_new, art_leaf *l_existing);
|
|
|
|
static void insert_before(art_leaf *l_new, art_leaf *l_existing);
|
|
|
|
void add_child(art_node *n, art_node **ref, unsigned char c, void *child);
|
|
|
|
void add_child256(art_node256 *n, art_node **ref, unsigned char c, void *child);
|
|
|
|
void add_child48(art_node48 *n, art_node **ref, unsigned char c, void *child);
|
|
|
|
void add_child16(art_node16 *n, art_node **ref, unsigned char c, void *child);
|
|
|
|
void add_child4(art_node4 *n, art_node **ref, unsigned char c, void *child);
|
|
|
|
public:
|
|
art_tree(Arena &a) {
|
|
this->arena = &a;
|
|
this->root = alloc_node(ART_NODE4); //Sentinel node. Also needed for empty key
|
|
this->size = 0;
|
|
}
|
|
|
|
art_iterator lower_bound(const KeyRef &k);
|
|
|
|
art_iterator upper_bound(const KeyRef &k);
|
|
|
|
art_iterator insert(KeyRef &key, void *value);
|
|
|
|
art_iterator insert_if_absent(KeyRef &key, void *value, int *replaced);
|
|
|
|
void erase(const art_iterator &it);
|
|
|
|
uint64_t count() {
|
|
return size;
|
|
}
|
|
|
|
|
|
}; //art_tree
|
|
|
|
struct art_iterator {
|
|
|
|
private:
|
|
art_tree::art_leaf *leaf;
|
|
|
|
public:
|
|
art_iterator(art_tree::art_leaf *l) {
|
|
leaf = l;
|
|
}
|
|
|
|
art_iterator(const art_iterator &i) {
|
|
leaf = i.leaf;
|
|
}
|
|
|
|
art_iterator() {
|
|
leaf = nullptr;
|
|
}
|
|
|
|
art_iterator &operator++() {
|
|
leaf = leaf->next;
|
|
return (*this);
|
|
}
|
|
|
|
art_iterator &operator--() {
|
|
leaf = leaf->prev;
|
|
return (*this);
|
|
}
|
|
|
|
bool operator==(const art_iterator &other) const {
|
|
return leaf == other.leaf;
|
|
}
|
|
|
|
bool operator!=(const art_iterator &other) const {
|
|
return leaf != other.leaf;
|
|
}
|
|
|
|
const KeyRef &key() const {
|
|
return leaf->key;
|
|
}
|
|
|
|
void *value() const {
|
|
return leaf->value;
|
|
}
|
|
|
|
void **value_ptr() {
|
|
return &(leaf->value);
|
|
}
|
|
};
|
|
|
|
|
|
#endif //ART_H
|