@@ -4334,12 +4334,60 @@ grn_hash_cursor_open_by_key(grn_ctx *ctx, grn_hash *hash,
4334
4334
const void * max , uint32_t max_size ,
4335
4335
int offset , int limit , int flags )
4336
4336
{
4337
+ int dir ;
4338
+ grn_hash_cursor * c ;
4339
+ if (!ctx || !hash ) {
4340
+ return NULL ;
4341
+ }
4342
+ if (!(c = GRN_CALLOC (sizeof (grn_hash_cursor )))) {
4343
+ return NULL ;
4344
+ }
4345
+ GRN_DB_OBJ_SET_TYPE (c , GRN_CURSOR_TABLE_HASH_KEY );
4346
+ c -> ctx = ctx ;
4347
+ c -> hash = hash ;
4348
+ c -> obj .header .flags = (grn_obj_flags ){flags };
4349
+ c -> obj .header .domain = GRN_ID_NIL ;
4350
+ c -> dir = dir = 1 ; // TODO: support for decendin order.
4351
+
4352
+ // TODO: Is GRN_ARRAY_TINY really enough?
4353
+ grn_array * sorted = grn_array_create (ctx , NULL , sizeof (grn_id ), GRN_ARRAY_TINY );
4354
+ if (!sorted ) {
4355
+ GRN_LOG (ctx ,
4356
+ GRN_LOG_ALERT ,
4357
+ "grn_hash_sort on grn_hash_cursor_open_by_key failed !" );
4358
+ grn_hash_close (ctx , hash );
4359
+ return NULL ;
4360
+ }
4361
+ grn_table_sort_optarg sort_opt = {0 };
4362
+ int n_sorted = grn_hash_sort (ctx , c -> hash , limit , sorted , & sort_opt );
4363
+ if (n_sorted == 0 ) {
4364
+ grn_array_close (ctx , sorted );
4365
+ return NULL ;
4366
+ }
4367
+
4368
+ size_t start_idx = (offset > 0 ) ? offset : 0 ;
4369
+ grn_hash_cursor_sorted_entries * sorted_entries =
4370
+ GRN_MALLOC (sizeof (grn_hash_cursor_sorted_entries ));
4371
+ if (!sorted_entries ) {
4372
+ grn_array_close (ctx , sorted );
4373
+ return NULL ;
4374
+ }
4375
+ sorted_entries -> sorted_entries = (grn_id * )sorted ;
4376
+ sorted_entries -> n_entries = grn_array_size (ctx , sorted );
4377
+ sorted_entries -> curr = start_idx ;
4378
+ c -> sorted_entries = sorted_entries ;
4379
+ c -> rest = (limit < 0 ) ? GRN_ARRAY_MAX : (unsigned int )limit ;
4380
+
4381
+ return c ;
4337
4382
}
4338
4383
4339
4384
void
4340
4385
grn_hash_cursor_close (grn_ctx * ctx , grn_hash_cursor * c )
4341
4386
{
4342
4387
GRN_ASSERT (c -> ctx == ctx );
4388
+ if (c -> sorted_entries ) {
4389
+ GRN_FREE (c -> sorted_entries );
4390
+ }
4343
4391
GRN_FREE (c );
4344
4392
}
4345
4393
@@ -4358,7 +4406,7 @@ grn_hash_cursor_open(grn_ctx *ctx, grn_hash *hash,
4358
4406
return NULL ;
4359
4407
}
4360
4408
if (!(c = GRN_CALLOC (sizeof (grn_hash_cursor )))) { return NULL ; }
4361
- if ((flags & GRN_CURSOR_BY_KEY )) {
4409
+ if (! (flags & GRN_CURSOR_BY_ID )) {
4362
4410
return grn_hash_cursor_open_by_key (ctx ,
4363
4411
hash ,
4364
4412
min ,
@@ -4434,13 +4482,23 @@ grn_id
4434
4482
grn_hash_cursor_next (grn_ctx * ctx , grn_hash_cursor * c )
4435
4483
{
4436
4484
if (c && c -> rest ) {
4437
- while (c -> curr_rec != c -> tail ) {
4438
- c -> curr_rec = (grn_id )((int64_t )(c -> curr_rec ) + c -> dir );
4439
- if (* c -> hash -> n_entries != HASH_CURR_MAX (c -> hash )) {
4440
- if (!grn_hash_bitmap_at (ctx , c -> hash , c -> curr_rec )) { continue ; }
4441
- }
4485
+ if (c -> sorted_entries ) {
4486
+ grn_hash_cursor_sorted_entries * se = c -> sorted_entries ;
4487
+ if (se -> curr >= se -> n_entries )
4488
+ return GRN_ID_NIL ;
4489
+ grn_id id = se -> sorted_entries [se -> curr ];
4490
+ se -> curr ++ ;
4442
4491
c -> rest -- ;
4443
- return c -> curr_rec ;
4492
+ return id ;
4493
+ } else {
4494
+ while (c -> curr_rec != c -> tail ) {
4495
+ c -> curr_rec = (grn_id )((int64_t )(c -> curr_rec ) + c -> dir );
4496
+ if (* c -> hash -> n_entries != HASH_CURR_MAX (c -> hash )) {
4497
+ if (!grn_hash_bitmap_at (ctx , c -> hash , c -> curr_rec )) { continue ; }
4498
+ }
4499
+ c -> rest -- ;
4500
+ return c -> curr_rec ;
4501
+ }
4444
4502
}
4445
4503
}
4446
4504
return GRN_ID_NIL ;
0 commit comments