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
25static grn_obj *
26func_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
73static grn_obj *
74func_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
327static grn_obj *
328func_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
374grn_rc
375GRN_PLUGIN_INIT(grn_ctx *ctx)
376{
377 return ctx->rc;
378}
379
380grn_rc
381GRN_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
397grn_rc
398GRN_PLUGIN_FIN(grn_ctx *ctx)
399{
400 return GRN_SUCCESS;
401}
402