From 8c7930feaed06439b97fbd02ba4ca70415652995 Mon Sep 17 00:00:00 2001 From: Andrew Sasmito Date: Tue, 28 Jul 2026 21:58:24 -0400 Subject: [PATCH 1/5] Make bit operations constexpr Signed-off-by: Andrew Sasmito --- cpp/csp/core/DynamicBitSet.h | 12 ++------ cpp/csp/core/Platform.h | 57 +++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/cpp/csp/core/DynamicBitSet.h b/cpp/csp/core/DynamicBitSet.h index 9ab7c62ed..bc5bf12ba 100644 --- a/cpp/csp/core/DynamicBitSet.h +++ b/cpp/csp/core/DynamicBitSet.h @@ -155,19 +155,13 @@ class DynamicBitSet private: using nbit_type = uint8_t; -#ifndef WIN32 -#define CLZ_CONSTEXPR constexpr -#else -#define CLZ_CONSTEXPR -#endif - template::value, bool> = true> static constexpr nbit_type nbits() { return sizeof( value_type ) * 8; } template::value, bool> = true> - static CLZ_CONSTEXPR nbit_type log2( U n ) { return nbits() - clz(static_cast( n )) - 1; } //upcast to 32 bit to avoid truncation for log2 - static CLZ_CONSTEXPR nbit_type log2(uint64_t n) { return nbits() - clz(n) - 1; } + static constexpr nbit_type log2( U n ) { return nbits() - clz(static_cast( n )) - 1; } //upcast to 32 bit to avoid truncation for log2 + static constexpr nbit_type log2(uint64_t n) { return nbits() - clz(n) - 1; } static constexpr node_type mask( nbit_type bitIndex ) { return ( node_type )1 << bitIndex; } @@ -182,7 +176,7 @@ class DynamicBitSet } static constexpr nbit_type _bits = nbits(); - static inline CLZ_CONSTEXPR nbit_type _logBits = log2( _bits ); + static inline constexpr nbit_type _logBits = log2( _bits ); node_type * m_nodes; index_type m_size; diff --git a/cpp/csp/core/Platform.h b/cpp/csp/core/Platform.h index 37474faf6..f1ef59228 100644 --- a/cpp/csp/core/Platform.h +++ b/cpp/csp/core/Platform.h @@ -10,6 +10,7 @@ #include #include #include +#include #undef ERROR #undef GetMessage @@ -52,40 +53,56 @@ inline int nanosleep(const timespec* req, timespec* rem) return 0; } -inline uint8_t clz(uint64_t n) +inline constexpr uint8_t clz(uint64_t n) { - unsigned long index = 0; - if (_BitScanReverse64(&index, n)) - return 64 - index - 1; - return 0; + if (std::is_constant_evaluated()) { + return std::countl_zero(n); + } else { + unsigned long index = 0; + if (_BitScanReverse(&index, n)) + return 64 - index - 1; + return 0; + } } -inline uint8_t clz(uint32_t n) +inline constexpr uint8_t clz(uint32_t n) { - unsigned long index = 0; - if (_BitScanReverse(&index, n)) - return 32 - index - 1; - return 0; + if (std::is_constant_evaluated()) { + return std::countl_zero(n); + } else { + unsigned long index = 0; + if (_BitScanReverse(&index, n)) + return 32 - index - 1; + return 0; + } } -inline uint8_t clz(uint16_t n) { return clz(static_cast(n)) - 16; } -inline uint8_t clz(uint8_t n) { return clz(static_cast(n)) - 24; } +inline constexpr uint8_t clz(uint16_t n) { return clz(static_cast(n)) - 16; } +inline constexpr uint8_t clz(uint8_t n) { return clz(static_cast(n)) - 24; } template::value, bool> = true> inline uint8_t ffs(U n) { - unsigned long index = 0; - if (_BitScanForward(&index, n)) - return index + 1; - return 0; + if (std::is_constant_evaluated()) { + return std::countr_zero(n); + } else { + unsigned long index = 0; + if (_BitScanForward(&index, n)) + return index + 1; + return 0; + } } inline uint8_t ffs(uint64_t n) { - unsigned long index = 0; - if (_BitScanForward64(&index, n)) - return index + 1; - return 0; + if (std::is_constant_evaluated()) { + return std::countr_zero(n); + } else { + unsigned long index = 0; + if (_BitScanForward(&index, n)) + return index + 1; + return 0; + } } #else From 68545cab8fd28e9ffebd5910327938fda71d991d Mon Sep 17 00:00:00 2001 From: Andrew Sasmito Date: Thu, 13 Aug 2026 10:22:16 -0400 Subject: [PATCH 2/5] Fix bug Signed-off-by: Andrew Sasmito --- cpp/csp/core/Platform.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/csp/core/Platform.h b/cpp/csp/core/Platform.h index f1ef59228..541fdd815 100644 --- a/cpp/csp/core/Platform.h +++ b/cpp/csp/core/Platform.h @@ -59,7 +59,7 @@ inline constexpr uint8_t clz(uint64_t n) return std::countl_zero(n); } else { unsigned long index = 0; - if (_BitScanReverse(&index, n)) + if (_BitScanReverse64(&index, n)) return 64 - index - 1; return 0; } @@ -81,7 +81,7 @@ inline constexpr uint8_t clz(uint16_t n) { return clz(static_cast(n)) inline constexpr uint8_t clz(uint8_t n) { return clz(static_cast(n)) - 24; } template::value, bool> = true> -inline uint8_t ffs(U n) +inline constexpr uint8_t ffs(U n) { if (std::is_constant_evaluated()) { return std::countr_zero(n); @@ -93,13 +93,13 @@ inline uint8_t ffs(U n) } } -inline uint8_t ffs(uint64_t n) +inline constexpr uint8_t ffs(uint64_t n) { if (std::is_constant_evaluated()) { return std::countr_zero(n); } else { unsigned long index = 0; - if (_BitScanForward(&index, n)) + if (_BitScanForward64(&index, n)) return index + 1; return 0; } From 6c04e0e0c68705431582ff266ca4e83a3fd5f250 Mon Sep 17 00:00:00 2001 From: Andrew Sasmito Date: Thu, 13 Aug 2026 19:20:33 -0400 Subject: [PATCH 3/5] Update nanosecond bug + Switch to one branch for bit operations Signed-off-by: Andrew Sasmito --- cpp/csp/core/Platform.h | 67 +++--------------------------------- cpp/tests/core/test_time.cpp | 12 +++++++ 2 files changed, 17 insertions(+), 62 deletions(-) diff --git a/cpp/csp/core/Platform.h b/cpp/csp/core/Platform.h index 541fdd815..7f31d7f93 100644 --- a/cpp/csp/core/Platform.h +++ b/cpp/csp/core/Platform.h @@ -1,5 +1,6 @@ #ifndef _IN_CSP_CORE_PLATFORM_H #define _IN_CSP_CORE_PLATFORM_H +#include #include #include #include @@ -10,7 +11,6 @@ #include #include #include -#include #undef ERROR #undef GetMessage @@ -48,63 +48,11 @@ inline tm * localtime_r( const time_t * timep, tm * result ) inline int nanosleep(const timespec* req, timespec* rem) { assert(rem == nullptr); - int64_t millis = req->tv_sec * 1000 + req->tv_nsec * 1000000; + int64_t millis = req->tv_sec * 1000 + req->tv_nsec / 1000000; Sleep(millis); return 0; } -inline constexpr uint8_t clz(uint64_t n) -{ - if (std::is_constant_evaluated()) { - return std::countl_zero(n); - } else { - unsigned long index = 0; - if (_BitScanReverse64(&index, n)) - return 64 - index - 1; - return 0; - } -} - -inline constexpr uint8_t clz(uint32_t n) -{ - if (std::is_constant_evaluated()) { - return std::countl_zero(n); - } else { - unsigned long index = 0; - if (_BitScanReverse(&index, n)) - return 32 - index - 1; - return 0; - } -} - -inline constexpr uint8_t clz(uint16_t n) { return clz(static_cast(n)) - 16; } -inline constexpr uint8_t clz(uint8_t n) { return clz(static_cast(n)) - 24; } - -template::value, bool> = true> -inline constexpr uint8_t ffs(U n) -{ - if (std::is_constant_evaluated()) { - return std::countr_zero(n); - } else { - unsigned long index = 0; - if (_BitScanForward(&index, n)) - return index + 1; - return 0; - } -} - -inline constexpr uint8_t ffs(uint64_t n) -{ - if (std::is_constant_evaluated()) { - return std::countr_zero(n); - } else { - unsigned long index = 0; - if (_BitScanForward64(&index, n)) - return index + 1; - return 0; - } -} - #else #define CSPIMPL_EXPORT @@ -117,18 +65,13 @@ inline constexpr uint8_t ffs(uint64_t n) #define NO_INLINE __attribute__ ((noinline)) -inline constexpr uint8_t clz(uint32_t n) { return __builtin_clz(n); } -inline constexpr uint8_t clz(uint64_t n) { return __builtin_clzl(n); } - // clz (count leading zeros) returns number of leading zeros before MSB (i.e. clz(00110..) = 2 ) -// __builtin_clz auto-promotes to 32-bits: need to subtract off extra leading zeros -inline constexpr uint8_t clz(uint16_t n) { return clz(static_cast(n)) - 16; } -inline constexpr uint8_t clz(uint8_t n) { return clz(static_cast(n)) - 24; } +template::value, bool> = true> +inline constexpr uint8_t clz( U n ) { return std::countl_zero(n); } // ffs (find first set) returns offset of first set bit (i.e. ffs(..0110) = 2 ), with ffs(0) = 0 template::value, bool> = true> -inline constexpr uint8_t ffs( U n ) { return __builtin_ffs(n); } -inline constexpr uint8_t ffs( uint64_t n ) { return __builtin_ffsl(n); } +inline constexpr uint8_t ffs( U n ) { return n ? std::countr_zero(n) + 1 : 0; } #endif diff --git a/cpp/tests/core/test_time.cpp b/cpp/tests/core/test_time.cpp index a50bf15d9..1772e1f93 100644 --- a/cpp/tests/core/test_time.cpp +++ b/cpp/tests/core/test_time.cpp @@ -296,6 +296,18 @@ TEST( DateTest, test_basic_functionality ) } } +TEST( sleep, nanoseconds ) +{ + TimeDelta waittime = TimeDelta::fromNanoseconds( 100'000'000 ); // 100 ms + DateTime t1 = DateTime::now(); + + csp::sleep( waittime ); + + DateTime t2 = DateTime::now(); + + ASSERT_GE( t2 - t1, waittime ); +} + TEST( sleep, basic_functionality ) { TimeDelta waittime = TimeDelta::fromSeconds( 1 ); From 06dc231f3c9fe83ac873e2c1c824372f5cd6929e Mon Sep 17 00:00:00 2001 From: Andrew Sasmito Date: Fri, 14 Aug 2026 12:46:47 -0400 Subject: [PATCH 4/5] Remove nanosecond change + Fix bug Signed-off-by: Andrew Sasmito --- cpp/csp/core/DynamicBitSet.h | 3 +-- cpp/csp/core/Platform.h | 6 +++--- cpp/tests/core/test_time.cpp | 12 ------------ 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/cpp/csp/core/DynamicBitSet.h b/cpp/csp/core/DynamicBitSet.h index bc5bf12ba..de82000ba 100644 --- a/cpp/csp/core/DynamicBitSet.h +++ b/cpp/csp/core/DynamicBitSet.h @@ -160,8 +160,7 @@ class DynamicBitSet static constexpr nbit_type nbits() { return sizeof( value_type ) * 8; } template::value, bool> = true> - static constexpr nbit_type log2( U n ) { return nbits() - clz(static_cast( n )) - 1; } //upcast to 32 bit to avoid truncation for log2 - static constexpr nbit_type log2(uint64_t n) { return nbits() - clz(n) - 1; } + static constexpr nbit_type log2( U n ) { return nbits() - clz( n ) - 1; } //upcast to 32 bit to avoid truncation for log2 static constexpr node_type mask( nbit_type bitIndex ) { return ( node_type )1 << bitIndex; } diff --git a/cpp/csp/core/Platform.h b/cpp/csp/core/Platform.h index 7f31d7f93..3f3cdd0db 100644 --- a/cpp/csp/core/Platform.h +++ b/cpp/csp/core/Platform.h @@ -48,7 +48,7 @@ inline tm * localtime_r( const time_t * timep, tm * result ) inline int nanosleep(const timespec* req, timespec* rem) { assert(rem == nullptr); - int64_t millis = req->tv_sec * 1000 + req->tv_nsec / 1000000; + int64_t millis = req->tv_sec * 1000 + req->tv_nsec * 1000000; Sleep(millis); return 0; } @@ -65,6 +65,8 @@ inline int nanosleep(const timespec* req, timespec* rem) #define NO_INLINE __attribute__ ((noinline)) +#endif + // clz (count leading zeros) returns number of leading zeros before MSB (i.e. clz(00110..) = 2 ) template::value, bool> = true> inline constexpr uint8_t clz( U n ) { return std::countl_zero(n); } @@ -74,5 +76,3 @@ template::value, bool> = true> inline constexpr uint8_t ffs( U n ) { return n ? std::countr_zero(n) + 1 : 0; } #endif - -#endif diff --git a/cpp/tests/core/test_time.cpp b/cpp/tests/core/test_time.cpp index 1772e1f93..a50bf15d9 100644 --- a/cpp/tests/core/test_time.cpp +++ b/cpp/tests/core/test_time.cpp @@ -296,18 +296,6 @@ TEST( DateTest, test_basic_functionality ) } } -TEST( sleep, nanoseconds ) -{ - TimeDelta waittime = TimeDelta::fromNanoseconds( 100'000'000 ); // 100 ms - DateTime t1 = DateTime::now(); - - csp::sleep( waittime ); - - DateTime t2 = DateTime::now(); - - ASSERT_GE( t2 - t1, waittime ); -} - TEST( sleep, basic_functionality ) { TimeDelta waittime = TimeDelta::fromSeconds( 1 ); From 8d971ad96ccce0264744630dfe8b4660c2bda0a5 Mon Sep 17 00:00:00 2001 From: Andrew Sasmito Date: Sun, 16 Aug 2026 17:38:52 -0400 Subject: [PATCH 5/5] Remove unnecessary comment Signed-off-by: Andrew Sasmito --- cpp/csp/core/DynamicBitSet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/csp/core/DynamicBitSet.h b/cpp/csp/core/DynamicBitSet.h index de82000ba..3d55679ba 100644 --- a/cpp/csp/core/DynamicBitSet.h +++ b/cpp/csp/core/DynamicBitSet.h @@ -160,7 +160,7 @@ class DynamicBitSet static constexpr nbit_type nbits() { return sizeof( value_type ) * 8; } template::value, bool> = true> - static constexpr nbit_type log2( U n ) { return nbits() - clz( n ) - 1; } //upcast to 32 bit to avoid truncation for log2 + static constexpr nbit_type log2( U n ) { return nbits() - clz( n ) - 1; } static constexpr node_type mask( nbit_type bitIndex ) { return ( node_type )1 << bitIndex; }