From 519a73e4e72348fe0adc2e5b7180ec0e0b3297e3 Mon Sep 17 00:00:00 2001 From: Justin King Date: Mon, 22 Jun 2026 06:15:16 -0700 Subject: [PATCH] Remove packing from `cel_Duration` and `cel_Timestamp` PiperOrigin-RevId: 936018807 --- cel-c/config.h | 25 ++++++++++ cel-c/duration.cc | 24 ++++----- cel-c/duration.h | 88 ++++++++++++++++++++------------- cel-c/internal/config.h | 17 ------- cel-c/internal/timestampconv.cc | 11 ++--- cel-c/timestamp.cc | 36 +++++++------- cel-c/timestamp.h | 88 ++++++++++++++++++++------------- 7 files changed, 168 insertions(+), 121 deletions(-) diff --git a/cel-c/config.h b/cel-c/config.h index 84f5a7f..4c90eb3 100644 --- a/cel-c/config.h +++ b/cel-c/config.h @@ -40,6 +40,31 @@ #include // IWYU pragma: keep #endif +#ifdef _CEL_IS_BIG_ENDIAN +#error _CEL_IS_BIG_ENDIAN cannot be directly set +#endif + +#ifdef _CEL_IS_LITTLE_ENDIAN +#error _CEL_IS_LITTLE_ENDIAN cannot be directly set +#endif + +#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || defined(_MIPSEB) || defined(__MIPSEB) || \ + defined(__MIPSEB__) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define _CEL_IS_BIG_ENDIAN 1 +#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ + defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ + defined(__MIPSEL) || defined(__MIPSEL__) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ + defined(_WIN32) +#define _CEL_IS_LITTLE_ENDIAN 1 +#else +#error Endian detection needs to be set up for your environment. +#endif + #ifdef CEL_STATIC_ASSERT #error CEL_STATIC_ASSERT cannot be directly set #endif diff --git a/cel-c/duration.cc b/cel-c/duration.cc index e2e257f..63b01c1 100644 --- a/cel-c/duration.cc +++ b/cel-c/duration.cc @@ -53,15 +53,15 @@ extern "C" bool cel_Duration_Normalize(int64_t* cel_nonnull sec, extern "C" bool cel_Duration_Add(cel_Duration* cel_nonnull out, cel_Duration lhs, cel_Duration rhs) { CEL_ASSERT_NOT_NULL(out); - CEL_ASSERT(cel_Duration_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - int64_t lhs_sec = lhs.sec; - int64_t rhs_sec = rhs.sec; + int64_t lhs_sec; + int64_t rhs_sec; int64_t sec; int32_t nsec; - int32_t lhs_nsec = lhs.nsec; - int32_t rhs_nsec = rhs.nsec; + int32_t lhs_nsec; + int32_t rhs_nsec; + cel_Duration_ToUnix(lhs, &lhs_sec, &lhs_nsec); + cel_Duration_ToUnix(rhs, &rhs_sec, &rhs_nsec); if (CEL_UNLIKELY(_cel_ckd_add(&sec, lhs_sec, rhs_sec))) { return false; @@ -82,15 +82,15 @@ extern "C" bool cel_Duration_Add(cel_Duration* cel_nonnull out, extern "C" bool cel_Duration_Sub(cel_Duration* cel_nonnull out, cel_Duration lhs, cel_Duration rhs) { CEL_ASSERT_NOT_NULL(out); - CEL_ASSERT(cel_Duration_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - int64_t lhs_sec = lhs.sec; - int64_t rhs_sec = rhs.sec; + int64_t lhs_sec; + int64_t rhs_sec; int64_t sec; int32_t nsec; - int32_t lhs_nsec = lhs.nsec; - int32_t rhs_nsec = rhs.nsec; + int32_t lhs_nsec; + int32_t rhs_nsec; + cel_Duration_ToUnix(lhs, &lhs_sec, &lhs_nsec); + cel_Duration_ToUnix(rhs, &rhs_sec, &rhs_nsec); if (CEL_UNLIKELY(_cel_ckd_sub(&sec, lhs_sec, rhs_sec))) { return false; diff --git a/cel-c/duration.h b/cel-c/duration.h index ac07980..4b91a31 100644 --- a/cel-c/duration.h +++ b/cel-c/duration.h @@ -58,26 +58,50 @@ CEL_BEGIN_DECLS #define cel_Duration_kMinNanos INT32_C(-999999999) #define cel_Duration_kMaxNanos INT32_C(999999999) -#define cel_Duration_kZero ((cel_Duration){INT64_C(0), INT32_C(0)}) -#define cel_Duration_kMin \ - ((cel_Duration){cel_Duration_kMinSeconds, cel_Duration_kMinNanos}) -#define cel_Duration_kMax \ - ((cel_Duration){cel_Duration_kMaxSeconds, cel_Duration_kMaxNanos}) - -#ifdef _MSC_VER -#pragma pack(push, 4) +#ifdef _CEL_IS_BIG_ENDIAN +#define cel_Duration_kZero \ + ((cel_Duration){{INT32_C(0), UINT32_C{0}}, INT32_C(0)}) +#define cel_Duration_kMin \ + ((cel_Duration){ \ + {(int32_t)(uint32_t)(((uint64_t)cel_Duration_kMinSeconds) >> 32), \ + ((uint32_t)(uint64_t)cel_Duration_kMinSeconds)}, \ + cel_Duration_kMinNanos}) +#define cel_Duration_kMax \ + ((cel_Duration){ \ + {(int32_t)(uint32_t)(((uint64_t)cel_Duration_kMaxSeconds) >> 32), \ + ((uint32_t)(uint64_t)cel_Duration_kMaxSeconds)}, \ + cel_Duration_kMaxNanos}) +#endif +#ifdef _CEL_IS_LITTLE_ENDIAN +#define cel_Duration_kZero \ + ((cel_Duration){{UINT32_C(0), INT32_C(0)}, INT32_C(0)}) +#define cel_Duration_kMin \ + ((cel_Duration){ \ + {((uint32_t)(uint64_t)cel_Duration_kMinSeconds), \ + (int32_t)(uint32_t)(((uint64_t)cel_Duration_kMinSeconds) >> 32)}, \ + cel_Duration_kMinNanos}) +#define cel_Duration_kMax \ + ((cel_Duration){ \ + {((uint32_t)(uint64_t)cel_Duration_kMaxSeconds), \ + (int32_t)(uint32_t)(((uint64_t)cel_Duration_kMaxSeconds) >> 32)}, \ + cel_Duration_kMaxNanos}) #endif -typedef struct CEL_ATTRIBUTE_PACKED(4) { - // As this structure is packed, do not access these members directly. - int64_t sec; +typedef struct { + // Alter layout based on endianness for consistency. + struct { +#ifdef _CEL_IS_BIG_ENDIAN + int32_t hi; + uint32_t lo; +#endif +#ifdef _CEL_IS_LITTLE_ENDIAN + uint32_t lo; + int32_t hi; +#endif + } sec; int32_t nsec; } cel_Duration; -#ifdef _MSC_VER -#pragma pack(pop) -#endif - CEL_STATIC_ASSERT(sizeof(cel_Duration) == 12); CEL_STATIC_ASSERT(alignof(cel_Duration) == 4); @@ -101,7 +125,8 @@ static CEL_INLINE cel_Duration cel_Duration_FromUnix(int64_t sec, CEL_ASSERT(cel_Duration_Valid(sec, nsec)); cel_Duration d; - d.sec = sec; + d.sec.hi = (int32_t)(uint32_t)(((uint64_t)sec) >> 32); + d.sec.lo = (uint32_t)(uint64_t)sec; d.nsec = nsec; return d; } @@ -112,13 +137,10 @@ static CEL_INLINE cel_Duration cel_Duration_FromUnix(int64_t sec, // in `sec` and `nsec` respectively. static CEL_INLINE void cel_Duration_ToUnix(cel_Duration d, int64_t* cel_nonnull sec, - int32_t* cel_nullable nsec) { - CEL_ASSERT(cel_Duration_Valid(d.sec, d.nsec)); - - *sec = d.sec; - if (nsec != cel_nullptr) { - *nsec = d.nsec; - } + int32_t* cel_nonnull nsec) { + *sec = (int64_t)((((uint64_t)(uint32_t)d.sec.hi) << 32) | d.sec.lo); + *nsec = d.nsec; + CEL_ASSERT(cel_Duration_Valid(*sec, *nsec)); } // cel_Duration_ToUnixSeconds @@ -126,8 +148,9 @@ static CEL_INLINE void cel_Duration_ToUnix(cel_Duration d, // Returns the seconds part of the cel_Duration. CEL_ATTRIBUTE_NODISCARD static CEL_INLINE int64_t cel_Duration_ToUnixSeconds(cel_Duration d) { - CEL_ASSERT(cel_Duration_Valid(d.sec, d.nsec)); - return d.sec; + int64_t sec = (int64_t)((((uint64_t)(uint32_t)d.sec.hi) << 32) | d.sec.lo); + CEL_ASSERT(cel_Duration_Valid(sec, d.nsec)); + return sec; } // cel_Duration_Equals @@ -135,10 +158,8 @@ static CEL_INLINE int64_t cel_Duration_ToUnixSeconds(cel_Duration d) { // Tests the two durations for equality. CEL_ATTRIBUTE_NODISCARD static CEL_INLINE bool cel_Duration_Equals(cel_Duration lhs, cel_Duration rhs) { - CEL_ASSERT(cel_Duration_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - - return lhs.sec == rhs.sec && lhs.nsec == rhs.nsec; + return lhs.sec.hi == rhs.sec.hi && lhs.sec.lo == rhs.sec.lo && + lhs.nsec == rhs.nsec; } // cel_Duration_Compare @@ -146,13 +167,12 @@ static CEL_INLINE bool cel_Duration_Equals(cel_Duration lhs, cel_Duration rhs) { // Compares the two durations. CEL_ATTRIBUTE_NODISCARD static CEL_INLINE int cel_Duration_Compare(cel_Duration lhs, cel_Duration rhs) { - CEL_ASSERT(cel_Duration_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - - if (lhs.sec < rhs.sec) { + int64_t lhs_sec = cel_Duration_ToUnixSeconds(lhs); + int64_t rhs_sec = cel_Duration_ToUnixSeconds(rhs); + if (lhs_sec < rhs_sec) { return -1; } - if (lhs.sec > rhs.sec) { + if (lhs_sec > rhs_sec) { return 1; } if (lhs.nsec < rhs.nsec) { diff --git a/cel-c/internal/config.h b/cel-c/internal/config.h index 02edebd..417d0b5 100644 --- a/cel-c/internal/config.h +++ b/cel-c/internal/config.h @@ -23,23 +23,6 @@ #include "cel-c/config.h" // IWYU pragma: export -#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || \ - defined(__AARCH64EB__) || defined(_MIPSEB) || defined(__MIPSEB) || \ - defined(__MIPSEB__) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define _CEL_IS_BIG_ENDIAN 1 -#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ - defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ - defined(__MIPSEL) || defined(__MIPSEL__) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(_WIN32) -#define _CEL_IS_LITTLE_ENDIAN 1 -#else -#error Endian detection needs to be set up for your environment. -#endif - #if (defined(__clang__) && !defined(_WIN32)) || \ (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) || \ diff --git a/cel-c/internal/timestampconv.cc b/cel-c/internal/timestampconv.cc index 9dba091..531ccd2 100644 --- a/cel-c/internal/timestampconv.cc +++ b/cel-c/internal/timestampconv.cc @@ -20,7 +20,6 @@ #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "cel-c/arena.h" -#include "cel-c/assert.h" #include "cel-c/internal/config.h" #include "cel-c/string_view.h" #include "cel-c/string_view_absl.h" @@ -32,8 +31,10 @@ CEL_ATTRIBUTE_NODISCARD CEL_ATTRIBUTE_NOTHROW bool _cel_Timestamp_ToRFC3339(cel_Timestamp ts, cel_StringView* cel_nonnull out, CEL_NONNULL(cel_Arena*) arena) { - CEL_ASSERT(cel_Timestamp_Valid(ts.sec, ts.nsec)); - absl::Time time = absl::FromUnixSeconds(ts.sec) + absl::Nanoseconds(ts.nsec); + int64_t sec; + int32_t nsec; + cel_Timestamp_ToUnix(ts, &sec, &nsec); + absl::Time time = absl::FromUnixSeconds(sec) + absl::Nanoseconds(nsec); absl::TimeZone utc = absl::UTCTimeZone(); std::string rfc3339 = absl::FormatTime("%Y-%m-%d%ET%H:%M:%E*SZ", time, utc); @@ -64,9 +65,7 @@ bool _cel_Timestamp_FromRFC3339(cel_Timestamp* cel_nonnull out, if (!cel_Timestamp_Valid(seconds, nanos)) { return false; } - - out->sec = seconds; - out->nsec = nanos; + *out = cel_Timestamp_FromUnix(seconds, nanos); return true; } diff --git a/cel-c/timestamp.cc b/cel-c/timestamp.cc index 27c5c36..bd26412 100644 --- a/cel-c/timestamp.cc +++ b/cel-c/timestamp.cc @@ -49,15 +49,15 @@ extern "C" bool cel_Timestamp_Normalize(int64_t* cel_nonnull sec, extern "C" bool cel_Timestamp_Add(cel_Timestamp* cel_nonnull out, cel_Timestamp lhs, cel_Duration rhs) { CEL_ASSERT_NOT_NULL(out); - CEL_ASSERT(cel_Timestamp_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - int64_t lhs_sec = lhs.sec; - int64_t rhs_sec = rhs.sec; + int64_t lhs_sec; + int64_t rhs_sec; int64_t sec; int32_t nsec; - int32_t lhs_nsec = lhs.nsec; - int32_t rhs_nsec = rhs.nsec; + int32_t lhs_nsec; + int32_t rhs_nsec; + cel_Timestamp_ToUnix(lhs, &lhs_sec, &lhs_nsec); + cel_Duration_ToUnix(rhs, &rhs_sec, &rhs_nsec); if (CEL_UNLIKELY(_cel_ckd_add(&sec, lhs_sec, rhs_sec))) { return false; @@ -78,15 +78,15 @@ extern "C" bool cel_Timestamp_Add(cel_Timestamp* cel_nonnull out, extern "C" bool cel_Timestamp_Sub(cel_Timestamp* cel_nonnull out, cel_Timestamp lhs, cel_Duration rhs) { CEL_ASSERT_NOT_NULL(out); - CEL_ASSERT(cel_Timestamp_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Duration_Valid(rhs.sec, rhs.nsec)); - int64_t lhs_sec = lhs.sec; - int64_t rhs_sec = rhs.sec; + int64_t lhs_sec; + int64_t rhs_sec; int64_t sec; int32_t nsec; - int32_t lhs_nsec = lhs.nsec; - int32_t rhs_nsec = rhs.nsec; + int32_t lhs_nsec; + int32_t rhs_nsec; + cel_Timestamp_ToUnix(lhs, &lhs_sec, &lhs_nsec); + cel_Duration_ToUnix(rhs, &rhs_sec, &rhs_nsec); if (CEL_UNLIKELY(_cel_ckd_sub(&sec, lhs_sec, rhs_sec))) { return false; @@ -107,15 +107,15 @@ extern "C" bool cel_Timestamp_Sub(cel_Timestamp* cel_nonnull out, extern "C" bool cel_Timestamp_Diff(cel_Duration* cel_nonnull out, cel_Timestamp lhs, cel_Timestamp rhs) { CEL_ASSERT_NOT_NULL(out); - CEL_ASSERT(cel_Timestamp_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Timestamp_Valid(rhs.sec, rhs.nsec)); - int64_t lhs_sec = lhs.sec; - int64_t rhs_sec = rhs.sec; + int64_t lhs_sec; + int64_t rhs_sec; int64_t sec; int32_t nsec; - int32_t lhs_nsec = lhs.nsec; - int32_t rhs_nsec = rhs.nsec; + int32_t lhs_nsec; + int32_t rhs_nsec; + cel_Timestamp_ToUnix(lhs, &lhs_sec, &lhs_nsec); + cel_Timestamp_ToUnix(rhs, &rhs_sec, &rhs_nsec); if (CEL_UNLIKELY(_cel_ckd_sub(&sec, lhs_sec, rhs_sec))) { return false; diff --git a/cel-c/timestamp.h b/cel-c/timestamp.h index ed7fc96..5c8b120 100644 --- a/cel-c/timestamp.h +++ b/cel-c/timestamp.h @@ -59,26 +59,50 @@ CEL_BEGIN_DECLS #define cel_Timestamp_kMinNanos INT32_C(0) #define cel_Timestamp_kMaxNanos INT32_C(999999999) -#define cel_Timestamp_kUnixEpoch ((cel_Timestamp){INT64_C(0), INT32_C(0)}) -#define cel_Timestamp_kMin \ - ((cel_Timestamp){cel_Timestamp_kMinSeconds, cel_Timestamp_kMinNanos}) -#define cel_Timestamp_kMax \ - ((cel_Timestamp){cel_Timestamp_kMaxSeconds, cel_Timestamp_kMaxNanos}) - -#ifdef _MSC_VER -#pragma pack(push, 4) +#ifdef _CEL_IS_BIG_ENDIAN +#define cel_Timestamp_kUnixEpoch \ + ((cel_Timestamp){{INT32_C(0), UINT32_C{0}}, INT32_C(0)}) +#define cel_Timestamp_kMin \ + ((cel_Timestamp){ \ + {(int32_t)(uint32_t)(((uint64_t)cel_Timestamp_kMinSeconds) >> 32), \ + ((uint32_t)(uint64_t)cel_Timestamp_kMinSeconds)}, \ + cel_Timestamp_kMinNanos}) +#define cel_Timestamp_kMax \ + ((cel_Timestamp){ \ + {(int32_t)(uint32_t)(((uint64_t)cel_Timestamp_kMaxSeconds) >> 32), \ + ((uint32_t)(uint64_t)cel_Timestamp_kMaxSeconds)}, \ + cel_Timestamp_kMaxNanos}) +#endif +#ifdef _CEL_IS_LITTLE_ENDIAN +#define cel_Timestamp_kUnixEpoch \ + ((cel_Timestamp){{UINT32_C(0), INT32_C(0)}, INT32_C(0)}) +#define cel_Timestamp_kMin \ + ((cel_Timestamp){ \ + {((uint32_t)(uint64_t)cel_Timestamp_kMinSeconds), \ + (int32_t)(uint32_t)(((uint64_t)cel_Timestamp_kMinSeconds) >> 32)}, \ + cel_Timestamp_kMinNanos}) +#define cel_Timestamp_kMax \ + ((cel_Timestamp){ \ + {((uint32_t)(uint64_t)cel_Timestamp_kMaxSeconds), \ + (int32_t)(uint32_t)(((uint64_t)cel_Timestamp_kMaxSeconds) >> 32)}, \ + cel_Timestamp_kMaxNanos}) #endif -typedef struct CEL_ATTRIBUTE_PACKED(4) { - // As this structure is packed, do not access these members directly. - int64_t sec; +typedef struct { + // Alter layout based on endianness for consistency. + struct { +#ifdef _CEL_IS_BIG_ENDIAN + int32_t hi; + uint32_t lo; +#endif +#ifdef _CEL_IS_LITTLE_ENDIAN + uint32_t lo; + int32_t hi; +#endif + } sec; int32_t nsec; } cel_Timestamp; -#ifdef _MSC_VER -#pragma pack(pop) -#endif - CEL_STATIC_ASSERT(sizeof(cel_Timestamp) == 12); CEL_STATIC_ASSERT(alignof(cel_Timestamp) == 4); @@ -102,7 +126,8 @@ static CEL_INLINE cel_Timestamp cel_Timestamp_FromUnix(int64_t sec, CEL_ASSERT(cel_Timestamp_Valid(sec, nsec)); cel_Timestamp t; - t.sec = sec; + t.sec.hi = (int32_t)(uint32_t)(((uint64_t)sec) >> 32); + t.sec.lo = (uint32_t)(uint64_t)sec; t.nsec = nsec; return t; } @@ -113,13 +138,10 @@ static CEL_INLINE cel_Timestamp cel_Timestamp_FromUnix(int64_t sec, // in `sec` and `nsec` respectively. static CEL_INLINE void cel_Timestamp_ToUnix(cel_Timestamp t, int64_t* cel_nonnull sec, - int32_t* cel_nullable nsec) { - CEL_ASSERT(cel_Timestamp_Valid(t.sec, t.nsec)); - - *sec = t.sec; - if (nsec != cel_nullptr) { - *nsec = t.nsec; - } + int32_t* cel_nonnull nsec) { + *sec = (int64_t)((((uint64_t)(uint32_t)t.sec.hi) << 32) | t.sec.lo); + *nsec = t.nsec; + CEL_ASSERT(cel_Timestamp_Valid(*sec, *nsec)); } // cel_Timestamp_ToUnixSeconds @@ -127,8 +149,9 @@ static CEL_INLINE void cel_Timestamp_ToUnix(cel_Timestamp t, // Returns the seconds part of the cel_Timestamp. CEL_ATTRIBUTE_NODISCARD static CEL_INLINE int64_t cel_Timestamp_ToUnixSeconds(cel_Timestamp t) { - CEL_ASSERT(cel_Timestamp_Valid(t.sec, t.nsec)); - return t.sec; + int64_t sec = (int64_t)((((uint64_t)(uint32_t)t.sec.hi) << 32) | t.sec.lo); + CEL_ASSERT(cel_Timestamp_Valid(sec, t.nsec)); + return sec; } // cel_Timestamp_Equals @@ -137,10 +160,8 @@ static CEL_INLINE int64_t cel_Timestamp_ToUnixSeconds(cel_Timestamp t) { CEL_ATTRIBUTE_NODISCARD static CEL_INLINE bool cel_Timestamp_Equals(cel_Timestamp lhs, cel_Timestamp rhs) { - CEL_ASSERT(cel_Timestamp_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Timestamp_Valid(rhs.sec, rhs.nsec)); - - return lhs.sec == rhs.sec && lhs.nsec == rhs.nsec; + return lhs.sec.hi == rhs.sec.hi && lhs.sec.lo == rhs.sec.lo && + lhs.nsec == rhs.nsec; } // cel_Timestamp_Compare @@ -149,13 +170,12 @@ static CEL_INLINE bool cel_Timestamp_Equals(cel_Timestamp lhs, CEL_ATTRIBUTE_NODISCARD static CEL_INLINE int cel_Timestamp_Compare(cel_Timestamp lhs, cel_Timestamp rhs) { - CEL_ASSERT(cel_Timestamp_Valid(lhs.sec, lhs.nsec)); - CEL_ASSERT(cel_Timestamp_Valid(rhs.sec, rhs.nsec)); - - if (lhs.sec < rhs.sec) { + int64_t lhs_sec = cel_Timestamp_ToUnixSeconds(lhs); + int64_t rhs_sec = cel_Timestamp_ToUnixSeconds(rhs); + if (lhs_sec < rhs_sec) { return -1; } - if (lhs.sec > rhs.sec) { + if (lhs_sec > rhs_sec) { return 1; } if (lhs.nsec < rhs.nsec) {