1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2016 Brazil |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License version 2.1 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with this library; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #ifdef GRN_EMBEDDED |
20 | # define GRN_PLUGIN_FUNCTION_TAG functions_number |
21 | #endif |
22 | |
23 | #include <groonga/plugin.h> |
24 | |
25 | #include <math.h> |
26 | |
27 | static grn_obj * |
28 | func_number_classify(grn_ctx *ctx, int n_args, grn_obj **args, |
29 | grn_user_data *user_data) |
30 | { |
31 | grn_obj *number; |
32 | grn_obj *interval; |
33 | grn_obj casted_interval; |
34 | grn_obj *classed_number; |
35 | |
36 | if (n_args != 2) { |
37 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
38 | "number_classify(): wrong number of arguments (%d for 2)" , |
39 | n_args); |
40 | return NULL; |
41 | } |
42 | |
43 | number = args[0]; |
44 | if (!(number->header.type == GRN_BULK && |
45 | grn_type_id_is_number_family(ctx, number->header.domain))) { |
46 | grn_obj inspected; |
47 | |
48 | GRN_TEXT_INIT(&inspected, 0); |
49 | grn_inspect(ctx, &inspected, number); |
50 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
51 | "number_classify(): the first argument must be a number: " |
52 | "<%.*s>" , |
53 | (int)GRN_TEXT_LEN(&inspected), |
54 | GRN_TEXT_VALUE(&inspected)); |
55 | GRN_OBJ_FIN(ctx, &inspected); |
56 | return NULL; |
57 | } |
58 | |
59 | interval = args[1]; |
60 | if (!(interval->header.type == GRN_BULK && |
61 | grn_type_id_is_number_family(ctx, interval->header.domain))) { |
62 | grn_obj inspected; |
63 | |
64 | GRN_TEXT_INIT(&inspected, 0); |
65 | grn_inspect(ctx, &inspected, interval); |
66 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
67 | "number_classify(): the second argument must be a number: " |
68 | "<%.*s>" , |
69 | (int)GRN_TEXT_LEN(&inspected), |
70 | GRN_TEXT_VALUE(&inspected)); |
71 | GRN_OBJ_FIN(ctx, &inspected); |
72 | return NULL; |
73 | } |
74 | |
75 | classed_number = grn_plugin_proc_alloc(ctx, |
76 | user_data, |
77 | number->header.domain, |
78 | 0); |
79 | if (!classed_number) { |
80 | return NULL; |
81 | } |
82 | |
83 | GRN_VALUE_FIX_SIZE_INIT(&casted_interval, 0, number->header.domain); |
84 | grn_obj_cast(ctx, interval, &casted_interval, GRN_FALSE); |
85 | |
86 | #define CLASSIFY_RAW(type, getter, setter, classifier) { \ |
87 | type number_raw; \ |
88 | type interval_raw; \ |
89 | type class_raw; \ |
90 | type classed_number_raw; \ |
91 | \ |
92 | number_raw = getter(number); \ |
93 | interval_raw = getter(&casted_interval); \ |
94 | class_raw = classifier(number_raw, interval_raw); \ |
95 | classed_number_raw = class_raw * interval_raw; \ |
96 | setter(ctx, classed_number, classed_number_raw); \ |
97 | } |
98 | |
99 | #define CLASSIFIER_INT(number_raw, interval_raw) \ |
100 | (number_raw) < 0 ? \ |
101 | ((((number_raw) + 1) / (interval_raw)) - 1) : \ |
102 | (((number_raw) / (interval_raw))) |
103 | |
104 | #define CLASSIFY_INT(type, getter, setter) \ |
105 | CLASSIFY_RAW(type, getter, setter, CLASSIFIER_INT) |
106 | |
107 | #define CLASSIFIER_UINT(number_raw, interval_raw) \ |
108 | ((number_raw) / (interval_raw)) |
109 | |
110 | #define CLASSIFY_UINT(type, getter, setter) \ |
111 | CLASSIFY_RAW(type, getter, setter, CLASSIFIER_UINT) |
112 | |
113 | #define CLASSIFIER_FLOAT(number_raw, interval_raw) \ |
114 | floor((number_raw) / (interval_raw)) |
115 | |
116 | #define CLASSIFY_FLOAT(getter, setter) \ |
117 | CLASSIFY_RAW(double, getter, setter, CLASSIFIER_FLOAT) |
118 | |
119 | switch (number->header.domain) { |
120 | case GRN_DB_INT8 : |
121 | CLASSIFY_INT(int8_t, GRN_INT8_VALUE, GRN_INT8_SET); |
122 | break; |
123 | case GRN_DB_UINT8 : |
124 | CLASSIFY_UINT(uint8_t, GRN_UINT8_VALUE, GRN_UINT8_SET); |
125 | break; |
126 | case GRN_DB_INT16 : |
127 | CLASSIFY_INT(int16_t, GRN_INT16_VALUE, GRN_INT16_SET); |
128 | break; |
129 | case GRN_DB_UINT16 : |
130 | CLASSIFY_UINT(uint16_t, GRN_UINT16_VALUE, GRN_UINT16_SET); |
131 | break; |
132 | case GRN_DB_INT32 : |
133 | CLASSIFY_INT(int32_t, GRN_INT32_VALUE, GRN_INT32_SET); |
134 | break; |
135 | case GRN_DB_UINT32 : |
136 | CLASSIFY_UINT(uint32_t, GRN_UINT32_VALUE, GRN_UINT32_SET); |
137 | break; |
138 | case GRN_DB_INT64 : |
139 | CLASSIFY_INT(int64_t, GRN_INT64_VALUE, GRN_INT64_SET); |
140 | break; |
141 | case GRN_DB_UINT64 : |
142 | CLASSIFY_UINT(uint64_t, GRN_UINT64_VALUE, GRN_UINT64_SET); |
143 | break; |
144 | case GRN_DB_FLOAT : |
145 | CLASSIFY_FLOAT(GRN_FLOAT_VALUE, GRN_FLOAT_SET); |
146 | break; |
147 | default : |
148 | break; |
149 | } |
150 | #undef CLASSIFY_FLOAT |
151 | #undef CLASSIFIER_FLAOT |
152 | #undef CLASSIFY_UINT |
153 | #undef CLASSIFIER_UINT |
154 | #undef CLASSIFY_INT |
155 | #undef CLASSIFIER_INT |
156 | #undef CLASSIFY_RAW |
157 | |
158 | GRN_OBJ_FIN(ctx, &casted_interval); |
159 | |
160 | return classed_number; |
161 | } |
162 | |
163 | grn_rc |
164 | GRN_PLUGIN_INIT(grn_ctx *ctx) |
165 | { |
166 | return ctx->rc; |
167 | } |
168 | |
169 | grn_rc |
170 | GRN_PLUGIN_REGISTER(grn_ctx *ctx) |
171 | { |
172 | grn_rc rc = GRN_SUCCESS; |
173 | |
174 | grn_proc_create(ctx, |
175 | "number_classify" , -1, |
176 | GRN_PROC_FUNCTION, |
177 | func_number_classify, |
178 | NULL, NULL, 0, NULL); |
179 | |
180 | return rc; |
181 | } |
182 | |
183 | grn_rc |
184 | GRN_PLUGIN_FIN(grn_ctx *ctx) |
185 | { |
186 | return GRN_SUCCESS; |
187 | } |
188 | |