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 : 21 : 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 : 21 : return std::abs (x - y)
43 : 21 : < numeric_limits<T>::epsilon () * std::abs (x + y) * ulp
44 : : // unless the result is subnormal
45 : 21 : || 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 : 417 : Value::Value () noexcept
89 : 417 : : _type{Type::Null}
90 : : {
91 : 417 : }
92 : :
93 : 37 : Value::Value (int val) noexcept
94 : 37 : : _type{Type::Int}
95 : : {
96 : 37 : _store.intval = val;
97 : 37 : }
98 : :
99 : 2 : Value::Value (int64_t val) noexcept
100 : 2 : : _type{Type::Int}
101 : : {
102 : 2 : _store.intval = val;
103 : 2 : }
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)); // LCOV_EXCL_BR_LINE
109 : 21 : }
110 : :
111 : 20 : Value::Value (const char* val)
112 : 20 : : _type{Type::Text}
113 : : {
114 : 40 : new (&_store.textval) std::string (val); // LCOV_EXCL_BR_LINE
115 : 20 : }
116 : :
117 : 37 : Value::Value (double val) noexcept
118 : 37 : : _type{Type::Real}
119 : : {
120 : 37 : _store.realval = val;
121 : 37 : }
122 : :
123 : 37 : Value::Value (Blob val) noexcept
124 : 37 : : _type{Type::Blob}
125 : : {
126 : 37 : new (&_store.blobval) Blob (std::move (val)); // LCOV_EXCL_BR_LINE
127 : 37 : }
128 : :
129 : 1416 : Value::~Value () noexcept
130 : : {
131 : 1416 : if (_type == Type::Text)
132 : : {
133 : 222 : _store.textval.~basic_string<std::string::value_type> ();
134 : : }
135 : 1194 : else if (_type == Type::Blob)
136 : : {
137 : 107 : _store.blobval.~vector<Blob::value_type> ();
138 : : }
139 : 1416 : }
140 : :
141 : 434 : Value::Value (const Value& other) noexcept
142 : 434 : : _type{other._type}
143 : : {
144 : 434 : switch (_type)
145 : : {
146 : 90 : case Type::Null:
147 : 90 : break;
148 : :
149 : 128 : case Type::Int:
150 : 128 : _store.intval = other._store.intval;
151 : 128 : break;
152 : :
153 : 73 : case Type::Real:
154 : 73 : _store.realval = other._store.realval;
155 : 73 : break;
156 : :
157 : 84 : case Type::Text:
158 : 84 : new (&_store.textval) std::string (other._store.textval); // LCOV_EXCL_BR_LINE
159 : 84 : break;
160 : :
161 : 59 : case Type::Blob:
162 : 59 : new (&_store.blobval) Blob (other._store.blobval); // LCOV_EXCL_BR_LINE
163 : 59 : break;
164 : :
165 : 0 : default:
166 : : raiseErrUnexpected ("never reach"); // LCOV_EXCL_LINE
167 : : }
168 : 434 : }
169 : :
170 : 411 : Value::Value (Value&& other) noexcept
171 : 411 : : _type (other._type)
172 : : {
173 : : // gcc 5.3, only release, will complain if uninitialized
174 : 411 : _store.intval = 0;
175 : :
176 : 411 : switch (_type)
177 : : {
178 : 33 : case Type::Null:
179 : 33 : break;
180 : :
181 : 159 : case Type::Int:
182 : 159 : _store.intval = std::move (other._store.intval);
183 : 159 : break;
184 : :
185 : 56 : case Type::Real:
186 : 56 : _store.realval = std::move (other._store.realval);
187 : 56 : break;
188 : :
189 : 138 : case Type::Text:
190 : 138 : new (&_store.textval) std::string (std::move (other._store.textval)); // LCOV_EXCL_BR_LINE
191 : 138 : other._store.textval.~basic_string ();
192 : 138 : break;
193 : :
194 : 25 : case Type::Blob:
195 : 25 : new (&_store.blobval) Blob (std::move (other._store.blobval)); // LCOV_EXCL_BR_LINE
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 : 411 : other._type = Type::Null;
206 : 411 : }
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); // LCOV_EXCL_BR_LINE
248 : 21 : break;
249 : :
250 : 14 : case Type::Blob:
251 : 14 : new (&_store.blobval) Blob (other._store.blobval); // LCOV_EXCL_BR_LINE
252 : 14 : break;
253 : :
254 : : case Type::Variant: // LCOV_EXCL_LINE
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)); // LCOV_EXCL_BR_LINE
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)); // LCOV_EXCL_BR_LINE
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 : 60 : Value::operator= (int val)
326 : : {
327 : 60 : if (_type == Type::Text)
328 : : {
329 : 1 : _store.textval.~basic_string<std::string::value_type> ();
330 : : }
331 : 59 : else if (_type == Type::Blob)
332 : : {
333 : 1 : _store.blobval.~vector<Blob::value_type> ();
334 : : }
335 : 60 : _store.intval = val;
336 : 60 : _type = Type::Int;
337 : 60 : return *this;
338 : : }
339 : :
340 : : Value&
341 : 81 : Value::operator= (const int64_t& val)
342 : : {
343 : 81 : if (_type == Type::Text)
344 : : {
345 : 1 : _store.textval.~basic_string<std::string::value_type> ();
346 : : }
347 : 80 : else if (_type == Type::Blob)
348 : : {
349 : 1 : _store.blobval.~vector<Blob::value_type> ();
350 : : }
351 : 81 : _store.intval = val;
352 : 81 : _type = Type::Int;
353 : 81 : return *this;
354 : : }
355 : :
356 : : Value&
357 : 68 : Value::operator= (const double& val)
358 : : {
359 : 68 : if (_type == Type::Text)
360 : : {
361 : 1 : _store.textval.~basic_string<std::string::value_type> ();
362 : : }
363 : 67 : else if (_type == Type::Blob)
364 : : {
365 : 1 : _store.blobval.~vector<Blob::value_type> ();
366 : : }
367 : 68 : _store.realval = val;
368 : 68 : _type = Type::Real;
369 : 68 : return *this;
370 : : }
371 : :
372 : : Value&
373 : 107 : Value::operator= (const std::string& val)
374 : : {
375 : 107 : if (_type == Type::Text)
376 : : {
377 : 1 : _store.textval = val;
378 : 1 : return *this;
379 : : }
380 : 106 : else if (_type == Type::Blob)
381 : : {
382 : 1 : _store.blobval.~vector<Blob::value_type> ();
383 : : }
384 : :
385 : 106 : new (&_store.textval) std::string (val); // LCOV_EXCL_BR_LINE
386 : 106 : _type = Type::Text;
387 : 106 : return *this;
388 : : }
389 : :
390 : : Value&
391 : 26 : Value::operator= (const Blob& val)
392 : : {
393 : 26 : if (_type == Type::Text)
394 : : {
395 : 2 : _store.textval.~basic_string<std::string::value_type> ();
396 : : }
397 : 24 : else if (_type == Type::Blob)
398 : : {
399 : 1 : _store.blobval = val;
400 : 1 : return *this;
401 : : }
402 : 25 : new (&_store.blobval) Blob (val); // LCOV_EXCL_BR_LINE
403 : 25 : _type = Type::Blob;
404 : 25 : return *this;
405 : : }
406 : :
407 : 8 : Value::
408 : : operator int () const
409 : : {
410 : 8 : if (isNull ())
411 : 1 : throw ErrNullValueAccess ();
412 : 7 : else if (_type == Type::Real)
413 : 3 : return losslessConvert1<double, int> (_store.realval);
414 : 4 : else if (_type != Type::Int)
415 : 2 : throw ErrTypeMisMatch ("Implicit conversion: " + typeName (_type)
416 : 3 : + " to int64_t");
417 : :
418 : : using limit = std::numeric_limits<int>;
419 : :
420 : 3 : if (_store.intval < limit::min () || _store.intval > limit::max ())
421 : 2 : throw ErrOutOfRange ("Implicit conversion int64_t to int, value to big");
422 : :
423 : 1 : return static_cast<int> (_store.intval);
424 : : }
425 : :
426 : 42 : Value::
427 : : operator int64_t () const
428 : : {
429 : 42 : if (isNull ())
430 : 1 : throw ErrNullValueAccess ();
431 : 41 : else if (_type == Type::Real)
432 : 7 : return losslessConvert1<double, int64_t> (_store.realval);
433 : 34 : else if (_type != Type::Int)
434 : 24 : throw ErrTypeMisMatch ("Implicit conversion: " + typeName (_type)
435 : 36 : + " to int64_t");
436 : :
437 : 22 : return _store.intval;
438 : : }
439 : :
440 : 20 : Value::
441 : : operator double () const
442 : : {
443 : 20 : if (isNull ())
444 : : {
445 : 1 : throw ErrNullValueAccess ();
446 : : }
447 : 19 : else if (_type == Type::Int)
448 : : {
449 : : // using limit = std::numeric_limits<double>;
450 : : // if (_store.intval < limit::min () || _store.intval >
451 : : // limit::max ())
452 : : // throw Not possible :- );
453 : :
454 : 1 : return static_cast<double> (_store.intval);
455 : : }
456 : 18 : else if (_type != Type::Real)
457 : : {
458 : 24 : throw ErrTypeMisMatch (typeName (_type)
459 : 36 : + " != " + typeName (Type::Real));
460 : : }
461 : :
462 : 6 : return _store.realval;
463 : : }
464 : :
465 : 30 : Value::
466 : : operator const std::string&() const
467 : : {
468 : 30 : if (isNull ())
469 : 1 : throw ErrNullValueAccess ();
470 : 29 : else if (_type != Type::Text)
471 : 46 : throw ErrTypeMisMatch (typeName (_type)
472 : 69 : + " != " + typeName (Type::Text));
473 : :
474 : 6 : return _store.textval;
475 : : }
476 : :
477 : 30 : Value::
478 : : operator const Blob&() const
479 : : {
480 : 30 : if (isNull ())
481 : 1 : throw ErrNullValueAccess ();
482 : 29 : else if (_type != Type::Blob)
483 : 46 : throw ErrTypeMisMatch (typeName (_type)
484 : 69 : + " != " + typeName (Type::Blob));
485 : :
486 : 6 : return _store.blobval;
487 : : }
488 : :
489 : : const int64_t&
490 : 113 : Value::int64 () const
491 : : {
492 : 113 : if (isNull ())
493 : 3 : throw ErrNullValueAccess ();
494 : :
495 : 110 : const auto wanted = Type::Int;
496 : 110 : if (_type != wanted)
497 : 30 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
498 : :
499 : 80 : return _store.intval;
500 : : }
501 : :
502 : : const double&
503 : 57 : Value::real () const
504 : : {
505 : 57 : if (isNull ())
506 : 3 : throw ErrNullValueAccess ();
507 : :
508 : 54 : const auto wanted = Type::Real;
509 : 54 : if (_type != wanted)
510 : 16 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
511 : :
512 : 38 : return _store.realval;
513 : : }
514 : :
515 : : const std::string&
516 : 101 : Value::text () const
517 : : {
518 : 101 : if (isNull ())
519 : 3 : throw ErrNullValueAccess ();
520 : :
521 : 98 : const auto wanted = Type::Text;
522 : 98 : if (_type != wanted)
523 : 28 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
524 : :
525 : 70 : return _store.textval;
526 : : }
527 : :
528 : : const Blob&
529 : 63 : Value::blob () const
530 : : {
531 : 63 : if (isNull ())
532 : 3 : throw ErrNullValueAccess ();
533 : :
534 : 60 : const auto wanted = Type::Blob;
535 : 60 : if (_type != wanted)
536 : 27 : throw ErrTypeMisMatch (typeName (_type) + " != " + typeName (wanted));
537 : :
538 : 33 : return _store.blobval;
539 : : }
540 : :
541 : : std::string
542 : 5 : Value::ejectText ()
543 : : {
544 : 5 : if (_type == Type::Null)
545 : : {
546 : 3 : throw ErrNullValueAccess ();
547 : : }
548 : 2 : else if (_type != Type::Text)
549 : : {
550 : 2 : throw ErrTypeMisMatch (typeName (_type)
551 : 3 : + " != " + typeName (Type::Text));
552 : : }
553 : 1 : auto tmp = std::move (_store.textval);
554 : : // setNull (); // does not works,
555 : : // gcc reports some obscure error in release build
556 : : // therefore we do it manually
557 : 1 : _store.textval.~basic_string<std::string::value_type> ();
558 : 1 : _type = Type::Null;
559 : 1 : return tmp;
560 : : }
561 : :
562 : : Blob
563 : 5 : Value::ejectBlob ()
564 : : {
565 : 5 : if (_type == Type::Null)
566 : : {
567 : 3 : throw ErrNullValueAccess ();
568 : : }
569 : 2 : else if (_type != Type::Blob)
570 : : {
571 : 2 : throw ErrTypeMisMatch (typeName (_type)
572 : 3 : + " != " + typeName (Type::Blob));
573 : : }
574 : :
575 : 1 : auto tmp = std::move (_store.blobval);
576 : : // setNull (); // does not works,
577 : : // gcc reports some obscure error in release build
578 : : // therefore we do it manually
579 : 1 : _store.blobval.~vector<Blob::value_type> ();
580 : 1 : _type = Type::Null;
581 : 1 : return tmp;
582 : : }
583 : :
584 : : void
585 : 5 : Value::setNull () noexcept
586 : : {
587 : 5 : if (_type == Type::Text)
588 : : {
589 : 3 : _store.textval.~basic_string<std::string::value_type> ();
590 : : }
591 : 2 : else if (_type == Type::Blob)
592 : : {
593 : 2 : _store.blobval.~vector<Blob::value_type> ();
594 : : }
595 : 5 : _type = Type::Null;
596 : 5 : }
597 : :
598 : : bool
599 : 749 : Value::isNull () const noexcept
600 : : {
601 : 749 : return _type == Type::Null;
602 : : }
603 : :
604 : : Type
605 : 1134 : Value::getType () const noexcept
606 : : {
607 : 1134 : return _type;
608 : : }
609 : :
610 : : std::ostream&
611 : 23 : operator<< (std::ostream& stm, const sl3::Value& v)
612 : : {
613 : 23 : switch (v.getType ())
614 : : {
615 : 2 : case Type::Null:
616 : 2 : stm << "<NULL>";
617 : 2 : break;
618 : :
619 : 6 : case Type::Int:
620 : 6 : stm << v._store.intval;
621 : 6 : break;
622 : :
623 : 6 : case Type::Real:
624 : 6 : stm << v._store.realval;
625 : 6 : break;
626 : :
627 : 7 : case Type::Text:
628 : 7 : stm << v._store.textval;
629 : 7 : break;
630 : :
631 : 2 : case Type::Blob:
632 : 2 : stm << "<BLOB>";
633 : 2 : break;
634 : :
635 : 0 : default:
636 : : stm << "unknown storage type !!"; // LCOV_EXCL_LINE
637 : : break; // LCOV_EXCL_LINE
638 : : }
639 : :
640 : 23 : return stm;
641 : : }
642 : :
643 : : bool
644 : 115 : value_type_eq (const Value& a, const Value& b) noexcept
645 : : {
646 : 115 : if (a.getType () != b.getType ())
647 : 21 : return false;
648 : :
649 : 94 : bool retval = false;
650 : :
651 : 94 : switch (a.getType ())
652 : : {
653 : 16 : case Type::Null:
654 : 16 : retval = b.isNull ();
655 : 16 : break;
656 : :
657 : 22 : case Type::Int:
658 : 22 : retval = a._store.intval == b._store.intval;
659 : :
660 : 22 : break;
661 : :
662 : 21 : case Type::Real:
663 : 21 : retval = almost_equal (a._store.realval, b._store.realval, 2);
664 : 21 : break;
665 : :
666 : 18 : case Type::Text:
667 : 18 : retval = a._store.textval == b._store.textval;
668 : 18 : break;
669 : :
670 : 17 : case Type::Blob:
671 : 17 : retval = a._store.blobval == b._store.blobval;
672 : 17 : break;
673 : :
674 : 0 : default:
675 : : break; // LCOV_EXCL_LINE
676 : : }
677 : :
678 : 94 : return retval;
679 : : }
680 : :
681 : : bool
682 : 38 : value_type_lt (const Value& a, const Value& b) noexcept
683 : : {
684 : 38 : if (b.isNull ())
685 : 4 : return false;
686 : :
687 : 34 : if (a.isNull ())
688 : 4 : return true;
689 : :
690 : 30 : if (a.getType () == Type::Int)
691 : : {
692 : 11 : if (b.getType () == Type::Int)
693 : 6 : return a._store.intval < b._store.intval;
694 : :
695 : 5 : if (b.getType () == Type::Real)
696 : 3 : return is_less_equal (a._store.intval, b._store.realval);
697 : : // respect type, int type smaller if equal to real value
698 : :
699 : 2 : return true;
700 : : }
701 : :
702 : 19 : if (a.getType () == Type::Real)
703 : : {
704 : 7 : if (b.getType () == Type::Int)
705 : 2 : return is_less (a._store.realval, b._store.intval);
706 : : // respect type, int type smaller if equal to real value
707 : :
708 : 5 : if (b.getType () == Type::Real)
709 : 3 : return a._store.realval < b._store.realval;
710 : :
711 : 2 : return true;
712 : : }
713 : :
714 : 12 : if (a.getType () == Type::Text)
715 : : {
716 : 6 : if (b.getType () == Type::Text)
717 : 3 : return a._store.textval < b._store.textval;
718 : :
719 : : // only blob types are bigger
720 : 3 : return b.getType () == Type::Blob;
721 : : }
722 : :
723 : : // ASSERT_EXCEPT(a.getType () == Type::Blob, ErrUnexpected) ;
724 : :
725 : : // this is blob
726 : 6 : if (b.getType () != Type::Blob)
727 : 3 : return false;
728 : :
729 : : // we are both blobs
730 : 3 : return a._store.blobval < b._store.blobval;
731 : : }
732 : :
733 : : void
734 : 1 : Value::swap (Value& other) noexcept
735 : : {
736 : 1 : Value t{std::move (other)};
737 : : // should be auto t{...} but 4.8.2 does not like it
738 : 1 : other = std::move (*this);
739 : 1 : *this = std::move (t);
740 : 1 : }
741 : :
742 : : void
743 : 1 : swap (Value& a, Value& b) noexcept
744 : : {
745 : 1 : a.swap (b);
746 : 1 : }
747 : :
748 : : bool
749 : 30 : value_eq (const Value& a, const Value& b) noexcept
750 : : {
751 : 30 : bool retval = false;
752 : :
753 : 30 : switch (a.getType ())
754 : : {
755 : 5 : case Type::Null:
756 : 5 : retval = b.isNull ();
757 : 5 : break;
758 : :
759 : 9 : case Type::Int:
760 : 9 : if (b._type == Type::Int)
761 : 3 : retval = a._store.intval == b._store.intval;
762 : 6 : else if (b._type == Type::Real)
763 : 3 : retval = is_equal (a._store.intval, b._store.realval);
764 : :
765 : 9 : break;
766 : :
767 : 6 : case Type::Real:
768 : 6 : if (b._type == Type::Int)
769 : 1 : retval = is_equal (a._store.realval, b._store.intval);
770 : 5 : else if (b._type == Type::Real)
771 : 2 : retval = a._store.realval == b._store.realval;
772 : :
773 : 6 : break;
774 : :
775 : 5 : case Type::Text:
776 : 5 : if (b._type == Type::Text)
777 : 1 : retval = a._store.textval == b._store.textval;
778 : 5 : break;
779 : :
780 : 5 : case Type::Blob:
781 : 5 : if (b._type == Type::Blob)
782 : 1 : retval = a._store.blobval == b._store.blobval;
783 : 5 : break;
784 : :
785 : : default: // LCOV_EXCL_LINE
786 : : break; // LCOV_EXCL_LINE
787 : : }
788 : :
789 : 30 : return retval;
790 : : }
791 : :
792 : : bool
793 : 51 : value_lt (const Value& a, const Value& b) noexcept
794 : : {
795 : 51 : if (b.isNull ())
796 : 4 : return false;
797 : :
798 : 47 : if (a.isNull ())
799 : 4 : return true;
800 : :
801 : 43 : if (a.getType () == Type::Int)
802 : : {
803 : 23 : if (b.getType () == Type::Int)
804 : 18 : return a._store.intval < b._store.intval;
805 : :
806 : 5 : if (b.getType () == Type::Real)
807 : 3 : return is_less (a._store.intval, b._store.realval);
808 : :
809 : 2 : return true;
810 : : }
811 : :
812 : 20 : if (a.getType () == Type::Real)
813 : : {
814 : 7 : if (b.getType () == Type::Int)
815 : 2 : return is_less (a._store.realval, b._store.intval);
816 : :
817 : 5 : if (b.getType () == Type::Real)
818 : 3 : return a._store.realval < b._store.realval;
819 : :
820 : 2 : return true;
821 : : }
822 : :
823 : 13 : if (a.getType () == Type::Text)
824 : : {
825 : 7 : if (b.getType () == Type::Text)
826 : 4 : return a._store.textval < b._store.textval;
827 : :
828 : 3 : if (b.getType () == Type::Blob)
829 : 1 : return true;
830 : : else
831 : 2 : return false;
832 : : }
833 : :
834 : : // TODO assert a.getType () == Type::Blob
835 : :
836 : : // this is blob
837 : 6 : if (b.getType () != Type::Blob)
838 : 3 : return false;
839 : :
840 : : // we are both blobs
841 : 3 : return a._store.blobval < b._store.blobval;
842 : : }
843 : :
844 : : } // ns
|