[ Update 2021-03-18 ]
There was “a bug the size of the house” in there. strlen
and strnlen
do not count the end of string char. Of course. Godbolt code is here.Copy away.
[ 2017-10-19 ]
It is not me who first thought of this, but just today, I figured writing a “compile-time” aka “zero time” strlen()
and strnlen()
in modern C++ is actually possible and obvious. Not for pointers though. For arrays and for arrays of characters that is. If you haven’t from somewhere else copy-paste from here, at your pleasure. Perhaps you will find it a “proper” and tested modern C++ code.
Yes there are also dbj::strlen()
and dbj::strnlen()
to take proper care of char, wchar_t, char16_t
and char32_t
. Hint: char8_t
avoid if you can.
Usage? If you need strlen()
or strnlen()
just use dbj::strlen()
or dbj::strnlen()
. In case you are passing arrays of characters the execution time is “zero”. Both are based on dbj::arrlen
. Array length (aka count) includes '\0'
char, where str(n)len
does not.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// array count includes EOS static_assert( dbj::arrlen( "0123456789" ) == 11 ); static_assert( dbj::arrlen( L"0123456789" ) == 11 ); static_assert( dbj::arrlen( u8"0123456789" ) == 11 ); static_assert( dbj::arrlen( u"0123456789" ) == 11 ); static_assert( dbj::arrlen( U"0123456789" ) == 11 ); static_assert( dbj::arrlen( UR"#(0123456789)#" ) == 11 ); // str(n)len count excludes EOS static_assert( dbj::strlen( "0123456789" ) == 10 ); static_assert( dbj::strlen( L"0123456789" ) == 10 ); static_assert( dbj::strlen( u8"0123456789" ) == 10 ); static_assert( dbj::strlen( u"0123456789" ) == 10 ); static_assert( dbj::strlen( U"0123456789" ) == 10 ); static_assert( dbj::strlen( UR"#(0123456789)#" ) == 10 ); static_assert( dbj::arrlen( (int []){0,1,2,3}) == 4 ) ; static_assert( dbj::arrlen( (bool []){true,true,true,true}) == 4 ) ; // and so on ad infinitum |
All of the dbj::
calls above will take “zero” time to execute. That is: they are all compile-time. And whatever is the (legal) size of the arrays used, the execution time will be still “zero”.
Conclusions
What are then the real-time savings of using this? Yes, it is quite hard to compute., them real-time savings, if your app uses the code below.
It may be hard to measure but it is obvious there must be a time-saving. It depends on the compiler on the OS and on the number of static (char) arrays your application might contain.
This little “nugget” shows, perhaps dramatically, the advantages of using modern C++ compilers.
For more modern C++ speculations and more copy-paste opportunities, please click HERE .
Obviously, the whole idea is based on the count of a generic array of T. Above you have already spotted dbj::arrlen
and dbj::arrnlen
. Obviously fully compile-time enabled.
There are various COUNT_OF macros as you might know about. But none of them is trivial and still, that is just C pre-proc mumbo jumbo. Here is an infinitely more clear solution.
The full source
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
//#include <cstdlib> #include <type_traits> namespace dbj { using std::size_t ; template<class T> constexpr inline const T& min(const T& a, const T& b) noexcept { return (b < a) ? b : a; } // arrnlen and arrlen are "counting" all the elements of the arrays // that is not what strlen and strnlen do template<typename T, size_t N> inline constexpr size_t arrnlen(const T(&)[N], const size_t & maxlen) noexcept { return dbj::min(N, maxlen) ; } template<typename T, size_t N> inline constexpr size_t arrlen(const T(&)[N]) noexcept { return N ; } // type trait // usage: constexpr bool is_it = is_char< char >{}() ; template< typename C > struct is_char : std::integral_constant<bool, std::is_same<C, char>::value || std::is_same<C, char8_t>::value || std::is_same<C, char16_t>::value || std::is_same<C, char32_t>::value || std::is_same<C, wchar_t>::value> {}; // usage: constexpr bool isit = is_char_v<char> ; template<typename C> constexpr inline bool is_char_v = is_char< C >{}() ; // strnlen and strlne do not count the end of string char template<typename T, size_t N> inline constexpr size_t strnlen(const T(& str)[N], const size_t & maxlen) noexcept { static_assert( dbj::is_char<T>{}() ) ; return dbj::arrnlen(str, maxlen) - 1 ; } template<typename T, size_t N> inline constexpr size_t strlen(const T(& str)[N]) noexcept { static_assert( dbj::is_char<T>{}() ) ; return dbj::arrlen(str) - 1 ; } } // dbj // for array count includes EOS static_assert( dbj::arrlen( "0123456789" ) == 11 ); static_assert( dbj::arrlen( L"0123456789" ) == 11 ); static_assert( dbj::arrlen( u8"0123456789" ) == 11 ); static_assert( dbj::arrlen( u"0123456789" ) == 11 ); static_assert( dbj::arrlen( U"0123456789" ) == 11 ); static_assert( dbj::arrlen( UR"#(0123456789)#" ) == 11 ); // for str(n)len count excludes EOS static_assert( dbj::strlen( "0123456789" ) == 10 ); static_assert( dbj::strlen( L"0123456789" ) == 10 ); static_assert( dbj::strlen( u8"0123456789" ) == 10 ); static_assert( dbj::strlen( u"0123456789" ) == 10 ); static_assert( dbj::strlen( U"0123456789" ) == 10 ); static_assert( dbj::strlen( UR"#(0123456789)#" ) == 10 ); static_assert( dbj::arrlen( (int []){0,1,2,3}) == 4 ) ; static_assert( dbj::arrlen( (bool []){true,true,true,true}) == 4 ) ; // and so on ad infinitum int main( void ) { return 42; } |