diff --git a/include/boost/type_index/ctti_type_index.hpp b/include/boost/type_index/ctti_type_index.hpp index ac1e5d2..3b05565 100644 --- a/include/boost/type_index/ctti_type_index.hpp +++ b/include/boost/type_index/ctti_type_index.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) Antony Polukhin, 2013-2014. +// Copyright (c) Antony Polukhin, 2013-2015. // // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -92,34 +92,48 @@ inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT { /// This class is a wrapper that pretends to work exactly like stl_type_index, but does /// not require RTTI support. \b For \b description \b of \b functions \b see type_index_facade. /// +/// This class on C++14 compatible compilers has following functions marked as constexpr: +/// * default constructor +/// * copy constructors and assignemnt operations +/// * class methods: name(), before(const ctti_type_index& rhs), equal(const ctti_type_index& rhs) +/// * static methods type_id(), type_id_with_cvr() +/// * comparison operators +/// /// This class produces slightly longer type names, so consider using stl_type_index /// in situations when typeid() is working. class ctti_type_index: public type_index_facade { - const detail::ctti_data* data_; + const char* data_; inline std::size_t get_raw_name_length() const BOOST_NOEXCEPT; + BOOST_CXX14_CONSTEXPR inline explicit ctti_type_index(const char* data) BOOST_NOEXCEPT + : data_(data) + {} + public: typedef detail::ctti_data type_info_t; - inline ctti_type_index() BOOST_NOEXCEPT - : data_(&ctti_construct()) + BOOST_CXX14_CONSTEXPR inline ctti_type_index() BOOST_NOEXCEPT + : data_(boost::detail::ctti::n()) {} inline ctti_type_index(const type_info_t& data) BOOST_NOEXCEPT - : data_(&data) + : data_(reinterpret_cast(&data)) {} - inline const type_info_t& type_info() const BOOST_NOEXCEPT; - inline const char* raw_name() const BOOST_NOEXCEPT; + inline const type_info_t& type_info() const BOOST_NOEXCEPT; + BOOST_CXX14_CONSTEXPR inline const char* raw_name() const BOOST_NOEXCEPT; inline std::string pretty_name() const; inline std::size_t hash_code() const BOOST_NOEXCEPT; - template - inline static ctti_type_index type_id() BOOST_NOEXCEPT; + BOOST_CXX14_CONSTEXPR inline bool equal(const ctti_type_index& rhs) const BOOST_NOEXCEPT; + BOOST_CXX14_CONSTEXPR inline bool before(const ctti_type_index& rhs) const BOOST_NOEXCEPT; template - inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT; + BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id() BOOST_NOEXCEPT; + + template + BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT; template inline static ctti_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT; @@ -127,22 +141,35 @@ public: inline const ctti_type_index::type_info_t& ctti_type_index::type_info() const BOOST_NOEXCEPT { - return *data_; + return *reinterpret_cast(data_); +} + + +BOOST_CXX14_CONSTEXPR inline bool ctti_type_index::equal(const ctti_type_index& rhs) const BOOST_NOEXCEPT { + const char* const left = raw_name(); + const char* const right = rhs.raw_name(); + return left == right || !boost::typeindex::detail::constexpr_strcmp(left, right); +} + +BOOST_CXX14_CONSTEXPR inline bool ctti_type_index::before(const ctti_type_index& rhs) const BOOST_NOEXCEPT { + const char* const left = raw_name(); + const char* const right = rhs.raw_name(); + return left != right && boost::typeindex::detail::constexpr_strcmp(left, right) < 0; } template -inline ctti_type_index ctti_type_index::type_id() BOOST_NOEXCEPT { +BOOST_CXX14_CONSTEXPR inline ctti_type_index ctti_type_index::type_id() BOOST_NOEXCEPT { typedef BOOST_DEDUCED_TYPENAME boost::remove_reference::type no_ref_t; typedef BOOST_DEDUCED_TYPENAME boost::remove_cv::type no_cvr_t; - return ctti_construct(); + return ctti_type_index(boost::detail::ctti::n()); } template -inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT { - return ctti_construct(); +BOOST_CXX14_CONSTEXPR inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT { + return ctti_type_index(boost::detail::ctti::n()); } @@ -152,8 +179,8 @@ inline ctti_type_index ctti_type_index::type_id_runtime(const T& variable) BOOST } -inline const char* ctti_type_index::raw_name() const BOOST_NOEXCEPT { - return reinterpret_cast(data_); +BOOST_CXX14_CONSTEXPR inline const char* ctti_type_index::raw_name() const BOOST_NOEXCEPT { + return data_; } inline std::size_t ctti_type_index::get_raw_name_length() const BOOST_NOEXCEPT { @@ -173,6 +200,94 @@ inline std::size_t ctti_type_index::hash_code() const BOOST_NOEXCEPT { } +/// @cond +BOOST_CXX14_CONSTEXPR inline bool operator == (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return lhs.equal(rhs); +} + +BOOST_CXX14_CONSTEXPR inline bool operator < (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return lhs.before(rhs); +} + + +BOOST_CXX14_CONSTEXPR inline bool operator > (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return rhs < lhs; +} + +BOOST_CXX14_CONSTEXPR inline bool operator <= (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(lhs > rhs); +} + +BOOST_CXX14_CONSTEXPR inline bool operator >= (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(lhs < rhs); +} + +BOOST_CXX14_CONSTEXPR inline bool operator != (const ctti_type_index& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(lhs == rhs); +} + + +// ######################### COMPARISONS with detail::ctti_data ############################ // +inline bool operator == (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return ctti_type_index(lhs) == rhs; +} + +inline bool operator < (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return ctti_type_index(lhs) < rhs; +} + +inline bool operator > (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return rhs < ctti_type_index(lhs); +} + +inline bool operator <= (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(ctti_type_index(lhs) > rhs); +} + +inline bool operator >= (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(ctti_type_index(lhs) < rhs); +} + +inline bool operator != (const boost::typeindex::detail::ctti_data& lhs, const ctti_type_index& rhs) BOOST_NOEXCEPT { + return !(ctti_type_index(lhs) == rhs); +} + + +inline bool operator == (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return lhs == ctti_type_index(rhs); +} + +inline bool operator < (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return lhs < ctti_type_index(rhs); +} + +inline bool operator > (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return ctti_type_index(rhs) < lhs; +} + +inline bool operator <= (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return !(lhs > ctti_type_index(rhs)); +} + +inline bool operator >= (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return !(lhs < ctti_type_index(rhs)); +} + +inline bool operator != (const ctti_type_index& lhs, const boost::typeindex::detail::ctti_data& rhs) BOOST_NOEXCEPT { + return !(lhs == ctti_type_index(rhs)); +} + +// ######################### COMPARISONS with detail::ctti_data END ############################ // + +/// @endcond + +#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) +/// c++14 constexpr noexcept comparison operators for type_index_facade classes. +constexpr bool operator ==, !=, <, ... (const ctti_type_index& lhs, const ctti_type_index& rhs) noexcept; +#endif + + + }} // namespace boost::typeindex #endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP diff --git a/include/boost/type_index/detail/compile_time_type_info.hpp b/include/boost/type_index/detail/compile_time_type_info.hpp index 89e1a0b..c981931 100644 --- a/include/boost/type_index/detail/compile_time_type_info.hpp +++ b/include/boost/type_index/detail/compile_time_type_info.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) Antony Polukhin, 2012-2014. +// Copyright (c) Antony Polukhin, 2012-2015. // // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,7 +16,6 @@ #include #include #include -#include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -76,7 +75,7 @@ namespace boost { namespace typeindex { namespace detail { template - inline void assert_compile_time_legths() BOOST_NOEXCEPT { + BOOST_CXX14_CONSTEXPR inline void assert_compile_time_legths() BOOST_NOEXCEPT { BOOST_STATIC_ASSERT_MSG( Condition, "TypeIndex library is misconfigured for your compiler. " @@ -84,15 +83,52 @@ namespace boost { namespace typeindex { namespace detail { "'RTTI emulation limitations' of the documentation for more information." ); } - + template - inline const char* skip_begining_runtime(const char* begin, boost::mpl::false_) BOOST_NOEXCEPT { + BOOST_CXX14_CONSTEXPR inline const char* skip_begining_runtime(const char* begin, boost::mpl::false_) BOOST_NOEXCEPT { return begin; } + template + BOOST_CXX14_CONSTEXPR inline ForwardIterator1 constexpr_search( + ForwardIterator1 first1, + ForwardIterator1 last1, + ForwardIterator2 first2, + ForwardIterator2 last2) BOOST_NOEXCEPT + { + if (first2 == last2) { + return first1; // specified in C++11 + } + + while (first1 != last1) { + ForwardIterator1 it1 = first1; + ForwardIterator2 it2 = first2; + + while (*it1 == *it2) { + ++it1; + ++it2; + if (it2 == last2) return first1; + if (it1 == last1) return last1; + } + + ++first1; + } + + return last1; + } + + BOOST_CXX14_CONSTEXPR inline int constexpr_strcmp(const char *v1, const char *v2) BOOST_NOEXCEPT { + while (*v1 != '\0' && *v1 == *v2) { + ++v1; + ++v2; + }; + + return static_cast(*v1) - *v2; + } + template - inline const char* skip_begining_runtime(const char* begin, boost::mpl::true_) BOOST_NOEXCEPT { - const char* const it = std::search( + BOOST_CXX14_CONSTEXPR inline const char* skip_begining_runtime(const char* begin, boost::mpl::true_) BOOST_NOEXCEPT { + const char* const it = constexpr_search( begin, begin + ArrayLength, ctti_skip_until_runtime, ctti_skip_until_runtime + sizeof(ctti_skip_until_runtime) - 1 ); @@ -100,7 +136,7 @@ namespace boost { namespace typeindex { namespace detail { } template - inline const char* skip_begining(const char* begin) BOOST_NOEXCEPT { + BOOST_CXX14_CONSTEXPR inline const char* skip_begining(const char* begin) BOOST_NOEXCEPT { assert_compile_time_legths<(ArrayLength > ctti_skip_size_at_begin + ctti_skip_size_at_end)>(); return skip_begining_runtime( begin + ctti_skip_size_at_begin, @@ -118,7 +154,7 @@ template struct ctti { /// Returns raw name. Must be as short, as possible, to avoid code bloat - static const char* n() BOOST_NOEXCEPT { + BOOST_CXX14_CONSTEXPR static const char* n() BOOST_NOEXCEPT { #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) return boost::typeindex::detail::skip_begining< sizeof(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE >(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE); #elif defined(__FUNCSIG__) diff --git a/include/boost/type_index/type_index_facade.hpp b/include/boost/type_index/type_index_facade.hpp index 931dedc..97c8ff4 100644 --- a/include/boost/type_index/type_index_facade.hpp +++ b/include/boost/type_index/type_index_facade.hpp @@ -160,7 +160,7 @@ inline bool operator == (const type_index_facade& lhs, const template inline bool operator < (const type_index_facade& lhs, const type_index_facade& rhs) BOOST_NOEXCEPT { - return static_cast(lhs).before(static_cast(rhs));; + return static_cast(lhs).before(static_cast(rhs)); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a4550d1..6986c96 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -40,6 +40,7 @@ exe testing_crossmodule_anonymous_no_rtti : testing_crossmodule_anonymous.cpp te test-suite type_index : [ run type_index_test.cpp ] + [ run type_index_constexpr_test.cpp ] [ run type_index_test.cpp : : : off $(norttidefines) : type_index_test_no_rtti ] [ run ctti_print_name.cpp : : : always_show_run_output ] [ run testing_crossmodule.cpp test_lib_rtti ] diff --git a/test/ctti_print_name.cpp b/test/ctti_print_name.cpp index b72e918..34f03d0 100644 --- a/test/ctti_print_name.cpp +++ b/test/ctti_print_name.cpp @@ -1,5 +1,5 @@ // -// Copyright Antony Polukhin, 2012-2014. +// Copyright Antony Polukhin, 2012-2015. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at diff --git a/test/type_index_constexpr_test.cpp b/test/type_index_constexpr_test.cpp new file mode 100644 index 0000000..fe5ca54 --- /dev/null +++ b/test/type_index_constexpr_test.cpp @@ -0,0 +1,148 @@ +// +// Copyright Antony Polukhin, 2015. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include +#include + +#include +#define BOOST_TEST_LE(x, y) BOOST_TEST(x <= y) +#define BOOST_TEST_GE(x, y) BOOST_TEST(x >= y) + +const char* hello1 = "Hello word"; +const char* hello1_end = hello1 + sizeof("Hello word"); +const char* hello2 = "Hello word, pal!"; +const char* hello2_end = hello2 + sizeof("Hello word, pal!"); + +void strcmp_same() { + using boost::typeindex::detail::constexpr_strcmp; + + BOOST_TEST( + constexpr_strcmp(hello1, hello1) == 0 + ); + + BOOST_TEST( + constexpr_strcmp(hello2, hello2) == 0 + ); + + BOOST_TEST( + constexpr_strcmp(hello1, hello2) != 0 + ); + + BOOST_TEST( + constexpr_strcmp(hello2, hello1) != 0 + ); + + BOOST_TEST( + (constexpr_strcmp(hello2, hello1) < 0) + == + (std::strcmp(hello2, hello1) < 0) + ); + + BOOST_TEST( + (constexpr_strcmp(hello1, hello2) < 0) + == + (std::strcmp(hello1, hello2) < 0) + ); +} + +void search_same() { + using boost::typeindex::detail::constexpr_search; + BOOST_TEST( + constexpr_search(hello1, hello1_end, hello2, hello2_end) == std::search(hello1, hello1_end, hello2, hello2_end) + ); + + BOOST_TEST( + constexpr_search(hello2, hello2_end, hello1, hello1_end) == std::search(hello2, hello2_end, hello1, hello1_end) + ); + + const char* word = "word"; + const char* word_end = word + sizeof("word") - 1; + BOOST_TEST( + constexpr_search(hello1, hello1_end, word, word_end) == std::search(hello1, hello1_end, word, word_end) + ); + + BOOST_TEST( + constexpr_search(hello2, hello2_end, word, word_end) == std::search(hello2, hello2_end, word, word_end) + ); +} + + +#ifndef BOOST_NO_CXX14_CONSTEXPR +template +struct is_boost_namespace { + constexpr char cb[5] = {'b', 'o', 'o', 's', 't'}; + constexpr boost::typeindex::ctti_type_index type = boost::typeindex::ctti_type_index::type_id(); + constexpr bool value = (boost::typeindex::detail::constexpr_search(type.name(), type.name() + 5, cb, cb + 5) != cb + 5); +}; +#endif + + +void constexpr_test() { + using namespace boost::typeindex; + + BOOST_CXX14_CONSTEXPR ctti_type_index t_int0 = ctti_type_index::type_id(); + BOOST_CXX14_CONSTEXPR ctti_type_index t_short0 = ctti_type_index::type_id(); + BOOST_CXX14_CONSTEXPR ctti_type_index t_int1 = ctti_type_index::type_id(); + BOOST_CXX14_CONSTEXPR ctti_type_index t_short1 = ctti_type_index::type_id(); + + BOOST_CXX14_CONSTEXPR bool same0 = (t_int0 == t_int1); + BOOST_TEST(same0); + + BOOST_CXX14_CONSTEXPR bool same1 = (t_short1 == t_short0); + BOOST_TEST(same1); + + BOOST_CXX14_CONSTEXPR bool same2 = (t_int1 == t_int1); + BOOST_TEST(same2); + + BOOST_CXX14_CONSTEXPR bool same3 = (t_short0 == t_short0); + BOOST_TEST(same3); + + BOOST_CXX14_CONSTEXPR bool same4 = !(t_short0 < t_short0 || t_short0 > t_short0); + BOOST_TEST(same4); + + BOOST_CXX14_CONSTEXPR bool same5 = (t_short0 <= t_short0 && t_short0 >= t_short0); + BOOST_TEST(same5); + + + BOOST_CXX14_CONSTEXPR bool not_same0 = (t_int0 != t_short1); + BOOST_TEST(not_same0); + + BOOST_CXX14_CONSTEXPR bool not_same1 = (t_int1 != t_short0); + BOOST_TEST(not_same1); + + BOOST_CXX14_CONSTEXPR bool not_same2 = (t_int1 < t_short0 || t_int1 > t_short0); + BOOST_TEST(not_same2); + + + BOOST_CXX14_CONSTEXPR const char* int_name = t_int0.name(); + BOOST_TEST(int_name); + + BOOST_CXX14_CONSTEXPR const char* short_name = t_short0.name(); + BOOST_TEST(short_name); + +#ifndef BOOST_NO_CXX14_CONSTEXPR + constexpr bool in_namespace = is_boost_namespace::value; + BOOST_TEST(in_namespace); + + constexpr bool not_in_namespace = !is_boost_namespace::value; + BOOST_TEST(not_in_namespace); +#endif + +} + + +int main() { + strcmp_same(); + search_same(); + constexpr_test(); + return boost::report_errors(); +} + diff --git a/test/type_index_test.cpp b/test/type_index_test.cpp index 4631cef..c022812 100644 --- a/test/type_index_test.cpp +++ b/test/type_index_test.cpp @@ -381,7 +381,6 @@ void comparators_type_id_vs_type_info() #endif // BOOST_NO_RTTI - int main() { names_matches_type_id(); default_construction(); @@ -399,6 +398,7 @@ int main() { #ifndef BOOST_NO_RTTI comparators_type_id_vs_type_info(); #endif + return boost::report_errors(); }