LCOV - code coverage report
Current view: top level - src - compare.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 84 84 100.0 %
Date: 2026-08-20 23:47:58 Functions: 4 4 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 95 96 99.0 %

           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                 :            : #include "date.h"
       6                 :            : #include "date_time.h"
       7                 :            : #include "duration.h"
       8                 :            : #include "time.h"
       9                 :            : 
      10                 :            : #include <exess/exess.h>
      11                 :            : 
      12                 :            : #include <stdbool.h>
      13                 :            : #include <stdint.h>
      14                 :            : #include <string.h>
      15                 :            : 
      16                 :            : static EXESS_NONBLOCKING ExessOrder
      17                 :          8 : compare_datatypes(const ExessDatatype lhs_datatype,
      18                 :            :                   const ExessDatatype rhs_datatype)
      19                 :            : {
      20                 :          8 :   const char* const lhs_name = exess_datatype_name(lhs_datatype);
      21                 :          8 :   const char* const rhs_name = exess_datatype_name(rhs_datatype);
      22                 :            :   return !lhs_name                          ? EXESS_ORDER_MAYBE_LESS
      23   [ +  +  +  + ]:         12 :          : !rhs_name                        ? EXESS_ORDER_MAYBE_GREATER
      24         [ +  + ]:          4 :          : (strcmp(lhs_name, rhs_name) < 0) ? EXESS_ORDER_MAYBE_LESS
      25                 :            :                                             : EXESS_ORDER_MAYBE_GREATER;
      26                 :            : }
      27                 :            : 
      28                 :            : static EXESS_NONBLOCKING ExessOrder
      29                 :         56 : compare_decimal(const void* const lhs_value, const void* const rhs_value)
      30                 :            : {
      31                 :         56 :   EXESS_CONSTEXPR int8_t kind_orders[7][7] = {
      32                 :            :     //   -I  +I  -0  +0  -N  +N
      33                 :            :     {+0, -1, -1, -1, -1, -1, -1},  // NaN
      34                 :            :     {+1, +0, -2, -2, -2, -2, -2},  // -I
      35                 :            :     {+1, +2, +0, +2, +2, +2, +2},  // +I
      36                 :            :     {+1, +2, -2, +0, +0, +2, -2},  // -0
      37                 :            :     {+1, +2, -2, +0, +0, +2, -2},  // +0
      38                 :            :     {+1, +2, -2, -2, -2, +0, -2},  // -N
      39                 :            :     {+1, +2, -2, +2, +2, +2, +0}}; // +N
      40                 :            : 
      41                 :         56 :   const BigDecimal lhs = *(const BigDecimal*)lhs_value;
      42                 :         56 :   const BigDecimal rhs = *(const BigDecimal*)rhs_value;
      43         [ +  + ]:         56 :   if (lhs.kind != rhs.kind) {
      44                 :         18 :     return (ExessOrder)kind_orders[lhs.kind][rhs.kind];
      45                 :            :   }
      46                 :            : 
      47                 :            :   // The internal representation has digits without leading zeros
      48                 :         38 :   const char* const lhs_digits = (const char*)lhs_value + sizeof(lhs);
      49                 :         38 :   const char* const rhs_digits = (const char*)rhs_value + sizeof(rhs);
      50                 :         38 :   const bool        negative   = lhs.kind == EXESS_NEGATIVE;
      51         [ +  + ]:         38 :   const int         factor     = negative ? -1 : 1;
      52                 :            : 
      53         [ +  + ]:         38 :   if (lhs.expt != rhs.expt) {
      54                 :          8 :     return (ExessOrder)(factor * ((lhs.expt < rhs.expt)
      55                 :            :                                     ? EXESS_ORDER_STRICTLY_LESS
      56         [ +  + ]:          8 :                                     : EXESS_ORDER_STRICTLY_GREATER));
      57                 :            :   }
      58                 :            : 
      59                 :         30 :   const int cmp = strncmp(lhs_digits, rhs_digits, lhs.n_digits);
      60                 :         30 :   return (ExessOrder)(factor * (cmp < 0   ? EXESS_ORDER_STRICTLY_LESS
      61         [ +  + ]:         54 :                                 : cmp > 0 ? EXESS_ORDER_STRICTLY_GREATER
      62         [ +  + ]:         24 :                                           : EXESS_ORDER_EQUAL));
      63                 :            : }
      64                 :            : 
      65                 :            : static ExessOrder
      66                 :         44 : compare_blob(const size_t      lhs_size,
      67                 :            :              const void* const lhs_value,
      68                 :            :              const size_t      rhs_size,
      69                 :            :              const void* const rhs_value)
      70                 :            : {
      71                 :         44 :   const bool   shorter_lhs = lhs_size < rhs_size;
      72         [ +  + ]:         44 :   const size_t cmp_size    = shorter_lhs ? lhs_size : rhs_size;
      73                 :         44 :   const int    cmp         = memcmp(lhs_value, rhs_value, cmp_size);
      74                 :            : 
      75                 :            :   return cmp < 0                  ? EXESS_ORDER_MAYBE_LESS
      76   [ +  +  +  +  :         65 :          : cmp > 0                ? EXESS_ORDER_MAYBE_GREATER
                   +  + ]
      77                 :            :          : shorter_lhs            ? EXESS_ORDER_MAYBE_LESS
      78                 :            :          : (lhs_size == rhs_size) ? EXESS_ORDER_EQUAL
      79                 :         21 :                                   : EXESS_ORDER_MAYBE_GREATER;
      80                 :            : }
      81                 :            : 
      82                 :            : EXESS_NONBLOCKING ExessOrder
      83                 :        680 : exess_compare_value(const ExessDatatype lhs_datatype,
      84                 :            :                     const size_t        lhs_size,
      85                 :            :                     const void* const   lhs_value,
      86                 :            :                     const ExessDatatype rhs_datatype,
      87                 :            :                     const size_t        rhs_size,
      88                 :            :                     const void* const   rhs_value)
      89                 :            : {
      90         [ +  + ]:        680 :   if (lhs_datatype != rhs_datatype) {
      91                 :          8 :     return compare_datatypes(lhs_datatype, rhs_datatype);
      92                 :            :   }
      93                 :            : 
      94                 :            : #ifdef __cplusplus
      95                 :            : #  define DATE(y, m, d, z) (ExessDate{y, m, d, z})
      96                 :            : #else
      97                 :            : #  define DATE(y, m, d, z) ((ExessDate){y, m, d, z})
      98                 :            : #endif
      99                 :            : 
     100                 :            : #define COMPARE(lhs, rhs)                          \
     101                 :            :   ((lhs) < (rhs))   ? EXESS_ORDER_STRICTLY_LESS    \
     102                 :            :   : ((rhs) < (lhs)) ? EXESS_ORDER_STRICTLY_GREATER \
     103                 :            :                     : EXESS_ORDER_EQUAL
     104                 :            : 
     105   [ +  +  +  +  :        672 :   switch (lhs_datatype) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  +  
                      - ]
     106                 :          2 :   case EXESS_NOTHING:
     107                 :          2 :     break;
     108                 :         30 :   case EXESS_BOOLEAN:
     109   [ +  +  +  + ]:        670 :     return COMPARE(*(const bool*)lhs_value, *(const bool*)rhs_value);
     110                 :          6 :   case EXESS_DOUBLE:
     111   [ +  +  +  + ]:          6 :     return COMPARE(*(const double*)lhs_value, *(const double*)rhs_value);
     112                 :          6 :   case EXESS_FLOAT:
     113   [ +  +  +  + ]:          6 :     return COMPARE(*(const float*)lhs_value, *(const float*)rhs_value);
     114                 :          6 :   case EXESS_LONG:
     115   [ +  +  +  + ]:          6 :     return COMPARE(*(const int64_t*)lhs_value, *(const int64_t*)rhs_value);
     116                 :          6 :   case EXESS_INT:
     117   [ +  +  +  + ]:          6 :     return COMPARE(*(const int32_t*)lhs_value, *(const int32_t*)rhs_value);
     118                 :          6 :   case EXESS_SHORT:
     119   [ +  +  +  + ]:          6 :     return COMPARE(*(const int16_t*)lhs_value, *(const int16_t*)rhs_value);
     120                 :          6 :   case EXESS_BYTE:
     121   [ +  +  +  + ]:          6 :     return COMPARE(*(const int8_t*)lhs_value, *(const int8_t*)rhs_value);
     122                 :          6 :   case EXESS_ULONG:
     123   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint64_t*)lhs_value, *(const uint64_t*)rhs_value);
     124                 :          6 :   case EXESS_UINT:
     125   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint32_t*)lhs_value, *(const uint32_t*)rhs_value);
     126                 :          6 :   case EXESS_USHORT:
     127   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint16_t*)lhs_value, *(const uint16_t*)rhs_value);
     128                 :          6 :   case EXESS_UBYTE:
     129   [ +  +  +  + ]:          6 :     return COMPARE(*(const uint8_t*)lhs_value, *(const uint8_t*)rhs_value);
     130                 :         56 :   case EXESS_DECIMAL:
     131                 :            :   case EXESS_INTEGER:
     132                 :            :   case EXESS_NON_POSITIVE_INTEGER:
     133                 :            :   case EXESS_NEGATIVE_INTEGER:
     134                 :            :   case EXESS_NON_NEGATIVE_INTEGER:
     135                 :            :   case EXESS_POSITIVE_INTEGER:
     136                 :         56 :     return compare_decimal(lhs_value, rhs_value);
     137                 :        104 :   case EXESS_DURATION:
     138                 :            :   case EXESS_YEAR_MONTH_DURATION:
     139                 :            :   case EXESS_DAY_TIME_DURATION:
     140                 :        104 :     return exess_compare_duration(*(const ExessDuration*)lhs_value,
     141                 :            :                                   *(const ExessDuration*)rhs_value);
     142                 :            : 
     143                 :        122 :   case EXESS_DATE_TIME:
     144                 :            :   case EXESS_DATE_TIME_STAMP:
     145                 :        122 :     return exess_compare_date_time(*(const ExessDateTime*)lhs_value,
     146                 :            :                                    *(const ExessDateTime*)rhs_value);
     147                 :            : 
     148                 :         96 :   case EXESS_TIME:
     149                 :         96 :     return exess_compare_time(*(const ExessTime*)lhs_value,
     150                 :            :                               *(const ExessTime*)rhs_value);
     151                 :            : 
     152                 :         68 :   case EXESS_DATE:
     153                 :         68 :     return exess_compare_date(*(const ExessDate*)lhs_value,
     154                 :            :                               *(const ExessDate*)rhs_value);
     155                 :            : 
     156                 :         18 :   case EXESS_YEAR_MONTH:
     157                 :         18 :     return exess_compare_date(DATE(((const ExessYearMonth*)lhs_value)->year,
     158                 :            :                                    ((const ExessYearMonth*)lhs_value)->month,
     159                 :            :                                    1U,
     160                 :            :                                    ((const ExessYearMonth*)lhs_value)->zone),
     161                 :         18 :                               DATE(((const ExessYearMonth*)rhs_value)->year,
     162                 :            :                                    ((const ExessYearMonth*)rhs_value)->month,
     163                 :            :                                    1U,
     164                 :            :                                    ((const ExessYearMonth*)rhs_value)->zone));
     165                 :            : 
     166                 :         18 :   case EXESS_YEAR:
     167                 :         18 :     return exess_compare_date(DATE(((const ExessYear*)lhs_value)->year,
     168                 :            :                                    1U,
     169                 :            :                                    1U,
     170                 :            :                                    ((const ExessYear*)lhs_value)->zone),
     171                 :         18 :                               DATE(((const ExessYear*)rhs_value)->year,
     172                 :            :                                    1U,
     173                 :            :                                    1U,
     174                 :            :                                    ((const ExessYear*)rhs_value)->zone));
     175                 :            : 
     176                 :         18 :   case EXESS_MONTH_DAY:
     177                 :         18 :     return exess_compare_date(DATE(0U,
     178                 :            :                                    ((const ExessMonthDay*)lhs_value)->month,
     179                 :            :                                    ((const ExessMonthDay*)lhs_value)->day,
     180                 :            :                                    ((const ExessMonthDay*)lhs_value)->zone),
     181                 :         18 :                               DATE(0U,
     182                 :            :                                    ((const ExessMonthDay*)rhs_value)->month,
     183                 :            :                                    ((const ExessMonthDay*)rhs_value)->day,
     184                 :            :                                    ((const ExessMonthDay*)rhs_value)->zone));
     185                 :            : 
     186                 :         18 :   case EXESS_DAY:
     187                 :         18 :     return exess_compare_date(DATE(0U,
     188                 :            :                                    1U,
     189                 :            :                                    ((const ExessDay*)lhs_value)->day,
     190                 :            :                                    ((const ExessDay*)lhs_value)->zone),
     191                 :         18 :                               DATE(0U,
     192                 :            :                                    1U,
     193                 :            :                                    ((const ExessDay*)rhs_value)->day,
     194                 :            :                                    ((const ExessDay*)rhs_value)->zone));
     195                 :            : 
     196                 :         18 :   case EXESS_MONTH:
     197                 :         18 :     return exess_compare_date(DATE(0U,
     198                 :            :                                    ((const ExessMonth*)lhs_value)->month,
     199                 :            :                                    1U,
     200                 :            :                                    ((const ExessMonth*)lhs_value)->zone),
     201                 :         18 :                               DATE(0U,
     202                 :            :                                    ((const ExessMonth*)rhs_value)->month,
     203                 :            :                                    1U,
     204                 :            :                                    ((const ExessMonth*)rhs_value)->zone));
     205                 :            : 
     206                 :         44 :   case EXESS_HEX:
     207                 :            :   case EXESS_BASE64:
     208                 :         44 :     return compare_blob(lhs_size, lhs_value, rhs_size, rhs_value);
     209                 :            :   }
     210                 :            : 
     211                 :            : #undef COMPARE
     212                 :            : #undef DATE
     213                 :            : 
     214                 :          2 :   return EXESS_ORDER_EQUAL;
     215                 :            : }

Generated by: LCOV version 1.16