Initial C++14 constexpr version of ctti_type_index. No ABI breakage

This commit is contained in:
Antony Polukhin
2015-08-01 20:13:38 +03:00
parent 7e2a538eb5
commit 743b2a8851
7 changed files with 329 additions and 29 deletions

View File

@ -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<T>(), type_id_with_cvr<T>()
/// * 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<ctti_type_index, detail::ctti_data> {
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<void>())
BOOST_CXX14_CONSTEXPR inline ctti_type_index() BOOST_NOEXCEPT
: data_(boost::detail::ctti<void>::n())
{}
inline ctti_type_index(const type_info_t& data) BOOST_NOEXCEPT
: data_(&data)
: data_(reinterpret_cast<const char*>(&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 <class T>
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 <class T>
inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT;
BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id() BOOST_NOEXCEPT;
template <class T>
BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT;
template <class T>
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<const detail::ctti_data*>(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 <class T>
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<T>::type no_ref_t;
typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<no_ref_t>::type no_cvr_t;
return ctti_construct<no_cvr_t>();
return ctti_type_index(boost::detail::ctti<no_cvr_t>::n());
}
template <class T>
inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
return ctti_construct<T>();
BOOST_CXX14_CONSTEXPR inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
return ctti_type_index(boost::detail::ctti<T>::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<const char*>(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

View File

@ -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 <boost/config.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/bool.hpp>
#include <algorithm>
#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
@ -70,7 +69,7 @@
namespace boost { namespace typeindex { namespace detail {
template <bool Condition>
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. "
@ -78,15 +77,52 @@ namespace boost { namespace typeindex { namespace detail {
"'RTTI emulation limitations' of the documentation for more information."
);
}
template <std::size_t ArrayLength>
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<class ForwardIterator1, class ForwardIterator2>
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<int>(*v1) - *v2;
}
template <std::size_t ArrayLength>
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
);
@ -94,7 +130,7 @@ namespace boost { namespace typeindex { namespace detail {
}
template <std::size_t ArrayLength>
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<ArrayLength - ctti_skip_size_at_begin>(
begin + ctti_skip_size_at_begin,
@ -112,7 +148,7 @@ template <class T>
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__)

View File

@ -160,7 +160,7 @@ inline bool operator == (const type_index_facade<Derived, TypeInfo>& lhs, const
template <class Derived, class TypeInfo>
inline bool operator < (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
return static_cast<Derived const&>(lhs).before(static_cast<Derived const&>(rhs));;
return static_cast<Derived const&>(lhs).before(static_cast<Derived const&>(rhs));
}

View File

@ -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 : : : <rtti>off $(norttidefines) : type_index_test_no_rtti ]
[ run ctti_print_name.cpp : : : <test-info>always_show_run_output ]
[ run testing_crossmodule.cpp test_lib_rtti ]

View File

@ -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

View File

@ -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 <boost/type_index/ctti_type_index.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <string>
#include <boost/core/lightweight_test.hpp>
#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 <class T>
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<T>();
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<int>();
BOOST_CXX14_CONSTEXPR ctti_type_index t_short0 = ctti_type_index::type_id<short>();
BOOST_CXX14_CONSTEXPR ctti_type_index t_int1 = ctti_type_index::type_id<int>();
BOOST_CXX14_CONSTEXPR ctti_type_index t_short1 = ctti_type_index::type_id<short>();
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<ctti_type_index>::value;
BOOST_TEST(in_namespace);
constexpr bool not_in_namespace = !is_boost_namespace<std::string>::value;
BOOST_TEST(not_in_namespace);
#endif
}
int main() {
strcmp_same();
search_same();
constexpr_test();
return boost::report_errors();
}

View File

@ -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();
}