1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2015-2017 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_vector |
21 | #endif |
22 | |
23 | #include <groonga/plugin.h> |
24 | |
25 | static grn_obj * |
26 | func_vector_size(grn_ctx *ctx, int n_args, grn_obj **args, |
27 | grn_user_data *user_data) |
28 | { |
29 | grn_obj *target; |
30 | unsigned int size; |
31 | grn_obj *grn_size; |
32 | |
33 | if (n_args != 1) { |
34 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
35 | "vector_size(): wrong number of arguments (%d for 1)" , |
36 | n_args); |
37 | return NULL; |
38 | } |
39 | |
40 | target = args[0]; |
41 | switch (target->header.type) { |
42 | case GRN_VECTOR : |
43 | case GRN_PVECTOR : |
44 | case GRN_UVECTOR : |
45 | size = grn_vector_size(ctx, target); |
46 | break; |
47 | default : |
48 | { |
49 | grn_obj inspected; |
50 | |
51 | GRN_TEXT_INIT(&inspected, 0); |
52 | grn_inspect(ctx, target, &inspected); |
53 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
54 | "vector_size(): target object must be vector: <%.*s>" , |
55 | (int)GRN_TEXT_LEN(&inspected), |
56 | GRN_TEXT_VALUE(&inspected)); |
57 | GRN_OBJ_FIN(ctx, &inspected); |
58 | return NULL; |
59 | } |
60 | break; |
61 | } |
62 | |
63 | grn_size = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, 0); |
64 | if (!grn_size) { |
65 | return NULL; |
66 | } |
67 | |
68 | GRN_UINT32_SET(ctx, grn_size, size); |
69 | |
70 | return grn_size; |
71 | } |
72 | |
73 | static grn_obj * |
74 | func_vector_slice(grn_ctx *ctx, int n_args, grn_obj **args, |
75 | grn_user_data *user_data) |
76 | { |
77 | grn_obj *target; |
78 | grn_obj *from_raw = NULL; |
79 | grn_obj *length_raw = NULL; |
80 | int64_t from = 0; |
81 | int64_t length = -1; |
82 | uint32_t to = 0; |
83 | uint32_t size = 0; |
84 | grn_obj *slice; |
85 | |
86 | if (n_args < 2 || n_args > 3) { |
87 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
88 | "vector_slice(): wrong number of arguments (%d for 2..3)" , |
89 | n_args); |
90 | return NULL; |
91 | } |
92 | |
93 | target = args[0]; |
94 | from_raw = args[1]; |
95 | if (n_args == 3) { |
96 | length_raw = args[2]; |
97 | } |
98 | switch (target->header.type) { |
99 | case GRN_VECTOR : |
100 | case GRN_PVECTOR : |
101 | case GRN_UVECTOR : |
102 | size = grn_vector_size(ctx, target); |
103 | break; |
104 | default : |
105 | { |
106 | grn_obj inspected; |
107 | |
108 | GRN_TEXT_INIT(&inspected, 0); |
109 | grn_inspect(ctx, target, &inspected); |
110 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
111 | "vector_slice(): target object must be vector: <%.*s>" , |
112 | (int)GRN_TEXT_LEN(&inspected), |
113 | GRN_TEXT_VALUE(&inspected)); |
114 | GRN_OBJ_FIN(ctx, &inspected); |
115 | return NULL; |
116 | } |
117 | break; |
118 | } |
119 | |
120 | if (!grn_type_id_is_number_family(ctx, from_raw->header.domain)) { |
121 | grn_obj inspected; |
122 | |
123 | GRN_TEXT_INIT(&inspected, 0); |
124 | grn_inspect(ctx, &inspected, from_raw); |
125 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
126 | "vector_slice(): from must be a number: <%.*s>" , |
127 | (int)GRN_TEXT_LEN(&inspected), |
128 | GRN_TEXT_VALUE(&inspected)); |
129 | GRN_OBJ_FIN(ctx, &inspected); |
130 | return NULL; |
131 | } |
132 | if (from_raw->header.domain == GRN_DB_INT32) { |
133 | from = GRN_INT32_VALUE(from_raw); |
134 | } else if (from_raw->header.domain == GRN_DB_INT64) { |
135 | from = GRN_INT64_VALUE(from_raw); |
136 | } else { |
137 | grn_obj buffer; |
138 | grn_rc rc; |
139 | |
140 | GRN_INT64_INIT(&buffer, 0); |
141 | rc = grn_obj_cast(ctx, from_raw, &buffer, GRN_FALSE); |
142 | if (rc == GRN_SUCCESS) { |
143 | from = GRN_INT64_VALUE(&buffer); |
144 | } |
145 | GRN_OBJ_FIN(ctx, &buffer); |
146 | |
147 | if (rc != GRN_SUCCESS) { |
148 | grn_obj inspected; |
149 | |
150 | GRN_TEXT_INIT(&inspected, 0); |
151 | grn_inspect(ctx, &inspected, from_raw); |
152 | GRN_PLUGIN_ERROR(ctx, rc, |
153 | "vector_slice(): " |
154 | "failed to cast from value to number: <%.*s>" , |
155 | (int)GRN_TEXT_LEN(&inspected), |
156 | GRN_TEXT_VALUE(&inspected)); |
157 | GRN_OBJ_FIN(ctx, &inspected); |
158 | return NULL; |
159 | } |
160 | } |
161 | |
162 | if (length_raw) { |
163 | if (!grn_type_id_is_number_family(ctx, length_raw->header.domain)) { |
164 | grn_obj inspected; |
165 | |
166 | GRN_TEXT_INIT(&inspected, 0); |
167 | grn_inspect(ctx, &inspected, length_raw); |
168 | GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, |
169 | "vector_slice(): length must be a number: <%.*s>" , |
170 | (int)GRN_TEXT_LEN(&inspected), |
171 | GRN_TEXT_VALUE(&inspected)); |
172 | GRN_OBJ_FIN(ctx, &inspected); |
173 | return NULL; |
174 | } |
175 | if (length_raw->header.domain == GRN_DB_INT32) { |
176 | length = GRN_INT32_VALUE(length_raw); |
177 | } else if (length_raw->header.domain == GRN_DB_INT64) { |
178 | length = GRN_INT64_VALUE(length_raw); |
179 | } else { |
180 | grn_obj buffer; |
181 | grn_rc rc; |
182 | |
183 | GRN_INT64_INIT(&buffer, 0); |
184 | rc = grn_obj_cast(ctx, length_raw, &buffer, GRN_FALSE); |
185 | if (rc == GRN_SUCCESS) { |
186 | length = GRN_INT64_VALUE(&buffer); |
187 | } |
188 | GRN_OBJ_FIN(ctx, &buffer); |
189 | |
190 | if (rc != GRN_SUCCESS) { |
191 | grn_obj inspected; |
192 | |
193 | GRN_TEXT_INIT(&inspected, 0); |
194 | grn_inspect(ctx, &inspected, length_raw); |
195 | GRN_PLUGIN_ERROR(ctx, rc, |
196 | "vector_slice(): " |
197 | "failed to cast length value to number: <%.*s>" , |
198 | (int)GRN_TEXT_LEN(&inspected), |
199 | GRN_TEXT_VALUE(&inspected)); |
200 | GRN_OBJ_FIN(ctx, &inspected); |
201 | return NULL; |
202 | } |
203 | } |
204 | } |
205 | |
206 | slice = grn_plugin_proc_alloc(ctx, user_data, target->header.domain, GRN_OBJ_VECTOR); |
207 | if (!slice) { |
208 | return NULL; |
209 | } |
210 | |
211 | if (target->header.flags & GRN_OBJ_WITH_WEIGHT) { |
212 | slice->header.flags |= GRN_OBJ_WITH_WEIGHT; |
213 | } |
214 | |
215 | if (length < 0) { |
216 | length = size + length + 1; |
217 | } |
218 | |
219 | if (length > size) { |
220 | length = size; |
221 | } |
222 | |
223 | if (length <= 0) { |
224 | return slice; |
225 | } |
226 | |
227 | while (from < 0) { |
228 | from += size; |
229 | } |
230 | |
231 | to = from + length; |
232 | if (to > size) { |
233 | to = size; |
234 | } |
235 | |
236 | switch (target->header.type) { |
237 | case GRN_VECTOR : |
238 | { |
239 | unsigned int i; |
240 | for (i = from; i < to; i++) { |
241 | const char *content; |
242 | unsigned int content_length; |
243 | unsigned int weight; |
244 | grn_id domain; |
245 | content_length = grn_vector_get_element(ctx, target, i, |
246 | &content, &weight, &domain); |
247 | grn_vector_add_element(ctx, slice, |
248 | content, content_length, weight, domain); |
249 | } |
250 | } |
251 | break; |
252 | case GRN_PVECTOR : |
253 | { |
254 | unsigned int i; |
255 | for (i = from; i < to; i++) { |
256 | grn_obj *element = GRN_PTR_VALUE_AT(target, i); |
257 | GRN_PTR_PUT(ctx, slice, element); |
258 | } |
259 | } |
260 | break; |
261 | case GRN_UVECTOR : |
262 | { |
263 | grn_obj *domain; |
264 | |
265 | domain = grn_ctx_at(ctx, target->header.domain); |
266 | if (grn_obj_is_table(ctx, domain)) { |
267 | unsigned int i; |
268 | for (i = from; i < to; i++) { |
269 | grn_id id; |
270 | unsigned int weight; |
271 | id = grn_uvector_get_element(ctx, target, i, &weight); |
272 | grn_uvector_add_element(ctx, slice, id, weight); |
273 | } |
274 | } else { |
275 | #define PUT_SLICE_VALUES(type) do { \ |
276 | unsigned int i; \ |
277 | for (i = from; i < to; i++) { \ |
278 | GRN_ ## type ## _PUT(ctx, \ |
279 | slice, \ |
280 | GRN_ ## type ## _VALUE_AT(target, i)); \ |
281 | } \ |
282 | } while (GRN_FALSE) |
283 | switch (target->header.domain) { |
284 | case GRN_DB_BOOL : |
285 | PUT_SLICE_VALUES(BOOL); |
286 | break; |
287 | case GRN_DB_INT8 : |
288 | PUT_SLICE_VALUES(INT8); |
289 | break; |
290 | case GRN_DB_UINT8 : |
291 | PUT_SLICE_VALUES(UINT8); |
292 | break; |
293 | case GRN_DB_INT16 : |
294 | PUT_SLICE_VALUES(INT16); |
295 | break; |
296 | case GRN_DB_UINT16 : |
297 | PUT_SLICE_VALUES(UINT16); |
298 | break; |
299 | case GRN_DB_INT32 : |
300 | PUT_SLICE_VALUES(INT32); |
301 | break; |
302 | case GRN_DB_UINT32 : |
303 | PUT_SLICE_VALUES(UINT32); |
304 | break; |
305 | case GRN_DB_INT64 : |
306 | PUT_SLICE_VALUES(INT64); |
307 | break; |
308 | case GRN_DB_UINT64 : |
309 | PUT_SLICE_VALUES(UINT64); |
310 | break; |
311 | case GRN_DB_FLOAT : |
312 | PUT_SLICE_VALUES(FLOAT); |
313 | break; |
314 | case GRN_DB_TIME : |
315 | PUT_SLICE_VALUES(TIME); |
316 | break; |
317 | } |
318 | } |
319 | } |
320 | break; |
321 | #undef PUT_SLICE_VALUES |
322 | } |
323 | |
324 | return slice; |
325 | } |
326 | |
327 | static grn_obj * |
328 | func_vector_new(grn_ctx *ctx, int n_args, grn_obj **args, |
329 | grn_user_data *user_data) |
330 | { |
331 | grn_obj *vector = NULL; |
332 | int i; |
333 | |
334 | if (n_args == 0) { |
335 | return grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, GRN_OBJ_VECTOR); |
336 | } |
337 | |
338 | vector = grn_plugin_proc_alloc(ctx, |
339 | user_data, |
340 | args[0]->header.domain, |
341 | GRN_OBJ_VECTOR); |
342 | if (!vector) { |
343 | return NULL; |
344 | } |
345 | |
346 | for (i = 0; i < n_args; i++) { |
347 | grn_obj *element = args[i]; |
348 | switch (vector->header.type) { |
349 | case GRN_VECTOR : |
350 | grn_vector_add_element(ctx, |
351 | vector, |
352 | GRN_BULK_HEAD(element), |
353 | GRN_BULK_VSIZE(element), |
354 | 0, |
355 | element->header.domain); |
356 | break; |
357 | case GRN_UVECTOR : |
358 | grn_bulk_write(ctx, |
359 | vector, |
360 | GRN_BULK_HEAD(element), |
361 | GRN_BULK_VSIZE(element)); |
362 | break; |
363 | case GRN_PVECTOR : |
364 | GRN_PTR_PUT(ctx, vector, element); |
365 | break; |
366 | default : |
367 | break; |
368 | } |
369 | } |
370 | |
371 | return vector; |
372 | } |
373 | |
374 | grn_rc |
375 | GRN_PLUGIN_INIT(grn_ctx *ctx) |
376 | { |
377 | return ctx->rc; |
378 | } |
379 | |
380 | grn_rc |
381 | GRN_PLUGIN_REGISTER(grn_ctx *ctx) |
382 | { |
383 | grn_rc rc = GRN_SUCCESS; |
384 | |
385 | grn_proc_create(ctx, "vector_size" , -1, GRN_PROC_FUNCTION, func_vector_size, |
386 | NULL, NULL, 0, NULL); |
387 | |
388 | grn_proc_create(ctx, "vector_slice" , -1, GRN_PROC_FUNCTION, func_vector_slice, |
389 | NULL, NULL, 0, NULL); |
390 | |
391 | grn_proc_create(ctx, "vector_new" , -1, GRN_PROC_FUNCTION, func_vector_new, |
392 | NULL, NULL, 0, NULL); |
393 | |
394 | return rc; |
395 | } |
396 | |
397 | grn_rc |
398 | GRN_PLUGIN_FIN(grn_ctx *ctx) |
399 | { |
400 | return GRN_SUCCESS; |
401 | } |
402 | |