C++11 const string length, gcc 4.7+ and clang 3.5+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://godbolt.org/z/uu4TMP | |
// API: constexpr size_t const_strlen( "foo" ); | |
// Much more readable version here: https://gist.github.com/kaidokert/dfc08be8e75a3fc650d3daf8e89c3fe9 | |
// but that doesn't work with GCC before version 7 | |
#include <utility> //std::forward | |
#include <cstddef> //std::size_t | |
namespace detail { | |
template<size_t COUNTER, typename T> | |
struct recursive_array {}; | |
template<size_t COUNTER, size_t N> // General case, Counter=0...N-1 | |
struct recursive_array<COUNTER, const char (&)[N]> { | |
constexpr static size_t check(const char(&x)[N]) { | |
return x[COUNTER] == '\0' ? COUNTER : | |
recursive_array<COUNTER + 1, const char(&)[N]>::check(x); | |
} | |
}; | |
template<size_t N> // Termination case, COUNTER = N | |
struct recursive_array<N, const char (&)[N]> { | |
constexpr static size_t check(const char(&)[N]) { | |
return N; | |
} | |
}; | |
template<typename T> | |
struct len_helper { | |
constexpr static size_t len(const char *x) { | |
return *x == '\0' ? 0 : 1 + len(x + 1); | |
} | |
}; | |
template<> | |
struct len_helper<std::nullptr_t> { | |
constexpr static size_t len(std::nullptr_t) { | |
return 0; | |
} | |
}; | |
template<size_t N> | |
struct len_helper<const char (&)[N]> { | |
constexpr static size_t len(const char (&x)[N]) { | |
return recursive_array<0, const char (&)[N]>::check(x); | |
} | |
}; | |
} // namespace detail | |
template<typename T> | |
constexpr size_t const_strlen(T&& x) { | |
return detail::len_helper< T >::len(std::forward< T >(x) ); | |
} | |
int main() { | |
constexpr const char ce_const_arr_empty[] = ""; | |
constexpr const char ce_const_arr[] = "foo"; | |
constexpr char ce_arr[] = "foo"; | |
constexpr const char * ptr = "foo"; | |
constexpr const char real_long[] = | |
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sit amet erat accumsan, " | |
"pellentesque libero id, pulvinar diam. Cras ullamcorper velit vitae tortor ultricies, at semper mi consequat. " | |
"Vestibulum pretium aliquam sapien, sit amet" | |
#if !(__clang_major__ < 4) | |
" placerat libero. Fusce in tempus risus. Lorem ipsum dolor sit amet, " | |
"consectetur adipiscing elit. Aenean lobortis, ante maximus tempor ullamcorper, tortor sem iaculis purus, dignissim " | |
"consectetur massa leo a mauris. Aliquam aliquam bibendum eros eget viverra." | |
#endif | |
; | |
SASSERT_EQ( const_stringlen(nullptr), 0); | |
SASSERT_EQ( const_stringlen(""), 0); | |
SASSERT_EQ( const_stringlen("\0" "bar"), 0); | |
SASSERT_EQ( const_stringlen("f\0" "ba"), 1); | |
SASSERT_EQ( const_stringlen("fo\0" "b"), 2); | |
SASSERT_EQ( const_stringlen((const char*)"\0" "bar"), 0); | |
SASSERT_EQ( const_stringlen(ce_const_arr_empty) ,0); | |
SASSERT_EQ( const_stringlen(ptr) ,3); | |
SASSERT_EQ( const_stringlen(ce_const_arr) ,3); | |
SASSERT_EQ( const_stringlen(ce_arr) ,3); | |
#if (__clang_major__ < 4) //old clang defaults to 256 recursion depth | |
SASSERT_EQ( const_stringlen(real_long) ,245); | |
#else //gcc defaults to 512 | |
SASSERT_EQ( const_stringlen(real_long) ,504); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment