1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 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_math
21#endif
22
23#include <groonga/plugin.h>
24
25#include <math.h>
26#include <stdlib.h>
27
28static grn_obj *
29func_math_abs(grn_ctx *ctx, int n_args, grn_obj **args,
30 grn_user_data *user_data)
31{
32 grn_obj *number;
33 grn_obj *grn_abs_number = NULL;
34
35 if (n_args != 1) {
36 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
37 "math_abs(): wrong number of arguments (%d for 1)",
38 n_args);
39 return NULL;
40 }
41
42 number = args[0];
43 if (!(number->header.type == GRN_BULK &&
44 grn_type_id_is_number_family(ctx, number->header.domain))) {
45 grn_obj inspected;
46
47 GRN_TEXT_INIT(&inspected, 0);
48 grn_inspect(ctx, &inspected, number);
49 GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
50 "math_abs(): the first argument must be a number: "
51 "<%.*s>",
52 (int)GRN_TEXT_LEN(&inspected),
53 GRN_TEXT_VALUE(&inspected));
54 GRN_OBJ_FIN(ctx, &inspected);
55 return NULL;
56 }
57
58#define ABS_AS_IS(return_type, to_type, getter, setter) { \
59 grn_abs_number = grn_plugin_proc_alloc(ctx, \
60 user_data, \
61 (return_type), \
62 0); \
63 if (!grn_abs_number) { \
64 return NULL; \
65 } \
66 setter(ctx, grn_abs_number, getter(number)); \
67 }
68#define ABS_CONVERT_TYPE(func, return_type, to_type, getter, setter) { \
69 grn_abs_number = grn_plugin_proc_alloc(ctx, \
70 user_data, \
71 (return_type), \
72 0); \
73 if (!grn_abs_number) { \
74 return NULL; \
75 } else { \
76 to_type abs_number_raw = (to_type)(func)(getter(number)); \
77 setter(ctx, grn_abs_number, abs_number_raw); \
78 } \
79 }
80
81 switch (number->header.domain) {
82 case GRN_DB_INT8:
83 ABS_CONVERT_TYPE(abs, GRN_DB_UINT8, uint8_t, GRN_INT8_VALUE, GRN_UINT8_SET);
84 break;
85 case GRN_DB_UINT8:
86 ABS_AS_IS(GRN_DB_UINT8, uint8_t, GRN_UINT8_VALUE, GRN_UINT8_SET);
87 break;
88 case GRN_DB_INT16:
89 ABS_CONVERT_TYPE(abs, GRN_DB_UINT16, uint16_t, GRN_INT16_VALUE, GRN_UINT16_SET);
90 break;
91 case GRN_DB_UINT16:
92 ABS_AS_IS(GRN_DB_UINT16, uint16_t, GRN_UINT16_VALUE, GRN_UINT16_SET);
93 break;
94 case GRN_DB_INT32:
95 ABS_CONVERT_TYPE(labs, GRN_DB_UINT32, uint32_t, GRN_INT32_VALUE, GRN_UINT32_SET);
96 break;
97 case GRN_DB_UINT32:
98 ABS_AS_IS(GRN_DB_UINT32, uint32_t, GRN_UINT32_VALUE, GRN_UINT32_SET);
99 break;
100 case GRN_DB_INT64:
101 ABS_CONVERT_TYPE(llabs, GRN_DB_UINT64, uint64_t, GRN_INT64_VALUE, GRN_UINT64_SET);
102 break;
103 case GRN_DB_UINT64:
104 ABS_AS_IS(GRN_DB_UINT64, uint64_t, GRN_UINT64_VALUE, GRN_UINT64_SET);
105 break;
106 case GRN_DB_FLOAT:
107 ABS_CONVERT_TYPE(fabs, GRN_DB_FLOAT, double, GRN_FLOAT_VALUE, GRN_FLOAT_SET);
108 break;
109 default :
110 break;
111 }
112#undef ABS_CONVERT_TYPE
113#undef ABS_AS_IS
114
115 return grn_abs_number;
116}
117
118grn_rc
119GRN_PLUGIN_INIT(grn_ctx *ctx)
120{
121 return ctx->rc;
122}
123
124grn_rc
125GRN_PLUGIN_REGISTER(grn_ctx *ctx)
126{
127 grn_rc rc = GRN_SUCCESS;
128
129 grn_proc_create(ctx,
130 "math_abs", -1,
131 GRN_PROC_FUNCTION,
132 func_math_abs,
133 NULL, NULL, 0, NULL);
134
135 return rc;
136}
137
138grn_rc
139GRN_PLUGIN_FIN(grn_ctx *ctx)
140{
141 return GRN_SUCCESS;
142}
143