diff --git a/mod/box/box.lua b/mod/box/box.lua index a7887721dd60bf9d02068349fba3d768b145eff6..e582ca72e8c0e245b1ca82a09beed2d375535145 100644 --- a/mod/box/box.lua +++ b/mod/box/box.lua @@ -40,6 +40,15 @@ function box.select_range(sno, ino, limit, ...) return box.space[tonumber(sno)].index[tonumber(ino)]:select_range(tonumber(limit), ...) end +-- +-- Select a range of tuples in a given namespace via a given +-- index in reverse order. If key is NULL, starts from the end, otherwise +-- starts from the key. +-- +function box.select_reverse_range(sno, ino, limit, ...) + return box.space[tonumber(sno)].index[tonumber(ino)]:select_reverse_range(tonumber(limit), ...) +end + -- -- delete can be done only by the primary key, whose -- index is always 0. It doesn't accept compound keys @@ -103,6 +112,8 @@ function box.on_reload_configuration() -- index_mt.next = function(index, ...) return index.idx:next(...) end + index_mt.prev = function(index, ...) + return index.idx:prev(...) end -- index_mt.select_range = function(index, limit, ...) local range = {} @@ -114,6 +125,16 @@ function box.on_reload_configuration() end return unpack(range) end + index_mt.select_reverse_range = function(index, limit, ...) + local range = {} + for k, v in index.idx.prev, index.idx, ... do + if #range >= limit then + break + end + table.insert(range, v) + end + return unpack(range) + end -- local space_mt = {} space_mt.len = function(space) return space.index[0]:len() end @@ -122,6 +143,9 @@ function box.on_reload_configuration() space_mt.select_range = function(space, ino, limit, ...) return space.index[ino]:select_range(limit, ...) end + space_mt.select_reverse_range = function(space, ino, limit, ...) + return space.index[ino]:select_reverse_range(limit, ...) + end space_mt.select_limit = function(space, ino, offset, limit, ...) return box.select_limit(space.n, ino, offset, limit, ...) end diff --git a/mod/box/box.m b/mod/box/box.m index 115c83af0d454ea3db91c3af43d6557ef452f8f3..3635efecf6b0441014d9d65fd3fabcce6e8170b9 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -1072,7 +1072,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) } struct iterator *it = index->position; - [index initIterator: it :key :key_cardinality]; + [index initIterator: it :ITER_FORWARD :key :key_cardinality]; while ((tuple = it->next_equal(it)) != NULL) { if (tuple->flags & GHOST) @@ -2241,7 +2241,7 @@ mod_snapshot(struct log_io_iter *i) Index *pk = space[n].index[0]; struct iterator *it = pk->position; - [pk initIterator: it]; + [pk initIterator: it :ITER_FORWARD]; while ((tuple = it->next(it))) { snapshot_write_tuple(i, n, tuple); } diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m index b46089ca53b2ebcc08ce6fb13c5e0106ed6b82eb..dd4d77281c034ea4d858d7af2207e4ac069a7f66 100644 --- a/mod/box/box_lua.m +++ b/mod/box/box_lua.m @@ -372,6 +372,7 @@ void append_key_part(struct lua_State *L, int i, * Lua iterator over a Taratnool/Box index. * * (iteration_state, tuple) = index.next(index, [iteration_state]) + * (iteration_state, tuple) = index.prev(index, [iteration_state]) * * When [iteration_state] is absent or nil * returns a pointer to a new iterator and @@ -388,7 +389,7 @@ void append_key_part(struct lua_State *L, int i, * offset. */ static int -lbox_index_next(struct lua_State *L) +lbox_index_move(struct lua_State *L, enum iterator_type type) { Index *index = lua_checkindex(L, 1); int argc = lua_gettop(L) - 1; @@ -396,10 +397,11 @@ lbox_index_next(struct lua_State *L) if (argc == 0 || (argc == 1 && lua_type(L, 2) == LUA_TNIL)) { /* * If there is nothing or nil on top of the stack, - * start iteration from the beginning. + * start iteration from the beginning (ITER_FORWARD) or + * end (ITER_REVERSE). */ it = [index allocIterator]; - [index initIterator: it]; + [index initIterator: it :type]; lbox_pushiterator(L, it); } else if (argc > 1 || lua_type(L, 2) != LUA_TUSERDATA) { /* @@ -435,7 +437,7 @@ lbox_index_next(struct lua_State *L) "does not match index cardinality (%d)", cardinality, index->key_def->part_count); it = [index allocIterator]; - [index initIterator: it :key :cardinality]; + [index initIterator: it :type :key :cardinality]; lbox_pushiterator(L, it); } else { /* 1 item on the stack and it's a userdata. */ it = lua_checkiterator(L, 2); @@ -446,12 +448,35 @@ lbox_index_next(struct lua_State *L) return tuple ? 2 : 1; } +/** + * Lua forward index iterator function. + * See lbox_index_move comment for a functional + * description. + */ +static int +lbox_index_next(struct lua_State *L) +{ + return lbox_index_move(L, ITER_FORWARD); +} + +/** + * Lua reverse index iterator function. + * See lbox_index_move comment for a functional + * description. + */ +static int +lbox_index_prev(struct lua_State *L) +{ + return lbox_index_move(L, ITER_REVERSE); +} + static const struct luaL_reg lbox_index_meta[] = { {"__tostring", lbox_index_tostring}, {"__len", lbox_index_len}, {"min", lbox_index_min}, {"max", lbox_index_max}, {"next", lbox_index_next}, + {"prev", lbox_index_prev}, {NULL, NULL} }; @@ -506,7 +531,6 @@ iov_add_lua_table(struct lua_State *L, int index) iov_dup(field, field_len); *tuple_len += field_len_len + field_len; break; - case LUA_TCDATA: field = tarantool_lua_tostring(L, -1); field_len = strlen(field); diff --git a/mod/box/index.h b/mod/box/index.h index e3cb401c391dc15f4ece1ac8191093825c5537c3..07e706e74624724ad188f2bcd7c78c2c711df0b4 100644 --- a/mod/box/index.h +++ b/mod/box/index.h @@ -44,6 +44,8 @@ extern const char *field_data_type_strs[]; enum index_type { HASH, TREE, index_type_MAX }; extern const char *index_type_strs[]; +enum iterator_type { ITER_FORWARD, ITER_REVERSE }; + /** Descriptor of a single part in a multipart key. */ struct key_part { u32 fieldno; @@ -124,8 +126,9 @@ struct key_def { * initialized separately. */ - (struct iterator *) allocIterator; -- (void) initIterator: (struct iterator *) iterator; -- (void) initIterator: (struct iterator *) iterator :(void *) key +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type; +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) key :(int) part_count; @end diff --git a/mod/box/index.m b/mod/box/index.m index e304c32decc241e098b6e6ac15e4ce80ec032cdb..066745bfc2fba23f6af494e0f6e43a0fb023d910 100644 --- a/mod/box/index.m +++ b/mod/box/index.m @@ -166,16 +166,19 @@ iterator_first_equal(struct iterator *it) return NULL; } -- (void) initIterator: (struct iterator *) iterator +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type { (void) iterator; + (void) type; [self subclassResponsibility: _cmd]; } -- (void) initIterator: (struct iterator *) iterator :(void *) key +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) key :(int) part_count { (void) iterator; + (void) type; (void) part_count; (void) key; [self subclassResponsibility: _cmd]; @@ -205,8 +208,7 @@ hash_iterator(struct iterator *it) struct box_tuple * hash_iterator_next(struct iterator *iterator) { - assert(iterator->next = hash_iterator_next); - + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); while (it->h_pos != mh_end(it->hash)) { @@ -220,7 +222,7 @@ hash_iterator_next(struct iterator *iterator) void hash_iterator_free(struct iterator *iterator) { - assert(iterator->next = hash_iterator_next); + assert(iterator->next == hash_iterator_next); sfree(iterator); } @@ -247,7 +249,7 @@ hash_iterator_free(struct iterator *iterator) struct iterator *it = pk->position; struct box_tuple *tuple; - [pk initIterator: it]; + [pk initIterator: it :ITER_FORWARD]; while ((tuple = it->next(it))) [self replace: NULL :tuple]; @@ -387,25 +389,30 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type { + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); - assert(iterator->next = hash_iterator_next); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); it->base.next_equal = 0; /* Should not be used. */ it->h_pos = mh_begin(int_hash); it->hash = int_hash; } -- (void) initIterator: (struct iterator *) iterator :(void *) key +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) key :(int) part_count { - assert(iterator->next = hash_iterator_next); (void) part_count; /* Silence gcc warning in release mode. */ - + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); + if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); @@ -514,25 +521,30 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type { - assert(iterator->next = hash_iterator_next); - + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); it->base.next_equal = 0; /* Should not be used if not positioned. */ it->h_pos = mh_begin(int64_hash); it->hash = (struct mh_i32ptr_t *) int64_hash; } -- (void) initIterator: (struct iterator *) iterator :(void *) field +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) field :(int) part_count { (void) part_count; /* Silence gcc warning in release mode. */ - assert(iterator->next = hash_iterator_next); + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); + if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); @@ -633,24 +645,30 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type { - assert(iterator->next = hash_iterator_next); - + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); + it->base.next_equal = 0; /* Should not be used if not positioned. */ it->h_pos = mh_begin(str_hash); it->hash = (struct mh_i32ptr_t *) str_hash; } -- (void) initIterator: (struct iterator *) iterator :(void *) key +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) key :(int) part_count { (void) part_count; /* Silence gcc warning in release mode. */ - assert(iterator->next = hash_iterator_next); + assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); + if (type == ITER_REVERSE) + tnt_raise(IllegalParams, :"hash iterator is forward only"); + if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); diff --git a/mod/box/memcached.m b/mod/box/memcached.m index 3717294c505f4fc718ef84361c8625c2ce6d1cec..a0d57a9ab8f80a0baade5a403bce755d5a9fa106 100644 --- a/mod/box/memcached.m +++ b/mod/box/memcached.m @@ -285,7 +285,7 @@ flush_all(void *data) fiber_sleep(delay - ev_now()); struct box_tuple *tuple; struct iterator *it = [memcached_index allocIterator]; - [memcached_index initIterator: it]; + [memcached_index initIterator: it :ITER_FORWARD]; while ((tuple = it->next(it))) { meta(tuple)->exptime = 1; } @@ -505,7 +505,7 @@ memcached_expire_loop(void *data __attribute__((unused))) @try { restart: if (tuple == NULL) - [memcached_index initIterator: memcached_it]; + [memcached_index initIterator: memcached_it :ITER_FORWARD]; struct tbuf *keys_to_delete = tbuf_alloc(fiber->gc_pool); diff --git a/mod/box/tree.m b/mod/box/tree.m index ac0fe6d80ebbcfade42145fd841d0fa333c04128..ed396364e258904867a7d60f61095d93916cdff5 100644 --- a/mod/box/tree.m +++ b/mod/box/tree.m @@ -676,6 +676,16 @@ tree_iterator_next(struct iterator *iterator) return [it->index unfold: node]; } +static struct box_tuple * +tree_iterator_reverse_next(struct iterator *iterator) +{ + assert(iterator->next == tree_iterator_reverse_next); + struct tree_iterator *it = tree_iterator(iterator); + + void *node = sptree_index_iterator_reverse_next(it->iter); + return [it->index unfold: node]; +} + static struct box_tuple * tree_iterator_next_equal(struct iterator *iterator) { @@ -691,12 +701,26 @@ tree_iterator_next_equal(struct iterator *iterator) return NULL; } +static struct box_tuple * +tree_iterator_reverse_next_equal(struct iterator *iterator) +{ + assert(iterator->next == tree_iterator_reverse_next); + struct tree_iterator *it = tree_iterator(iterator); + + void *node = sptree_index_iterator_reverse_next(it->iter); + if (node != NULL + && it->index->tree.compare(&it->key_data, node, it->index) == 0) { + return [it->index unfold: node]; + } + + return NULL; +} + static void tree_iterator_free(struct iterator *iterator) { - assert(iterator->next == tree_iterator_next); + assert(iterator->free == tree_iterator_free); struct tree_iterator *it = tree_iterator(iterator); - if (it->iter) sptree_index_iterator_free(it->iter); @@ -821,30 +845,36 @@ tree_iterator_free(struct iterator *iterator) if (it) { memset(it, 0, sizeof(struct tree_iterator)); it->index = self; - it->base.next = tree_iterator_next; it->base.free = tree_iterator_free; } return (struct iterator *) it; } -- (void) initIterator: (struct iterator *) iterator +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type { - [self initIterator: iterator :NULL :0]; + [self initIterator: iterator :type :NULL :0]; } -- (void) initIterator: (struct iterator *) iterator - : (void *) key - : (int) part_count +- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type + :(void *) key + :(int) part_count { - assert(iterator->next == tree_iterator_next); + assert(iterator->free == tree_iterator_free); struct tree_iterator *it = tree_iterator(iterator); - it->base.next_equal = tree_iterator_next_equal; - it->key_data.data = key; it->key_data.part_count = part_count; fold_with_key_parts(key_def, &it->key_data); - sptree_index_iterator_init_set(&tree, &it->iter, &it->key_data); + + if (type == ITER_FORWARD) { + it->base.next = tree_iterator_next; + it->base.next_equal = tree_iterator_next_equal; + sptree_index_iterator_init_set(&tree, &it->iter, &it->key_data); + } else if (type == ITER_REVERSE) { + it->base.next = tree_iterator_reverse_next; + it->base.next_equal = tree_iterator_reverse_next_equal; + sptree_index_iterator_reverse_init_set(&tree, &it->iter, &it->key_data); + } } - (void) build: (Index *) pk @@ -868,7 +898,7 @@ tree_iterator_free(struct iterator *iterator) } struct iterator *it = pk->position; - [pk initIterator: it]; + [pk initIterator: it :ITER_FORWARD]; struct box_tuple *tuple; for (u32 i = 0; (tuple = it->next(it)) != NULL; ++i) { diff --git a/test/box/lua.result b/test/box/lua.result index 09b30eafb0d31a157775c4e5a1d5704833a8987b..398da2507c8a6de94762259a8cb30f692413c2be 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -17,6 +17,7 @@ lua for n in pairs(box) do print(' - box.', n) end - box.cfg - box.on_reload_configuration - box.update + - box.select_reverse_range - box.insert - box.select_limit - box.delete diff --git a/test/box_big/lua.result b/test/box_big/lua.result index 7824c223facbbab8a642fb92e964a64334222bac..f42e59f83b6602b689e6c7ebec3c6d5ec35ba69f 100644 --- a/test/box_big/lua.result +++ b/test/box_big/lua.result @@ -70,6 +70,10 @@ call box.select_range(5, 1, 2, 'of') Found 2 tuples: ['00000001', 'of', 'might', 'and', 'magic'] ['00000000', 'of', 'puppets'] +call box.select_reverse_range(5, 1, 2, 'of') +Found 2 tuples: +['00000000', 'of', 'puppets'] +['00000001', 'of', 'might', 'and', 'magic'] lua box.space[5]:truncate() --- ... @@ -110,3 +114,76 @@ lua num2 == tonumber64('18446744073709551615') --- - true ... +lua box.insert('9', 0, 0) +--- + - 0: {0} +... +lua box.insert('9', 1, 0) +--- + - 1: {0} +... +lua box.insert('9', 2, 0) +--- + - 2: {0} +... +lua box.insert('9', 3, 0) +--- + - 3: {0} +... +lua box.insert('9', 4, 0) +--- + - 4: {0} +... +lua box.insert('9', 5, 0) +--- + - 5: {0} +... +lua box.insert('9', 6, 0) +--- + - 6: {0} +... +lua box.insert('9', 7, 0) +--- + - 7: {0} +... +lua box.insert('9', 8, 0) +--- + - 8: {0} +... +lua box.insert('9', 9, 0) +--- + - 9: {0} +... +lua box.select_range(9, 1, 10) +--- + - 0: {0} + - 1: {0} + - 2: {0} + - 3: {0} + - 4: {0} + - 5: {0} + - 6: {0} + - 7: {0} + - 8: {0} + - 9: {0} +... +lua box.select_reverse_range(9, 1, 10) +--- + - 9: {0} + - 8: {0} + - 7: {0} + - 6: {0} + - 5: {0} + - 4: {0} + - 3: {0} + - 2: {0} + - 1: {0} + - 0: {0} +... +lua box.select_reverse_range(9, 1, 4) +--- + - 9: {0} + - 8: {0} + - 7: {0} + - 6: {0} +... diff --git a/test/box_big/lua.test b/test/box_big/lua.test index 557f85498b9b7acc86008536441694908eeed1fb..3484b4163ce145dff4e730815b17076aed4e9823 100644 --- a/test/box_big/lua.test +++ b/test/box_big/lua.test @@ -36,6 +36,7 @@ exec sql "insert into t5 values ('01234567', 'new', 'world')" exec sql "insert into t5 values ('00000000', 'of', 'puppets')" exec sql "insert into t5 values ('00000001', 'of', 'might', 'and', 'magic')" exec sql "call box.select_range(5, 1, 2, 'of')" +exec sql "call box.select_reverse_range(5, 1, 2, 'of')" exec admin "lua box.space[5]:truncate()" # @@ -51,3 +52,20 @@ exec admin "lua num,num1,num2 = box.unpack('lll', tu[0], tu[0], tu[0])" exec admin "lua num == tonumber64('18446744073709551615')" exec admin "lua num1 == tonumber64('18446744073709551615')" exec admin "lua num2 == tonumber64('18446744073709551615')" + +# +# Lua select_reverse_range +# +exec admin "lua box.insert('9', 0, 0)" +exec admin "lua box.insert('9', 1, 0)" +exec admin "lua box.insert('9', 2, 0)" +exec admin "lua box.insert('9', 3, 0)" +exec admin "lua box.insert('9', 4, 0)" +exec admin "lua box.insert('9', 5, 0)" +exec admin "lua box.insert('9', 6, 0)" +exec admin "lua box.insert('9', 7, 0)" +exec admin "lua box.insert('9', 8, 0)" +exec admin "lua box.insert('9', 9, 0)" +exec admin "lua box.select_range(9, 1, 10)" +exec admin "lua box.select_reverse_range(9, 1, 10)" +exec admin "lua box.select_reverse_range(9, 1, 4)" diff --git a/test/box_big/tarantool.cfg b/test/box_big/tarantool.cfg index ff574b31e74268e76ebb80fad58b3750ceebfa1b..97c4840d02e5f9550aadc677c5089d212c2850d5 100644 --- a/test/box_big/tarantool.cfg +++ b/test/box_big/tarantool.cfg @@ -143,3 +143,17 @@ space[8].index[0].type = "TREE" space[8].index[0].unique = 1 space[8].index[0].key_field[0].fieldno = 0 space[8].index[0].key_field[0].type = "NUM64" + +# lua select_reverse_range() testing +# https://blueprints.launchpad.net/tarantool/+spec/backward-tree-index-iterator +space[9].enabled = true +space[9].index[0].type = "TREE" +space[9].index[0].unique = 1 +space[9].index[0].key_field[0].fieldno = 0 +space[9].index[0].key_field[0].type = "NUM" +space[9].index[1].type = "TREE" +space[9].index[1].unique = 1 +space[9].index[1].key_field[0].fieldno = 1 +space[9].index[1].key_field[0].type = "NUM" +space[9].index[1].key_field[1].fieldno = 0 +space[9].index[1].key_field[1].type = "NUM" diff --git a/third_party/sptree.h b/third_party/sptree.h index 0bae478873bcf39e611abe98111d696ba3d30d66..5a65bf9533aa886f9fe4414f6ea345a1064ab45c 100644 --- a/third_party/sptree.h +++ b/third_party/sptree.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Mail.RU + * Copyright (C) 2012 Mail.RU * Copyright (C) 2010 Teodor Sigaev * * Redistribution and use in source and binary forms, with or without @@ -47,16 +47,16 @@ typedef struct sptree_node_pointers { } sptree_node_pointers; #define GET_SPNODE_LEFT(snp) ( (snp)->left ) -#define SET_SPNODE_LEFT(snp, v) (snp)->left = (v) -#define GET_SPNODE_RIGHT(snp) ( (snp)->right ) +#define SET_SPNODE_LEFT(snp, v) (snp)->left = (v) +#define GET_SPNODE_RIGHT(snp) ( (snp)->right ) #define SET_SPNODE_RIGHT(snp, v) (snp)->right = (v) #endif /* SPTREE_NODE_SELF */ #ifndef alpha -#define alpha ((double)0.75) +#define alpha ((double)0.75) #endif -#define COUNTALPHA(size) floor(log((double)(size))/log((double)1.0/alpha)) +#define COUNTALPHA(size) floor(log((double)(size))/log((double)1.0/alpha)) #define _GET_SPNODE_LEFT(n) GET_SPNODE_LEFT( t->lrpointers + (n) ) #define _SET_SPNODE_LEFT(n, v) SET_SPNODE_LEFT( t->lrpointers + (n), (v) ) @@ -76,15 +76,22 @@ typedef struct sptree_node_pointers { * int (*compare)(const void *key, const void *elem, void *arg), * int (*elemcompare)(const void *e1, const void *e2, void *arg), * void *arg) - * void* sptree_NAME_find(sptree_NAME *tree, void *key) + * * void sptree_NAME_insert(sptree_NAME *tree, void *value) * void sptree_NAME_delete(sptree_NAME *tree, void *value) + * void* sptree_NAME_find(sptree_NAME *tree, void *key) + * * spnode_t sptree_NAME_walk(sptree_NAME *t, void* array, spnode_t limit, spnode_t offset) - * sptree_NAME_walk_cb(sptree_NAME *t, int (*cb)(void* cb_arg, void* elem), void *cb_arg ) + * void sptree_NAME_walk_cb(sptree_NAME *t, int (*cb)(void* cb_arg, void* elem), void *cb_arg) + * * sptree_NAME_iterator* sptree_NAME_iterator_init(sptree_NAME *t) * void sptree_NAME_iterator_init_set(sptree_NAME *t, sptree_NAME_iterator **iterator, void *start) - * void* sptree_NAME_iterator_next(sptree_NAME_iterator *i) + * sptree_NAME_iterator* sptree_NAME_iterator_reverse_init(sptree_NAME *t) + * void sptree_NAME_iterator_reverse_init_set(sptree_NAME *t, sptree_NAME_iterator **iterator, void *start) * void sptree_NAME_iterator_free(sptree_NAME_iterator *i) + * + * void* sptree_NAME_iterator_next(sptree_NAME_iterator *i) + * void* sptree_NAME_iterator_reverse_next(sptree_NAME_iterator *i) */ #define SPTREE_DEF(name, realloc) \ @@ -108,8 +115,7 @@ typedef struct sptree_##name { } sptree_##name; \ \ static spnode_t \ -sptree_##name##_mktree(sptree_##name *t, spnode_t depth, \ - spnode_t start, spnode_t end) { \ +sptree_##name##_mktree(sptree_##name *t, spnode_t depth, spnode_t start, spnode_t end) { \ spnode_t half = ( (end + start) >> 1 ), tmp; \ \ if (depth > t->max_depth) t->max_depth = depth; \ @@ -130,16 +136,16 @@ sptree_##name##_mktree(sptree_##name *t, spnode_t depth, \ static inline void \ sptree_##name##_init(sptree_##name *t, size_t elemsize, void *m, \ - spnode_t nm, spnode_t nt, \ - int (*compare)(const void *, const void *, void *), \ - int (*elemcompare)(const void *, const void *, void *), \ - void *arg) { \ + spnode_t nm, spnode_t nt, \ + int (*compare)(const void *, const void *, void *), \ + int (*elemcompare)(const void *, const void *, void *), \ + void *arg) { \ memset(t, 0, sizeof(*t)); \ t->members = m; \ t->max_size = t->size = t->nmember = nm; \ t->ntotal = (nt==0) ? nm : nt; \ t->compare = compare != NULL ? compare : elemcompare; \ - t->elemcompare = elemcompare != NULL ? elemcompare : compare; \ + t->elemcompare = elemcompare != NULL ? elemcompare : compare; \ t->arg = arg; \ t->elemsize = elemsize; \ t->garbage_head = t->root = SPNIL; \ @@ -169,12 +175,12 @@ sptree_##name##_init(sptree_##name *t, size_t elemsize, void *m, static inline void \ sptree_##name##_destroy(sptree_##name *t) { \ if (t == NULL) return; \ - free(t->members); \ - free(t->lrpointers); \ + free(t->members); \ + free(t->lrpointers); \ } \ \ static inline void* \ -sptree_##name##_find(sptree_##name *t, void *k) { \ +sptree_##name##_find(sptree_##name *t, void *k) { \ spnode_t node = t->root; \ while(node != SPNIL) { \ int r = t->compare(k, ITHELEM(t, node), t->arg); \ @@ -190,7 +196,7 @@ sptree_##name##_find(sptree_##name *t, void *k) { } \ \ static inline void* \ -sptree_##name##_first(sptree_##name *t) { \ +sptree_##name##_first(sptree_##name *t) { \ spnode_t node = t->root; \ spnode_t first = SPNIL; \ while (node != SPNIL) { \ @@ -203,7 +209,7 @@ sptree_##name##_first(sptree_##name *t) { } \ \ static inline void* \ -sptree_##name##_last(sptree_##name *t) { \ +sptree_##name##_last(sptree_##name *t) { \ spnode_t node = t->root; \ spnode_t last = SPNIL; \ while (node != SPNIL) { \ @@ -247,7 +253,7 @@ sptree_##name##_get_place(sptree_##name *t) { } \ \ static inline spnode_t \ -sptree_##name##_flatten_tree(sptree_##name *t, spnode_t root, spnode_t head){ \ +sptree_##name##_flatten_tree(sptree_##name *t, spnode_t root, spnode_t head) { \ spnode_t node; \ if (root == SPNIL) \ return head; \ @@ -510,16 +516,22 @@ typedef struct sptree_##name##_iterator { } sptree_##name##_iterator; \ \ static inline sptree_##name##_iterator * \ -sptree_##name##_iterator_init(sptree_##name *t) { \ - sptree_##name##_iterator *i; \ - spnode_t node; \ - \ - if (t->root == SPNIL) return NULL; \ - \ - i = realloc(NULL, sizeof(*i) + sizeof(spnode_t) * (t->max_depth + 1)); \ +sptree_##name##_iterator_alloc(sptree_##name *t) { \ + sptree_##name##_iterator *i = \ + realloc(NULL, sizeof(*i) + sizeof(spnode_t) * (t->max_depth + 1)); \ i->t = t; \ i->level = 0; \ i->stack[0] = t->root; \ + return i; \ +} \ + \ +static inline sptree_##name##_iterator * \ +sptree_##name##_iterator_init(sptree_##name *t) { \ + sptree_##name##_iterator *i; \ + spnode_t node; \ + \ + if (t->root == SPNIL) return NULL; \ + i = sptree_##name##_iterator_alloc(t); \ \ while( (node = _GET_SPNODE_LEFT( i->stack[i->level] )) != SPNIL ) { \ i->level++; \ @@ -530,7 +542,8 @@ sptree_##name##_iterator_init(sptree_##name *t) { } \ \ static inline void \ -sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i, void *k) { \ +sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i, \ + void *k) { \ spnode_t node; \ int lastLevelEq = -1, cmp; \ \ @@ -569,14 +582,71 @@ sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i (*i)->level = lastLevelEq; \ } \ \ +static inline sptree_##name##_iterator * \ +sptree_##name##_iterator_reverse_init(sptree_##name *t) { \ + sptree_##name##_iterator *i; \ + spnode_t node; \ + \ + if (t->root == SPNIL) return NULL; \ + i = sptree_##name##_iterator_alloc(t); \ + \ + while( (node = _GET_SPNODE_RIGHT( i->stack[i->level] )) != SPNIL ) { \ + i->level++; \ + i->stack[i->level] = node; \ + } \ + \ + return i; \ +} \ + \ +static inline void \ +sptree_##name##_iterator_reverse_init_set(sptree_##name *t, sptree_##name##_iterator **i, \ + void *k) { \ + spnode_t node; \ + int lastLevelEq = -1, cmp; \ + \ + if ((*i) == NULL || t->max_depth > (*i)->max_depth) \ + *i = realloc(*i, sizeof(**i) + sizeof(spnode_t) * (t->max_depth + 1)); \ + \ + (*i)->t = t; \ + (*i)->level = -1; \ + if (t->root == SPNIL) { \ + (*i)->max_depth = 0; \ + return; \ + } \ + \ + (*i)->max_depth = t->max_depth; \ + (*i)->stack[0] = t->root; \ + \ + node = t->root; \ + while(node != SPNIL) { \ + cmp = t->compare(k, ITHELEM(t, node), t->arg); \ + \ + (*i)->level++; \ + (*i)->stack[(*i)->level] = node; \ + \ + if (cmp < 0) { \ + (*i)->level--; \ + node = _GET_SPNODE_LEFT(node); \ + } else if (cmp > 0) { \ + node = _GET_SPNODE_RIGHT(node); \ + } else { \ + lastLevelEq = (*i)->level; \ + node = _GET_SPNODE_RIGHT(node); \ + } \ + } \ + \ + if (lastLevelEq >= 0) \ + (*i)->level = lastLevelEq; \ +} \ + \ static inline void \ -sptree_##name##_iterator_free(sptree_##name##_iterator *i) { \ +sptree_##name##_iterator_free(sptree_##name##_iterator *i) { \ if (i == NULL) return; \ free(i); \ } \ \ static inline void* \ -sptree_##name##_iterator_next(sptree_##name##_iterator *i) { \ +sptree_##name##_iterator_next(sptree_##name##_iterator *i) { \ sptree_##name *t; \ spnode_t node, returnNode = SPNIL; \ \ @@ -596,6 +666,29 @@ sptree_##name##_iterator_next(sptree_##name##_iterator *i) { } \ \ return (returnNode == SPNIL) ? NULL : ITHELEM(t, returnNode); \ +} \ + \ +static inline void* \ +sptree_##name##_iterator_reverse_next(sptree_##name##_iterator *i) { \ + sptree_##name *t; \ + spnode_t node, returnNode = SPNIL; \ + \ + if (i == NULL) return NULL; \ + \ + t = i->t; \ + if ( i->level >= 0 ) { \ + returnNode = i->stack[i->level]; \ + \ + node = _GET_SPNODE_LEFT( i->stack[i->level] ); \ + i->level--; \ + while( node != SPNIL ) { \ + i->level++; \ + i->stack[i->level] = node; \ + node = _GET_SPNODE_RIGHT( i->stack[i->level] ); \ + } \ + } \ + \ + return (returnNode == SPNIL) ? NULL : ITHELEM(t, returnNode); \ } #endif