Branch data Line data Source code
1 : : /******************************************************************************
2 : : ------------- Copyright (c) 2009-2023 H a r a l d A c h i t z ---------------
3 : : ---------- < h a r a l d dot a c h i t z at g m a i l dot c o m > ------------
4 : : ---- This Source Code Form is subject to the terms of the Mozilla Public -----
5 : : ---- License, v. 2.0. If a copy of the MPL was not distributed with this -----
6 : : ---------- file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------
7 : : ******************************************************************************/
8 : :
9 : : #include <sl3/error.hpp>
10 : : #include <sl3/value.hpp>
11 : :
12 : : #include <algorithm>
13 : : #include <climits>
14 : : #include <cmath>
15 : : #include <iomanip>
16 : : #include <limits>
17 : : #include <ostream>
18 : : #include <type_traits>
19 : :
20 : : #include "utils.hpp"
21 : :
22 : : namespace sl3
23 : : {
24 : : namespace
25 : : {
26 : : // not in coverage, only used in never reachable case/if branches
27 : : void
28 : : raiseErrUnexpected (const std::string& msg) // LCOV_EXCL_LINE
29 : : {
30 : : throw ErrUnexpected (msg); // LCOV_EXCL_LINE
31 : : }
32 : :
33 : : template <class T>
34 : : typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
35 : 19 : almost_equal (T x, T y, int ulp)
36 : : {
37 : : using std::numeric_limits;
38 : : // the machine epsilon has to be scaled to the magnitude of the values
39 : : // used
40 : : // and multiplied by the desired precision in ULPs (units in the last
41 : : // place)
42 : 19 : return std::abs (x - y)
43 : 19 : < numeric_limits<T>::epsilon () * std::abs (x + y) * ulp
44 : : // unless the result is subnormal
45 [ - + - - ]: 19 : || std::abs (x - y) < numeric_limits<T>::min ();
46 : : }
47 : :
48 : : template <typename InT, typename OutT>
49 : : // requires std::is_integral<OutT>::value
50 : : // requires is_floating_point<InT>::value
51 : : inline OutT
52 : 10 : losslessConvert1 (InT in)
53 : : {
54 : 10 : InT converted = std::trunc (in);
55 [ + + ]: 10 : if (in - converted != 0.0)
56 [ + - ]: 7 : throw ErrTypeMisMatch{"Conversion loses fraction"};
57 : :
58 : : using limit = std::numeric_limits<OutT>;
59 : : // if (converted < limit::min () || converted > limit::max ())
60 [ + - ]: 3 : if (is_less (converted, limit::min ())
61 [ + - + - : 3 : || is_greater (converted, limit::max ()))
+ + + + ]
62 [ + - ]: 2 : throw ErrOutOfRange{"Converted value to big"};
63 : :
64 : 1 : return static_cast<OutT> (converted);
65 : : }
66 : :
67 : : template <typename InT, typename OutT>
68 : : // requires std::is_integral<OutT>::value
69 : : // requires is_floating_point<InT>::value
70 : : inline OutT
71 : : losslessConvert2 (InT in)
72 : : {
73 : : InT converted{0.0};
74 : : InT fraction = std::modf (in, &converted);
75 : :
76 : : if (fraction != 0.0)
77 : : throw ErrOutOfRange{"Conversion loses fraction"};
78 : :
79 : : using limit = std::numeric_limits<OutT>;
80 : : if (converted < limit::min () || converted > limit::max ())
81 : : throw ErrOutOfRange{"Converted value to big"};
82 : :
83 : : return static_cast<OutT> (converted);
84 : : }
85 : :
86 : : } //--------------------------------------------------------------------------
87 : :
88 : 384 : Value::Value () noexcept
89 : 384 : : _type{Type::Null}
90 : : {
91 : 384 : }
92 : :
93 : 37 : Value::Value (int val) noexcept
94 : 37 : : _type{Type::Int}
95 : : {
96 : 37 : _store.intval = val;
97 : 37 : }
98 : :
99 : 1 : Value::Value (int64_t val) noexcept
100 : 1 : : _type{Type::Int}
101 : : {
102 : 1 : _store.intval = val;
103 : 1 : }
104 : :
105 : 21 : Value::Value (std::string val) noexcept
106 : 21 : : _type{Type::Text}
107 : : {
108 : 21 : new (&_store.textval) std::string (std::move (val));
109 : 21 : }
110 : :
111 : 19 : Value::Value (const char* val)
112 : 19 : : _type{Type::Text}
113 : : {
114 [ + - - - ]: 38 : new (&_store.textval) std::string (val);
115 : 19 : }
116 : :
117 : 35 : Value::Value (double val) noexcept
118 : 35 : : _type{Type::Real}
119 : : {
120 : 35 : _store.realval = val;
121 : 35 : }
122 : :
123 : 36 : Value::Value (Blob val) noexcept
124 : 36 : : _type{Type::Blob}
125 : : {
126 : 36 : new (&_store.blobval) Blob (std::move (val));
127 : 36 : }
128 : :
129 : 1333 : Value::~Value () noexcept
130 : : {
131 [ + + ]: 1333 : if (_type == Type::Text)
132 : : {
133 : 202 : _store.textval.~basic_string<std::string::value_type> ();
134 : : }
135 [ + + ]: 1131 : else if (_type == Type::Blob)
136 : : {
137 : 101 : _store.blobval.~vector<Blob::value_type> ();
138 : : }
139 : 1333 : }
140 : :
141 : 409 : Value::Value (const Value& other) noexcept
142 : 409 : : _type{other._type}
143 : : {
144 [ + + + + : 409 : switch (_type)
+ - ]
145 : : {
146 : 86 : case Type::Null:
147 : 86 : break;
148 : :
149 : 124 : case Type::Int:
150 : 124 : _store.intval = other._store.intval;
151 : 124 : break;
152 : :
153 : 69 : case Type::Real:
154 : 69 : _store.realval = other._store.realval;
155 : 69 : break;
156 : :
157 : 74 : case Type::Text:
158 : 74 : new (&_store.textval) std::string (other._store.textval);
159 : 74 : break;
160 : :
161 : 56 : case Type::Blob:
162 : 56 : new (&_store.blobval) Blob (other._store.blobval);
163 : 56 : break;
164 : :
165 : 0 : default:
166 : : raiseErrUnexpected ("never reach"); // LCOV_EXCL_LINE
167 : : }
168 : 409 : }
169 : :
170 : 391 : Value::Value (Value&& other) noexcept
171 : 391 : : _type (other._type)
172 : : {
173 : : // gcc 5.3, only release, will complain if uninitialized
174 : 391 : _store.intval = 0;
175 : :
176 [ + + + + : 391 : switch (_type)
+ - - ]
177 : : {
178 : 33 : case Type::Null:
179 : 33 : break;
180 : :
181 : 151 : case Type::Int:
182 : 151 : _store.intval = std::move (other._store.intval);
183 : 151 : break;
184 : :
185 : 54 : case Type::Real:
186 : 54 : _store.realval = std::move (other._store.realval);
187 : 54 : break;
188 : :
189 : 128 : case Type::Text:
190 : 128 : new (&_store.textval) std::string (std::move (other._store.textval));
191 : 128 : other._store.textval.~basic_string ();
192 : 128 : break;
193 : :
194 : 25 : case Type::Blob:
195 : 25 : new (&_store.blobval) Blob (std::move (other._store.blobval));
196 : 25 : other._store.blobval.~vector ();
197 : 25 : break;
198 : :
199 : 0 : case Type::Variant:
200 : : raiseErrUnexpected ("never reach"); // LCOV_EXCL_LINE
201 : : break; // LCOV_EXCL_LINE
202 : : }
203 : :
204 : : // important, set other to null so that clear does not trial to clear
205 : 391 : other._type = Type::Null;
206 : 391 : }
207 : :
208 : : Value&
209 : 107 : Value::operator= (const Value& other)
210 : : {
211 [ + + ]: 107 : if (_type == Type::Text)
212 : : {
213 [ + + ]: 15 : if (other._type == Type::Text)
214 : : {
215 : 5 : _store.textval = other._store.textval;
216 : 5 : return *this;
217 : : }
218 : :
219 : 10 : _store.textval.~basic_string<std::string::value_type> ();
220 : : }
221 [ + + ]: 92 : else if (_type == Type::Blob)
222 : : {
223 [ + + ]: 12 : if (other._type == Type::Blob)
224 : : {
225 : 1 : _store.blobval = other._store.blobval;
226 : 1 : return *this;
227 : : }
228 : 11 : _store.blobval.~vector<Blob::value_type> ();
229 : : }
230 : :
231 : 101 : _type = other._type;
232 : :
233 [ + + + + : 101 : switch (_type)
+ - - ]
234 : : {
235 : 14 : case Type::Null:
236 : 14 : break;
237 : :
238 : 29 : case Type::Int:
239 : 29 : _store.intval = other._store.intval;
240 : 29 : break;
241 : :
242 : 23 : case Type::Real:
243 : 23 : _store.realval = other._store.realval;
244 : 23 : break;
245 : :
246 : 21 : case Type::Text:
247 [ + - - - ]: 21 : new (&_store.textval) std::string (other._store.textval);
248 : 21 : break;
249 : :
250 : 14 : case Type::Blob:
251 [ + - - - ]: 14 : new (&_store.blobval) Blob (other._store.blobval);
252 : 14 : break;
253 : :
254 : 0 : case Type::Variant:
255 : : raiseErrUnexpected ("never reach"); // LCOV_EXCL_LINE
256 : : break; // LCOV_EXCL_LINE
257 : : }
258 : :
259 : 101 : return *this;
260 : : }
261 : :
262 : : Value&
263 : 62 : Value::operator= (Value&& other)
264 : : {
265 [ + + ]: 62 : if (_type == Type::Text)
266 : : {
267 [ + + ]: 12 : if (other._type == Type::Text)
268 : : {
269 : 1 : _store.textval = std::move (other._store.textval);
270 : 1 : other.setNull ();
271 : 1 : return *this;
272 : : }
273 : :
274 : 11 : _store.textval.~basic_string<std::string::value_type> ();
275 : : }
276 [ + + ]: 50 : else if (_type == Type::Blob)
277 : : {
278 [ + + ]: 11 : if (other._type == Type::Blob)
279 : : {
280 : 1 : _store.blobval = std::move (other._store.blobval);
281 : 1 : other.setNull ();
282 : 1 : return *this;
283 : : }
284 : :
285 : 10 : _store.blobval.~vector<Blob::value_type> ();
286 : : }
287 : :
288 : 60 : _type = other._type;
289 : :
290 [ + + + + : 60 : switch (_type)
+ - - ]
291 : : {
292 : 12 : case Type::Null:
293 : 12 : break;
294 : :
295 : 18 : case Type::Int:
296 : 18 : _store.intval = std::move (other._store.intval);
297 : 18 : break;
298 : :
299 : 10 : case Type::Real:
300 : 10 : _store.realval = std::move (other._store.realval);
301 : 10 : break;
302 : :
303 : 11 : case Type::Text:
304 : 11 : new (&_store.textval) std::string (std::move (other._store.textval));
305 : 11 : other._store.textval.~basic_string ();
306 : 11 : break;
307 : :
308 : 9 : case Type::Blob:
309 : 9 : new (&_store.blobval) Blob (std::move (other._store.blobval));
310 : 9 : other._store.blobval.~vector ();
311 : 9 : break;
312 : :
313 : 0 : case Type::Variant:
314 : : raiseErrUnexpected ("never reach"); // LCOV_EXCL_LINE
315 : : break; // LCOV_EXCL_LINE
316 : : }
317 : :
318 : : // important, set other to null so that clear does not trial to clear
319 : 60 : other._type = Type::Null;
320 : :
321 : 60 : return *this;
322 : : }
323 : :
324 : : Value&
325 : 57 : Value::operator= (int val)
326 : : {
327 [ + + ]: 57 : if (_type == Type::Text)
328 : : {
329 : 1 : _store.textval.~basic_string<std::string::value_type> ();
330 : : }
331 [ + + ]: 56 : else if (_type == Type::Blob)
332 : : {
333 : 1 : _store.blobval.~vector<Blob::value_type> ();
334 : : }
335 : 57 : _store.intval = val;
336 : 57 : _type = Type::Int;
337 : 57 : return *this;
338 : : }
339 : :
340 : : Value&
341 : 75 : Value::operator= (const int64_t& val)
342 : : {
343 [ + + ]: 75 : if (_type == Type::Text)
344 : : {
345 : 1 : _store.textval.~basic_string<std::string::value_type> ();
346 : : }
347 [ + + ]: 74 : else if (_type == Type::Blob)
348 : : {
349 : 1 : _store.blobval.~vector<Blob::value_type> ();
350 : : }
351 : 75 : _store.intval = val;
352 : 75 : _type = Type::Int;
353 : 75 : return *this;
354 : : }
355 : :
356 : : Value&
357 : 62 : Value::operator= (const double& val)
358 : : {
359 [ + + ]: 62 : if (_type == Type::Text)
360 : : {
361 : 1 : _store.textval.~basic_string<std::string::value_type> ();
362 : : }
363 [ + + ]: 61 : else if (_type == Type::Blob)
364 : : {
365 : 1 : _store.blobval.~vector<Blob::value_type> ();
366 : : }
367 : 62 : _store.realval = val;
368 : 62 : _type = Type::Real;
369 : 62 : return *this;
370 : : }
371 : :
372 : : Value&
373 : 97 : Value::operator= (const std::string& val)
374 : : {
375 [ + + ]: 97 : if (_type == Type::Text)
376 : : {
377 : 1 : _store.textval = val;
378 : 1 : return *this;
379 : : }
380 [ + + ]: 96 : else if (_type == Type::Blob)
381 : : {
382 : 1 : _store.blobval.~vector<Blob::value_type> ();
383 : : }
384 : :
385 [ + - - - ]: 96 : new (&_store.textval) std::string (val);
386 : 96 : _type = Type::Text;
387 : 96 : return *this;
388 : : }
389 : :
390 : : Value&
391 : 23 : Value::operator= (const Blob& val)
392 : : {
393 [ + + ]: 23 : if (_type == Type::Text)
394 : : {
395 : 2 : _store.textval.~basic_string<std::string::value_type> ();
396 : : }
397 [ + + ]: 21 : else if (_type == Type::Blob)
398 : : {
399 : 1 : _store.blobval = val;
400 : 1 : return *this;
401 : : }
402 [ + - - - ]: 22 : new (&_store.blobval) Blob (val);
403 : 22 : _type = Type::Blob;
404 : 22 : return *this;
405 : : }
406 : :
407 : 7 : Value::operator int () const
408 : : {
409 [ + + ]: 7 : if (isNull ())
410 [ + - ]: 1 : throw ErrNullValueAccess ();
411 [ + + ]: 6 : else if (_type == Type::Real)
412 : 3 : return losslessConvert1<double, int> (_store.realval);
413 [ + + ]: 3 : else if (_type != Type::Int)
414 [ + - ]: 2 : throw ErrTypeMisMatch ("Implicit conversion: " + typeName (_type)
415 [ + - + - : 3 : + " to int64_t");
+ - ]
416 : :
417 : : using limit = std::numeric_limits<int>;
418 : :
419 [ + - + + : 2 : if (_store.intval < limit::min () || _store.intval > limit::max ())
+ + ]
420 [ + - ]: 1 : throw ErrOutOfRange ("Implicit conversion int64_t to int, value to big");
421 : :
422 : 1 : return static_cast<int> (_store.intval);
423 : : }
424 : :
425 : 42 : Value::operator int64_t () const
426 : : {
427 [ + + ]: 42 : if (isNull ())
428 [ + - ]: 1 : throw ErrNullValueAccess ();
429 [ + + ]: 41 : else if (_type == Type::Real)
430 : 7 : return losslessConvert1<double, int64_t> (_store.realval);
431 [ + + ]: 34 : else if (_type != Type::Int)
432 [ + - ]: 24 : throw ErrTypeMisMatch ("Implicit conversion: " + typeName (_type)
433 [ + - + - : 36 : + " to int64_t");
+ - ]
434 : :
435 : 22 : return _store.intval;
436 : : }
437 : :
438 : 20 : Value::operator double () const
439 : : {
440 [ + + ]: 20 : if (isNull ())
441 : : {
442 [ + - ]: 1 : throw ErrNullValueAccess ();
443 : : }
444 [ + + ]: 19 : else if (_type == Type::Int)
445 : : {
446 : : // using limit = std::numeric_limits<double>;
447 : : // if (_store.intval < limit::min () || _store.intval >
448 : : // limit::max ())
449 : : // throw Not possible :- );
450 : :
451 : 1 : return static_cast<double> (_store.intval);
452 : : }
453 [ + + ]: 18 : else if (_type != Type::Real)
454 : : {
455 [ + - ]: 24 : throw ErrTypeMisMatch (typeName (_type)
456 [ + - + - : 36 : + " != " + typeName (Type::Real));
+ - + - ]
457 : : }
458 : :
459 : 6 : return _store.realval;
460 : : }
461 : :
462 : 30 : Value::operator const std::string& () const
463 : : {
464 [ + + ]: 30 : if (isNull ())
465 [ + - ]: 1 : throw ErrNullValueAccess ();
466 [ + + ]: 29 : else if (_type != Type::Text)
467 [ + - ]: 46 : throw ErrTypeMisMatch (typeName (_type)
468 [ + - + - : 69 : + " != " + typeName (Type::Text));
+ - + - ]
469 : :
470 : 6 : return _store.textval;
471 : : }
472 : :
473 : 30 : Value::operator const Blob& () const
474 : : {
475 [ + + ]: 30 : if (isNull ())
476 [ + - ]: 1 : throw ErrNullValueAccess ();
477 [ + + ]: 29 : else if (_type != Type::Blob)
478 [ + - ]: 46 : throw ErrTypeMisMatch (typeName (_type)
479 [ + - + - : 69 : + " != " + typeName (Type::Blob));
+ - + - ]
480 : :
481 : 6 : return _store.blobval;
482 : : }
483 : :
484 : : const int64_t&
485 : 109 : Value::int64 () const
486 : : {
487 [ + + ]: 109 : if (isNull ())
488 [ + - ]: 3 : throw ErrNullValueAccess ();
489 : :
490 : 106 : const auto wanted = Type::Int;
491 [ + + ]: 106 : if (_type != wanted)
492 [ + - + - : 30 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
+ - + - +
- ]
493 : :
494 : 76 : return _store.intval;
495 : : }
496 : :
497 : : const double&
498 : 53 : Value::real () const
499 : : {
500 [ + + ]: 53 : if (isNull ())
501 [ + - ]: 3 : throw ErrNullValueAccess ();
502 : :
503 : 50 : const auto wanted = Type::Real;
504 [ + + ]: 50 : if (_type != wanted)
505 [ + - + - : 16 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
+ - + - +
- ]
506 : :
507 : 34 : return _store.realval;
508 : : }
509 : :
510 : : const std::string&
511 : 94 : Value::text () const
512 : : {
513 [ + + ]: 94 : if (isNull ())
514 [ + - ]: 3 : throw ErrNullValueAccess ();
515 : :
516 : 91 : const auto wanted = Type::Text;
517 [ + + ]: 91 : if (_type != wanted)
518 [ + - + - : 28 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
+ - + - +
- ]
519 : :
520 : 63 : return _store.textval;
521 : : }
522 : :
523 : : const Blob&
524 : 60 : Value::blob () const
525 : : {
526 [ + + ]: 60 : if (isNull ())
527 [ + - ]: 3 : throw ErrNullValueAccess ();
528 : :
529 : 57 : const auto wanted = Type::Blob;
530 [ + + ]: 57 : if (_type != wanted)
531 [ + - + - : 27 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
+ - + - +
- ]
532 : :
533 : 30 : return _store.blobval;
534 : : }
535 : :
536 : : std::string
537 : 5 : Value::ejectText ()
538 : : {
539 [ + + ]: 5 : if (_type == Type::Null)
540 : : {
541 [ + - ]: 3 : throw ErrNullValueAccess ();
542 : : }
543 [ + + ]: 2 : else if (_type != Type::Text)
544 : : {
545 [ + - ]: 2 : throw ErrTypeMisMatch (typeName (_type)
546 [ + - + - : 3 : + " != " + typeName (Type::Text));
+ - + - ]
547 : : }
548 : 1 : auto tmp = std::move (_store.textval);
549 : : // setNull (); // does not works,
550 : : // gcc reports some obscure error in release build
551 : : // therefore we do it manually
552 : 1 : _store.textval.~basic_string<std::string::value_type> ();
553 : 1 : _type = Type::Null;
554 : 1 : return tmp;
555 : : }
556 : :
557 : : Blob
558 : 5 : Value::ejectBlob ()
559 : : {
560 [ + + ]: 5 : if (_type == Type::Null)
561 : : {
562 [ + - ]: 3 : throw ErrNullValueAccess ();
563 : : }
564 [ + + ]: 2 : else if (_type != Type::Blob)
565 : : {
566 [ + - ]: 2 : throw ErrTypeMisMatch (typeName (_type)
567 [ + - + - : 3 : + " != " + typeName (Type::Blob));
+ - + - ]
568 : : }
569 : :
570 : 1 : auto tmp = std::move (_store.blobval);
571 : : // setNull (); // does not works,
572 : : // gcc reports some obscure error in release build
573 : : // therefore we do it manually
574 : 1 : _store.blobval.~vector<Blob::value_type> ();
575 : 1 : _type = Type::Null;
576 : 1 : return tmp;
577 : : }
578 : :
579 : : void
580 : 3 : Value::setNull () noexcept
581 : : {
582 [ + + ]: 3 : if (_type == Type::Text)
583 : : {
584 : 2 : _store.textval.~basic_string<std::string::value_type> ();
585 : : }
586 [ + - ]: 1 : else if (_type == Type::Blob)
587 : : {
588 : 1 : _store.blobval.~vector<Blob::value_type> ();
589 : : }
590 : 3 : _type = Type::Null;
591 : 3 : }
592 : :
593 : : bool
594 : 723 : Value::isNull () const noexcept
595 : : {
596 : 723 : return _type == Type::Null;
597 : : }
598 : :
599 : : Type
600 : 1128 : Value::getType () const noexcept
601 : : {
602 : 1128 : return _type;
603 : : }
604 : :
605 : : std::ostream&
606 : 23 : operator<< (std::ostream& stm, const sl3::Value& v)
607 : : {
608 [ + + + + : 23 : switch (v.getType ())
+ - ]
609 : : {
610 : 2 : case Type::Null:
611 : 2 : stm << "<NULL>";
612 : 2 : break;
613 : :
614 : 6 : case Type::Int:
615 : 6 : stm << v._store.intval;
616 : 6 : break;
617 : :
618 : 6 : case Type::Real:
619 : 6 : stm << v._store.realval;
620 : 6 : break;
621 : :
622 : 7 : case Type::Text:
623 : 7 : stm << v._store.textval;
624 : 7 : break;
625 : :
626 : 2 : case Type::Blob:
627 : 2 : stm << "<BLOB>";
628 : 2 : break;
629 : :
630 : 0 : default:
631 : : stm << "unknown storage type !!"; // LCOV_EXCL_LINE
632 : : break; // LCOV_EXCL_LINE
633 : : }
634 : :
635 : 23 : return stm;
636 : : }
637 : :
638 : : bool
639 : 113 : value_type_eq (const Value& a, const Value& b) noexcept
640 : : {
641 [ + + ]: 113 : if (a.getType () != b.getType ())
642 : 21 : return false;
643 : :
644 : 92 : bool retval = false;
645 : :
646 [ + + + + : 92 : switch (a.getType ())
+ - ]
647 : : {
648 : 16 : case Type::Null:
649 : 16 : retval = b.isNull ();
650 : 16 : break;
651 : :
652 : 22 : case Type::Int:
653 : 22 : retval = a._store.intval == b._store.intval;
654 : :
655 : 22 : break;
656 : :
657 : 19 : case Type::Real:
658 : 19 : retval = almost_equal (a._store.realval, b._store.realval, 2);
659 : 19 : break;
660 : :
661 : 18 : case Type::Text:
662 : 18 : retval = a._store.textval == b._store.textval;
663 : 18 : break;
664 : :
665 : 17 : case Type::Blob:
666 : 17 : retval = a._store.blobval == b._store.blobval;
667 : 17 : break;
668 : :
669 : 0 : default:
670 : : break; // LCOV_EXCL_LINE
671 : : }
672 : :
673 : 92 : return retval;
674 : : }
675 : :
676 : : bool
677 : 38 : value_type_lt (const Value& a, const Value& b) noexcept
678 : : {
679 [ + + ]: 38 : if (b.isNull ())
680 : 4 : return false;
681 : :
682 [ + + ]: 34 : if (a.isNull ())
683 : 4 : return true;
684 : :
685 [ + + ]: 30 : if (a.getType () == Type::Int)
686 : : {
687 [ + + ]: 11 : if (b.getType () == Type::Int)
688 : 6 : return a._store.intval < b._store.intval;
689 : :
690 [ + + ]: 5 : if (b.getType () == Type::Real)
691 : 3 : return is_less_equal (a._store.intval, b._store.realval);
692 : : // respect type, int type smaller if equal to real value
693 : :
694 : 2 : return true;
695 : : }
696 : :
697 [ + + ]: 19 : if (a.getType () == Type::Real)
698 : : {
699 [ + + ]: 7 : if (b.getType () == Type::Int)
700 : 2 : return is_less (a._store.realval, b._store.intval);
701 : : // respect type, int type smaller if equal to real value
702 : :
703 [ + + ]: 5 : if (b.getType () == Type::Real)
704 : 3 : return a._store.realval < b._store.realval;
705 : :
706 : 2 : return true;
707 : : }
708 : :
709 [ + + ]: 12 : if (a.getType () == Type::Text)
710 : : {
711 [ + + ]: 6 : if (b.getType () == Type::Text)
712 : 3 : return a._store.textval < b._store.textval;
713 : :
714 : : // only blob types are bigger
715 : 3 : return b.getType () == Type::Blob;
716 : : }
717 : :
718 : : // ASSERT_EXCEPT(a.getType () == Type::Blob, ErrUnexpected) ;
719 : :
720 : : // this is blob
721 [ + + ]: 6 : if (b.getType () != Type::Blob)
722 : 3 : return false;
723 : :
724 : : // we are both bolb
725 : 3 : return a._store.blobval < b._store.blobval;
726 : : }
727 : :
728 : : void
729 : 1 : Value::swap (Value& other) noexcept
730 : : {
731 : 1 : Value t{std::move (other)};
732 : : // should be auto t{...} but 4.8.2 does not like it
733 : 1 : other = std::move (*this);
734 : 1 : *this = std::move (t);
735 : 1 : }
736 : :
737 : : void
738 : 1 : swap (Value& a, Value& b) noexcept
739 : : {
740 : 1 : a.swap (b);
741 : 1 : }
742 : :
743 : : bool
744 : 30 : value_eq (const Value& a, const Value& b) noexcept
745 : : {
746 : 30 : bool retval = false;
747 : :
748 [ + + + + : 30 : switch (a.getType ())
+ - ]
749 : : {
750 : 5 : case Type::Null:
751 : 5 : retval = b.isNull ();
752 : 5 : break;
753 : :
754 : 9 : case Type::Int:
755 [ + + ]: 9 : if (b._type == Type::Int)
756 : 3 : retval = a._store.intval == b._store.intval;
757 [ + + ]: 6 : else if (b._type == Type::Real)
758 : 3 : retval = is_equal (a._store.intval, b._store.realval);
759 : :
760 : 9 : break;
761 : :
762 : 6 : case Type::Real:
763 [ + + ]: 6 : if (b._type == Type::Int)
764 : 1 : retval = is_equal (a._store.realval, b._store.intval);
765 [ + + ]: 5 : else if (b._type == Type::Real)
766 : 2 : retval = a._store.realval == b._store.realval;
767 : :
768 : 6 : break;
769 : :
770 : 5 : case Type::Text:
771 [ + + ]: 5 : if (b._type == Type::Text)
772 : 1 : retval = a._store.textval == b._store.textval;
773 : 5 : break;
774 : :
775 : 5 : case Type::Blob:
776 [ + + ]: 5 : if (b._type == Type::Blob)
777 : 1 : retval = a._store.blobval == b._store.blobval;
778 : 5 : break;
779 : :
780 : 0 : default:
781 : : break; // LCOV_EXCL_LINE
782 : : }
783 : :
784 : 30 : return retval;
785 : : }
786 : :
787 : : bool
788 : 51 : value_lt (const Value& a, const Value& b) noexcept
789 : : {
790 [ + + ]: 51 : if (b.isNull ())
791 : 4 : return false;
792 : :
793 [ + + ]: 47 : if (a.isNull ())
794 : 4 : return true;
795 : :
796 [ + + ]: 43 : if (a.getType () == Type::Int)
797 : : {
798 [ + + ]: 23 : if (b.getType () == Type::Int)
799 : 18 : return a._store.intval < b._store.intval;
800 : :
801 [ + + ]: 5 : if (b.getType () == Type::Real)
802 : 3 : return is_less (a._store.intval, b._store.realval);
803 : :
804 : 2 : return true;
805 : : }
806 : :
807 [ + + ]: 20 : if (a.getType () == Type::Real)
808 : : {
809 [ + + ]: 7 : if (b.getType () == Type::Int)
810 : 2 : return is_less (a._store.realval, b._store.intval);
811 : :
812 [ + + ]: 5 : if (b.getType () == Type::Real)
813 : 3 : return a._store.realval < b._store.realval;
814 : :
815 : 2 : return true;
816 : : }
817 : :
818 [ + + ]: 13 : if (a.getType () == Type::Text)
819 : : {
820 [ + + ]: 7 : if (b.getType () == Type::Text)
821 : 4 : return a._store.textval < b._store.textval;
822 : :
823 [ + + ]: 3 : if (b.getType () == Type::Blob)
824 : 1 : return true;
825 : : else
826 : 2 : return false;
827 : : }
828 : :
829 : : // TODO assert a.getType () == Type::Blob
830 : :
831 : : // this is blob
832 [ + + ]: 6 : if (b.getType () != Type::Blob)
833 : 3 : return false;
834 : :
835 : : // we are both bolb
836 : 3 : return a._store.blobval < b._store.blobval;
837 : : }
838 : :
839 : : } // ns
|