null+****@clear*****
null+****@clear*****
2011年 10月 16日 (日) 16:45:39 JST
Kouhei Sutou 2011-10-16 07:45:39 +0000 (Sun, 16 Oct 2011) New Revision: 611b673026e7884e3c72c4daaa1f93aec81c185d Log: add grn_geo_cursor. Modified files: include/groonga.h lib/db.c lib/geo.c lib/geo.h lib/ii.c lib/ii.h test/benchmark/bench-geo-select.c Modified: include/groonga.h (+34 -0) =================================================================== --- include/groonga.h 2011-10-17 21:50:55 +0000 (1ef25f0) +++ include/groonga.h 2011-10-16 07:45:39 +0000 (60c0b60) @@ -419,6 +419,7 @@ typedef unsigned short int grn_obj_flags; #define GRN_CURSOR_TABLE_NO_KEY (0x13) #define GRN_CURSOR_TABLE_VIEW (0x14) #define GRN_CURSOR_COLUMN_INDEX (0x18) +#define GRN_CURSOR_GEO (0x1a) #define GRN_TYPE (0x20) #define GRN_PROC (0x21) #define GRN_EXPR (0x22) @@ -1793,6 +1794,39 @@ GRN_API int grn_geo_estimate_in_rectangle(grn_ctx *ctx, grn_obj *top_left_point, grn_obj *bottom_right_point); +/** + * grn_geo_cursor_open_in_rectangle: + * @index: the index column for TokyoGeoPoint or WGS84GeoPpoint type. + * @top_left_point: the top left point of the target + * rectangle. (ShortText, Text, LongText, TokyoGeoPoint or + * WGS84GeoPoint) + * @bottom_right_point: the bottom right point of the target + * rectangle. (ShortText, Text, LongText, TokyoGeoPoint or + * WGS84GeoPoint) + * @offset: the cursor returns records from @offset + * position. @offset is based on 0. + * @limit: the cursor returns at most @limit records. -1 + * means no limit. + * + * It opens a cursor to get records in the rectangle + * specfied by @top_left_point and @bottom_right_point. + **/ +GRN_API grn_obj *grn_geo_cursor_open_in_rectangle(grn_ctx *ctx, + grn_obj *index, + grn_obj *top_left_point, + grn_obj *bottom_right_point, + int offset, + int limit); + +/** + * grn_geo_cursor_next: + * @cursor: the geo cursor. + * + * It returns the next posting that has record ID. It + * returns NULL after all records are returned. + **/ +GRN_API grn_posting *grn_geo_cursor_next(grn_ctx *ctx, grn_obj *cursor); + /* query & snippet */ Modified: lib/db.c (+3 -0) =================================================================== --- lib/db.c 2011-10-17 21:50:55 +0000 (23aac34) +++ lib/db.c 2011-10-16 07:45:39 +0000 (ce93a5b) @@ -6373,6 +6373,9 @@ grn_obj_close(grn_ctx *ctx, grn_obj *obj) GRN_FREE(ic); } break; + case GRN_CURSOR_GEO : + grn_geo_cursor_close(ctx, obj); + break; case GRN_TYPE : GRN_FREE(obj); rc = GRN_SUCCESS; Modified: lib/geo.c (+286 -22) =================================================================== --- lib/geo.c 2011-10-17 21:50:55 +0000 (6fa284b) +++ lib/geo.c 2011-10-16 07:45:39 +0000 (9d15352) @@ -18,16 +18,9 @@ #include <string.h> #include <stdlib.h> #include "geo.h" -#include "ii.h" -#include "db.h" #include "pat.h" #include "util.h" -typedef enum { - MESH_LATITUDE, - MESH_LONGITUDE -} mesh_direction; - typedef struct { grn_id id; double d; @@ -52,7 +45,7 @@ typedef struct { int end; int distance; int diff_bit; - mesh_direction direction; + grn_geo_mesh_direction direction; } in_rectangle_data; static int @@ -860,12 +853,12 @@ in_rectangle_data_prepare(grn_ctx *ctx, grn_obj *index, latitude_distance = top_left->latitude - bottom_right->latitude; longitude_distance = bottom_right->longitude - top_left->longitude; if (latitude_distance > longitude_distance) { - data->direction = MESH_LATITUDE; + data->direction = GRN_GEO_MESH_LATITUDE; geo_point_input = bottom_right; data->base.latitude = bottom_right->latitude; data->base.longitude = bottom_right->longitude - longitude_distance; } else { - data->direction = MESH_LONGITUDE; + data->direction = GRN_GEO_MESH_LONGITUDE; geo_point_input = top_left; data->base.latitude = top_left->latitude - latitude_distance; data->base.longitude = top_left->longitude; @@ -875,18 +868,21 @@ in_rectangle_data_prepare(grn_ctx *ctx, grn_obj *index, data->diff_bit = compute_diff_bit(geo_key_input, geo_key_base); compute_min_and_max(&(data->base), data->diff_bit, &(data->min), &(data->max)); - if (data->direction == MESH_LATITUDE) { + switch (data->direction) { + case GRN_GEO_MESH_LATITUDE : data->distance = data->max.latitude - data->min.latitude + 1; data->start = data->min.latitude; data->end = top_left->latitude; - } else { + break; + case GRN_GEO_MESH_LONGITUDE : data->distance = data->max.longitude - data->min.longitude + 1; data->start = data->min.longitude; data->end = bottom_right->longitude; + break; } #ifdef GEO_DEBUG printf("direction: %s\n", - data->direction == MESH_LATITUDE ? "latitude" : "longitude"); + data->direction == GRN_GEO_MESH_LATITUDE ? "latitude" : "longitude"); printf("base: "); grn_p_geo_point(ctx, &(data->base)); printf("input: "); @@ -913,10 +909,218 @@ exit : return ctx->rc; } +grn_obj * +grn_geo_cursor_open_in_rectangle(grn_ctx *ctx, + grn_obj *index, + grn_obj *top_left_point, + grn_obj *bottom_right_point, + int offset, + int limit) +{ + grn_geo_cursor_in_rectangle *cursor = NULL; + in_rectangle_data data; + + GRN_VOID_INIT(&(data.top_left_point_buffer)); + GRN_VOID_INIT(&(data.bottom_right_point_buffer)); + if (in_rectangle_data_prepare(ctx, index, top_left_point, bottom_right_point, + "geo_in_rectangle()", &data)) { + goto exit; + } + + cursor = GRN_MALLOCN(grn_geo_cursor_in_rectangle, 1); + if (!cursor) { + ERR(GRN_NO_MEMORY_AVAILABLE, + "[geo][cursor][in-rectangle] failed to allocate memory for geo cursor"); + goto exit; + } + + cursor->obj.header.type = GRN_CURSOR_GEO; + cursor->obj.header.impl_flags = GRN_OBJ_ALLOCATED; + cursor->obj.header.flags = 0; + cursor->obj.header.domain = GRN_ID_NIL; + + cursor->pat = data.pat; + cursor->index = index; + cursor->diff_bit = data.diff_bit; + cursor->start_mesh_point = data.start; + cursor->end_mesh_point = data.end; + cursor->distance = data.distance; + cursor->direction = data.direction; + memcpy(&(cursor->top_left), data.top_left, sizeof(grn_geo_point)); + memcpy(&(cursor->bottom_right), data.bottom_right, sizeof(grn_geo_point)); + memcpy(&(cursor->base), &(data.base), sizeof(grn_geo_point)); + cursor->pat_cursor = NULL; + cursor->ii_cursor = NULL; + cursor->offset = offset; + cursor->rest = limit; + +exit : + grn_obj_unlink(ctx, &(data.top_left_point_buffer)); + grn_obj_unlink(ctx, &(data.bottom_right_point_buffer)); + return (grn_obj *)cursor; +} + +typedef grn_bool (*grn_geo_cursor_callback)(grn_ctx *ctx, grn_ii_posting *posting, void *user_data); + +static void +grn_geo_cursor_each(grn_ctx *ctx, grn_obj *geo_cursor, + grn_geo_cursor_callback callback, void *user_data) +{ + grn_geo_cursor_in_rectangle *cursor; + grn_obj *pat; + grn_table_cursor *pat_cursor; + grn_ii *ii; + grn_ii_cursor *ii_cursor; + grn_ii_posting *posting = NULL; + grn_geo_point *current, *base, *top_left, *bottom_right; + int diff_bit, distance, end_mesh_point; + grn_geo_mesh_direction direction; + int i = 0; + int mesh_point; + grn_id index_id; + + cursor = (grn_geo_cursor_in_rectangle *)geo_cursor; + if (cursor->rest == 0) { + return; + } + + pat = cursor->pat; + pat_cursor = cursor->pat_cursor; + ii = (grn_ii *)(cursor->index); + ii_cursor = cursor->ii_cursor; + current = &(cursor->current); + base = &(cursor->base); + top_left = &(cursor->top_left); + bottom_right = &(cursor->bottom_right); + diff_bit = cursor->diff_bit; + distance = cursor->distance; + end_mesh_point = cursor->end_mesh_point; + direction = cursor->direction; + + while (GRN_TRUE) { + if (!pat_cursor) { + if (!(cursor->pat_cursor = pat_cursor = + grn_table_cursor_open(ctx, + pat, + base, + diff_bit, + NULL, 0, + 0, -1, + GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT))) { + cursor->rest = 0; + return; + } +#ifdef GEO_DEBUG + { + switch (direction) { + case GRN_GEO_MESH_LATITUDE : + mesh_point = base->latitude; + break; + case GRN_GEO_MESH_LONGITUDE : + mesh_point = base->longitude; + break; + } + printf("mesh-point: %10d\n", mesh_point); + inspect_mesh(ctx, base, diff_bit, + (mesh_point - cursor->start_mesh_point) / + distance); + } +#endif + } + + while (ii_cursor || (index_id = grn_table_cursor_next(ctx, pat_cursor))) { + if (!ii_cursor) { + grn_table_get_key(ctx, pat, index_id, current, sizeof(grn_geo_point)); + if (grn_geo_in_rectangle_raw(ctx, current, top_left, bottom_right)) { + inspect_tid(ctx, index_id, current, 0); + if (!(cursor->ii_cursor = ii_cursor = + grn_ii_cursor_open(ctx, + ii, + index_id, + GRN_ID_NIL, + GRN_ID_MAX, + ii->n_elements, + 0))) { + continue; + } + } else { + continue; + } + } + + while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) { + if (cursor->offset == 0) { + if (!callback(ctx, posting, user_data)) { + return; + } + if (cursor->rest > 0) { + if (--(cursor->rest) == 0) { + return; + } + } + } else { + cursor->offset--; + } + } + grn_ii_cursor_close(ctx, ii_cursor); + cursor->ii_cursor = ii_cursor = NULL; + } + grn_table_cursor_close(ctx, pat_cursor); + cursor->pat_cursor = pat_cursor = NULL; + + switch (direction) { + case GRN_GEO_MESH_LATITUDE : + mesh_point = (base->latitude += distance); + break; + case GRN_GEO_MESH_LONGITUDE : + mesh_point = (base->longitude += distance); + break; + } + if (mesh_point > end_mesh_point + distance) { + cursor->rest = 0; + return; + } + } +} + +static grn_bool +grn_geo_cursor_next_callback(grn_ctx *ctx, grn_ii_posting *posting, + void *user_data) +{ + grn_ii_posting **return_posting = user_data; + *return_posting = posting; +} + +grn_posting * +grn_geo_cursor_next(grn_ctx *ctx, grn_obj *geo_cursor) +{ + grn_ii_posting *posting = NULL; + grn_geo_cursor_each(ctx, geo_cursor, grn_geo_cursor_next_callback, &posting); + return (grn_posting *)posting; +} + grn_rc -grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, - grn_obj *top_left_point, grn_obj *bottom_right_point, - grn_obj *res, grn_operator op) +grn_geo_cursor_close(grn_ctx *ctx, grn_obj *geo_cursor) +{ + grn_geo_cursor_in_rectangle *cursor; + + if (!geo_cursor) { return GRN_INVALID_ARGUMENT; } + + cursor = (grn_geo_cursor_in_rectangle *)geo_cursor; + if (cursor->pat) { grn_obj_unlink(ctx, cursor->pat); } + if (cursor->index) { grn_obj_unlink(ctx, cursor->index); } + if (cursor->pat_cursor) { grn_table_cursor_close(ctx, cursor->pat_cursor); } + if (cursor->ii_cursor) { grn_ii_cursor_close(ctx, cursor->ii_cursor); } + GRN_FREE(cursor); + + return GRN_SUCCESS; +} + +static inline grn_rc +grn_geo_select_in_rectangle_loop(grn_ctx *ctx, grn_obj *index, + grn_obj *top_left_point, + grn_obj *bottom_right_point, + grn_obj *res, grn_operator op) { in_rectangle_data data; @@ -929,9 +1133,9 @@ grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, { grn_obj *pat; - int diff_bit, i, start, end, distance; + int diff_bit, mesh_point, start, end, distance; grn_geo_point *top_left, *bottom_right, *base; - mesh_direction direction; + grn_geo_mesh_direction direction; pat = data.pat; start = data.start; @@ -942,7 +1146,7 @@ grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, bottom_right = data.bottom_right; base = &(data.base); diff_bit = data.diff_bit; - for (i = start; i < end + distance; i += distance) { + for (mesh_point = start; mesh_point < end + distance; mesh_point += distance) { grn_table_cursor *tc; tc = grn_table_cursor_open(ctx, pat, base, diff_bit, @@ -950,9 +1154,9 @@ grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, 0, -1, GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT); #ifdef GEO_DEBUG - printf("i: %10d\n", i); + printf("mesh-point: %10d\n", mesh_point); #endif - inspect_mesh(ctx, base, diff_bit, (i - data.start) / distance); + inspect_mesh(ctx, base, diff_bit, (mesh_point - start) / distance); if (tc) { grn_id tid; grn_geo_point point; @@ -966,7 +1170,7 @@ grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, } grn_table_cursor_close(ctx, tc); } - if (direction == MESH_LATITUDE) { + if (direction == GRN_GEO_MESH_LATITUDE) { base->latitude += distance; } else { base->longitude += distance; @@ -980,6 +1184,66 @@ exit : return ctx->rc; } +typedef struct { + grn_hash *res; + grn_operator op; +} grn_geo_select_in_rectangle_data; + +static grn_bool +grn_geo_select_in_rectangle_callback(grn_ctx *ctx, grn_ii_posting *posting, + void *user_data) +{ + grn_geo_select_in_rectangle_data *data = user_data; + grn_ii_posting_add(ctx, posting, data->res, data->op); + return GRN_TRUE; +} + +static inline grn_rc +grn_geo_select_in_rectangle_cursor(grn_ctx *ctx, grn_obj *index, + grn_obj *top_left_point, + grn_obj *bottom_right_point, + grn_obj *res, grn_operator op) +{ + grn_obj *cursor; + grn_posting *posting; + + cursor = grn_geo_cursor_open_in_rectangle(ctx, index, + top_left_point, bottom_right_point, + 0, -1); + if (cursor) { + grn_geo_cursor_in_rectangle *geo_cursor = (grn_geo_cursor_in_rectangle *)cursor; + grn_geo_select_in_rectangle_data data; + data.res = (grn_hash *)res; + data.op = op; + grn_geo_cursor_each(ctx, cursor, grn_geo_select_in_rectangle_callback, + &data); + grn_obj_unlink(ctx, cursor); + grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op); + } + + return ctx->rc; +} + +grn_rc +grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index, + grn_obj *top_left_point, grn_obj *bottom_right_point, + grn_obj *res, grn_operator op) +{ + char *grn_geo_select_in_rectangle_env; + + grn_geo_select_in_rectangle_env = getenv("GRN_GEO_SELECT_IN_RECTANGLE"); + if (grn_geo_select_in_rectangle_env && + strcmp(grn_geo_select_in_rectangle_env, "cursor") == 0) { + return grn_geo_select_in_rectangle_cursor(ctx, index, + top_left_point, bottom_right_point, + res, op); + } else { + return grn_geo_select_in_rectangle_loop(ctx, index, + top_left_point, bottom_right_point, + res, op); + } +} + static grn_rc geo_point_get(grn_ctx *ctx, grn_obj *pat, int flags, grn_geo_point *geo_point) { Modified: lib/geo.h (+32 -0) =================================================================== --- lib/geo.h 2011-10-17 21:50:55 +0000 (c5832e4) +++ lib/geo.h 2011-10-16 07:45:39 +0000 (791f7c5) @@ -21,6 +21,9 @@ #include "groonga_in.h" #endif /* GROONGA_IN_H */ +#include "ii.h" +#include "db.h" + #ifdef WIN32 #define _USE_MATH_DEFINES #endif /* WIN32 */ @@ -51,6 +54,35 @@ extern "C" { _longitude = GRN_GEO_INT2RAD(_val->longitude);\ } while (0) +typedef enum _grn_geo_mesh_direction grn_geo_mesh_direction; +enum _grn_geo_mesh_direction { + GRN_GEO_MESH_LATITUDE, + GRN_GEO_MESH_LONGITUDE +}; + +typedef struct _grn_geo_cursor_in_rectangle grn_geo_cursor_in_rectangle; +struct _grn_geo_cursor_in_rectangle { + grn_db_obj obj; + grn_obj *pat; + grn_obj *index; + int diff_bit; + int start_mesh_point; + int end_mesh_point; + int distance; + grn_geo_mesh_direction direction; + grn_geo_point top_left; + grn_geo_point bottom_right; + grn_geo_point base; + grn_geo_point current; + grn_table_cursor *pat_cursor; + grn_ii_cursor *ii_cursor; + int offset; + int rest; +}; + +grn_rc grn_geo_cursor_close(grn_ctx *ctx, grn_obj *geo_cursor); + + int grn_geo_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit, grn_obj *result, grn_table_sort_key *keys, int n_keys); Modified: lib/ii.c (+7 -0) =================================================================== --- lib/ii.c 2011-10-17 21:50:55 +0000 (7fe6433) +++ lib/ii.c 2011-10-16 07:45:39 +0000 (14ac12d) @@ -5472,6 +5472,13 @@ res_add(grn_ctx *ctx, grn_hash *s, grn_rset_posinfo *pi, uint32_t score, } } +grn_rc +grn_ii_posting_add(grn_ctx *ctx, grn_ii_posting *pos, grn_hash *s, grn_operator op) +{ + res_add(ctx, s, (grn_rset_posinfo *)(pos), (1 + pos->weight), op); + return ctx->rc; +} + #ifdef USE_BHEAP /* todo */ Modified: lib/ii.h (+3 -0) =================================================================== --- lib/ii.h 2011-10-17 21:50:55 +0000 (ce894ec) +++ lib/ii.h 2011-10-16 07:45:39 +0000 (c0c609e) @@ -129,6 +129,9 @@ typedef struct { typedef struct _grn_ii_cursor grn_ii_cursor; +GRN_API grn_rc grn_ii_posting_add(grn_ctx *ctx, grn_ii_posting *pos, + grn_hash *s, grn_operator op); + GRN_API grn_ii_cursor *grn_ii_cursor_open(grn_ctx *ctx, grn_ii *ii, grn_id tid, grn_id min, grn_id max, int nelements, int flags); grn_ii_cursor *grn_ii_cursor_openv1(grn_ii *ii, uint32_t key); Modified: test/benchmark/bench-geo-select.c (+117 -12) =================================================================== --- test/benchmark/bench-geo-select.c 2011-10-17 21:50:55 +0000 (2ff53f0) +++ test/benchmark/bench-geo-select.c 2011-10-16 07:45:39 +0000 (867306f) @@ -18,13 +18,16 @@ /* groonga: e65e87f0039f6bb2da3d9b959423774d3f66b567 - CFLAGS: -O0 -g - CPU: Intel(R) Core(TM) i5 CPU U 470 @ 1.33GHz stepping 05 + CFLAGS: -O0 -ggdb3 + CPU: Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz stepping 05 % (cd test/benchmark; make --quiet run-bench-geo-select) run-bench-geo-select: - (time) - select_in_rectangle: (1.84038) + (time) + select_in_rectangle (1st) (loop): (0.943075) + select_in_rectangle (1st) (cursor): (0.937281) + select_in_rectangle (2nd) (loop): (0.928663) + select_in_rectangle (2nd) (cursor): (0.947011) */ #include <string.h> @@ -48,6 +51,8 @@ typedef struct _BenchmarkData grn_obj top_left_point; grn_obj bottom_right_point; + + const gchar *original_in_rectangle_implementation; } BenchmarkData; static void @@ -62,12 +67,15 @@ set_geo_point(grn_ctx *context, grn_obj *geo_point, const gchar *geo_point_text) } static void -bench_setup(gpointer user_data) +bench_setup_common(gpointer user_data) { BenchmarkData *data = user_data; const gchar *tokyo_station = "35.68136,139.76609"; const gchar *ikebukuro_station = "35.72890,139.71036"; + data->original_in_rectangle_implementation = + g_getenv("GRN_GEO_SELECT_IN_RECTANGLE"); + data->result = grn_table_create(data->context, NULL, 0, NULL, GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC, data->table, NULL); @@ -79,6 +87,76 @@ bench_setup(gpointer user_data) } static void +bench_setup_implementation_loop(gpointer user_data) +{ + g_setenv("GRN_GEO_SELECT_IN_RECTANGLE", "loop", TRUE); +} + +static void +bench_setup_implementation_cursor(gpointer user_data) +{ + g_setenv("GRN_GEO_SELECT_IN_RECTANGLE", "cursor", TRUE); +} + +static void +bench_setup_query_partial(gpointer user_data) +{ + BenchmarkData *data = user_data; + const gchar *tokyo_station = "35.68136,139.76609"; + const gchar *ikebukuro_station = "35.72890,139.71036"; + + set_geo_point(data->context, &(data->top_left_point), + ikebukuro_station); + set_geo_point(data->context, &(data->bottom_right_point), + tokyo_station); +} + +static void +bench_setup_query_all(gpointer user_data) +{ + BenchmarkData *data = user_data; + const gchar *tokyo_station = "35.0,140.0"; + const gchar *ikebukuro_station = "36.0,139.0"; + + set_geo_point(data->context, &(data->top_left_point), + ikebukuro_station); + set_geo_point(data->context, &(data->bottom_right_point), + tokyo_station); +} + +static void +bench_setup_in_rectangle_loop_partial(gpointer user_data) +{ + bench_setup_common(user_data); + bench_setup_implementation_loop(user_data); + bench_setup_query_partial(user_data); +} + +static void +bench_setup_in_rectangle_cursor_partial(gpointer user_data) +{ + bench_setup_common(user_data); + bench_setup_implementation_cursor(user_data); + bench_setup_query_partial(user_data); +} + +static void +bench_setup_in_rectangle_loop_all(gpointer user_data) +{ + bench_setup_common(user_data); + bench_setup_implementation_loop(user_data); + bench_setup_query_all(user_data); +} + +static void +bench_setup_in_rectangle_cursor_all(gpointer user_data) +{ + bench_setup_common(user_data); + bench_setup_implementation_cursor(user_data); + bench_setup_query_all(user_data); +} + +static void bench_geo_select_in_rectangle(gpointer user_data) { BenchmarkData *data = user_data; @@ -101,6 +179,15 @@ bench_teardown(gpointer user_data) } grn_obj_unlink(data->context, data->result); + + if (data->original_in_rectangle_implementation) { + g_setenv("GRN_GEO_SELECT_IN_RECTANGLE", + data->original_in_rectangle_implementation, + TRUE); + } else { + g_unsetenv("GRN_GEO_SELECT_IN_RECTANGLE"); + } + data->original_in_rectangle_implementation = NULL; } static gchar * @@ -169,13 +256,31 @@ main(int argc, gchar **argv) reporter = bench_reporter_new(); -#define REGISTER(label, type) \ - bench_reporter_register(reporter, label, n, \ - bench_setup, \ - bench_geo_select_ ## type, \ - bench_teardown, \ - &data) - REGISTER("select_in_rectangle", in_rectangle); +#define REGISTER(label, type, implementation, area) \ + bench_reporter_register( \ + reporter, \ + label, \ + n, \ + bench_setup_ ## type ## _ ## implementation ## _ ## area, \ + bench_geo_select_ ## type, \ + bench_teardown, \ + &data) + REGISTER("1st: select_in_rectangle (loop) (partial)", + in_rectangle, loop, partial); + REGISTER("1st: select_in_rectangle (cursor) (partial)", + in_rectangle, cursor, partial); + REGISTER("2nd: select_in_rectangle (loop) (partial)", + in_rectangle, loop, partial); + REGISTER("2nd: select_in_rectangle (cursor) (partial)", + in_rectangle, cursor, partial); + REGISTER("1st: select_in_rectangle (loop) (all)", + in_rectangle, loop, all); + REGISTER("1st: select_in_rectangle (cursor) (all)", + in_rectangle, cursor, all); + REGISTER("2nd: select_in_rectangle (loop) (all)", + in_rectangle, loop, all); + REGISTER("2nd: select_in_rectangle (cursor) (all)", + in_rectangle, cursor, all); #undef REGISTER bench_reporter_run(reporter);