1/*
2 * particle_float.c
3 *
4 * Copyright (C) 2015 Aerospike, Inc.
5 *
6 * Portions may be licensed to Aerospike, Inc. under one or more contributor
7 * license agreements.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Affero General Public License as published by the Free
11 * Software Foundation, either version 3 of the License, or (at your option) any
12 * later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see http://www.gnu.org/licenses/
21 */
22
23
24#include <stddef.h>
25#include <stdint.h>
26
27#include "aerospike/as_double.h"
28#include "aerospike/as_msgpack.h"
29#include "aerospike/as_val.h"
30#include "citrusleaf/cf_byte_order.h"
31
32#include "fault.h"
33
34#include "base/datamodel.h"
35#include "base/particle.h"
36#include "base/particle_integer.h"
37#include "base/proto.h"
38
39
40//==========================================================
41// FLOAT particle interface - function declarations.
42//
43
44// Most FLOAT particle table functions just use the equivalent INTEGER particle
45// functions. Here are the differences...
46
47// Handle "wire" format.
48int float_incr_from_wire(as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size, as_particle **pp);
49int float_from_wire(as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size, as_particle **pp);
50int float_compare_from_wire(const as_particle *p, as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size);
51
52// Handle as_val translation.
53void float_from_asval(const as_val *val, as_particle **pp);
54as_val *float_to_asval(const as_particle *p);
55uint32_t float_asval_to_wire(const as_val *val, uint8_t *wire);
56
57// Handle msgpack translation.
58void float_from_msgpack(const uint8_t *packed, uint32_t packed_size, as_particle **pp);
59
60// Handle on-device "flat" format.
61const uint8_t *float_skip_flat(const uint8_t *flat, const uint8_t *end);
62const uint8_t *float_from_flat(const uint8_t *flat, const uint8_t *end, as_particle **pp);
63uint32_t float_flat_size(const as_particle *p);
64uint32_t float_to_flat(const as_particle *p, uint8_t *flat);
65
66
67//==========================================================
68// FLOAT particle interface - vtable.
69//
70
71const as_particle_vtable float_vtable = {
72 integer_destruct,
73 integer_size,
74
75 integer_concat_size_from_wire,
76 integer_append_from_wire,
77 integer_prepend_from_wire,
78 float_incr_from_wire,
79 integer_size_from_wire,
80 float_from_wire,
81 float_compare_from_wire,
82 integer_wire_size,
83 integer_to_wire,
84
85 integer_size_from_asval,
86 float_from_asval,
87 float_to_asval,
88 integer_asval_wire_size,
89 float_asval_to_wire,
90
91 integer_size_from_msgpack,
92 float_from_msgpack,
93
94 float_skip_flat,
95 float_from_flat, // cast copies embedded value out
96 float_from_flat,
97 float_flat_size,
98 float_to_flat
99};
100
101
102//==========================================================
103// Typedefs & constants.
104//
105
106typedef struct float_flat_s {
107 uint8_t type;
108 uint64_t i;
109} __attribute__ ((__packed__)) float_flat;
110
111
112//==========================================================
113// FLOAT particle interface - function definitions.
114//
115
116// Most FLOAT particle table functions just use the equivalent INTEGER particle
117// functions. Here are the differences...
118
119//------------------------------------------------
120// Handle "wire" format.
121//
122
123int
124float_incr_from_wire(as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size, as_particle **pp)
125{
126 // For now we won't allow adding integers (or anything else) to floats.
127 if (wire_type != AS_PARTICLE_TYPE_FLOAT) {
128 cf_warning(AS_PARTICLE, "increment with non float type %u", wire_type);
129 return -AS_ERR_INCOMPATIBLE_TYPE;
130 }
131
132 uint64_t i;
133
134 switch (value_size) {
135 case 8:
136 i = cf_swap_from_be64(*(uint64_t *)wire_value);
137 break;
138 default:
139 cf_warning(AS_PARTICLE, "unexpected value size %u", value_size);
140 return -AS_ERR_PARAMETER;
141 }
142
143 (*(double *)pp) += *(double *)&i;
144
145 return 0;
146}
147
148int
149float_from_wire(as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size, as_particle **pp)
150{
151 if (value_size != 8) {
152 cf_warning(AS_PARTICLE, "unexpected value size %u", value_size);
153 return -AS_ERR_PARAMETER;
154 }
155
156 return integer_from_wire(wire_type, wire_value, value_size, pp);
157}
158
159int
160float_compare_from_wire(const as_particle *p, as_particle_type wire_type, const uint8_t *wire_value, uint32_t value_size)
161{
162 if (wire_type != AS_PARTICLE_TYPE_FLOAT) {
163 return 1;
164 }
165
166 if (value_size != 8) {
167 return -AS_ERR_UNKNOWN;
168 }
169
170 return integer_compare_from_wire(p, AS_PARTICLE_TYPE_INTEGER, wire_value, value_size);
171}
172
173//------------------------------------------------
174// Handle as_val translation.
175//
176
177void
178float_from_asval(const as_val *val, as_particle **pp)
179{
180 *(double *)pp = as_double_get(as_double_fromval(val));
181}
182
183as_val *
184float_to_asval(const as_particle *p)
185{
186 return (as_val *)as_double_new(*(double *)&p);
187}
188
189uint32_t
190float_asval_to_wire(const as_val *val, uint8_t *wire)
191{
192 double x = as_double_get(as_double_fromval(val));
193
194 *(uint64_t *)wire = cf_swap_to_be64(*(uint64_t *)&x);
195
196 return (uint32_t)sizeof(uint64_t);
197}
198
199//------------------------------------------------
200// Handle msgpack translation.
201//
202
203void
204float_from_msgpack(const uint8_t *packed, uint32_t packed_size, as_particle **pp)
205{
206 double x;
207 as_unpacker pk = {
208 .buffer = packed,
209 .offset = 0,
210 .length = packed_size
211 };
212
213 as_unpack_double(&pk, &x);
214
215 *(double *)pp = x;
216}
217
218//------------------------------------------------
219// Handle on-device "flat" format.
220//
221
222const uint8_t *
223float_skip_flat(const uint8_t *flat, const uint8_t *end)
224{
225 // Type is correct, since we got here - no need to check against end.
226 return flat + sizeof(float_flat);
227}
228
229const uint8_t *
230float_from_flat(const uint8_t *flat, const uint8_t *end, as_particle **pp)
231{
232 const float_flat *p_float_flat = (const float_flat *)flat;
233
234 flat += sizeof(float_flat);
235
236 if (flat > end) {
237 cf_warning(AS_PARTICLE, "incomplete flat float");
238 return NULL;
239 }
240
241 // Float values live in an as_bin instead of a pointer. Also, flat floats
242 // are host order, so no byte swap.
243 *pp = (as_particle *)p_float_flat->i;
244
245 return flat;
246}
247
248uint32_t
249float_flat_size(const as_particle *p)
250{
251 return sizeof(float_flat);
252}
253
254uint32_t
255float_to_flat(const as_particle *p, uint8_t *flat)
256{
257 float_flat *p_float_flat = (float_flat *)flat;
258
259 // Already wrote the type.
260 p_float_flat->i = (uint64_t)p;
261
262 return float_flat_size(p);
263}
264