LCOV - code coverage report
Current view: top level - src - compare.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 69 69 100.0 %
Date: 2026-07-14 21:28:07 Functions: 4 4 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 90 91 98.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright 2019-2026 David Robillard <d@drobilla.net>
       2                 :            : // SPDX-License-Identifier: ISC
       3                 :            : 
       4                 :            : #include "big_decimal.h"
       5                 :            : 
       6                 :            : #include <exess/exess.h>
       7                 :            : 
       8                 :            : #include <stdbool.h>
       9                 :            : #include <stdint.h>
      10                 :            : #include <string.h>
      11                 :            : 
      12                 :            : static EXESS_NONBLOCKING ExessOrder
      13                 :          8 : compare_datatypes(const ExessDatatype lhs_datatype,
      14                 :            :                   const ExessDatatype rhs_datatype)
      15                 :            : {
      16                 :          8 :   const char* const lhs_name = exess_datatype_name(lhs_datatype);
      17                 :          8 :   const char* const rhs_name = exess_datatype_name(rhs_datatype);
      18                 :            :   return !lhs_name                          ? EXESS_ORDER_MAYBE_LESS
      19   [ +  +  +  + ]:         12 :          : !rhs_name                        ? EXESS_ORDER_MAYBE_GREATER
      20         [ +  + ]:          4 :          : (strcmp(lhs_name, rhs_name) < 0) ? EXESS_ORDER_MAYBE_LESS
      21                 :            :                                             : EXESS_ORDER_MAYBE_GREATER;
      22                 :            : }
      23                 :            : 
      24                 :            : static EXESS_NONBLOCKING ExessOrder
      25                 :         56 : compare_decimal(const void* const lhs_value, const void* const rhs_value)
      26                 :            : {
      27                 :         56 :   EXESS_CONSTEXPR int8_t kind_orders[7][7] = {
      28                 :            :     //   -I  +I  -0  +0  -N  +N
      29                 :            :     {+0, -1, -1, -1, -1, -1, -1},  // NaN
      30                 :            :     {+1, +0, -2, -2, -2, -2, -2},  // -I
      31                 :            :     {+1, +2, +0, +2, +2, +2, +2},  // +I
      32                 :            :     {+1, +2, -2, +0, +0, +2, -2},  // -0
      33                 :            :     {+1, +2, -2, +0, +0, +2, -2},  // +0
      34                 :            :     {+1, +2, -2, -2, -2, +0, -2},  // -N
      35                 :            :     {+1, +2, -2, +2, +2, +2, +0}}; // +N
      36                 :            : 
      37                 :         56 :   const BigDecimal lhs = *(const BigDecimal*)lhs_value;
      38                 :         56 :   const BigDecimal rhs = *(const BigDecimal*)rhs_value;
      39         [ +  + ]:         56 :   if (lhs.kind != rhs.kind) {
      40                 :         18 :     return (ExessOrder)kind_orders[lhs.kind][rhs.kind];
      41                 :            :   }
      42                 :            : 
      43                 :            :   // The internal representation has digits without leading zeros
      44                 :         38 :   const char* const lhs_digits = (const char*)lhs_value + sizeof(lhs);
      45                 :         38 :   const char* const rhs_digits = (const char*)rhs_value + sizeof(rhs);
      46                 :         38 :   const bool        negative   = lhs.kind == EXESS_NEGATIVE;
      47         [ +  + ]:         38 :   const int         factor     = negative ? -1 : 1;
      48                 :            : 
      49         [ +  + ]:         38 :   if (lhs.expt != rhs.expt) {
      50                 :          8 :     return (ExessOrder)(factor * ((lhs.expt < rhs.expt)
      51                 :            :                                     ? EXESS_ORDER_STRICTLY_LESS
      52         [ +  + ]:          8 :                                     : EXESS_ORDER_STRICTLY_GREATER));
      53                 :            :   }
      54                 :            : 
      55                 :         30 :   const int cmp = strncmp(lhs_digits, rhs_digits, lhs.n_digits);
      56                 :         30 :   return (ExessOrder)(factor * (cmp < 0   ? EXESS_ORDER_STRICTLY_LESS
      57         [ +  + ]:         54 :                                 : cmp > 0 ? EXESS_ORDER_STRICTLY_GREATER
      58         [ +  + ]:         24 :                                           : EXESS_ORDER_EQUAL));
      59                 :            : }
      60                 :            : 
      61                 :            : static ExessOrder
      62                 :         44 : compare_blob(const size_t      lhs_size,
      63                 :            :              const void* const lhs_value,
      64                 :            :              const size_t      rhs_size,
      65                 :            :              const void* const rhs_value)
      66                 :            : {
      67                 :         44 :   const bool   shorter_lhs = lhs_size < rhs_size;
      68         [ +  + ]:         44 :   const size_t cmp_size    = shorter_lhs ? lhs_size : rhs_size;
      69                 :         44 :   const int    cmp         = memcmp(lhs_value, rhs_value, cmp_size);
      70                 :            : 
      71                 :            :   return cmp < 0                  ? EXESS_ORDER_MAYBE_LESS
      72   [ +  +  +  +  :         65 :          : cmp > 0                ? EXESS_ORDER_MAYBE_GREATER
                   +  + ]
      73                 :            :          : shorter_lhs            ? EXESS_ORDER_MAYBE_LESS
      74                 :            :          : (lhs_size == rhs_size) ? EXESS_ORDER_EQUAL
      75                 :         21 :                                   : EXESS_ORDER_MAYBE_GREATER;
      76                 :            : }
      77                 :            : 
      78                 :            : EXESS_NONBLOCKING ExessOrder
      79                 :        590 : exess_compare_value(const ExessDatatype lhs_datatype,
      80                 :            :                     const size_t        lhs_size,
      81                 :            :                     const void* const   lhs_value,
      82                 :            :                     const ExessDatatype rhs_datatype,
      83                 :            :                     const size_t        rhs_size,
      84                 :            :                     const void* const   rhs_value)
      85                 :            : {
      86         [ +  + ]:        590 :   if (lhs_datatype != rhs_datatype) {
      87                 :          8 :     return compare_datatypes(lhs_datatype, rhs_datatype);
      88                 :            :   }
      89                 :            : 
      90                 :            : #define COMPARE(lhs, rhs)                          \
      91                 :            :   ((lhs) < (rhs))   ? EXESS_ORDER_STRICTLY_LESS    \
      92                 :            :   : ((rhs) < (lhs)) ? EXESS_ORDER_STRICTLY_GREATER \
      93                 :            :                     : EXESS_ORDER_EQUAL
      94                 :            : 
      95   [ +  +  +  +  :        582 :   switch (lhs_datatype) {
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  +  
                      - ]
      96                 :          2 :   case EXESS_NOTHING:
      97                 :          2 :     break;
      98                 :         30 :   case EXESS_BOOLEAN:
      99   [ +  +  +  + ]:         30 :     return COMPARE(*(const bool*)lhs_value, *(const bool*)rhs_value);
     100                 :          6 :   case EXESS_DOUBLE:
     101   [ +  +  +  + ]:          6 :     return COMPARE(*(const double*)lhs_value, *(const double*)rhs_value);
     102                 :          6 :   case EXESS_FLOAT:
     103   [ +  +  +  + ]:          6 :     return COMPARE(*(const float*)lhs_value, *(const float*)rhs_value);
     104                 :          6 :   case EXESS_LONG:
     105   [ +  +  +  + ]:          6 :     return COMPARE(*(const int64_t*)lhs_value, *(const int64_t*)rhs_value);
     106                 :          6 :   case EXESS_INT:
     107   [ +  +  +  + ]:          6 :     return COMPARE(*(const int32_t*)lhs_value, *(const int32_t*)rhs_value);
     108                 :          6 :   case EXESS_SHORT:
     109   [ +  +  +  + ]:          6 :     return COMPARE(*(const int16_t*)lhs_value, *(const int16_t*)rhs_value);
     110                 :          6 :   case EXESS_BYTE:
     111   [ +  +  +  + ]:          6 :     return COMPARE(*(const int8_t*)lhs_value, *(const int8_t*)rhs_value);
     112                 :          6 :   case EXESS_ULONG:
     113   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint64_t*)lhs_value, *(const uint64_t*)rhs_value);
     114                 :          6 :   case EXESS_UINT:
     115   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint32_t*)lhs_value, *(const uint32_t*)rhs_value);
     116                 :          6 :   case EXESS_USHORT:
     117   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint16_t*)lhs_value, *(const uint16_t*)rhs_value);
     118                 :          6 :   case EXESS_UBYTE:
     119   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint8_t*)lhs_value, *(const uint8_t*)rhs_value);
     120                 :         56 :   case EXESS_DECIMAL:
     121                 :            :   case EXESS_INTEGER:
     122                 :            :   case EXESS_NON_POSITIVE_INTEGER:
     123                 :            :   case EXESS_NEGATIVE_INTEGER:
     124                 :            :   case EXESS_NON_NEGATIVE_INTEGER:
     125                 :            :   case EXESS_POSITIVE_INTEGER:
     126                 :         56 :     return compare_decimal(lhs_value, rhs_value);
     127                 :        104 :   case EXESS_DURATION:
     128                 :            :   case EXESS_YEAR_MONTH_DURATION:
     129                 :            :   case EXESS_DAY_TIME_DURATION:
     130                 :        104 :     return exess_compare_duration(*(const ExessDuration*)lhs_value,
     131                 :            :                                   *(const ExessDuration*)rhs_value);
     132                 :            : 
     133                 :        122 :   case EXESS_DATE_TIME:
     134                 :            :   case EXESS_DATE_TIME_STAMP:
     135                 :        122 :     return exess_compare_date_time(*(const ExessDateTime*)lhs_value,
     136                 :            :                                    *(const ExessDateTime*)rhs_value);
     137                 :            : 
     138                 :         96 :   case EXESS_TIME:
     139                 :         96 :     return exess_compare_time(*(const ExessTime*)lhs_value,
     140                 :            :                               *(const ExessTime*)rhs_value);
     141                 :            : 
     142                 :         68 :   case EXESS_DATE:
     143                 :         68 :     return exess_compare_date(*(const ExessDate*)lhs_value,
     144                 :            :                               *(const ExessDate*)rhs_value);
     145                 :            : 
     146                 :         44 :   case EXESS_HEX:
     147                 :            :   case EXESS_BASE64:
     148                 :         44 :     return compare_blob(lhs_size, lhs_value, rhs_size, rhs_value);
     149                 :            :   }
     150                 :            : 
     151                 :            : #undef COMPARE
     152                 :            : 
     153                 :          2 :   return EXESS_ORDER_EQUAL;
     154                 :            : }

Generated by: LCOV version 1.16