/* -*- c-basic-offset: 2 -*- */
/*
Copyright ( C ) 2009 - 2017 Brazil
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License version 2 . 1 as published by the Free Software Foundation .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1335 USA
*/
#include "grn.h"
#include <string.h>
#include <limits.h>
#include "grn_pat.h"
#include "grn_output.h"
#include "grn_util.h"
#include "grn_normalizer.h"
#define GRN_PAT_DELETED (GRN_ID_MAX + 1 )
#define GRN_PAT_SEGMENT_SIZE 0 x400000
#define W_OF_KEY_IN_A_SEGMENT 22
#define W_OF_PAT_IN_A_SEGMENT 18
#define W_OF_SIS_IN_A_SEGMENT 19
#define KEY_MASK_IN_A_SEGMENT 0 x3fffff
#define PAT_MASK_IN_A_SEGMENT 0 x3ffff
#define SIS_MASK_IN_A_SEGMENT 0 x7ffff
#define SEG_NOT_ASSIGNED 0 xffff
#define GRN_PAT_MAX_SEGMENT 0 x1000
#define GRN_PAT_MDELINFOS (GRN_PAT_NDELINFOS - 1 )
#define GRN_PAT_BIN_KEY 0 x70000
typedef struct {
grn_id lr[2 ];
/*
lr [ 0 ] : the left node .
lr [ 1 ] : the right node .
The left node has 0 at the nth bit at the nth byte .
The right node has 1 at the nth bit at the nth byte .
' check ' value indicate ' at the nth bit at the nth byte ' .
The both available nodes has larger check value rather
than the current node .
The first node ( PAT_AT ( pat , GRN_ID_NIL , node ) ) has only
the right node and the node is the start point .
*/
uint32_t key;
/*
PAT_IMD ( node ) = = 0 : key bytes offset in memory map .
PAT_IMD ( node ) = = 1 : the key bytes .
*/
uint16_t check;
/*
nth byte : 12 , nth bit : 3 , terminated : 1
nth byte is different in key bytes : ( check > > 4 ) : max = = 4095
the left most byte is the 0 th byte and the right most byte is the 11 th byte .
nth bit is different in nth byte : ( ( check > > 1 ) & 0 b111 )
the left most bit is the 0 th bit and the right most bit is the 7 th bit .
terminated : ( check & 0 b1 )
terminated = = 1 : key is terminated .
*/
uint16_t bits;
/* length: 13, immediate: 1, deleting: 1 */
} pat_node;
#define PAT_DELETING (1 <<1 )
#define PAT_IMMEDIATE (1 <<2 )
#define PAT_DEL(x) ((x)->bits & PAT_DELETING)
#define PAT_IMD(x) ((x)->bits & PAT_IMMEDIATE)
#define PAT_LEN(x) (((x)->bits >> 3 ) + 1 )
#define PAT_CHK(x) ((x)->check)
#define PAT_DEL_ON(x) ((x)->bits |= PAT_DELETING)
#define PAT_IMD_ON(x) ((x)->bits |= PAT_IMMEDIATE)
#define PAT_DEL_OFF(x) ((x)->bits &= ~PAT_DELETING)
#define PAT_IMD_OFF(x) ((x)->bits &= ~PAT_IMMEDIATE)
#define PAT_LEN_SET(x,v) ((x)->bits = ((x)->bits & ((1 <<3 ) - 1 ))|(((v) - 1 ) << 3 ))
#define PAT_CHK_SET(x,v) ((x)->check = (v))
typedef struct {
grn_id children;
grn_id sibling;
} sis_node;
enum {
segment_key = 0 ,
segment_pat = 1 ,
segment_sis = 2
};
void grn_p_pat_node(grn_ctx *ctx, grn_pat *pat, pat_node *node);
/* error utilities */
inline static int
grn_pat_name(grn_ctx *ctx, grn_pat *pat, char *buffer, int buffer_size)
{
int name_size;
if (DB_OBJ(pat)->id == GRN_ID_NIL) {
grn_strcpy(buffer, buffer_size, "(anonymous)" );
name_size = strlen(buffer);
} else {
name_size = grn_obj_name(ctx, (grn_obj *)pat, buffer, buffer_size);
}
return name_size;
}
/* bit operation */
#define nth_bit(key,n,l) ((((key)[(n)>>4 ]) >> (7 - (((n)>>1 ) & 7 ))) & 1 )
/* segment operation */
/* patricia array operation */
#define PAT_AT(pat,id,n) do {\
int flags = 0 ;\
GRN_IO_ARRAY_AT(pat->io, segment_pat, id, &flags, n);\
} while (0 )
inline static pat_node *
pat_get(grn_ctx *ctx, grn_pat *pat, grn_id id)
{
pat_node *res;
int flags = GRN_TABLE_ADD;
if (id > GRN_ID_MAX) { return NULL; }
GRN_IO_ARRAY_AT(pat->io, segment_pat, id, &flags, res);
return res;
}
/* sis operation */
inline static sis_node *
sis_at(grn_ctx *ctx, grn_pat *pat, grn_id id)
{
sis_node *res;
int flags = 0 ;
if (id > GRN_ID_MAX) { return NULL; }
GRN_IO_ARRAY_AT(pat->io, segment_sis, id, &flags, res);
return res;
}
inline static sis_node *
sis_get(grn_ctx *ctx, grn_pat *pat, grn_id id)
{
sis_node *res;
int flags = GRN_TABLE_ADD;
if (id > GRN_ID_MAX) { return NULL; }
GRN_IO_ARRAY_AT(pat->io, segment_sis, id, &flags, res);
return res;
}
#define MAX_LEVEL 16
static void
sis_collect(grn_ctx *ctx, grn_pat *pat, grn_hash *h, grn_id id, uint32_t level)
{
uint32_t *offset;
sis_node *sl = sis_at(ctx, pat, id);
if (sl) {
grn_id sid = sl->children;
while (sid && sid != id) {
if (grn_hash_add(ctx, h, &sid, sizeof (grn_id), (void **) &offset, NULL)) {
*offset = level;
if (level < MAX_LEVEL) { sis_collect(ctx, pat, h, sid, level + 1 ); }
if (!(sl = sis_at(ctx, pat, sid))) { break ; }
sid = sl->sibling;
} else {
/* todo : must be handled */
}
}
}
}
/* key operation */
#define KEY_AT(pat,pos,ptr,addp) do {\
int flags = addp;\
GRN_IO_ARRAY_AT(pat->io, segment_key, pos, &flags, ptr);\
} while (0 )
inline static uint32_t
key_put(grn_ctx *ctx, grn_pat *pat, const uint8_t *key, uint32_t len)
{
uint32_t res, ts;
// if (len >= GRN_PAT_SEGMENT_SIZE) { return 0; /* error */ }
res = pat->header->curr_key;
if (res < GRN_PAT_MAX_TOTAL_KEY_SIZE &&
len > GRN_PAT_MAX_TOTAL_KEY_SIZE - res) {
char name[GRN_TABLE_MAX_KEY_SIZE];
int name_size;
name_size = grn_pat_name(ctx, pat, name, GRN_TABLE_MAX_KEY_SIZE);
ERR(GRN_NOT_ENOUGH_SPACE,
"[pat][key][put] total key size is over: <%.*s>: "
"max=%u: current=%u: new key size=%u" ,
name_size, name,
GRN_PAT_MAX_TOTAL_KEY_SIZE,
res,
len);
return 0 ;
}
ts = (res + len) >> W_OF_KEY_IN_A_SEGMENT;
if (res >> W_OF_KEY_IN_A_SEGMENT != ts) {
res = pat->header->curr_key = ts << W_OF_KEY_IN_A_SEGMENT;
}
{
uint8_t *dest;
KEY_AT(pat, res, dest, GRN_TABLE_ADD);
if (!dest) {
char name[GRN_TABLE_MAX_KEY_SIZE];
int name_size;
name_size = grn_pat_name(ctx, pat, name, GRN_TABLE_MAX_KEY_SIZE);
ERR(GRN_NO_MEMORY_AVAILABLE,
"[pat][key][put] failed to allocate memory for new key: <%.*s>: "
"new offset:%u key size:%u" ,
name_size, name,
res,
len);
return 0 ;
}
grn_memcpy(dest, key, len);
}
pat->header->curr_key += len;
return res;
}
inline static uint8_t *
pat_node_get_key(grn_ctx *ctx, grn_pat *pat, pat_node *n)
{
if (PAT_IMD(n)) {
return (uint8_t *) &n->key;
} else {
uint8_t *res;
KEY_AT(pat, n->key, res, 0 );
return res;
}
}
inline static grn_rc
pat_node_set_key(grn_ctx *ctx, grn_pat *pat, pat_node *n, const uint8_t *key, uint32_t len)
{
grn_rc rc;
if (!key || !len) { return GRN_INVALID_ARGUMENT; }
PAT_LEN_SET(n, len);
if (len <= sizeof (uint32_t)) {
PAT_IMD_ON(n);
grn_memcpy(&n->key, key, len);
rc = GRN_SUCCESS;
} else {
PAT_IMD_OFF(n);
n->key = key_put(ctx, pat, key, len);
rc = ctx->rc;
}
return rc;
}
/* delinfo operation */
enum {
/* The delinfo is currently not used. */
DL_EMPTY = 0 ,
/*
* stat - > d refers to a deleting node ( in a tree ) .
* The deletion requires an additional operation .
*/
DL_PHASE1,
/*
* stat - > d refers to a deleted node ( not in a tree ) .
* The node is pending for safety .
*/
DL_PHASE2
};
inline static grn_pat_delinfo *
delinfo_search(grn_pat *pat, grn_id id)
{
int i;
grn_pat_delinfo *di;
for (i = (pat->header->curr_del2) & GRN_PAT_MDELINFOS;
i != pat->header->curr_del;
i = (i + 1 ) & GRN_PAT_MDELINFOS) {
di = &pat->header->delinfos[i];
if (di->stat != DL_PHASE1) { continue ; }
if (di->ld == id) { return di; }
if (di->d == id) { return di; }
}
return NULL;
}
inline static grn_rc
delinfo_turn_2(grn_ctx *ctx, grn_pat *pat, grn_pat_delinfo *di)
{
grn_id d, *p = NULL;
pat_node *ln, *dn;
// grn_log("delinfo_turn_2> di->d=%d di->ld=%d stat=%d", di->d, di->ld, di->stat);
if (di->stat != DL_PHASE1) {
return GRN_SUCCESS;
}
PAT_AT(pat, di->ld, ln);
if (!ln) {
return GRN_INVALID_ARGUMENT;
}
d = di->d;
if (!d) {
return GRN_INVALID_ARGUMENT;
}
PAT_AT(pat, d, dn);
if (!dn) {
return GRN_INVALID_ARGUMENT;
}
PAT_DEL_OFF(ln);
PAT_DEL_OFF(dn);
{
grn_id *p0;
pat_node *rn;
int c0 = -1 , c;
uint32_t len = PAT_LEN(dn) * 16 ;
const uint8_t *key = pat_node_get_key(ctx, pat, dn);
if (!key) {
return GRN_INVALID_ARGUMENT;
}
PAT_AT(pat, 0 , rn);
p0 = &rn->lr[1 ];
for (;;) {
grn_id r = *p0;
if (!r) {
break ;
}
if (r == d) {
p = p0;
break ;
}
PAT_AT(pat, r, rn);
if (!rn) {
return GRN_FILE_CORRUPT;
}
c = PAT_CHK(rn);
if ((int ) c <= (int ) c0 || (int ) len <= (int ) c) {
break ;
}
if (c & 1 ) {
p0 = (c + 1 < (int ) len) ? &rn->lr[1 ] : &rn->lr[0 ];
} else {
p0 = &rn->lr[nth_bit((uint8_t *)key, c, len)];
}
c0 = c;
}
}
if (p) {
PAT_CHK_SET(ln, PAT_CHK(dn));
ln->lr[1 ] = dn->lr[1 ];
ln->lr[0 ] = dn->lr[0 ];
*p = di->ld;
} else {
/* debug */
int j;
grn_id dd;
grn_pat_delinfo *ddi;
GRN_LOG(ctx, GRN_LOG_DEBUG, "failed to find d=%d" , d);
for (j = (pat->header->curr_del2 + 1 ) & GRN_PAT_MDELINFOS;
j != pat->header->curr_del;
j = (j + 1 ) & GRN_PAT_MDELINFOS) {
ddi = &pat->header->delinfos[j];
if (ddi->stat != DL_PHASE1) { continue ; }
PAT_AT(pat, ddi->ld, ln);
if (!ln) { continue ; }
if (!(dd = ddi->d)) { continue ; }
if (d == ddi->ld) {
GRN_LOG(ctx, GRN_LOG_DEBUG, "found!!!, d(%d) become ld of (%d)" , d, dd);
}
}
/* debug */
}
di->stat = DL_PHASE2;
di->d = d;
// grn_log("delinfo_turn_2< di->d=%d di->ld=%d", di->d, di->ld);
return GRN_SUCCESS;
}
inline static grn_rc
delinfo_turn_3(grn_ctx *ctx, grn_pat *pat, grn_pat_delinfo *di)
{
pat_node *dn;
uint32_t size;
if (di->stat != DL_PHASE2) { return GRN_SUCCESS; }
PAT_AT(pat, di->d, dn);
if (!dn) { return GRN_INVALID_ARGUMENT; }
if (di->shared) {
PAT_IMD_ON(dn);
size = 0 ;
} else {
if (PAT_IMD(dn)) {
size = 0 ;
} else {
size = PAT_LEN(dn);
}
}
di->stat = DL_EMPTY;
// dn->lr[1] = GRN_PAT_DELETED;
dn->lr[0 ] = pat->header->garbages[size];
pat->header->garbages[size] = di->d;
return GRN_SUCCESS;
}
inline static grn_pat_delinfo *
delinfo_new(grn_ctx *ctx, grn_pat *pat)
{
grn_pat_delinfo *res = &pat->header->delinfos[pat->header->curr_del];
uint32_t n = (pat->header->curr_del + 1 ) & GRN_PAT_MDELINFOS;
int gap = ((n + GRN_PAT_NDELINFOS - pat->header->curr_del2) & GRN_PAT_MDELINFOS)
- (GRN_PAT_NDELINFOS / 2 );
while (gap-- > 0 ) {
if (delinfo_turn_2(ctx, pat, &pat->header->delinfos[pat->header->curr_del2])) {
GRN_LOG(ctx, GRN_LOG_CRIT, "d2 failed: %d" , pat->header->delinfos[pat->header->curr_del2].ld);
}
pat->header->curr_del2 = (pat->header->curr_del2 + 1 ) & GRN_PAT_MDELINFOS;
}
if ((int ) n == (int ) pat->header->curr_del3) {
if (delinfo_turn_3(ctx, pat, &pat->header->delinfos[pat->header->curr_del3])) {
GRN_LOG(ctx, GRN_LOG_CRIT, "d3 failed: %d" , pat->header->delinfos[pat->header->curr_del3].ld);
}
pat->header->curr_del3 = (pat->header->curr_del3 + 1 ) & GRN_PAT_MDELINFOS;
}
pat->header->curr_del = n;
return res;
}
/* pat operation */
inline static grn_pat *
_grn_pat_create(grn_ctx *ctx, grn_pat *pat,
const char *path, uint32_t key_size,
uint32_t value_size, uint32_t flags) {
grn_io *io;
pat_node *node0;
struct grn_pat_header *header;
uint32_t entry_size, w_of_element;
grn_encoding encoding = ctx->encoding;
if (flags & GRN_OBJ_KEY_WITH_SIS) {
entry_size = sizeof (sis_node) + value_size;
} else {
entry_size = value_size;
}
for (w_of_element = 0 ; (1 << w_of_element) < entry_size; w_of_element++) {
/* nop */
}
{
grn_io_array_spec array_spec[3 ];
array_spec[segment_key].w_of_element = 0 ;
array_spec[segment_key].max_n_segments = 0 x400;
array_spec[segment_pat].w_of_element = 4 ;
array_spec[segment_pat].max_n_segments = 1 << (30 - (22 - 4 ));
array_spec[segment_sis].w_of_element = w_of_element;
array_spec[segment_sis].max_n_segments = 1 << (30 - (22 - w_of_element));
io = grn_io_create_with_array(ctx, path, sizeof (struct grn_pat_header),
GRN_PAT_SEGMENT_SIZE, grn_io_auto, 3 , array_spec);
}
if (!io) { return NULL; }
if (encoding == GRN_ENC_DEFAULT) { encoding = grn_gctx.encoding; }
header = grn_io_header(io);
grn_io_set_type(io, GRN_TABLE_PAT_KEY);
header->flags = flags;
header->encoding = encoding;
header->key_size = key_size;
header->value_size = value_size;
header->n_entries = 0 ;
header->curr_rec = 0 ;
header->curr_key = 0 ;
header->curr_del = 0 ;
header->curr_del2 = 0 ;
header->curr_del3 = 0 ;
header->n_garbages = 0 ;
header->tokenizer = GRN_ID_NIL;
if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
pat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1 );
header->normalizer = grn_obj_id(ctx, pat->normalizer);
} else {
pat->normalizer = NULL;
header->normalizer = GRN_ID_NIL;
}
header->truncated = GRN_FALSE;
GRN_PTR_INIT(&(pat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
pat->io = io;
pat->header = header;
pat->key_size = key_size;
pat->value_size = value_size;
pat->tokenizer = NULL;
pat->encoding = encoding;
pat->obj.header.flags = header->flags;
if (!(node0 = pat_get(ctx, pat, 0 ))) {
grn_io_close(ctx, io);
return NULL;
}
node0->lr[1 ] = 0 ;
node0->lr[0 ] = 0 ;
node0->key = 0 ;
return pat;
}
grn_pat *
grn_pat_create(grn_ctx *ctx, const char *path, uint32_t key_size,
uint32_t value_size, uint32_t flags)
{
grn_pat *pat;
if (!(pat = GRN_CALLOC(sizeof (grn_pat)))) {
return NULL;
}
GRN_DB_OBJ_SET_TYPE(pat, GRN_TABLE_PAT_KEY);
if (!_grn_pat_create(ctx, pat, path, key_size, value_size, flags)) {
GRN_FREE(pat);
return NULL;
}
pat->cache = NULL;
pat->cache_size = 0 ;
pat->is_dirty = GRN_FALSE;
CRITICAL_SECTION_INIT(pat->lock);
return pat;
}
/*
grn_pat_cache_enable ( ) and grn_pat_cache_disable ( ) are not thread - safe .
So far , they can be used only from single threaded programs .
*/
grn_rc
grn_pat_cache_enable(grn_ctx *ctx, grn_pat *pat, uint32_t cache_size)
{
if (pat->cache || pat->cache_size) {
ERR(GRN_INVALID_ARGUMENT, "cache is already enabled" );
return ctx->rc;
}
if (cache_size & (cache_size - 1 )) {
ERR(GRN_INVALID_ARGUMENT, "cache_size(%u) must be a power of two" , cache_size);
return ctx->rc;
}
if (!(pat->cache = GRN_CALLOC(cache_size * sizeof (grn_id)))) {
return ctx->rc;
}
pat->cache_size = cache_size;
return GRN_SUCCESS;
}
void
grn_pat_cache_disable(grn_ctx *ctx, grn_pat *pat)
{
if (pat->cache) {
GRN_FREE(pat->cache);
pat->cache_size = 0 ;
pat->cache = NULL;
}
}
grn_pat *
grn_pat_open(grn_ctx *ctx, const char *path)
{
grn_io *io;
grn_pat *pat;
pat_node *node0;
struct grn_pat_header *header;
uint32_t io_type;
io = grn_io_open(ctx, path, grn_io_auto);
if (!io) { return NULL; }
header = grn_io_header(io);
io_type = grn_io_get_type(io);
if (io_type != GRN_TABLE_PAT_KEY) {
ERR(GRN_INVALID_FORMAT, "[table][pat] file type must be %#04x: <%#04x>" ,
GRN_TABLE_PAT_KEY, io_type);
grn_io_close(ctx, io);
return NULL;
}
if (!(pat = GRN_MALLOC(sizeof (grn_pat)))) {
grn_io_close(ctx, io);
return NULL;
}
GRN_DB_OBJ_SET_TYPE(pat, GRN_TABLE_PAT_KEY);
pat->io = io;
pat->header = header;
pat->key_size = header->key_size;
pat->value_size = header->value_size;
pat->encoding = header->encoding;
pat->tokenizer = grn_ctx_at(ctx, header->tokenizer);
if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
pat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1 );
header->normalizer = grn_obj_id(ctx, pat->normalizer);
} else {
pat->normalizer = grn_ctx_at(ctx, header->normalizer);
}
GRN_PTR_INIT(&(pat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
pat->obj.header.flags = header->flags;
PAT_AT(pat, 0 , node0);
if (!node0) {
grn_io_close(ctx, io);
GRN_FREE(pat);
return NULL;
}
pat->cache = NULL;
pat->cache_size = 0 ;
pat->is_dirty = GRN_FALSE;
CRITICAL_SECTION_INIT(pat->lock);
return pat;
}
/*
* grn_pat_error_if_truncated ( ) logs an error and returns its error code if
* a pat is truncated by another process .
* Otherwise , this function returns GRN_SUCCESS .
* Note that ` ctx ` and ` pat ` must be valid .
*
* FIXME : A pat should be reopened if possible .
*/
static grn_rc
grn_pat_error_if_truncated(grn_ctx *ctx, grn_pat *pat)
{
if (pat->header->truncated) {
ERR(GRN_FILE_CORRUPT,
"pat is truncated, please unmap or reopen the database" );
return GRN_FILE_CORRUPT;
}
return GRN_SUCCESS;
}
grn_rc
grn_pat_close(grn_ctx *ctx, grn_pat *pat)
{
grn_rc rc;
CRITICAL_SECTION_FIN(pat->lock);
if (pat->is_dirty) {
uint32_t n_dirty_opens;
GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), -1 , n_dirty_opens);
}
if ((rc = grn_io_close(ctx, pat->io))) {
ERR(rc, "grn_io_close failed" );
} else {
grn_pvector_fin(ctx, &pat->token_filters);
if (pat->cache) { grn_pat_cache_disable(ctx, pat); }
GRN_FREE(pat);
}
return rc;
}
grn_rc
grn_pat_remove(grn_ctx *ctx, const char *path)
{
if (!path) {
ERR(GRN_INVALID_ARGUMENT, "path is null" );
return GRN_INVALID_ARGUMENT;
}
return grn_io_remove(ctx, path);
}
grn_rc
grn_pat_truncate(grn_ctx *ctx, grn_pat *pat)
{
grn_rc rc;
const char *io_path;
char *path;
uint32_t key_size, value_size, flags;
rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
if ((io_path = grn_io_path(pat->io)) && *io_path != '\0' ) {
if (!(path = GRN_STRDUP(io_path))) {
ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>" , io_path);
return GRN_NO_MEMORY_AVAILABLE;
}
} else {
path = NULL;
}
key_size = pat->key_size;
value_size = pat->value_size;
flags = pat->obj.header.flags;
if (path) {
pat->header->truncated = GRN_TRUE;
}
if ((rc = grn_io_close(ctx, pat->io))) { goto exit ; }
grn_pvector_fin(ctx, &pat->token_filters);
pat->io = NULL;
if (path && (rc = grn_io_remove(ctx, path))) { goto exit ; }
if (!_grn_pat_create(ctx, pat, path, key_size, value_size, flags)) {
rc = GRN_UNKNOWN_ERROR;
}
if (pat->cache && pat->cache_size) {
memset(pat->cache, 0 , pat->cache_size * sizeof (grn_id));
}
exit :
if (path) { GRN_FREE(path); }
return rc;
}
inline static grn_id
_grn_pat_add(grn_ctx *ctx, grn_pat *pat, const uint8_t *key, uint32_t size, uint32_t *new , uint32_t *lkey)
{
grn_id r, r0, *p0, *p1 = NULL;
pat_node *rn, *rn0;
int c, c0 = -1 , c1 = -1 , len;
uint32_t cache_id = 0 ;
*new = 0 ;
if (pat->cache) {
const uint8_t *p = key;
uint32_t length = size;
for (cache_id = 0 ; length--; p++) { cache_id = (cache_id * 37 ) + *p; }
cache_id &= (pat->cache_size - 1 );
if (pat->cache[cache_id]) {
PAT_AT(pat, pat->cache[cache_id], rn);
if (rn) {
const uint8_t *k = pat_node_get_key(ctx, pat, rn);
if (k && size == PAT_LEN(rn) && !memcmp(k, key, size)) {
return pat->cache[cache_id];
}
}
}
}
len = (int )size * 16 ;
PAT_AT(pat, 0 , rn0);
p0 = &rn0->lr[1 ];
if (*p0) {
uint32_t size2;
int xor , mask;
const uint8_t *s, *d;
for (;;) {
if (!(r0 = *p0)) {
if (!(s = pat_node_get_key(ctx, pat, rn0))) { return GRN_ID_NIL; }
size2 = PAT_LEN(rn0);
break ;
}
PAT_AT(pat, r0, rn0);
if (!rn0) { return GRN_ID_NIL; }
if (c0 < rn0->check && rn0->check < len) {
c1 = c0; c0 = rn0->check;
p1 = p0;
if (c0 & 1 ) {
p0 = (c0 + 1 < len) ? &rn0->lr[1 ] : &rn0->lr[0 ];
} else {
p0 = &rn0->lr[nth_bit(key, c0, len)];
}
} else {
if (!(s = pat_node_get_key(ctx, pat, rn0))) { return GRN_ID_NIL; }
size2 = PAT_LEN(rn0);
if (size == size2 && !memcmp(s, key, size)) {
if (pat->cache) { pat->cache[cache_id] = r0; }
return r0;
}
break ;
}
}
{
uint32_t min = size > size2 ? size2 : size;
for (c = 0 , d = key; min && *s == *d; c += 16 , s++, d++, min--);
if (min) {
for (xor = *s ^ *d, mask = 0 x80; !(xor & mask); mask >>= 1 , c += 2 );
} else {
c--;
}
}
if (c == c0 && !*p0) {
if (c < len - 2 ) { c += 2 ; }
} else {
if (c < c0) {
if (c > c1) {
p0 = p1;
} else {
PAT_AT(pat, 0 , rn0);
p0 = &rn0->lr[1 ];
while ((r0 = *p0)) {
PAT_AT(pat, r0, rn0);
if (!rn0) { return GRN_ID_NIL; }
c0 = PAT_CHK(rn0);
if (c < c0) { break ; }
if (c0 & 1 ) {
p0 = (c0 + 1 < len) ? &rn0->lr[1 ] : &rn0->lr[0 ];
} else {
p0 = &rn0->lr[nth_bit(key, c0, len)];
}
}
}
}
}
if (c >= len) { return GRN_ID_NIL; }
} else {
c = len - 2 ;
}
{
uint32_t size2 = size > sizeof (uint32_t) ? size : 0 ;
if (*lkey && size2) {
if (pat->header->garbages[0 ]) {
r = pat->header->garbages[0 ];
PAT_AT(pat, r, rn);
if (!rn) { return GRN_ID_NIL; }
pat->header->n_entries++;
pat->header->n_garbages--;
pat->header->garbages[0 ] = rn->lr[0 ];
} else {
r = pat->header->curr_rec + 1 ;
rn = pat_get(ctx, pat, r);
if (!rn) { return GRN_ID_NIL; }
pat->header->curr_rec = r;
pat->header->n_entries++;
}
PAT_IMD_OFF(rn);
PAT_LEN_SET(rn, size);
rn->key = *lkey;
} else {
if (pat->header->garbages[size2]) {
uint8_t *keybuf;
r = pat->header->garbages[size2];
PAT_AT(pat, r, rn);
if (!rn) { return GRN_ID_NIL; }
if (!(keybuf = pat_node_get_key(ctx, pat, rn))) { return GRN_ID_NIL; }
pat->header->n_entries++;
pat->header->n_garbages--;
pat->header->garbages[size2] = rn->lr[0 ];
PAT_LEN_SET(rn, size);
grn_memcpy(keybuf, key, size);
} else {
r = pat->header->curr_rec + 1 ;
rn = pat_get(ctx, pat, r);
if (!rn) { return GRN_ID_NIL; }
if (pat_node_set_key(ctx, pat, rn, key, size)) { return GRN_ID_NIL; }
pat->header->curr_rec = r;
pat->header->n_entries++;
}
*lkey = rn->key;
}
}
PAT_CHK_SET(rn, c);
PAT_DEL_OFF(rn);
if ((c & 1 ) ? (c + 1 < len) : nth_bit(key, c, len)) {
rn->lr[1 ] = r;
rn->lr[0 ] = *p0;
} else {
rn->lr[1 ] = *p0;
rn->lr[0 ] = r;
}
// smp_wmb();
*p0 = r;
*new = 1 ;
if (pat->cache) { pat->cache[cache_id] = r; }
return r;
}
inline static grn_bool
chop(grn_ctx *ctx, grn_pat *pat, const char **key, const char *end, uint32_t *lkey)
{
size_t len = grn_charlen(ctx, *key, end);
if (len) {
*lkey += len;
*key += len;
return (end - *key) > 0 ;
} else {
return GRN_FALSE;
}
}
#define MAX_FIXED_KEY_SIZE (sizeof (int64_t))
#define KEY_NEEDS_CONVERT(pat,size) \
(!((pat)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) && (size_t) (size) <= MAX_FIXED_KEY_SIZE)
#define KEY_ENC(pat,keybuf,key,size) do {\
switch ((pat)->obj.header.flags & GRN_OBJ_KEY_MASK) {\
case GRN_OBJ_KEY_UINT :\
if (((pat)->obj.header.domain != GRN_DB_TOKYO_GEO_POINT) &&\
((pat)->obj.header.domain != GRN_DB_WGS84_GEO_POINT)) {\
grn_hton((keybuf), (key), (size));\
break ;\
}\
case GRN_OBJ_KEY_GEO_POINT :\
grn_gton((keybuf), (key), (size));\
break ;\
case GRN_OBJ_KEY_INT :\
grn_hton((keybuf), (key), (size));\
*((uint8_t *)(keybuf)) ^= 0 x80;\
break ;\
case GRN_OBJ_KEY_FLOAT :\
if ((size) == sizeof (int64_t)) {\
int64_t v = *(int64_t *)(key);\
v ^= ((v >> 63 )|(1 ULL << 63 ));\
grn_hton((keybuf), &v, (size));\
}\
break ;\
}\
} while (0 )
#define KEY_DEC(pat,keybuf,key,size) do {\
switch ((pat)->obj.header.flags & GRN_OBJ_KEY_MASK) {\
case GRN_OBJ_KEY_UINT :\
if (((pat)->obj.header.domain != GRN_DB_TOKYO_GEO_POINT) &&\
((pat)->obj.header.domain != GRN_DB_WGS84_GEO_POINT)) {\
grn_ntoh((keybuf), (key), (size));\
break ;\
}\
case GRN_OBJ_KEY_GEO_POINT :\
grn_ntog((keybuf), (key), (size));\
break ;\
case GRN_OBJ_KEY_INT :\
grn_ntohi((keybuf), (key), (size));\
break ;\
case GRN_OBJ_KEY_FLOAT :\
if ((size) == sizeof (int64_t)) {\
int64_t v;\
grn_hton(&v, (key), (size));\
*((int64_t *)(keybuf)) = v ^ ((((int64_t)(v^(1 ULL<<63 )))>> 63 )|(1 ULL<<63 )); \
}\
break ;\
}\
} while (0 )
#define KEY_ENCODE(pat,keybuf,key,size) do {\
if (KEY_NEEDS_CONVERT(pat,size)) {\
KEY_ENC((pat), (keybuf), (key), (size));\
(key) = (keybuf);\
}\
} while (0 )
grn_id
grn_pat_add(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
void **value, int *added)
{
uint32_t new , lkey = 0 ;
grn_id r0;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
if (!key || !key_size) { return GRN_ID_NIL; }
if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
ERR(GRN_INVALID_ARGUMENT, "too long key: (%u)" , key_size);
return GRN_ID_NIL;
}
KEY_ENCODE(pat, keybuf, key, key_size);
r0 = _grn_pat_add(ctx, pat, (uint8_t *)key, key_size, &new , &lkey);
if (r0 == GRN_ID_NIL) { return GRN_ID_NIL; }
if (added) { *added = new ; }
if (r0 && (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) &&
(*((uint8_t *)key) & 0 x80)) { // todo: refine!!
sis_node *sl, *sr;
grn_id l = r0, r;
if (new && (sl = sis_get(ctx, pat, l))) {
const char *sis = key, *end = sis + key_size;
sl->children = l;
sl->sibling = 0 ;
while (chop(ctx, pat, &sis, end, &lkey)) {
if (!(*sis & 0 x80)) { break ; }
if (!(r = _grn_pat_add(ctx, pat, (uint8_t *)sis, end - sis, &new , &lkey))) {
break ;
}
if (!(sr = sis_get(ctx, pat, r))) { break ; }
if (new ) {
sl->sibling = r;
sr->children = l;
sr->sibling = 0 ;
} else {
sl->sibling = sr->children;
sr->children = l;
break ;
}
l = r;
sl = sr;
}
}
}
if (r0 && value) {
byte *v = (byte *)sis_get(ctx, pat, r0);
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
*value = v + sizeof (sis_node);
} else {
*value = v;
}
}
return r0;
}
inline static grn_id
_grn_pat_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size, void **value)
{
grn_id r;
pat_node *rn;
int c0 = -1 , c;
uint32_t len = key_size * 16 ;
PAT_AT(pat, 0 , rn);
for (r = rn->lr[1 ]; r;) {
PAT_AT(pat, r, rn);
if (!rn) { break ; /* corrupt? */ }
c = PAT_CHK(rn);
if ((int ) len <= c) { break ; }
if (c <= c0) {
const uint8_t *k = pat_node_get_key(ctx, pat, rn);
if (k && key_size == PAT_LEN(rn) && !memcmp(k, key, key_size)) {
if (value) {
byte *v = (byte *)sis_get(ctx, pat, r);
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
*value = v + sizeof (sis_node);
} else {
*value = v;
}
}
return r;
}
break ;
}
if (c & 1 ) {
r = (c + 1 < (int ) len) ? rn->lr[1 ] : rn->lr[0 ];
} else {
r = rn->lr[nth_bit((uint8_t *)key, c, len)];
}
c0 = c;
}
return GRN_ID_NIL;
}
grn_id
grn_pat_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size, void **value)
{
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
KEY_ENCODE(pat, keybuf, key, key_size);
return _grn_pat_get(ctx, pat, key, key_size, value);
}
grn_id
grn_pat_nextid(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
{
grn_id r = GRN_ID_NIL;
if (pat && key) {
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
if (!(r = pat->header->garbages[key_size > sizeof (uint32_t) ? key_size : 0 ])) {
r = pat->header->curr_rec + 1 ;
}
}
return r;
}
static void
get_tc(grn_ctx *ctx, grn_pat *pat, grn_hash *h, pat_node *rn)
{
grn_id id;
pat_node *node;
id = rn->lr[1 ];
if (id) {
PAT_AT(pat, id, node);
if (node) {
if (PAT_CHK(node) > PAT_CHK(rn)) {
get_tc(ctx, pat, h, node);
} else {
grn_hash_add(ctx, h, &id, sizeof (grn_id), NULL, NULL);
}
}
}
id = rn->lr[0 ];
if (id) {
PAT_AT(pat, id, node);
if (node) {
if (PAT_CHK(node) > PAT_CHK(rn)) {
get_tc(ctx, pat, h, node);
} else {
grn_hash_add(ctx, h, &id, sizeof (grn_id), NULL, NULL);
}
}
}
}
grn_rc
grn_pat_prefix_search(grn_ctx *ctx, grn_pat *pat,
const void *key, uint32_t key_size, grn_hash *h)
{
int c0 = -1 , c;
const uint8_t *k;
uint32_t len = key_size * 16 ;
grn_id r;
pat_node *rn;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
KEY_ENCODE(pat, keybuf, key, key_size);
PAT_AT(pat, 0 , rn);
r = rn->lr[1 ];
while (r) {
PAT_AT(pat, r, rn);
if (!rn) { return GRN_FILE_CORRUPT; }
c = PAT_CHK(rn);
if (c0 < c && c < (int ) len - 1 ) {
if (c & 1 ) {
r = (c + 1 < (int ) len) ? rn->lr[1 ] : rn->lr[0 ];
} else {
r = rn->lr[nth_bit((uint8_t *)key, c, len)];
}
c0 = c;
continue ;
}
if (!(k = pat_node_get_key(ctx, pat, rn))) { break ; }
if (PAT_LEN(rn) < key_size) { break ; }
if (!memcmp(k, key, key_size)) {
if (c >= (int ) len - 1 ) {
get_tc(ctx, pat, h, rn);
} else {
grn_hash_add(ctx, h, &r, sizeof (grn_id), NULL, NULL);
}
return GRN_SUCCESS;
}
break ;
}
return GRN_END_OF_DATA;
}
grn_hash *
grn_pat_prefix_search2(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
{
grn_hash *h;
if (!pat || !key) { return NULL; }
if ((h = grn_hash_create(ctx, NULL, sizeof (grn_id), 0 , 0 ))) {
if (grn_pat_prefix_search(ctx, pat, key, key_size, h)) {
grn_hash_close(ctx, h);
h = NULL;
}
}
return h;
}
grn_rc
grn_pat_suffix_search(grn_ctx *ctx, grn_pat *pat,
const void *key, uint32_t key_size, grn_hash *h)
{
grn_id r;
if ((r = grn_pat_get(ctx, pat, key, key_size, NULL))) {
uint32_t *offset;
if (grn_hash_add(ctx, h, &r, sizeof (grn_id), (void **) &offset, NULL)) {
*offset = 0 ;
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) { sis_collect(ctx, pat, h, r, 1 ); }
return GRN_SUCCESS;
}
}
return GRN_END_OF_DATA;
}
grn_hash *
grn_pat_suffix_search2(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
{
grn_hash *h;
if (!pat || !key) { return NULL; }
if ((h = grn_hash_create(ctx, NULL, sizeof (grn_id), sizeof (uint32_t), 0 ))) {
if (grn_pat_suffix_search(ctx, pat, key, key_size, h)) {
grn_hash_close(ctx, h);
h = NULL;
}
}
return h;
}
grn_id
grn_pat_lcp_search(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
{
pat_node *rn;
grn_id r, r2 = GRN_ID_NIL;
uint32_t len = key_size * 16 ;
int c0 = -1 , c;
if (!pat || !key) {
return GRN_ID_NIL;
}
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
if (!(pat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)) { return GRN_ID_NIL; }
PAT_AT(pat, 0 , rn);
for (r = rn->lr[1 ]; r;) {
PAT_AT(pat, r, rn);
if (!rn) { break ; /* corrupt? */ }
c = PAT_CHK(rn);
if (c <= c0) {
if (PAT_LEN(rn) <= key_size) {
uint8_t *p = pat_node_get_key(ctx, pat, rn);
if (!p) { break ; }
if (!memcmp(p, key, PAT_LEN(rn))) { return r; }
}
break ;
}
if ((int ) len <= c) { break ; }
if (c & 1 ) {
uint8_t *p;
pat_node *rn0;
grn_id r0 = rn->lr[0 ];
PAT_AT(pat, r0, rn0);
if (!rn0) { break ; /* corrupt? */ }
p = pat_node_get_key(ctx, pat, rn0);
if (!p) { break ; }
if (PAT_LEN(rn0) <= key_size && !memcmp(p, key, PAT_LEN(rn0))) { r2 = r0; }
r = (c + 1 < (int ) len) ? rn->lr[1 ] : rn->lr[0 ];
} else {
r = rn->lr[nth_bit((uint8_t *)key, c, len)];
}
c0 = c;
}
return r2;
}
static grn_id
common_prefix_pat_node_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
{
int c0 = -1 , c;
const uint8_t *k;
uint32_t len = key_size * 16 ;
grn_id r;
pat_node *rn;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
KEY_ENCODE(pat, keybuf, key, key_size);
PAT_AT(pat, 0 , rn);
r = rn->lr[1 ];
while (r) {
PAT_AT(pat, r, rn);
if (!rn) { return GRN_ID_NIL; }
c = PAT_CHK(rn);
if (c0 < c && c < (int ) len - 1 ) {
if (c & 1 ) {
r = (c + 1 < (int ) len) ? rn->lr[1 ] : rn->lr[0 ];
} else {
r = rn->lr[nth_bit((uint8_t *)key, c, len)];
}
c0 = c;
continue ;
}
if (!(k = pat_node_get_key(ctx, pat, rn))) { break ; }
if (PAT_LEN(rn) < key_size) { break ; }
if (!memcmp(k, key, key_size)) {
return r;
}
break ;
}
return GRN_ID_NIL;
}
typedef struct {
grn_id id;
uint16_t distance;
} fuzzy_heap_node;
typedef struct {
int n_entries;
int limit;
fuzzy_heap_node *nodes;
} fuzzy_heap;
static inline fuzzy_heap *
fuzzy_heap_open(grn_ctx *ctx, int max)
{
fuzzy_heap *h = GRN_MALLOC(sizeof (fuzzy_heap));
if (!h) { return NULL; }
h->nodes = GRN_MALLOC(sizeof (fuzzy_heap_node) * max);
if (!h->nodes) {
GRN_FREE(h);
return NULL;
}
h->n_entries = 0 ;
h->limit = max;
return h;
}
static inline grn_bool
fuzzy_heap_push(grn_ctx *ctx, fuzzy_heap *h, grn_id id, uint16_t distance)
{
int n, n2;
fuzzy_heap_node node = {id, distance};
fuzzy_heap_node node2;
if (h->n_entries >= h->limit) {
int max = h->limit * 2 ;
fuzzy_heap_node *nodes = GRN_REALLOC(h->nodes, sizeof (fuzzy_heap) * max);
if (!h) {
return GRN_FALSE;
}
h->limit = max;
h->nodes = nodes;
}
h->nodes[h->n_entries] = node;
n = h->n_entries++;
while (n) {
n2 = (n - 1 ) >> 1 ;
if (h->nodes[n2].distance <= h->nodes[n].distance) { break ; }
node2 = h->nodes[n];
h->nodes[n] = h->nodes[n2];
h->nodes[n2] = node2;
n = n2;
}
return GRN_TRUE;
}
static inline void
fuzzy_heap_close(grn_ctx *ctx, fuzzy_heap *h)
{
GRN_FREE(h->nodes);
GRN_FREE(h);
}
#define DIST(ox,oy) (dists[((lx + 1 ) * (oy)) + (ox)])
inline static uint16_t
calc_edit_distance_by_offset(grn_ctx *ctx,
const char *sx, const char *ex,
const char *sy, const char *ey,
uint16_t *dists, uint32_t lx,
uint32_t offset, uint32_t max_distance,
grn_bool *can_transition, int flags)
{
uint32_t cx, cy, x, y;
const char *px, *py;
/* Skip already calculated rows */
for (py = sy, y = 1 ; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, y++) {
if (py - sy >= offset) {
break ;
}
}
for (; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, y++) {
/* children nodes will be no longer smaller than max distance
* with only insertion costs .
* This is end of row on allocated memory. */
if (y > lx + max_distance) {
*can_transition = GRN_FALSE;
return max_distance + 1 ;
}
for (px = sx, x = 1 ; px < ex && (cx = grn_charlen(ctx, px, ex)); px += cx, x++) {
if (cx == cy && !memcmp(px, py, cx)) {
DIST(x, y) = DIST(x - 1 , y - 1 );
} else {
uint32_t a, b, c;
a = DIST(x - 1 , y) + 1 ;
b = DIST(x, y - 1 ) + 1 ;
c = DIST(x - 1 , y - 1 ) + 1 ;
DIST(x, y) = ((a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c));
if (flags & GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION &&
x > 1 && y > 1 &&
cx == cy &&
memcmp(px, py - cy, cx) == 0 &&
memcmp(px - cx, py, cx) == 0 ) {
uint32_t t = DIST(x - 2 , y - 2 ) + 1 ;
DIST(x, y) = ((DIST(x, y) < t) ? DIST(x, y) : t);
}
}
}
}
if (lx) {
/* If there is no cell which is smaller than equal to max distance on end of row,
* children nodes will be no longer smaller than max distance */
*can_transition = GRN_FALSE;
for (x = 1 ; x <= lx; x++) {
if (DIST(x, y - 1 ) <= max_distance) {
*can_transition = GRN_TRUE;
break ;
}
}
}
return DIST(lx, y - 1 );
}
typedef struct {
const char *key;
int key_length;
grn_bool can_transition;
} fuzzy_node;
inline static void
_grn_pat_fuzzy_search(grn_ctx *ctx, grn_pat *pat, grn_id id,
const char *key, uint32_t key_size,
uint16_t *dists, uint32_t lx,
int last_check, fuzzy_node *last_node,
uint32_t max_distance, int flags, fuzzy_heap *heap)
{
pat_node *node = NULL;
int check, len;
const char *k;
uint32_t offset = 0 ;
PAT_AT(pat, id, node);
if (!node) {
return ;
}
check = PAT_CHK(node);
len = PAT_LEN(node);
k = pat_node_get_key(ctx, pat, node);
if (check > last_check) {
if (len >= last_node->key_length &&
!memcmp(k, last_node->key, last_node->key_length)) {
if (last_node->can_transition == GRN_FALSE) {
return ;
}
}
_grn_pat_fuzzy_search(ctx, pat, node->lr[0 ],
key, key_size, dists, lx,
check, last_node,
max_distance, flags, heap);
_grn_pat_fuzzy_search(ctx, pat, node->lr[1 ],
key, key_size, dists, lx,
check, last_node,
max_distance, flags, heap);
} else {
if (id) {
/* Set already calculated common prefix length */
if (len >= last_node->key_length &&
!memcmp(k, last_node->key, last_node->key_length)) {
if (last_node->can_transition == GRN_FALSE) {
return ;
}
offset = last_node->key_length;
} else {
if (last_node->can_transition == GRN_FALSE) {
last_node->can_transition = GRN_TRUE;
}
if (last_node->key_length) {
const char *kp = k;
const char *ke = k + len;
const char *p = last_node->key;
const char *e = last_node->key + last_node->key_length;
int lp;
for (;p < e && kp < ke && (lp = grn_charlen(ctx, p, e));
p += lp, kp += lp) {
if (p + lp <= e && kp + lp <= ke && memcmp(p, kp, lp)) {
break ;
}
}
offset = kp - k;
}
}
if (len - offset) {
uint16_t distance;
distance =
calc_edit_distance_by_offset(ctx,
key, key + key_size,
k, k + len,
dists, lx,
offset, max_distance,
&(last_node->can_transition), flags);
if (distance <= max_distance) {
fuzzy_heap_push(ctx, heap, id, distance);
}
}
last_node->key = k;
last_node->key_length = len;
}
}
return ;
}
#define HEAP_SIZE 256
grn_rc
grn_pat_fuzzy_search(grn_ctx *ctx, grn_pat *pat,
const void *key, uint32_t key_size,
grn_fuzzy_search_optarg *args, grn_hash *h)
{
pat_node *node;
grn_id id;
uint16_t *dists;
uint32_t lx, len, x, y, i;
const char *s = key;
const char *e = (const char *)key + key_size;
fuzzy_node last_node;
fuzzy_heap *heap;
uint32_t max_distance = 1 ;
uint32_t max_expansion = 0 ;
uint32_t prefix_match_size = 0 ;
int flags = 0 ;
grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
if (args) {
max_distance = args->max_distance;
max_expansion = args->max_expansion;
prefix_match_size = args->prefix_match_size;
flags = args->flags;
}
if (key_size > GRN_TABLE_MAX_KEY_SIZE ||
max_distance > GRN_TABLE_MAX_KEY_SIZE ||
prefix_match_size > key_size) {
return GRN_INVALID_ARGUMENT;
}
heap = fuzzy_heap_open(ctx, HEAP_SIZE);
if (!heap) {
return GRN_NO_MEMORY_AVAILABLE;
}
PAT_AT(pat, GRN_ID_NIL, node);
id = node->lr[1 ];
if (prefix_match_size) {
grn_id tid;
tid = common_prefix_pat_node_get(ctx, pat, key, prefix_match_size);
if (tid != GRN_ID_NIL) {
id = tid;
} else {
return GRN_END_OF_DATA;
}
}
for (lx = 0 ; s < e && (len = grn_charlen(ctx, s, e)); s += len) {
lx++;
}
dists = GRN_MALLOC((lx + 1 ) * (lx + max_distance + 1 ) * sizeof (uint16_t));
if (!dists) {
return GRN_NO_MEMORY_AVAILABLE;
}
for (x = 0 ; x <= lx; x++) { DIST(x, 0 ) = x; }
for (y = 0 ; y <= lx + max_distance ; y++) { DIST(0 , y) = y; }
last_node.key = NULL;
last_node.key_length = 0 ;
last_node.can_transition = GRN_TRUE;
_grn_pat_fuzzy_search(ctx, pat, id,
key, key_size, dists, lx,
-1 , &last_node, max_distance, flags, heap);
GRN_FREE(dists);
for (i = 0 ; i < (uint32_t) heap->n_entries; i++) {
if (max_expansion > 0 && i >= max_expansion) {
break ;
}
if (DB_OBJ(h)->header.flags & GRN_OBJ_WITH_SUBREC) {
grn_rset_recinfo *ri;
if (grn_hash_add(ctx, h, &(heap->nodes[i].id), sizeof (grn_id), (void **)&ri, NULL)) {
ri->score = max_distance - heap->nodes[i].distance + 1 ;
}
} else {
grn_hash_add(ctx, h, &(heap->nodes[i].id), sizeof (grn_id), NULL, NULL);
}
}
fuzzy_heap_close(ctx, heap);
if (grn_hash_size(ctx, h)) {
return GRN_SUCCESS;
} else {
return GRN_END_OF_DATA;
}
}
inline static grn_rc
_grn_pat_del(grn_ctx *ctx, grn_pat *pat, const char *key, uint32_t key_size, int shared,
grn_table_delete_optarg *optarg)
{
grn_pat_delinfo *di;
pat_node *rn, *rn0 = NULL, *rno = NULL;
int c = -1 , c0 = -1 , ch;
uint32_t len = key_size * 16 ;
grn_id r, otherside, *proot, *p, *p0 = NULL;
/* delinfo_new() must be called before searching for rn. */
di = delinfo_new(ctx, pat);
di->shared = shared;
/*
* Search a patricia tree for a given key .
* If the key exists , get its output node .
*
* rn , rn0 : the output node and its previous node .
* rno : the other side of rn ( the other destination of rn0 ) .
* c , c0 : checks of rn0 and its previous node .
* p , p0 : pointers to transitions ( IDs ) that refer to rn and rn0 .
*/
PAT_AT(pat, 0 , rn);
proot = p = &rn->lr[1 ];
for (;;) {
r = *p;
if (!r) {
return GRN_INVALID_ARGUMENT;
}
PAT_AT(pat, r, rn);
if (!rn) {
return GRN_FILE_CORRUPT;
}
ch = PAT_CHK(rn);
if ((int ) len <= ch) {
return GRN_INVALID_ARGUMENT;
}
if (c >= ch) {
/* Output node found. */
const uint8_t *k = pat_node_get_key(ctx, pat, rn);
if (!k) {
return GRN_INVALID_ARGUMENT;
}
if (key_size != PAT_LEN(rn) || memcmp(k, key, key_size)) {
return GRN_INVALID_ARGUMENT;
}
/* Given key found. */
break ;
}
c0 = c;
p0 = p;
c = ch;
if (c & 1 ) {
p = (c + 1 < (int ) len) ? &rn->lr[1 ] : &rn->lr[0 ];
} else {
p = &rn->lr[nth_bit((uint8_t *)key, c, len)];
}
rn0 = rn;
}
if (optarg && optarg->func &&
!optarg->func(ctx, (grn_obj *)pat, r, optarg->func_arg)) {
return GRN_SUCCESS;
}
if (rn0->lr[0 ] == rn0->lr[1 ]) {
GRN_LOG(ctx, GRN_LOG_DEBUG, "*p0 (%d), rn0->lr[0] == rn0->lr[1] (%d)" ,
*p0, rn0->lr[0 ]);
return GRN_FILE_CORRUPT;
}
otherside = (rn0->lr[1 ] == r) ? rn0->lr[0 ] : rn0->lr[1 ];
if (otherside) {
PAT_AT(pat, otherside, rno);
if (!rno) {
return GRN_FILE_CORRUPT;
}
}
if (rn == rn0) {
/* The last transition (p) is a self-loop. */
di->stat = DL_PHASE2;
di->d = r;
if (otherside) {
if (c0 < PAT_CHK(rno) && PAT_CHK(rno) <= c) {
/* To keep rno as an output node, its check is set to zero. */
if (!delinfo_search(pat, otherside)) {
GRN_LOG(ctx, GRN_LOG_DEBUG, "no delinfo found %d" , otherside);
}
PAT_CHK_SET(rno, 0 );
}
if (proot == p0 && !rno->check) {
/*
* Update rno - > lr because the first node , rno becomes the new first
* node , is not an output node even if its check is zero .
*/
const uint8_t *k = pat_node_get_key(ctx, pat, rno);
int direction = k ? (*k >> 7 ) : 1 ;
rno->lr[direction] = otherside;
rno->lr[!direction] = 0 ;
}
}
*p0 = otherside;
} else if ((!rn->lr[0 ] && rn->lr[1 ] == r) ||
(!rn->lr[1 ] && rn->lr[0 ] == r)) {
/* The output node has only a disabled self-loop. */
di->stat = DL_PHASE2;
di->d = r;
*p = 0 ;
} else {
/* The last transition (p) is not a self-loop. */
grn_pat_delinfo *ldi = NULL, *ddi = NULL;
if (PAT_DEL(rn)) {
ldi = delinfo_search(pat, r);
}
if (PAT_DEL(rn0)) {
ddi = delinfo_search(pat, *p0);
}
if (ldi) {
PAT_DEL_OFF(rn);
di->stat = DL_PHASE2;
if (ddi) {
PAT_DEL_OFF(rn0);
ddi->stat = DL_PHASE2;
if (ddi == ldi) {
if (r != ddi->ld) {
GRN_LOG(ctx, GRN_LOG_ERROR, "r(%d) != ddi->ld(%d)" , r, ddi->ld);
}
di->d = r;
} else {
ldi->ld = ddi->ld;
di->d = r;
}
} else {
PAT_DEL_ON(rn0);
ldi->ld = *p0;
di->d = r;
}
} else {
PAT_DEL_ON(rn);
if (ddi) {
if (ddi->d != *p0) {
GRN_LOG(ctx, GRN_LOG_ERROR, "ddi->d(%d) != *p0(%d)" , ddi->d, *p0);
}
PAT_DEL_OFF(rn0);
ddi->stat = DL_PHASE2;
di->stat = DL_PHASE1;
di->ld = ddi->ld;
di->d = r;
/*
PAT_DEL_OFF ( rn0 ) ;
ddi - > d = r ;
di - > stat = DL_PHASE2 ;
di - > d = * p0 ;
*/
} else {
PAT_DEL_ON(rn0);
di->stat = DL_PHASE1;
di->ld = *p0;
di->d = r;
// grn_log("pat_del d=%d ld=%d stat=%d", r, *p0, DL_PHASE1);
}
}
if (*p0 == otherside) {
/* The previous node (*p0) has a self-loop (rn0 == rno). */
PAT_CHK_SET(rno, 0 );
if (proot == p0) {
/*
* Update rno - > lr because the first node , rno becomes the new first
* node , is not an output node even if its check is zero .
*/
const uint8_t *k = pat_node_get_key(ctx, pat, rno);
int direction = k ? (*k >> 7 ) : 1 ;
rno->lr[direction] = otherside;
rno->lr[!direction] = 0 ;
}
} else {
if (otherside) {
if (c0 < PAT_CHK(rno) && PAT_CHK(rno) <= c) {
/* To keep rno as an output node, its check is set to zero. */
if (!delinfo_search(pat, otherside)) {
GRN_LOG(ctx, GRN_LOG_ERROR, "no delinfo found %d" , otherside);
}
PAT_CHK_SET(rno, 0 );
}
if (proot == p0 && !rno->check) {
/*
* Update rno - > lr because the first node , rno becomes the new first
* node , is not an output node even if its check is zero .
*/
const uint8_t *k = pat_node_get_key(ctx, pat, rno);
int direction = k ? (*k >> 7 ) : 1 ;
rno->lr[direction] = otherside;
rno->lr[!direction] = 0 ;
}
}
*p0 = otherside;
}
}
pat->header->n_entries--;
pat->header->n_garbages++;
return GRN_SUCCESS;
}
static grn_rc
_grn_pat_delete(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
grn_table_delete_optarg *optarg)
{
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
if (id && grn_pat_delete_with_sis(ctx, pat, id, optarg)) {
return GRN_SUCCESS;
}
return GRN_INVALID_ARGUMENT;
}
return _grn_pat_del(ctx, pat, key, key_size, 0 , optarg);
}
grn_rc
grn_pat_delete(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
grn_table_delete_optarg *optarg)
{
grn_rc rc;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
if (!pat || !key || !key_size) { return GRN_INVALID_ARGUMENT; }
rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
KEY_ENCODE(pat, keybuf, key, key_size);
return _grn_pat_delete(ctx, pat, key, key_size, optarg);
}
uint32_t
grn_pat_size(grn_ctx *ctx, grn_pat *pat)
{
if (!pat) { return GRN_INVALID_ARGUMENT; }
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
return pat->header->n_entries;
}
const char *
_grn_pat_key(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *key_size)
{
pat_node *node;
uint8_t *key;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
*key_size = 0 ;
return NULL;
}
PAT_AT(pat, id, node);
if (!node) {
*key_size = 0 ;
return NULL;
}
key = pat_node_get_key(ctx, pat, node);
if (key) {
*key_size = PAT_LEN(node);
} else {
*key_size = 0 ;
}
return (const char *)key;
}
grn_rc
grn_pat_delete_by_id(grn_ctx *ctx, grn_pat *pat, grn_id id,
grn_table_delete_optarg *optarg)
{
grn_rc rc;
if (!pat || !id) { return GRN_INVALID_ARGUMENT; }
rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
{
uint32_t key_size;
const char *key = _grn_pat_key(ctx, pat, id, &key_size);
return _grn_pat_delete(ctx, pat, key, key_size, optarg);
}
}
int
grn_pat_get_key(grn_ctx *ctx, grn_pat *pat, grn_id id, void *keybuf, int bufsize)
{
int len;
uint8_t *key;
pat_node *node;
if (!pat) { return 0 ; }
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
if (!id) { return 0 ; }
PAT_AT(pat, id, node);
if (!node) { return 0 ; }
if (!(key = pat_node_get_key(ctx, pat, node))) { return 0 ; }
len = PAT_LEN(node);
if (keybuf && bufsize >= len) {
if (KEY_NEEDS_CONVERT(pat, len)) {
KEY_DEC(pat, keybuf, key, len);
} else {
grn_memcpy(keybuf, key, len);
}
}
return len;
}
int
grn_pat_get_key2(grn_ctx *ctx, grn_pat *pat, grn_id id, grn_obj *bulk)
{
uint32_t len;
uint8_t *key;
pat_node *node;
if (!pat) { return GRN_INVALID_ARGUMENT; }
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
if (!id) { return 0 ; }
PAT_AT(pat, id, node);
if (!node) { return 0 ; }
if (!(key = pat_node_get_key(ctx, pat, node))) { return 0 ; }
len = PAT_LEN(node);
if (KEY_NEEDS_CONVERT(pat, len)) {
if (bulk->header.impl_flags & GRN_OBJ_REFER) {
GRN_TEXT_INIT(bulk, 0 );
}
if (!grn_bulk_reserve(ctx, bulk, len)) {
char *curr = GRN_BULK_CURR(bulk);
KEY_DEC(pat, curr, key, len);
grn_bulk_truncate(ctx, bulk, GRN_BULK_VSIZE(bulk) + len);
}
} else {
if (bulk->header.impl_flags & GRN_OBJ_REFER) {
bulk->u.b.head = (char *)key;
bulk->u.b.curr = (char *)key + len;
} else {
grn_bulk_write(ctx, bulk, (char *)key, len);
}
}
return len;
}
int
grn_pat_get_value(grn_ctx *ctx, grn_pat *pat, grn_id id, void *valuebuf)
{
int value_size;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
value_size = (int )pat->value_size;
if (value_size) {
byte *v = (byte *)sis_at(ctx, pat, id);
if (v) {
if (valuebuf) {
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
grn_memcpy(valuebuf, v + sizeof (sis_node), value_size);
} else {
grn_memcpy(valuebuf, v, value_size);
}
}
return value_size;
}
}
return 0 ;
}
const char *
grn_pat_get_value_(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *size)
{
const char *value = NULL;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return NULL;
}
if ((*size = pat->value_size)) {
if ((value = (const char *)sis_at(ctx, pat, id))
&& (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS)) {
value += sizeof (sis_node);
}
}
return value;
}
grn_rc
grn_pat_set_value(grn_ctx *ctx, grn_pat *pat, grn_id id,
const void *value, int flags)
{
grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
if (value) {
uint32_t value_size = pat->value_size;
if (value_size) {
byte *v = (byte *)sis_get(ctx, pat, id);
if (v) {
if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) { v += sizeof (sis_node); }
switch ((flags & GRN_OBJ_SET_MASK)) {
case GRN_OBJ_SET :
grn_memcpy(v, value, value_size);
return GRN_SUCCESS;
case GRN_OBJ_INCR :
switch (value_size) {
case sizeof (int32_t) :
*((int32_t *)v) += *((int32_t *)value);
return GRN_SUCCESS;
case sizeof (int64_t) :
*((int64_t *)v) += *((int64_t *)value);
return GRN_SUCCESS;
default :
return GRN_INVALID_ARGUMENT;
}
break ;
case GRN_OBJ_DECR :
switch (value_size) {
case sizeof (int32_t) :
*((int32_t *)v) -= *((int32_t *)value);
return GRN_SUCCESS;
case sizeof (int64_t) :
*((int64_t *)v) -= *((int64_t *)value);
return GRN_SUCCESS;
default :
return GRN_INVALID_ARGUMENT;
}
break ;
default :
// todo : support other types.
return GRN_INVALID_ARGUMENT;
}
} else {
return GRN_NO_MEMORY_AVAILABLE;
}
}
}
return GRN_INVALID_ARGUMENT;
}
grn_rc
grn_pat_info(grn_ctx *ctx, grn_pat *pat, int *key_size, unsigned int *flags,
grn_encoding *encoding, unsigned int *n_entries, unsigned int *file_size)
{
grn_rc rc;
ERRCLR(NULL);
if (!pat) { return GRN_INVALID_ARGUMENT; }
rc = grn_pat_error_if_truncated(ctx, pat);
if (rc != GRN_SUCCESS) {
return rc;
}
if (key_size) { *key_size = pat->key_size; }
if (flags) { *flags = pat->obj.header.flags; }
if (encoding) { *encoding = pat->encoding; }
if (n_entries) { *n_entries = pat->header->n_entries; }
if (file_size) {
uint64_t tmp = 0 ;
if ((rc = grn_io_size(ctx, pat->io, &tmp))) {
return rc;
}
*file_size = (unsigned int ) tmp; /* FIXME: inappropriate cast */
}
return GRN_SUCCESS;
}
int
grn_pat_delete_with_sis(grn_ctx *ctx, grn_pat *pat, grn_id id,
grn_table_delete_optarg *optarg)
{
int level = 0 , shared;
const char *key = NULL, *_key;
sis_node *sp, *ss = NULL, *si;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
si = sis_at(ctx, pat, id);
while (id) {
pat_node *rn;
uint32_t key_size;
if ((si && si->children && si->children != id) ||
(optarg && optarg->func &&
!optarg->func(ctx, (grn_obj *)pat, id, optarg->func_arg))) {
break ;
}
PAT_AT(pat, id, rn);
if (!(_key = (char *)pat_node_get_key(ctx, pat, rn))) { return 0 ; }
if (_key == key) {
shared = 1 ;
} else {
key = _key;
shared = 0 ;
}
key_size = PAT_LEN(rn);
if (key && key_size) { _grn_pat_del(ctx, pat, key, key_size, shared, NULL); }
if (si) {
grn_id *p, sid;
uint32_t lkey = 0 ;
if ((*key & 0 x80) && chop(ctx, pat, &key, key + key_size, &lkey)) {
if ((sid = grn_pat_get(ctx, pat, key, key_size - lkey, NULL)) &&
(ss = sis_at(ctx, pat, sid))) {
for (p = &ss->children; *p && *p != sid; p = &sp->sibling) {
if (*p == id) {
*p = si->sibling;
break ;
}
if (!(sp = sis_at(ctx, pat, *p))) { break ; }
}
}
} else {
sid = GRN_ID_NIL;
}
si->sibling = 0 ;
si->children = 0 ;
id = sid;
si = ss;
} else {
id = GRN_ID_NIL;
}
level++;
}
if (level) {
uint32_t lkey = 0 ;
while (id && key) {
uint32_t key_size;
if (_grn_pat_key(ctx, pat, id, &key_size) != key) { break ; }
{
pat_node *rn;
PAT_AT(pat, id, rn);
if (!rn) { break ; }
if (lkey) {
rn->key = lkey;
} else {
pat_node_set_key(ctx, pat, rn, (uint8_t *)key, key_size);
lkey = rn->key;
}
}
{
const char *end = key + key_size;
if (!((*key & 0 x80) && chop(ctx, pat, &key, end, &lkey))) { break ; }
id = grn_pat_get(ctx, pat, key, end - key, NULL);
}
}
}
return level;
}
grn_id
grn_pat_next(grn_ctx *ctx, grn_pat *pat, grn_id id)
{
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
while (++id <= pat->header->curr_rec) {
uint32_t key_size;
const char *key = _grn_pat_key(ctx, pat, id, &key_size);
if (id == grn_pat_get(ctx, pat, key, key_size, NULL)) {
return id;
}
}
return GRN_ID_NIL;
}
grn_id
grn_pat_at(grn_ctx *ctx, grn_pat *pat, grn_id id)
{
uint32_t key_size;
const char *key = _grn_pat_key(ctx, pat, id, &key_size);
if (key && (id == _grn_pat_get(ctx, pat, key, key_size, NULL))) { return id; }
return GRN_ID_NIL;
}
grn_id
grn_pat_curr_id(grn_ctx *ctx, grn_pat *pat)
{
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return GRN_ID_NIL;
}
return pat->header->curr_rec;
}
int
grn_pat_scan(grn_ctx *ctx, grn_pat *pat, const char *str, unsigned int str_len,
grn_pat_scan_hit *sh, unsigned int sh_size, const char **rest)
{
int n = 0 ;
grn_id tid;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return 0 ;
}
if (pat->normalizer) {
int flags =
GRN_STRING_REMOVE_BLANK |
GRN_STRING_WITH_TYPES |
GRN_STRING_WITH_CHECKS;
grn_obj *nstr = grn_string_open(ctx, str, str_len,
pat->normalizer, flags);
if (nstr) {
const short *cp = grn_string_get_checks(ctx, nstr);
const unsigned char *tp = grn_string_get_types(ctx, nstr);
unsigned int offset = 0 , offset0 = 0 ;
unsigned int normalized_length_in_bytes;
const char *sp, *se;
grn_string_get_normalized(ctx, nstr, &sp, &normalized_length_in_bytes,
NULL);
se = sp + normalized_length_in_bytes;
while (n < (int ) sh_size) {
if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
const char *key;
uint32_t len;
int first_key_char_len;
key = _grn_pat_key(ctx, pat, tid, &len);
sh[n].id = tid;
sh[n].offset = (*cp > 0 ) ? offset : offset0;
first_key_char_len = grn_charlen(ctx, key, key + len);
if (sh[n].offset > 0 &&
GRN_CHAR_IS_BLANK(tp[-1 ]) &&
((first_key_char_len == 1 && key[0 ] != ' ' ) ||
first_key_char_len > 1 )){
/* Remove leading spaces. */
const char *original_str = str + sh[n].offset;
while (grn_charlen(ctx, original_str, str + str_len) == 1 &&
original_str[0 ] == ' ' ) {
original_str++;
sh[n].offset++;
}
}
{
grn_bool blank_in_alnum = GRN_FALSE;
const unsigned char *start_tp = tp;
const unsigned char *blank_in_alnum_check_tp;
while (len--) {
if (*cp > 0 ) { offset0 = offset; offset += *cp; tp++; }
sp++; cp++;
}
sh[n].length = offset - sh[n].offset;
for (blank_in_alnum_check_tp = start_tp + 1 ;
blank_in_alnum_check_tp < tp;
blank_in_alnum_check_tp++) {
#define GRN_CHAR_IS_ALNUM(char_type) \
(GRN_CHAR_TYPE(char_type) == GRN_CHAR_ALPHA || \
GRN_CHAR_TYPE(char_type) == GRN_CHAR_DIGIT)
if (GRN_CHAR_IS_BLANK(blank_in_alnum_check_tp[0 ]) &&
GRN_CHAR_IS_ALNUM(blank_in_alnum_check_tp[-1 ]) &&
(blank_in_alnum_check_tp + 1 ) < tp &&
GRN_CHAR_IS_ALNUM(blank_in_alnum_check_tp[1 ])) {
blank_in_alnum = GRN_TRUE;
}
#undef GRN_CHAR_IS_ALNUM
}
if (!blank_in_alnum) {
n++;
}
}
} else {
if (*cp > 0 ) { offset0 = offset; offset += *cp; tp++; }
do {
sp++; cp++;
} while (sp < se && !*cp);
}
if (se <= sp) { offset = str_len; break ; }
}
if (rest) {
grn_string_get_original(ctx, nstr, rest, NULL);
*rest += offset;
}
grn_obj_close(ctx, nstr);
} else {
n = -1 ;
if (rest) { *rest = str; }
}
} else {
uint32_t len;
const char *sp, *se = str + str_len;
for (sp = str; sp < se && n < (int ) sh_size; sp += len) {
if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
_grn_pat_key(ctx, pat, tid, &len);
sh[n].id = tid;
sh[n].offset = sp - str;
sh[n].length = len;
n++;
} else {
len = grn_charlen(ctx, sp, se);
}
if (!len) { break ; }
}
if (rest) { *rest = sp; }
}
return n;
}
#define INITIAL_SIZE 512
inline static void
push(grn_pat_cursor *c, grn_id id, uint16_t check)
{
grn_ctx *ctx = c->ctx;
grn_pat_cursor_entry *se;
if (c->size <= c->sp) {
if (c->ss) {
uint32_t size = c->size * 4 ;
grn_pat_cursor_entry *ss = GRN_REALLOC(c->ss, size);
if (!ss) { return ; /* give up */ }
c->ss = ss;
c->size = size;
} else {
if (!(c->ss = GRN_MALLOC(sizeof (grn_pat_cursor_entry) * INITIAL_SIZE))) {
return ; /* give up */
}
c->size = INITIAL_SIZE;
}
}
se = &c->ss[c->sp++];
se->id = id;
se->check = check;
}
inline static grn_pat_cursor_entry *
pop(grn_pat_cursor *c)
{
return c->sp ? &c->ss[--c->sp] : NULL;
}
static grn_id
grn_pat_cursor_next_by_id(grn_ctx *ctx, grn_pat_cursor *c)
{
grn_pat *pat = c->pat;
int dir = (c->obj.header.flags & GRN_CURSOR_DESCENDING) ? -1 : 1 ;
while (c->curr_rec != c->tail) {
c->curr_rec += dir;
if (pat->header->n_garbages) {
uint32_t key_size;
const void *key = _grn_pat_key(ctx, pat, c->curr_rec, &key_size);
if (_grn_pat_get(ctx, pat, key, key_size, NULL) != c->curr_rec) {
continue ;
}
}
c->rest--;
return c->curr_rec;
}
return GRN_ID_NIL;
}
grn_id
grn_pat_cursor_next(grn_ctx *ctx, grn_pat_cursor *c)
{
pat_node *node;
grn_pat_cursor_entry *se;
if (!c->rest) { return GRN_ID_NIL; }
if ((c->obj.header.flags & GRN_CURSOR_BY_ID)) {
return grn_pat_cursor_next_by_id(ctx, c);
}
while ((se = pop(c))) {
grn_id id = se->id;
int check = se->check, ch;
while (id) {
PAT_AT(c->pat, id, node);
if (!node) {
break ;
}
ch = PAT_CHK(node);
if (ch > check) {
if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
push(c, node->lr[0 ], ch);
id = node->lr[1 ];
} else {
push(c, node->lr[1 ], ch);
id = node->lr[0 ];
}
check = ch;
continue ;
} else {
if (id == c->tail) {
c->sp = 0 ;
} else {
if (!c->curr_rec && c->tail) {
uint32_t lmin, lmax;
pat_node *nmin, *nmax;
const uint8_t *kmin, *kmax;
if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
PAT_AT(c->pat, c->tail, nmin);
PAT_AT(c->pat, id, nmax);
} else {
PAT_AT(c->pat, id, nmin);
PAT_AT(c->pat, c->tail, nmax);
}
lmin = PAT_LEN(nmin);
lmax = PAT_LEN(nmax);
kmin = pat_node_get_key(ctx, c->pat, nmin);
kmax = pat_node_get_key(ctx, c->pat, nmax);
if ((lmin < lmax) ?
(memcmp(kmin, kmax, lmin) > 0 ) :
(memcmp(kmin, kmax, lmax) >= 0 )) {
c->sp = 0 ;
break ;
}
}
}
c->curr_rec = id;
c->rest--;
return id;
}
}
}
return GRN_ID_NIL;
}
void
grn_pat_cursor_close(grn_ctx *ctx, grn_pat_cursor *c)
{
GRN_ASSERT(c->ctx == ctx);
if (c->ss) { GRN_FREE(c->ss); }
GRN_FREE(c);
}
inline static int
bitcmp(const void *s1, const void *s2, int offset, int length)
{
int r, rest = length + (offset & 7 ) - 8 , bl = offset >> 3 , mask = 0 xff >> (offset & 7 );
unsigned char *a = (unsigned char *)s1 + bl, *b = (unsigned char *)s2 + bl;
if (rest <= 0 ) {
mask &= 0 xff << -rest;
return (*a & mask) - (*b & mask);
}
if ((r = (*a & mask) - (*b & mask))) { return r; }
a++; b++;
if ((bl = rest >> 3 )) {
if ((r = memcmp(a, b, bl))) { return r; }
a += bl; b += bl;
}
mask = 0 xff << (8 - (rest & 7 ));
return (*a & mask) - (*b & mask);
}
inline static grn_rc
set_cursor_prefix(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
const void *key, uint32_t key_size, int flags)
{
int c0 = -1 , ch;
const uint8_t *k;
uint32_t len, byte_len;
grn_id id;
pat_node *node;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
if (flags & GRN_CURSOR_SIZE_BY_BIT) {
len = key_size * 2 ;
byte_len = key_size >> 3 ;
} else {
len = key_size * 16 ;
byte_len = key_size;
}
KEY_ENCODE(pat, keybuf, key, byte_len);
PAT_AT(pat, 0 , node);
id = node->lr[1 ];
while (id) {
PAT_AT(pat, id, node);
if (!node) { return GRN_FILE_CORRUPT; }
ch = PAT_CHK(node);
if (c0 < ch && ch < (int ) len - 1 ) {
if (ch & 1 ) {
id = (ch + 1 < (int ) len) ? node->lr[1 ] : node->lr[0 ];
} else {
id = node->lr[nth_bit((uint8_t *)key, ch, len)];
}
c0 = ch;
continue ;
}
if (!(k = pat_node_get_key(ctx, pat, node))) { break ; }
if (PAT_LEN(node) < byte_len) { break ; }
if ((flags & GRN_CURSOR_SIZE_BY_BIT)
? !bitcmp(k, key, 0 , key_size)
: !memcmp(k, key, key_size)) {
if (c0 < ch) {
if (flags & GRN_CURSOR_DESCENDING) {
if ((ch > (int ) len - 1 ) || !(flags & GRN_CURSOR_GT)) {
push(c, node->lr[0 ], ch);
}
push(c, node->lr[1 ], ch);
} else {
push(c, node->lr[1 ], ch);
if ((ch > (int ) len - 1 ) || !(flags & GRN_CURSOR_GT)) {
push(c, node->lr[0 ], ch);
}
}
} else {
if (PAT_LEN(node) * 16 > len || !(flags & GRN_CURSOR_GT)) {
push(c, id, ch);
}
}
}
break ;
}
return GRN_SUCCESS;
}
inline static grn_rc
set_cursor_near(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
uint32_t min_size, const void *key, int flags)
{
grn_id id;
pat_node *node;
const uint8_t *k;
int r, check = -1 , ch;
uint32_t min = min_size * 16 ;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
KEY_ENCODE(pat, keybuf, key, pat->key_size);
PAT_AT(pat, 0 , node);
for (id = node->lr[1 ]; id;) {
PAT_AT(pat, id, node);
if (!node) { return GRN_FILE_CORRUPT; }
ch = PAT_CHK(node);
if (ch <= check) {
if (check >= (int ) min) { push(c, id, check); }
break ;
}
if ((check += 2 ) < ch) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
if ((r = bitcmp(key, k, check >> 1 , (ch - check) >> 1 ))) {
if (ch >= (int ) min) {
push(c, node->lr[1 ], ch);
push(c, node->lr[0 ], ch);
}
break ;
}
}
check = ch;
if (nth_bit((uint8_t *)key, check, pat->key_size)) {
if (check >= (int ) min) { push(c, node->lr[0 ], check); }
id = node->lr[1 ];
} else {
if (check >= (int ) min) { push(c, node->lr[1 ], check); }
id = node->lr[0 ];
}
}
return GRN_SUCCESS;
}
inline static grn_rc
set_cursor_common_prefix(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
uint32_t min_size, const void *key, uint32_t key_size, int flags)
{
grn_id id;
pat_node *node;
const uint8_t *k;
int check = -1 , ch;
uint32_t len = key_size * 16 ;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
KEY_ENCODE(pat, keybuf, key, key_size);
PAT_AT(pat, 0 , node);
for (id = node->lr[1 ]; id;) {
PAT_AT(pat, id, node);
if (!node) { return GRN_FILE_CORRUPT; }
ch = PAT_CHK(node);
if (ch <= check) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
{
uint32_t l = PAT_LEN(node);
if (min_size <= l && l <= key_size) {
if (!memcmp(key, k, l)) { push(c, id, check); }
}
}
break ;
}
check = ch;
if ((int ) len <= check) { break ; }
if (check & 1 ) {
grn_id id0 = node->lr[0 ];
pat_node *node0;
PAT_AT(pat, id0, node0);
if (!node0) { return GRN_FILE_CORRUPT; }
if (!(k = pat_node_get_key(ctx, pat, node0))) { return GRN_FILE_CORRUPT; }
{
uint32_t l = PAT_LEN(node0);
if (memcmp(key, k, l)) { break ; }
if (min_size <= l) {
push(c, id0, check);
}
}
id = node->lr[1 ];
} else {
id = node->lr[nth_bit((uint8_t *)key, check, len)];
}
}
return GRN_SUCCESS;
}
inline static grn_rc
set_cursor_ascend(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
const void *key, uint32_t key_size, int flags)
{
grn_id id;
pat_node *node;
const uint8_t *k;
int r, check = -1 , ch, c2;
uint32_t len = key_size * 16 ;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
KEY_ENCODE(pat, keybuf, key, key_size);
PAT_AT(pat, 0 , node);
for (id = node->lr[1 ]; id;) {
PAT_AT(pat, id, node);
if (!node) { return GRN_FILE_CORRUPT; }
ch = PAT_CHK(node);
if (ch <= check) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
{
uint32_t l = PAT_LEN(node);
if (l == key_size) {
if (flags & GRN_CURSOR_GT) {
if (memcmp(key, k, l) < 0 ) { push(c, id, check); }
} else {
if (memcmp(key, k, l) <= 0 ) { push(c, id, check); }
}
} else if (l < key_size) {
if (memcmp(key, k, l) < 0 ) { push(c, id, check); }
} else {
if (memcmp(key, k, key_size) <= 0 ) { push(c, id, check); }
}
}
break ;
}
c2 = (int ) len < ch ? (int ) len : ch;
if ((check += 2 ) < c2) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
if ((r = bitcmp(key, k, check >> 1 , ((c2 + 1 ) >> 1 ) - (check >> 1 )))) {
if (r < 0 ) {
push(c, node->lr[1 ], ch);
push(c, node->lr[0 ], ch);
}
break ;
}
}
check = ch;
if ((int ) len <= check) {
push(c, node->lr[1 ], ch);
push(c, node->lr[0 ], ch);
break ;
}
if (check & 1 ) {
if (check + 1 < (int ) len) {
id = node->lr[1 ];
} else {
push(c, node->lr[1 ], check);
id = node->lr[0 ];
}
} else {
if (nth_bit((uint8_t *)key, check, len)) {
id = node->lr[1 ];
} else {
push(c, node->lr[1 ], check);
id = node->lr[0 ];
}
}
}
return GRN_SUCCESS;
}
inline static grn_rc
set_cursor_descend(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
const void *key, uint32_t key_size, int flags)
{
grn_id id;
pat_node *node;
const uint8_t *k;
int r, check = -1 , ch, c2;
uint32_t len = key_size * 16 ;
uint8_t keybuf[MAX_FIXED_KEY_SIZE];
KEY_ENCODE(pat, keybuf, key, key_size);
PAT_AT(pat, 0 , node);
for (id = node->lr[1 ]; id;) {
PAT_AT(pat, id, node);
if (!node) { return GRN_FILE_CORRUPT; }
ch = PAT_CHK(node);
if (ch <= check) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
{
uint32_t l = PAT_LEN(node);
if (l <= key_size) {
if ((flags & GRN_CURSOR_LT) && l == key_size) {
if (memcmp(key, k, l) > 0 ) { push(c, id, check); }
} else {
if (memcmp(key, k, l) >= 0 ) { push(c, id, check); }
}
} else {
if (memcmp(key, k, key_size) > 0 ) { push(c, id, check); }
}
}
break ;
}
c2 = (int ) len < ch ? (int ) len : ch;
if ((check += 2 ) < c2) {
if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
if ((r = bitcmp(key, k, check >> 1 , ((c2 + 1 ) >> 1 ) - (check >> 1 )))) {
if (r >= 0 ) {
push(c, node->lr[0 ], ch);
push(c, node->lr[1 ], ch);
}
break ;
}
}
check = ch;
if ((int ) len <= check) { break ; }
if (check & 1 ) {
if (check + 1 < (int ) len) {
push(c, node->lr[0 ], check);
id = node->lr[1 ];
} else {
id = node->lr[0 ];
}
} else {
if (nth_bit((uint8_t *)key, check, len)) {
push(c, node->lr[0 ], check);
id = node->lr[1 ];
} else {
id = node->lr[0 ];
}
}
}
return GRN_SUCCESS;
}
static grn_pat_cursor *
grn_pat_cursor_open_by_id(grn_ctx *ctx, grn_pat *pat,
const void *min, uint32_t min_size,
const void *max, uint32_t max_size,
int offset, int limit, int flags)
{
int dir;
grn_pat_cursor *c;
if (!pat || !ctx) { return NULL; }
if (!(c = GRN_MALLOCN(grn_pat_cursor, 1 ))) { return NULL; }
GRN_DB_OBJ_SET_TYPE(c, GRN_CURSOR_TABLE_PAT_KEY);
c->pat = pat;
c->ctx = ctx;
c->obj.header.flags = flags;
c->obj.header.domain = GRN_ID_NIL;
c->size = 0 ;
c->sp = 0 ;
c->ss = NULL;
c->tail = 0 ;
if (flags & GRN_CURSOR_DESCENDING) {
dir = -1 ;
if (max) {
if (!(c->curr_rec = grn_pat_get(ctx, pat, max, max_size, NULL))) {
c->tail = GRN_ID_NIL;
goto exit ;
}
if (!(flags & GRN_CURSOR_LT)) { c->curr_rec++; }
} else {
c->curr_rec = pat->header->curr_rec + 1 ;
}
if (min) {
if (!(c->tail = grn_pat_get(ctx, pat, min, min_size, NULL))) {
c->curr_rec = GRN_ID_NIL;
goto exit ;
}
if ((flags & GRN_CURSOR_GT)) { c->tail++; }
} else {
c->tail = GRN_ID_NIL + 1 ;
}
if (c->curr_rec < c->tail) { c->tail = c->curr_rec; }
} else {
dir = 1 ;
if (min) {
if (!(c->curr_rec = grn_pat_get(ctx, pat, min, min_size, NULL))) {
c->tail = GRN_ID_NIL;
goto exit ;
}
if (!(flags & GRN_CURSOR_GT)) { c->curr_rec--; }
} else {
c->curr_rec = GRN_ID_NIL;
}
if (max) {
if (!(c->tail = grn_pat_get(ctx, pat, max, max_size, NULL))) {
c->curr_rec = GRN_ID_NIL;
goto exit ;
}
if ((flags & GRN_CURSOR_LT)) { c->tail--; }
} else {
c->tail = pat->header->curr_rec;
}
if (c->tail < c->curr_rec) { c->tail = c->curr_rec; }
}
if (pat->header->n_garbages) {
while (offset && c->curr_rec != c->tail) {
uint32_t key_size;
const void *key;
c->curr_rec += dir;
key = _grn_pat_key(ctx, pat, c->curr_rec, &key_size);
if (_grn_pat_get(ctx, pat, key, key_size, NULL) == c->curr_rec) {
offset--;
}
}
} else {
if ((int ) (dir * (c->tail - c->curr_rec)) < offset) {
c->curr_rec = c->tail;
} else {
c->curr_rec += dir * offset;
}
}
c->rest = (limit < 0 ) ? GRN_ID_MAX : limit;
exit :
return c;
}
static grn_rc set_cursor_rk(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
const void *key, uint32_t key_size, int flags);
grn_pat_cursor *
grn_pat_cursor_open(grn_ctx *ctx, grn_pat *pat,
const void *min, uint32_t min_size,
const void *max, uint32_t max_size,
int offset, int limit, int flags)
{
grn_id id;
pat_node *node;
grn_pat_cursor *c;
if (!pat || !ctx) { return NULL; }
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return NULL;
}
if ((flags & GRN_CURSOR_BY_ID)) {
return grn_pat_cursor_open_by_id(ctx, pat, min, min_size, max, max_size,
offset, limit, flags);
}
if (!(c = GRN_MALLOCN(grn_pat_cursor, 1 ))) { return NULL; }
GRN_DB_OBJ_SET_TYPE(c, GRN_CURSOR_TABLE_PAT_KEY);
c->pat = pat;
c->ctx = ctx;
c->size = 0 ;
c->sp = 0 ;
c->ss = NULL;
c->tail = 0 ;
c->rest = GRN_ID_MAX;
c->curr_rec = GRN_ID_NIL;
c->obj.header.domain = GRN_ID_NIL;
if (flags & GRN_CURSOR_PREFIX) {
if (max && max_size) {
if ((pat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
set_cursor_common_prefix(ctx, pat, c, min_size, max, max_size, flags);
} else {
set_cursor_near(ctx, pat, c, min_size, max, flags);
}
goto exit ;
} else {
if (min && min_size) {
if (flags & GRN_CURSOR_RK) {
set_cursor_rk(ctx, pat, c, min, min_size, flags);
} else {
set_cursor_prefix(ctx, pat, c, min, min_size, flags);
}
goto exit ;
}
}
}
if (flags & GRN_CURSOR_DESCENDING) {
if (min && min_size) {
set_cursor_ascend(ctx, pat, c, min, min_size, flags);
c->obj.header.flags = GRN_CURSOR_ASCENDING;
c->tail = grn_pat_cursor_next(ctx, c);
c->sp = 0 ;
if (!c->tail) { goto exit ; }
}
if (max && max_size) {
set_cursor_descend(ctx, pat, c, max, max_size, flags);
} else {
PAT_AT(pat, 0 , node);
if (!node) {
grn_pat_cursor_close(ctx, c);
return NULL;
}
if ((id = node->lr[1 ])) {
PAT_AT(pat, id, node);
if (node) {
int ch = PAT_CHK(node);
push(c, node->lr[0 ], ch);
push(c, node->lr[1 ], ch);
}
}
}
} else {
if (max && max_size) {
set_cursor_descend(ctx, pat, c, max, max_size, flags);
c->obj.header.flags = GRN_CURSOR_DESCENDING;
c->tail = grn_pat_cursor_next(ctx, c);
c->sp = 0 ;
if (!c->tail) { goto exit ; }
}
if (min && min_size) {
set_cursor_ascend(ctx, pat, c, min, min_size, flags);
} else {
PAT_AT(pat, 0 , node);
if (!node) {
grn_pat_cursor_close(ctx, c);
return NULL;
}
if ((id = node->lr[1 ])) {
PAT_AT(pat, id, node);
if (node) {
int ch = PAT_CHK(node);
push(c, node->lr[1 ], ch);
push(c, node->lr[0 ], ch);
}
}
}
}
exit :
c->obj.header.flags = flags;
c->curr_rec = GRN_ID_NIL;
while (offset--) { grn_pat_cursor_next(ctx, c); }
c->rest = (limit < 0 ) ? GRN_ID_MAX : limit;
return c;
}
int
grn_pat_cursor_get_key(grn_ctx *ctx, grn_pat_cursor *c, void **key)
{
*key = c->curr_key;
return grn_pat_get_key(ctx, c->pat, c->curr_rec, *key, GRN_TABLE_MAX_KEY_SIZE);
}
int
grn_pat_cursor_get_value(grn_ctx *ctx, grn_pat_cursor *c, void **value)
{
int value_size = (int )c->pat->value_size;
if (value_size) {
byte *v = (byte *)sis_at(ctx, c->pat, c->curr_rec);
if (v) {
if (c->pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
*value = v + sizeof (sis_node);
} else {
*value = v;
}
} else {
*value = NULL;
}
}
return value_size;
}
int
grn_pat_cursor_get_key_value(grn_ctx *ctx, grn_pat_cursor *c,
void **key, uint32_t *key_size, void **value)
{
int value_size = (int )c->pat->value_size;
if (key_size) {
*key_size = (uint32_t) grn_pat_get_key(ctx, c->pat, c->curr_rec, c->curr_key,
GRN_TABLE_MAX_KEY_SIZE);
if (key) { *key = c->curr_key; }
}
if (value && value_size) {
byte *v = (byte *)sis_at(ctx, c->pat, c->curr_rec);
if (v) {
if (c->pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
*value = v + sizeof (sis_node);
} else {
*value = v;
}
} else {
*value = NULL;
}
}
return value_size;
}
grn_rc
grn_pat_cursor_set_value(grn_ctx *ctx, grn_pat_cursor *c,
const void *value, int flags)
{
return grn_pat_set_value(ctx, c->pat, c->curr_rec, value, flags);
}
grn_rc
grn_pat_cursor_delete(grn_ctx *ctx, grn_pat_cursor *c,
grn_table_delete_optarg *optarg)
{
return grn_pat_delete_by_id(ctx, c->pat, c->curr_rec, optarg);
}
void
grn_pat_check(grn_ctx *ctx, grn_pat *pat)
{
char buf[8 ];
struct grn_pat_header *h = pat->header;
if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
return ;
}
GRN_OUTPUT_ARRAY_OPEN("RESULT" , 1 );
GRN_OUTPUT_MAP_OPEN("SUMMARY" , 23 );
GRN_OUTPUT_CSTR("flags" );
grn_itoh(h->flags, buf, 8 );
GRN_OUTPUT_STR(buf, 8 );
GRN_OUTPUT_CSTR("key size" );
GRN_OUTPUT_INT64(h->key_size);
GRN_OUTPUT_CSTR("value_size" );
GRN_OUTPUT_INT64(h->value_size);
GRN_OUTPUT_CSTR("tokenizer" );
GRN_OUTPUT_INT64(h->tokenizer);
GRN_OUTPUT_CSTR("normalizer" );
GRN_OUTPUT_INT64(h->normalizer);
GRN_OUTPUT_CSTR("n_entries" );
GRN_OUTPUT_INT64(h->n_entries);
GRN_OUTPUT_CSTR("curr_rec" );
GRN_OUTPUT_INT64(h->curr_rec);
GRN_OUTPUT_CSTR("curr_key" );
GRN_OUTPUT_INT64(h->curr_key);
GRN_OUTPUT_CSTR("curr_del" );
GRN_OUTPUT_INT64(h->curr_del);
GRN_OUTPUT_CSTR("curr_del2" );
GRN_OUTPUT_INT64(h->curr_del2);
GRN_OUTPUT_CSTR("curr_del3" );
GRN_OUTPUT_INT64(h->curr_del3);
GRN_OUTPUT_CSTR("n_garbages" );
GRN_OUTPUT_INT64(h->n_garbages);
GRN_OUTPUT_MAP_CLOSE();
GRN_OUTPUT_ARRAY_CLOSE();
}
/* utilities */
void
grn_p_pat_node(grn_ctx *ctx, grn_pat *pat, pat_node *node)
{
uint8_t *key = NULL;
if (!node) {
printf("#<pat_node:(null)>\n" );
return ;
}
if (PAT_IMD(node)) {
key = (uint8_t *)&(node->key);
} else {
KEY_AT(pat, node->key, key, 0 );
}
printf("#<pat_node:%p "
"left:%u "
"right:%u "
"deleting:%s "
"immediate:%s "
"length:%u "
"nth-byte:%u "
"nth-bit:%u "
"terminated:%s "
"key:<%.*s>"
">\n" ,
node,
node->lr[0 ],
node->lr[1 ],
PAT_DEL(node) ? "true" : "false" ,
PAT_IMD(node) ? "true" : "false" ,
PAT_LEN(node),
PAT_CHK(node) >> 4 ,
(PAT_CHK(node) >> 1 ) & 0 x7,
(PAT_CHK(node) & 0 x1) ? "true" : "false" ,
PAT_LEN(node),
(char *)key);
}
static void
grn_pat_inspect_check(grn_ctx *ctx, grn_obj *buf, int check)
{
GRN_TEXT_PUTS(ctx, buf, "{" );
grn_text_lltoa(ctx, buf, check >> 4 );
GRN_TEXT_PUTS(ctx, buf, "," );
grn_text_lltoa(ctx, buf, (check >> 1 ) & 7 );
GRN_TEXT_PUTS(ctx, buf, "," );
grn_text_lltoa(ctx, buf, check & 1 );
GRN_TEXT_PUTS(ctx, buf, "}" );
}
static void
grn_pat_inspect_node(grn_ctx *ctx, grn_pat *pat, grn_id id, int check,
grn_obj *key_buf, int indent, const char *prefix,
grn_obj *buf)
{
pat_node *node = NULL;
int i, c;
PAT_AT(pat, id, node);
c = PAT_CHK(node);
for (i = 0 ; i < indent; i++) {
GRN_TEXT_PUTC(ctx, buf, ' ' );
}
GRN_TEXT_PUTS(ctx, buf, prefix);
grn_text_lltoa(ctx, buf, id);
grn_pat_inspect_check(ctx, buf, c);
if (c > check) {
GRN_TEXT_PUTS(ctx, buf, "\n" );
grn_pat_inspect_node(ctx, pat, node->lr[0 ], c, key_buf,
indent + 2 , "L:" , buf);
GRN_TEXT_PUTS(ctx, buf, "\n" );
grn_pat_inspect_node(ctx, pat, node->lr[1 ], c, key_buf,
indent + 2 , "R:" , buf);
} else if (id) {
int key_size;
uint8_t *key;
key_size = PAT_LEN(node);
GRN_BULK_REWIND(key_buf);
grn_bulk_space(ctx, key_buf, key_size);
grn_pat_get_key(ctx, pat, id, GRN_BULK_HEAD(key_buf), key_size);
GRN_TEXT_PUTS(ctx, buf, "(" );
grn_inspect(ctx, buf, key_buf);
GRN_TEXT_PUTS(ctx, buf, ")" );
GRN_TEXT_PUTS(ctx, buf, "[" );
key = pat_node_get_key(ctx, pat, node);
for (i = 0 ; i < key_size; i++) {
int j;
uint8_t byte = key[i];
if (i != 0 ) {
GRN_TEXT_PUTS(ctx, buf, " " );
}
for (j = 0 ; j < 8 ; j++) {
grn_text_lltoa(ctx, buf, (byte >> (7 - j)) & 1 );
}
}
GRN_TEXT_PUTS(ctx, buf, "]" );
}
}
void
grn_pat_inspect_nodes(grn_ctx *ctx, grn_pat *pat, grn_obj *buf)
{
pat_node *node;
grn_obj key_buf;
GRN_TEXT_PUTS(ctx, buf, "{" );
PAT_AT(pat, GRN_ID_NIL, node);
if (node->lr[1 ]) {
GRN_TEXT_PUTS(ctx, buf, "\n" );
GRN_OBJ_INIT(&key_buf, GRN_BULK, 0 , pat->obj.header.domain);
grn_pat_inspect_node(ctx, pat, node->lr[1 ], -1 , &key_buf, 0 , "" , buf);
GRN_OBJ_FIN(ctx, &key_buf);
GRN_TEXT_PUTS(ctx, buf, "\n" );
}
GRN_TEXT_PUTS(ctx, buf, "}" );
}
static void
grn_pat_cursor_inspect_entries(grn_ctx *ctx, grn_pat_cursor *c, grn_obj *buf)
{
uint i;
GRN_TEXT_PUTS(ctx, buf, "[" );
for (i = 0 ; i < c->sp; i++) {
grn_pat_cursor_entry *e = c->ss + i;
if (i != 0 ) {
GRN_TEXT_PUTS(ctx, buf, ", " );
}
GRN_TEXT_PUTS(ctx, buf, "[" );
grn_text_lltoa(ctx, buf, e->id);
GRN_TEXT_PUTS(ctx, buf, "," );
grn_pat_inspect_check(ctx, buf, e->check);
GRN_TEXT_PUTS(ctx, buf, "]" );
}
GRN_TEXT_PUTS(ctx, buf, "]" );
}
void
grn_pat_cursor_inspect(grn_ctx *ctx, grn_pat_cursor *c, grn_obj *buf)
{
GRN_TEXT_PUTS(ctx, buf, "#<cursor:pat:" );
grn_inspect_name(ctx, buf, (grn_obj *)(c->pat));
GRN_TEXT_PUTS(ctx, buf, " " );
GRN_TEXT_PUTS(ctx, buf, "current:" );
grn_text_lltoa(ctx, buf, c->curr_rec);
GRN_TEXT_PUTS(ctx, buf, " " );
GRN_TEXT_PUTS(ctx, buf, "tail:" );
grn_text_lltoa(ctx, buf, c->tail);
GRN_TEXT_PUTS(ctx, buf, " " );
GRN_TEXT_PUTS(ctx, buf, "flags:" );
if (c->obj.header.flags & GRN_CURSOR_PREFIX) {
GRN_TEXT_PUTS(ctx, buf, "prefix" );
} else {
if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
GRN_TEXT_PUTS(ctx, buf, "descending" );
} else {
GRN_TEXT_PUTS(ctx, buf, "ascending" );
}
GRN_TEXT_PUTS(ctx, buf, "|" );
if (c->obj.header.flags & GRN_CURSOR_GT) {
GRN_TEXT_PUTS(ctx, buf, "greater-than" );
} else {
GRN_TEXT_PUTS(ctx, buf, "greater" );
}
GRN_TEXT_PUTS(ctx, buf, "|" );
if (c->obj.header.flags & GRN_CURSOR_LT) {
GRN_TEXT_PUTS(ctx, buf, "less-than" );
} else {
GRN_TEXT_PUTS(ctx, buf, "less" );
}
if (c->obj.header.flags & GRN_CURSOR_BY_ID) {
GRN_TEXT_PUTS(ctx, buf, "|by-id" );
}
if (c->obj.header.flags & GRN_CURSOR_BY_KEY) {
GRN_TEXT_PUTS(ctx, buf, "|by-key" );
}
}
GRN_TEXT_PUTS(ctx, buf, " " );
GRN_TEXT_PUTS(ctx, buf, "rest:" );
grn_text_lltoa(ctx, buf, c->rest);
GRN_TEXT_PUTS(ctx, buf, " " );
GRN_TEXT_PUTS(ctx, buf, "entries:" );
grn_pat_cursor_inspect_entries(ctx, c, buf);
GRN_TEXT_PUTS(ctx, buf, ">" );
}
typedef struct {
uint8_t code;
uint8_t next;
uint8_t emit;
uint8_t attr;
} rk_tree_node;
static uint16_t rk_str_idx[] = {
0 x0003, 0 x0006, 0 x0009, 0 x000c, 0 x0012, 0 x0015, 0 x0018, 0 x001e, 0 x0024, 0 x002a,
0 x0030, 0 x0036, 0 x003c, 0 x0042, 0 x0048, 0 x004e, 0 x0054, 0 x005a, 0 x0060, 0 x0066,
0 x006c, 0 x0072, 0 x0078, 0 x007e, 0 x0084, 0 x008a, 0 x0090, 0 x0096, 0 x009c, 0 x00a2,
0 x00a8, 0 x00ae, 0 x00b4, 0 x00ba, 0 x00c0, 0 x00c3, 0 x00c6, 0 x00c9, 0 x00cc, 0 x00cf,
0 x00d2, 0 x00d5, 0 x00db, 0 x00e1, 0 x00e7, 0 x00ea, 0 x00f0, 0 x00f6, 0 x00fc, 0 x00ff,
0 x0105, 0 x0108, 0 x010e, 0 x0111, 0 x0114, 0 x0117, 0 x011a, 0 x011d, 0 x0120, 0 x0123,
0 x0129, 0 x012f, 0 x0135, 0 x013b, 0 x013e, 0 x0144, 0 x014a, 0 x0150, 0 x0156, 0 x0159,
0 x015c, 0 x015f, 0 x0162, 0 x0165, 0 x0168, 0 x016b, 0 x016e, 0 x0171, 0 x0177, 0 x017d,
0 x0183, 0 x0189, 0 x018c, 0 x0192, 0 x0198, 0 x019e, 0 x01a1, 0 x01a4, 0 x01aa, 0 x01b0,
0 x01b6, 0 x01bc, 0 x01bf, 0 x01c2, 0 x01c8, 0 x01ce, 0 x01d1, 0 x01d7, 0 x01dd, 0 x01e0,
0 x01e6, 0 x01e9, 0 x01ef, 0 x01f2, 0 x01f5, 0 x01fb, 0 x0201, 0 x0207, 0 x020d, 0 x0213,
0 x0216, 0 x0219, 0 x021c, 0 x021f, 0 x0222, 0 x0225, 0 x0228, 0 x022e, 0 x0234, 0 x023a,
0 x023d, 0 x0243, 0 x0249, 0 x024f, 0 x0252, 0 x0258, 0 x025e, 0 x0264, 0 x0267, 0 x026d,
0 x0273, 0 x0279, 0 x027f, 0 x0285, 0 x0288, 0 x028b, 0 x028e, 0 x0291, 0 x0294, 0 x0297,
0 x029a, 0 x029d, 0 x02a0, 0 x02a3, 0 x02a9, 0 x02af, 0 x02b5, 0 x02b8, 0 x02bb, 0 x02be,
0 x02c1, 0 x02c4, 0 x02c7, 0 x02ca, 0 x02cd, 0 x02d0, 0 x02d3, 0 x02d6, 0 x02dc, 0 x02e2,
0 x02e8, 0 x02eb, 0 x02ee, 0 x02f1, 0 x02f4, 0 x02f7, 0 x02fa, 0 x02fd, 0 x0300, 0 x0303,
0 x0309, 0 x030c, 0 x0312, 0 x0318, 0 x031e, 0 x0324, 0 x0327, 0 x032a, 0 x032d
};
static char rk_str[] = {
0 xe3, 0 x82, 0 xa1, 0 xe3, 0 x82, 0 xa2, 0 xe3, 0 x82, 0 xa3, 0 xe3, 0 x82, 0 xa4, 0 xe3,
0 x82, 0 xa4, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x82, 0 xa5, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82,
0 xa6, 0 xe3, 0 x82, 0 xa2, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82, 0 xa3, 0 xe3, 0 x82, 0 xa6,
0 xe3, 0 x82, 0 xa4, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82, 0 xa6, 0 xe3,
0 x82, 0 xa7, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82, 0 xa8, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x82,
0 xaa, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa0, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa1,
0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa2, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa3, 0 xe3,
0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa4, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x82,
0 xa6, 0 xe3, 0 x83, 0 xa6, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x82, 0 xa6,
0 xe3, 0 x83, 0 xa8, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xa9, 0 xe3, 0 x82, 0 xa6, 0 xe3,
0 x83, 0 xaa, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xab, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83,
0 xac, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xad, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xae,
0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xaf, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xb0, 0 xe3,
0 x82, 0 xa6, 0 xe3, 0 x83, 0 xb1, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xb2, 0 xe3, 0 x82,
0 xa6, 0 xe3, 0 x83, 0 xb3, 0 xe3, 0 x82, 0 xa6, 0 xe3, 0 x83, 0 xbc, 0 xe3, 0 x82, 0 xa7,
0 xe3, 0 x82, 0 xa8, 0 xe3, 0 x82, 0 xa9, 0 xe3, 0 x82, 0 xaa, 0 xe3, 0 x82, 0 xab, 0 xe3,
0 x82, 0 xac, 0 xe3, 0 x82, 0 xad, 0 xe3, 0 x82, 0 xad, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x82,
0 xad, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x82, 0 xad, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x82, 0 xae,
0 xe3, 0 x82, 0 xae, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x82, 0 xae, 0 xe3, 0 x83, 0 xa5, 0 xe3,
0 x82, 0 xae, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x82, 0 xaf, 0 xe3, 0 x82, 0 xaf, 0 xe3, 0 x82,
0 xa1, 0 xe3, 0 x82, 0 xb0, 0 xe3, 0 x82, 0 xb0, 0 xe3, 0 x82, 0 xa1, 0 xe3, 0 x82, 0 xb1,
0 xe3, 0 x82, 0 xb2, 0 xe3, 0 x82, 0 xb3, 0 xe3, 0 x82, 0 xb4, 0 xe3, 0 x82, 0 xb5, 0 xe3,
0 x82, 0 xb6, 0 xe3, 0 x82, 0 xb7, 0 xe3, 0 x82, 0 xb7, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x82,
0 xb7, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x82, 0 xb7, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x82, 0 xb7,
0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x82, 0 xb8, 0 xe3, 0 x82, 0 xb8, 0 xe3, 0 x82, 0 xa7, 0 xe3,
0 x82, 0 xb8, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x82, 0 xb8, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x82,
0 xb8, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x82, 0 xb9, 0 xe3, 0 x82, 0 xba, 0 xe3, 0 x82, 0 xbb,
0 xe3, 0 x82, 0 xbc, 0 xe3, 0 x82, 0 xbd, 0 xe3, 0 x82, 0 xbe, 0 xe3, 0 x82, 0 xbf, 0 xe3,
0 x83, 0 x80, 0 xe3, 0 x83, 0 x81, 0 xe3, 0 x83, 0 x81, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x83,
0 x81, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x83, 0 x81, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x81,
0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83, 0 x82, 0 xe3, 0 x83, 0 x82, 0 xe3, 0 x83, 0 xa3, 0 xe3,
0 x83, 0 x82, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x82, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83,
0 x83, 0 xe3, 0 x83, 0 x84, 0 xe3, 0 x83, 0 x84, 0 xe3, 0 x82, 0 xa1, 0 xe3, 0 x83, 0 x84,
0 xe3, 0 x82, 0 xa3, 0 xe3, 0 x83, 0 x84, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x83, 0 x84, 0 xe3,
0 x82, 0 xa9, 0 xe3, 0 x83, 0 x85, 0 xe3, 0 x83, 0 x86, 0 xe3, 0 x83, 0 x86, 0 xe3, 0 x82,
0 xa3, 0 xe3, 0 x83, 0 x86, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x87, 0 xe3, 0 x83, 0 x87,
0 xe3, 0 x82, 0 xa3, 0 xe3, 0 x83, 0 x87, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x88, 0 xe3,
0 x83, 0 x88, 0 xe3, 0 x82, 0 xa5, 0 xe3, 0 x83, 0 x89, 0 xe3, 0 x83, 0 x89, 0 xe3, 0 x82,
0 xa5, 0 xe3, 0 x83, 0 x8a, 0 xe3, 0 x83, 0 x8b, 0 xe3, 0 x83, 0 x8b, 0 xe3, 0 x82, 0 xa3,
0 xe3, 0 x83, 0 x8b, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x83, 0 x8b, 0 xe3, 0 x83, 0 xa3, 0 xe3,
0 x83, 0 x8b, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x8b, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83,
0 x8c, 0 xe3, 0 x83, 0 x8d, 0 xe3, 0 x83, 0 x8e, 0 xe3, 0 x83, 0 x8f, 0 xe3, 0 x83, 0 x90,
0 xe3, 0 x83, 0 x91, 0 xe3, 0 x83, 0 x92, 0 xe3, 0 x83, 0 x92, 0 xe3, 0 x83, 0 xa3, 0 xe3,
0 x83, 0 x92, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x92, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83,
0 x93, 0 xe3, 0 x83, 0 x93, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x83, 0 x93, 0 xe3, 0 x83, 0 xa5,
0 xe3, 0 x83, 0 x93, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83, 0 x94, 0 xe3, 0 x83, 0 x94, 0 xe3,
0 x83, 0 xa3, 0 xe3, 0 x83, 0 x94, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x94, 0 xe3, 0 x83,
0 xa7, 0 xe3, 0 x83, 0 x95, 0 xe3, 0 x83, 0 x95, 0 xe3, 0 x82, 0 xa1, 0 xe3, 0 x83, 0 x95,
0 xe3, 0 x82, 0 xa3, 0 xe3, 0 x83, 0 x95, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x83, 0 x95, 0 xe3,
0 x82, 0 xa9, 0 xe3, 0 x83, 0 x95, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 x96, 0 xe3, 0 x83,
0 x97, 0 xe3, 0 x83, 0 x98, 0 xe3, 0 x83, 0 x99, 0 xe3, 0 x83, 0 x9a, 0 xe3, 0 x83, 0 x9b,
0 xe3, 0 x83, 0 x9c, 0 xe3, 0 x83, 0 x9d, 0 xe3, 0 x83, 0 x9e, 0 xe3, 0 x83, 0 x9f, 0 xe3,
0 x83, 0 x9f, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x83, 0 x9f, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83,
0 x9f, 0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83, 0 xa0, 0 xe3, 0 x83, 0 xa1, 0 xe3, 0 x83, 0 xa2,
0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x83, 0 xa4, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 xa6, 0 xe3,
0 x83, 0 xa7, 0 xe3, 0 x83, 0 xa8, 0 xe3, 0 x83, 0 xa9, 0 xe3, 0 x83, 0 xaa, 0 xe3, 0 x83,
0 xaa, 0 xe3, 0 x83, 0 xa3, 0 xe3, 0 x83, 0 xaa, 0 xe3, 0 x83, 0 xa5, 0 xe3, 0 x83, 0 xaa,
0 xe3, 0 x83, 0 xa7, 0 xe3, 0 x83, 0 xab, 0 xe3, 0 x83, 0 xac, 0 xe3, 0 x83, 0 xad, 0 xe3,
0 x83, 0 xae, 0 xe3, 0 x83, 0 xaf, 0 xe3, 0 x83, 0 xb0, 0 xe3, 0 x83, 0 xb1, 0 xe3, 0 x83,
0 xb2, 0 xe3, 0 x83, 0 xb3, 0 xe3, 0 x83, 0 xb3, 0 xe3, 0 x83, 0 xbc, 0 xe3, 0 x83, 0 xb4,
0 xe3, 0 x83, 0 xb4, 0 xe3, 0 x82, 0 xa1, 0 xe3, 0 x83, 0 xb4, 0 xe3, 0 x82, 0 xa3, 0 xe3,
0 x83, 0 xb4, 0 xe3, 0 x82, 0 xa7, 0 xe3, 0 x83, 0 xb4, 0 xe3, 0 x82, 0 xa9, 0 xe3, 0 x83,
0 xb5, 0 xe3, 0 x83, 0 xb6, 0 xe3, 0 x83, 0 xbc
};
static uint16_t rk_tree_idx[] = {
0 x001b, 0 x0022, 0 x0025, 0 x0028, 0 x002d, 0 x0030, 0 x0039, 0 x003b, 0 x003c, 0 x003f,
0 x0046, 0 x0047, 0 x004f, 0 x0050, 0 x0053, 0 x005a, 0 x005d, 0 x0064, 0 x0067, 0 x006f,
0 x0070, 0 x0073, 0 x007d, 0 x007f, 0 x0081, 0 x0082, 0 x0083, 0 x0088, 0 x008f, 0 x0092,
0 x00af, 0 x00b5, 0 x00bc, 0 x00bf, 0 x00c6, 0 x00c9, 0 x00d1, 0 x00d6, 0 x00da, 0 x00e4,
0 x00e6, 0 x00eb, 0 x00ec, 0 x00f0, 0 x00f6, 0 x00fc, 0 x00fe, 0 x0108, 0 x010a, 0 x010c,
0 x010d, 0 x010e, 0 x0113, 0 x0118, 0 x011f, 0 x0123, 0 x0125, 0 x0164, 0 x0180, 0 x0183,
0 x0199, 0 x01ad
};
static rk_tree_node rk_tree[] = {
{0 x2d, 0 x00, 0 xb2, 0 x01}, {0 x61, 0 x00, 0 x01, 0 x01}, {0 x62, 0 x01, 0 xff, 0 x01},
{0 x63, 0 x03, 0 xff, 0 x01}, {0 x64, 0 x06, 0 xff, 0 x01}, {0 x65, 0 x00, 0 x24, 0 x01},
{0 x66, 0 x0a, 0 xff, 0 x01}, {0 x67, 0 x0c, 0 xff, 0 x01}, {0 x68, 0 x0f, 0 xff, 0 x01},
{0 x69, 0 x00, 0 x03, 0 x01}, {0 x6a, 0 x11, 0 xff, 0 x01}, {0 x6b, 0 x13, 0 xff, 0 x01},
{0 x6c, 0 x16, 0 xff, 0 x01}, {0 x6d, 0 x1c, 0 xff, 0 x01}, {0 x6e, 0 x1e, 0 xff, 0 x01},
{0 x6f, 0 x00, 0 x26, 0 x01}, {0 x70, 0 x20, 0 xff, 0 x01}, {0 x72, 0 x22, 0 xff, 0 x01},
{0 x73, 0 x24, 0 xff, 0 x01}, {0 x74, 0 x27, 0 xff, 0 x01}, {0 x75, 0 x00, 0 x06, 0 x01},
{0 x76, 0 x2c, 0 xff, 0 x01}, {0 x77, 0 x2d, 0 xff, 0 x01}, {0 x78, 0 x2f, 0 xff, 0 x01},
{0 x79, 0 x35, 0 xff, 0 x01}, {0 x7a, 0 x36, 0 xff, 0 x01}, {0 xe3, 0 x38, 0 xff, 0 x01},
{0 x61, 0 x00, 0 x72, 0 x01}, {0 x62, 0 x01, 0 x56, 0 x01}, {0 x65, 0 x00, 0 x89, 0 x01},
{0 x69, 0 x00, 0 x78, 0 x01}, {0 x6f, 0 x00, 0 x8c, 0 x01}, {0 x75, 0 x00, 0 x86, 0 x01},
{0 x79, 0 x02, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x79, 0 x01}, {0 x6f, 0 x00, 0 x7b, 0 x01},
{0 x75, 0 x00, 0 x7a, 0 x01}, {0 x63, 0 x03, 0 x56, 0 x01}, {0 x68, 0 x04, 0 xff, 0 x01},
{0 x79, 0 x05, 0 xff, 0 x01}, {0 x61, 0 x00, 0 x4f, 0 x00}, {0 x65, 0 x00, 0 x4e, 0 x00},
{0 x69, 0 x00, 0 x4d, 0 x01}, {0 x6f, 0 x00, 0 x51, 0 x00}, {0 x75, 0 x00, 0 x50, 0 x00},
{0 x61, 0 x00, 0 x4f, 0 x01}, {0 x6f, 0 x00, 0 x51, 0 x01}, {0 x75, 0 x00, 0 x50, 0 x01},
{0 x61, 0 x00, 0 x4c, 0 x01}, {0 x64, 0 x06, 0 x56, 0 x01}, {0 x65, 0 x00, 0 x60, 0 x01},
{0 x68, 0 x07, 0 xff, 0 x00}, {0 x69, 0 x00, 0 x61, 0 x00}, {0 x6f, 0 x00, 0 x65, 0 x01},
{0 x75, 0 x00, 0 x5c, 0 x01}, {0 x77, 0 x08, 0 xff, 0 x00}, {0 x79, 0 x09, 0 xff, 0 x01},
{0 x69, 0 x00, 0 x61, 0 x01}, {0 x75, 0 x00, 0 x62, 0 x01}, {0 x75, 0 x00, 0 x66, 0 x01},
{0 x61, 0 x00, 0 x53, 0 x01}, {0 x6f, 0 x00, 0 x55, 0 x01}, {0 x75, 0 x00, 0 x54, 0 x01},
{0 x61, 0 x00, 0 x81, 0 x00}, {0 x65, 0 x00, 0 x83, 0 x00}, {0 x66, 0 x0a, 0 x56, 0 x01},
{0 x69, 0 x00, 0 x82, 0 x00}, {0 x6f, 0 x00, 0 x84, 0 x00}, {0 x75, 0 x00, 0 x80, 0 x01},
{0 x79, 0 x0b, 0 xff, 0 x00}, {0 x75, 0 x00, 0 x85, 0 x01}, {0 x61, 0 x00, 0 x28, 0 x01},
{0 x65, 0 x00, 0 x36, 0 x01}, {0 x67, 0 x0c, 0 x56, 0 x01}, {0 x69, 0 x00, 0 x2d, 0 x01},
{0 x6f, 0 x00, 0 x38, 0 x01}, {0 x75, 0 x00, 0 x33, 0 x01}, {0 x77, 0 x0d, 0 xff, 0 x00},
{0 x79, 0 x0e, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x34, 0 x01}, {0 x61, 0 x00, 0 x2e, 0 x01},
{0 x6f, 0 x00, 0 x30, 0 x01}, {0 x75, 0 x00, 0 x2f, 0 x01}, {0 x61, 0 x00, 0 x71, 0 x01},
{0 x65, 0 x00, 0 x88, 0 x01}, {0 x68, 0 x0f, 0 x56, 0 x01}, {0 x69, 0 x00, 0 x74, 0 x01},
{0 x6f, 0 x00, 0 x8b, 0 x01}, {0 x75, 0 x00, 0 x80, 0 x01}, {0 x79, 0 x10, 0 xff, 0 x00},
{0 x61, 0 x00, 0 x75, 0 x01}, {0 x6f, 0 x00, 0 x77, 0 x01}, {0 x75, 0 x00, 0 x76, 0 x01},
{0 x61, 0 x00, 0 x42, 0 x00}, {0 x65, 0 x00, 0 x41, 0 x00}, {0 x69, 0 x00, 0 x40, 0 x01},
{0 x6a, 0 x11, 0 x56, 0 x01}, {0 x6f, 0 x00, 0 x44, 0 x00}, {0 x75, 0 x00, 0 x43, 0 x00},
{0 x79, 0 x12, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x42, 0 x01}, {0 x6f, 0 x00, 0 x44, 0 x01},
{0 x75, 0 x00, 0 x43, 0 x01}, {0 x61, 0 x00, 0 x27, 0 x01}, {0 x65, 0 x00, 0 x35, 0 x01},
{0 x69, 0 x00, 0 x29, 0 x01}, {0 x6b, 0 x13, 0 x56, 0 x01}, {0 x6f, 0 x00, 0 x37, 0 x01},
{0 x75, 0 x00, 0 x31, 0 x01}, {0 x77, 0 x14, 0 xff, 0 x00}, {0 x79, 0 x15, 0 xff, 0 x00},
{0 x61, 0 x00, 0 x32, 0 x01}, {0 x61, 0 x00, 0 x2a, 0 x01}, {0 x6f, 0 x00, 0 x2c, 0 x01},
{0 x75, 0 x00, 0 x2b, 0 x01}, {0 x61, 0 x00, 0 x00, 0 x01}, {0 x65, 0 x00, 0 x23, 0 x01},
{0 x69, 0 x00, 0 x02, 0 x01}, {0 x6b, 0 x17, 0 xff, 0 x01}, {0 x6c, 0 x16, 0 x56, 0 x01},
{0 x6f, 0 x00, 0 x25, 0 x01}, {0 x74, 0 x18, 0 xff, 0 x01}, {0 x75, 0 x00, 0 x05, 0 x01},
{0 x77, 0 x1a, 0 xff, 0 x01}, {0 x79, 0 x1b, 0 xff, 0 x01}, {0 x61, 0 x00, 0 xb0, 0 x01},
{0 x65, 0 x00, 0 xb1, 0 x01}, {0 x73, 0 x19, 0 xff, 0 x00}, {0 x75, 0 x00, 0 x56, 0 x01},
{0 x75, 0 x00, 0 x56, 0 x01}, {0 x61, 0 x00, 0 xa4, 0 x01}, {0 x61, 0 x00, 0 x96, 0 x01},
{0 x65, 0 x00, 0 x23, 0 x01}, {0 x69, 0 x00, 0 x02, 0 x01}, {0 x6f, 0 x00, 0 x9a, 0 x01},
{0 x75, 0 x00, 0 x98, 0 x01}, {0 x61, 0 x00, 0 x8e, 0 x01}, {0 x65, 0 x00, 0 x94, 0 x01},
{0 x69, 0 x00, 0 x8f, 0 x01}, {0 x6d, 0 x1c, 0 x56, 0 x01}, {0 x6f, 0 x00, 0 x95, 0 x01},
{0 x75, 0 x00, 0 x93, 0 x01}, {0 x79, 0 x1d, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x90, 0 x01},
{0 x6f, 0 x00, 0 x92, 0 x01}, {0 x75, 0 x00, 0 x91, 0 x01}, {0 x00, 0 x00, 0 xa9, 0 x01},
{0 x27, 0 x00, 0 xa9, 0 x00}, {0 x2d, 0 x00, 0 xaa, 0 x00}, {0 x61, 0 x00, 0 x67, 0 x01},
{0 x62, 0 x01, 0 xa9, 0 x00}, {0 x63, 0 x03, 0 xa9, 0 x00}, {0 x64, 0 x06, 0 xa9, 0 x00},
{0 x65, 0 x00, 0 x6f, 0 x01}, {0 x66, 0 x0a, 0 xa9, 0 x00}, {0 x67, 0 x0c, 0 xa9, 0 x00},
{0 x68, 0 x0f, 0 xa9, 0 x00}, {0 x69, 0 x00, 0 x68, 0 x01}, {0 x6a, 0 x11, 0 xa9, 0 x00},
{0 x6b, 0 x13, 0 xa9, 0 x00}, {0 x6c, 0 x16, 0 xa9, 0 x00}, {0 x6d, 0 x1c, 0 xa9, 0 x00},
{0 x6e, 0 x00, 0 xa9, 0 x00}, {0 x6f, 0 x00, 0 x70, 0 x01}, {0 x70, 0 x20, 0 xa9, 0 x00},
{0 x72, 0 x22, 0 xa9, 0 x00}, {0 x73, 0 x24, 0 xa9, 0 x00}, {0 x74, 0 x27, 0 xa9, 0 x00},
{0 x75, 0 x00, 0 x6e, 0 x01}, {0 x76, 0 x2c, 0 xa9, 0 x00}, {0 x77, 0 x2d, 0 xa9, 0 x00},
{0 x78, 0 x2f, 0 xa9, 0 x00}, {0 x79, 0 x1f, 0 xff, 0 x00}, {0 x7a, 0 x36, 0 xa9, 0 x00},
{0 xe3, 0 x38, 0 xa9, 0 x00}, {0 x00, 0 x00, 0 xa9, 0 x01}, {0 x61, 0 x00, 0 x6b, 0 x01},
{0 x65, 0 x00, 0 x6a, 0 x01}, {0 x69, 0 x00, 0 x69, 0 x01}, {0 x6f, 0 x00, 0 x6d, 0 x01},
{0 x75, 0 x00, 0 x6c, 0 x01}, {0 x61, 0 x00, 0 x73, 0 x01}, {0 x65, 0 x00, 0 x8a, 0 x01},
{0 x69, 0 x00, 0 x7c, 0 x01}, {0 x6f, 0 x00, 0 x8d, 0 x01}, {0 x70, 0 x20, 0 x56, 0 x01},
{0 x75, 0 x00, 0 x87, 0 x01}, {0 x79, 0 x21, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x7d, 0 x01},
{0 x6f, 0 x00, 0 x7f, 0 x01}, {0 x75, 0 x00, 0 x7e, 0 x01}, {0 x61, 0 x00, 0 x9c, 0 x01},
{0 x65, 0 x00, 0 xa2, 0 x01}, {0 x69, 0 x00, 0 x9d, 0 x01}, {0 x6f, 0 x00, 0 xa3, 0 x01},
{0 x72, 0 x22, 0 x56, 0 x01}, {0 x75, 0 x00, 0 xa1, 0 x01}, {0 x79, 0 x23, 0 xff, 0 x00},
{0 x61, 0 x00, 0 x9e, 0 x01}, {0 x6f, 0 x00, 0 xa0, 0 x01}, {0 x75, 0 x00, 0 x9f, 0 x01},
{0 x61, 0 x00, 0 x39, 0 x01}, {0 x65, 0 x00, 0 x47, 0 x01}, {0 x68, 0 x25, 0 xff, 0 x00},
{0 x69, 0 x00, 0 x3b, 0 x01}, {0 x6f, 0 x00, 0 x49, 0 x01}, {0 x73, 0 x24, 0 x56, 0 x01},
{0 x75, 0 x00, 0 x45, 0 x01}, {0 x79, 0 x26, 0 xff, 0 x00}, {0 x61, 0 x00, 0 x3d, 0 x00},
{0 x65, 0 x00, 0 x3c, 0 x00}, {0 x69, 0 x00, 0 x3b, 0 x01}, {0 x6f, 0 x00, 0 x3f, 0 x00},
{0 x75, 0 x00, 0 x3e, 0 x00}, {0 x61, 0 x00, 0 x3d, 0 x01}, {0 x65, 0 x00, 0 x3c, 0 x01},
{0 x6f, 0 x00, 0 x3f, 0 x01}, {0 x75, 0 x00, 0 x3e, 0 x01}, {0 x61, 0 x00, 0 x4b, 0 x01},
{0 x65, 0 x00, 0 x5d, 0 x01}, {0 x68, 0 x28, 0 xff, 0 x00}, {0 x69, 0 x00, 0 x4d, 0 x01},
{0 x6f, 0 x00, 0 x63, 0 x01}, {0 x73, 0 x29, 0 xff, 0 x00}, {0 x74, 0 x27, 0 x56, 0 x01},
{0 x75, 0 x00, 0 x57, 0 x01}, {0 x77, 0 x2a, 0 xff, 0 x00}, {0 x79, 0 x2b, 0 xff, 0 x00},
{0 x69, 0 x00, 0 x5e, 0 x01}, {0 x75, 0 x00, 0 x5f, 0 x01}, {0 x61, 0 x00, 0 x58, 0 x00},
{0 x65, 0 x00, 0 x5a, 0 x00}, {0 x69, 0 x00, 0 x59, 0 x00}, {0 x6f, 0 x00, 0 x5b, 0 x00},
{0 x75, 0 x00, 0 x57, 0 x01}, {0 x75, 0 x00, 0 x64, 0 x01}, {0 x61, 0 x00, 0 x4f, 0 x01},
{0 x65, 0 x00, 0 x4e, 0 x01}, {0 x6f, 0 x00, 0 x51, 0 x01}, {0 x75, 0 x00, 0 x50, 0 x01},
{0 x61, 0 x00, 0 xac, 0 x00}, {0 x65, 0 x00, 0 xae, 0 x00}, {0 x69, 0 x00, 0 xad, 0 x00},
{0 x6f, 0 x00, 0 xaf, 0 x00}, {0 x75, 0 x00, 0 xab, 0 x01}, {0 x76, 0 x2c, 0 x56, 0 x01},
{0 x61, 0 x00, 0 xa5, 0 x01}, {0 x65, 0 x00, 0 x0b, 0 x01}, {0 x69, 0 x00, 0 x08, 0 x01},
{0 x6f, 0 x00, 0 xa8, 0 x01}, {0 x77, 0 x2d, 0 x56, 0 x01}, {0 x79, 0 x2e, 0 xff, 0 x01},
{0 x65, 0 x00, 0 xa7, 0 x01}, {0 x69, 0 x00, 0 xa6, 0 x01}, {0 x61, 0 x00, 0 x00, 0 x01},
{0 x65, 0 x00, 0 x23, 0 x01}, {0 x69, 0 x00, 0 x02, 0 x01}, {0 x6b, 0 x30, 0 xff, 0 x01},
{0 x6f, 0 x00, 0 x25, 0 x01}, {0 x74, 0 x31, 0 xff, 0 x01}, {0 x75, 0 x00, 0 x05, 0 x01},
{0 x77, 0 x33, 0 xff, 0 x01}, {0 x78, 0 x2f, 0 x56, 0 x01}, {0 x79, 0 x34, 0 xff, 0 x01},
{0 x61, 0 x00, 0 xb0, 0 x01}, {0 x65, 0 x00, 0 xb1, 0 x01}, {0 x73, 0 x32, 0 xff, 0 x00},
{0 x75, 0 x00, 0 x56, 0 x01}, {0 x75, 0 x00, 0 x56, 0 x01}, {0 x61, 0 x00, 0 xa4, 0 x01},
{0 x61, 0 x00, 0 x96, 0 x01}, {0 x65, 0 x00, 0 x23, 0 x01}, {0 x69, 0 x00, 0 x02, 0 x01},
{0 x6f, 0 x00, 0 x9a, 0 x01}, {0 x75, 0 x00, 0 x98, 0 x01}, {0 x61, 0 x00, 0 x97, 0 x01},
{0 x65, 0 x00, 0 x04, 0 x01}, {0 x6f, 0 x00, 0 x9b, 0 x01}, {0 x75, 0 x00, 0 x99, 0 x01},
{0 x79, 0 x35, 0 x56, 0 x01}, {0 x61, 0 x00, 0 x3a, 0 x01}, {0 x65, 0 x00, 0 x48, 0 x01},
{0 x69, 0 x00, 0 x40, 0 x01}, {0 x6f, 0 x00, 0 x4a, 0 x01}, {0 x75, 0 x00, 0 x46, 0 x01},
{0 x79, 0 x37, 0 xff, 0 x00}, {0 x7a, 0 x36, 0 x56, 0 x01}, {0 x61, 0 x00, 0 x42, 0 x01},
{0 x65, 0 x00, 0 x41, 0 x01}, {0 x6f, 0 x00, 0 x44, 0 x01}, {0 x75, 0 x00, 0 x43, 0 x01},
{0 x81, 0 x39, 0 xff, 0 x01}, {0 x82, 0 x3d, 0 xff, 0 x01}, {0 x81, 0 x00, 0 x00, 0 x01},
{0 x82, 0 x00, 0 x01, 0 x01}, {0 x83, 0 x00, 0 x02, 0 x01}, {0 x84, 0 x00, 0 x03, 0 x01},
{0 x85, 0 x00, 0 x05, 0 x01}, {0 x86, 0 x3a, 0 xff, 0 x01}, {0 x87, 0 x00, 0 x23, 0 x01},
{0 x88, 0 x00, 0 x24, 0 x01}, {0 x89, 0 x00, 0 x25, 0 x01}, {0 x8a, 0 x00, 0 x26, 0 x01},
{0 x8b, 0 x00, 0 x27, 0 x01}, {0 x8c, 0 x00, 0 x28, 0 x01}, {0 x8d, 0 x00, 0 x29, 0 x01},
{0 x8e, 0 x00, 0 x2d, 0 x01}, {0 x8f, 0 x00, 0 x31, 0 x01}, {0 x90, 0 x00, 0 x33, 0 x01},
{0 x91, 0 x00, 0 x35, 0 x01}, {0 x92, 0 x00, 0 x36, 0 x01}, {0 x93, 0 x00, 0 x37, 0 x01},
{0 x94, 0 x00, 0 x38, 0 x01}, {0 x95, 0 x00, 0 x39, 0 x01}, {0 x96, 0 x00, 0 x3a, 0 x01},
{0 x97, 0 x00, 0 x3b, 0 x01}, {0 x98, 0 x00, 0 x40, 0 x01}, {0 x99, 0 x00, 0 x45, 0 x01},
{0 x9a, 0 x00, 0 x46, 0 x01}, {0 x9b, 0 x00, 0 x47, 0 x01}, {0 x9c, 0 x00, 0 x48, 0 x01},
{0 x9d, 0 x00, 0 x49, 0 x01}, {0 x9e, 0 x00, 0 x4a, 0 x01}, {0 x9f, 0 x00, 0 x4b, 0 x01},
{0 xa0, 0 x00, 0 x4c, 0 x01}, {0 xa1, 0 x00, 0 x4d, 0 x01}, {0 xa2, 0 x00, 0 x52, 0 x01},
{0 xa3, 0 x00, 0 x56, 0 x01}, {0 xa4, 0 x00, 0 x57, 0 x01}, {0 xa5, 0 x00, 0 x5c, 0 x01},
{0 xa6, 0 x00, 0 x5d, 0 x01}, {0 xa7, 0 x00, 0 x60, 0 x01}, {0 xa8, 0 x00, 0 x63, 0 x01},
{0 xa9, 0 x00, 0 x65, 0 x01}, {0 xaa, 0 x00, 0 x67, 0 x01}, {0 xab, 0 x00, 0 x68, 0 x01},
{0 xac, 0 x00, 0 x6e, 0 x01}, {0 xad, 0 x00, 0 x6f, 0 x01}, {0 xae, 0 x00, 0 x70, 0 x01},
{0 xaf, 0 x00, 0 x71, 0 x01}, {0 xb0, 0 x00, 0 x72, 0 x01}, {0 xb1, 0 x00, 0 x73, 0 x01},
{0 xb2, 0 x00, 0 x74, 0 x01}, {0 xb3, 0 x00, 0 x78, 0 x01}, {0 xb4, 0 x00, 0 x7c, 0 x01},
{0 xb5, 0 x00, 0 x80, 0 x01}, {0 xb6, 0 x00, 0 x86, 0 x01}, {0 xb7, 0 x00, 0 x87, 0 x01},
{0 xb8, 0 x00, 0 x88, 0 x01}, {0 xb9, 0 x00, 0 x89, 0 x01}, {0 xba, 0 x00, 0 x8a, 0 x01},
{0 xbb, 0 x00, 0 x8b, 0 x01}, {0 xbc, 0 x00, 0 x8c, 0 x01}, {0 xbd, 0 x00, 0 x8d, 0 x01},
{0 xbe, 0 x00, 0 x8e, 0 x01}, {0 xbf, 0 x00, 0 x8f, 0 x01}, {0 x00, 0 x00, 0 x06, 0 x00},
{0 x2d, 0 x00, 0 x22, 0 x00}, {0 x61, 0 x00, 0 x07, 0 x00}, {0 x62, 0 x01, 0 x06, 0 x00},
{0 x63, 0 x03, 0 x06, 0 x00}, {0 x64, 0 x06, 0 x06, 0 x00}, {0 x65, 0 x00, 0 x0c, 0 x00},
{0 x66, 0 x0a, 0 x06, 0 x00}, {0 x67, 0 x0c, 0 x06, 0 x00}, {0 x68, 0 x0f, 0 x06, 0 x00},
{0 x69, 0 x00, 0 x09, 0 x00}, {0 x6a, 0 x11, 0 x06, 0 x00}, {0 x6b, 0 x13, 0 x06, 0 x00},
{0 x6c, 0 x16, 0 x06, 0 x00}, {0 x6d, 0 x1c, 0 x06, 0 x00}, {0 x6e, 0 x1e, 0 x06, 0 x00},
{0 x6f, 0 x00, 0 x0d, 0 x00}, {0 x70, 0 x20, 0 x06, 0 x00}, {0 x72, 0 x22, 0 x06, 0 x00},
{0 x73, 0 x24, 0 x06, 0 x00}, {0 x74, 0 x27, 0 x06, 0 x00}, {0 x75, 0 x00, 0 x0a, 0 x00},
{0 x76, 0 x2c, 0 x06, 0 x00}, {0 x77, 0 x2d, 0 x06, 0 x00}, {0 x78, 0 x2f, 0 x06, 0 x00},
{0 x79, 0 x35, 0 x06, 0 x00}, {0 x7a, 0 x36, 0 x06, 0 x00}, {0 xe3, 0 x3b, 0 xff, 0 x01},
{0 x00, 0 x00, 0 x06, 0 x00}, {0 x81, 0 x39, 0 x06, 0 x00}, {0 x82, 0 x3c, 0 xff, 0 x01},
{0 x00, 0 x00, 0 x06, 0 x01}, {0 x80, 0 x00, 0 x0e, 0 x00}, {0 x81, 0 x00, 0 x0f, 0 x00},
{0 x82, 0 x00, 0 x10, 0 x00}, {0 x83, 0 x00, 0 x11, 0 x00}, {0 x84, 0 x00, 0 x12, 0 x00},
{0 x85, 0 x00, 0 x13, 0 x00}, {0 x86, 0 x00, 0 x14, 0 x00}, {0 x87, 0 x00, 0 x15, 0 x00},
{0 x88, 0 x00, 0 x16, 0 x00}, {0 x89, 0 x00, 0 x17, 0 x00}, {0 x8a, 0 x00, 0 x18, 0 x00},
{0 x8b, 0 x00, 0 x19, 0 x00}, {0 x8c, 0 x00, 0 x1a, 0 x00}, {0 x8d, 0 x00, 0 x1b, 0 x00},
{0 x8e, 0 x00, 0 x1c, 0 x00}, {0 x8f, 0 x00, 0 x1d, 0 x00}, {0 x90, 0 x00, 0 x1e, 0 x00},
{0 x91, 0 x00, 0 x1f, 0 x00}, {0 x92, 0 x00, 0 x20, 0 x00}, {0 x93, 0 x00, 0 x21, 0 x00},
{0 x9b, 0 x00, 0 xab, 0 x01}, {0 x80, 0 x00, 0 x93, 0 x01}, {0 x81, 0 x00, 0 x94, 0 x01},
{0 x82, 0 x00, 0 x95, 0 x01}, {0 x83, 0 x00, 0 x96, 0 x01}, {0 x84, 0 x00, 0 x97, 0 x01},
{0 x85, 0 x00, 0 x98, 0 x01}, {0 x86, 0 x00, 0 x99, 0 x01}, {0 x87, 0 x00, 0 x9a, 0 x01},
{0 x88, 0 x00, 0 x9b, 0 x01}, {0 x89, 0 x00, 0 x9c, 0 x01}, {0 x8a, 0 x00, 0 x9d, 0 x01},
{0 x8b, 0 x00, 0 xa1, 0 x01}, {0 x8c, 0 x00, 0 xa2, 0 x01}, {0 x8d, 0 x00, 0 xa3, 0 x01},
{0 x8e, 0 x00, 0 xa4, 0 x01}, {0 x8f, 0 x00, 0 xa5, 0 x01}, {0 x90, 0 x00, 0 xa6, 0 x01},
{0 x91, 0 x00, 0 xa7, 0 x01}, {0 x92, 0 x00, 0 xa8, 0 x01}, {0 x93, 0 x00, 0 xa9, 0 x01}
};
static rk_tree_node *
rk_lookup(uint8_t state, uint8_t code)
{
if (state < sizeof (rk_tree_idx)/sizeof (uint16_t)) {
uint16_t ns = state ? rk_tree_idx[state - 1 ] : 0 ;
uint16_t ne = rk_tree_idx[state];
while (ns < ne) {
uint16_t m = (ns + ne)>>1 ;
rk_tree_node *rn = &rk_tree[m];
if (rn->code == code) { return rn; }
if (rn->code < code) {
ns = m + 1 ;
} else {
ne = m;
}
}
}
return NULL;
}
static uint32_t
rk_emit(rk_tree_node *rn, char **str)
{
if (rn && rn->emit != 0 xff) {
uint16_t pos = rn->emit ? rk_str_idx[rn->emit - 1 ] : 0 ;
*str = &rk_str[pos];
return (uint32_t)(rk_str_idx[rn->emit] - pos);
} else {
*str = NULL;
return 0 ;
}
}
#define RK_OUTPUT(e,l) do {\
if (oc < oe) {\
uint32_t l_ = (oc + (l) < oe) ? (l) : (oe - oc);\
grn_memcpy(oc, (e), l_);\
oc += l_;\
ic_ = ic;\
}\
} while (0 )
static uint32_t
rk_conv(const char *str, uint32_t str_len, uint8_t *buf, uint32_t buf_size, uint8_t *statep)
{
uint32_t l;
uint8_t state = 0 ;
rk_tree_node *rn;
char *e;
uint8_t *oc = buf, *oe = oc + buf_size;
const uint8_t *ic = (uint8_t *)str, *ic_ = ic, *ie = ic + str_len;
while (ic < ie) {
if ((rn = rk_lookup(state, *ic))) {
ic++;
if ((l = rk_emit(rn, &e))) { RK_OUTPUT(e, l); }
state = rn->next;
} else {
if (!state) { ic++; }
if (ic_ < ic) { RK_OUTPUT(ic_, ic - ic_); }
state = 0 ;
}
}
#ifdef FLUSH_UNRESOLVED_INPUT
if ((rn = rk_lookup(state, 0 ))) {
if ((l = rk_emit(rn, &e))) { RK_OUTPUT(e, l); }
state = rn->next;
} else {
if (ic_ < ic) { RK_OUTPUT(ic_, ic - ic_); }
}
#endif /* FLUSH_UNRESOLVED_INPUT */
*statep = state;
return oc - buf;
}
static grn_id
sub_search(grn_ctx *ctx, grn_pat *pat, grn_id id,
int *c0, uint8_t *key, uint32_t key_len)
{
pat_node *pn;
uint32_t len = key_len * 16 ;
if (!key_len) { return id; }
PAT_AT(pat, id, pn);
while (pn) {
int ch;
ch = PAT_CHK(pn);
if (*c0 < ch && ch < (int ) len - 1 ) {
if (ch & 1 ) {
id = (ch + 1 < (int ) len) ? pn->lr[1 ] : pn->lr[0 ];
} else {
id = pn->lr[nth_bit(key, ch, len)];
}
*c0 = ch;
PAT_AT(pat, id, pn);
} else {
const uint8_t *k = pat_node_get_key(ctx, pat, pn);
return (k && key_len <= PAT_LEN(pn) && !memcmp(k, key, key_len)) ? id : GRN_ID_NIL;
}
}
return GRN_ID_NIL;
}
static void
search_push(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
uint8_t *key, uint32_t key_len, uint8_t state, grn_id id, int c0, int flags)
{
if (state) {
int step;
uint16_t ns, ne;
if (flags & GRN_CURSOR_DESCENDING) {
ns = rk_tree_idx[state - 1 ];
ne = rk_tree_idx[state];
step = 1 ;
} else {
ns = rk_tree_idx[state] - 1 ;
ne = rk_tree_idx[state - 1 ] - 1 ;
step = -1 ;
}
for (; ns != ne; ns += step) {
rk_tree_node *rn = &rk_tree[ns];
if (rn->attr) {
char *e;
uint32_t l = rk_emit(rn, &e);
if (l) {
if (l + key_len <= GRN_TABLE_MAX_KEY_SIZE) {
int ch = c0;
grn_id i;
grn_memcpy(key + key_len, e, l);
if ((i = sub_search(ctx, pat, id, &ch, key, key_len + l))) {
search_push(ctx, pat, c, key, key_len + l, rn->next, i, ch, flags);
}
}
} else {
search_push(ctx, pat, c, key, key_len, rn->next, id, c0, flags);
}
}
}
} else {
pat_node *pn;
PAT_AT(pat, id, pn);
if (pn) {
int ch = PAT_CHK(pn);
uint32_t len = key_len * 16 ;
if (c0 < ch) {
if (flags & GRN_CURSOR_DESCENDING) {
if ((ch > (int ) len - 1 ) || !(flags & GRN_CURSOR_GT)) { push(c, pn->lr[0 ], ch); }
push(c, pn->lr[1 ], ch);
} else {
push(c, pn->lr[1 ], ch);
if ((ch > (int ) len - 1 ) || !(flags & GRN_CURSOR_GT)) { push(c, pn->lr[0 ], ch); }
}
} else {
if (PAT_LEN(pn) * 16 > len || !(flags & GRN_CURSOR_GT)) { push(c, id, ch); }
}
}
}
}
static grn_rc
set_cursor_rk(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
const void *key, uint32_t key_len, int flags)
{
grn_id id;
uint8_t state;
pat_node *pn;
int c0 = -1 ;
uint32_t byte_len;
uint8_t keybuf[GRN_TABLE_MAX_KEY_SIZE];
if (flags & GRN_CURSOR_SIZE_BY_BIT) { return GRN_OPERATION_NOT_SUPPORTED; }
byte_len = rk_conv(key, key_len, keybuf, GRN_TABLE_MAX_KEY_SIZE, &state);
PAT_AT(pat, 0 , pn);
id = pn->lr[1 ];
if ((id = sub_search(ctx, pat, id, &c0, keybuf, byte_len))) {
search_push(ctx, pat, c, keybuf, byte_len, state, id, c0, flags);
}
return ctx->rc;
}
uint32_t
grn_pat_total_key_size(grn_ctx *ctx, grn_pat *pat)
{
return pat->header->curr_key;
}
grn_bool
grn_pat_is_key_encoded(grn_ctx *ctx, grn_pat *pat)
{
grn_obj *domain;
uint32_t key_size;
domain = grn_ctx_at(ctx, pat->obj.header.domain);
if (grn_obj_is_type(ctx, domain)) {
key_size = grn_type_size(ctx, domain);
} else {
key_size = sizeof (grn_id);
}
return KEY_NEEDS_CONVERT(pat, key_size);
}
grn_rc
grn_pat_dirty(grn_ctx *ctx, grn_pat *pat)
{
grn_rc rc = GRN_SUCCESS;
CRITICAL_SECTION_ENTER(pat->lock);
if (!pat->is_dirty) {
uint32_t n_dirty_opens;
pat->is_dirty = GRN_TRUE;
GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), 1 , n_dirty_opens);
rc = grn_io_flush(ctx, pat->io);
}
CRITICAL_SECTION_LEAVE(pat->lock);
return rc;
}
grn_bool
grn_pat_is_dirty(grn_ctx *ctx, grn_pat *pat)
{
return pat->header->n_dirty_opens > 0 ;
}
grn_rc
grn_pat_clean(grn_ctx *ctx, grn_pat *pat)
{
grn_rc rc = GRN_SUCCESS;
CRITICAL_SECTION_ENTER(pat->lock);
if (pat->is_dirty) {
uint32_t n_dirty_opens;
pat->is_dirty = GRN_FALSE;
GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), -1 , n_dirty_opens);
rc = grn_io_flush(ctx, pat->io);
}
CRITICAL_SECTION_LEAVE(pat->lock);
return rc;
}
grn_rc
grn_pat_clear_dirty(grn_ctx *ctx, grn_pat *pat)
{
grn_rc rc = GRN_SUCCESS;
CRITICAL_SECTION_ENTER(pat->lock);
pat->is_dirty = GRN_FALSE;
pat->header->n_dirty_opens = 0 ;
rc = grn_io_flush(ctx, pat->io);
CRITICAL_SECTION_LEAVE(pat->lock);
return rc;
}
Messung V0.5 in Prozent C=99 H=91 G=94