
Tom Brinkman wrote:
Now that I think about it some more, there's really nothing stopping us from taking this much farther -- access individual characters, calculate the length, slice and substr, even search and replace. There's no reason why ctstring<> can't implement most of the std::string interface at compile time.
This would be great showcase of the advanced work being done by boost developers. This would have a "high" wow factor.
I bet, the vast horde of "old-style" c++ developers what immediately step up and take notice.
I fleshed out the compile-time string class, and called it mpl::string. (See attached.) It is a Front and Back Extensible, Random-Access MPL Sequence. The primary use is as follows: template<char const *sz> // template on a string struct foo { void bar() { std::printf("%s\n", sz); } }; foo< mpl::string<'hell','o wo','rld!'>::c_str > f; f.bar(); // prints "hello world!" Is there interest in adding this to the MPL? -- Eric Niebler Boost Consulting www.boost-consulting.com /////////////////////////////////////////////////////////////////////////////// // // Copyright 2008 Eric Niebler. 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 <string> #include <cstring> #include <iostream> #include <boost/mpl/at.hpp> #include <boost/mpl/long.hpp> #include <boost/mpl/back.hpp> #include <boost/mpl/copy.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/empty.hpp> #include <boost/mpl/front.hpp> #include <boost/mpl/clear.hpp> #include <boost/mpl/erase.hpp> #include <boost/mpl/insert.hpp> #include <boost/mpl/assert.hpp> #include <boost/mpl/size_t.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/joint_view.hpp> #include <boost/mpl/insert_range.hpp> #include <boost/mpl/back_inserter.hpp> #include <boost/mpl/iterator_range.hpp> #include <boost/preprocessor/arithmetic/dec.hpp> #include <boost/preprocessor/arithmetic/div.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/punctuation/comma_if.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/enum_shifted_params.hpp> #include <boost/preprocessor/repetition/enum_trailing_params.hpp> #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> // Define mpl::char_ #include <boost/mpl/aux_/adl_barrier.hpp> #include <boost/mpl/aux_/nttp_decl.hpp> BOOST_MPL_AUX_ADL_BARRIER_NAMESPACE_OPEN template< BOOST_MPL_AUX_NTTP_DECL(char, N) > struct char_; BOOST_MPL_AUX_ADL_BARRIER_NAMESPACE_CLOSE BOOST_MPL_AUX_ADL_BARRIER_DECL(char_) #define AUX_WRAPPER_VALUE_TYPE char #include <boost/mpl/aux_/integral_wrapper.hpp> #include <boost/detail/lightweight_test.hpp> namespace boost { namespace mpl { //#define BOOST_MPL_STRING_MAX_LENGTH 128 #define BOOST_MPL_STRING_MAX_LENGTH 32 #define BOOST_MPL_STRING_MAX_PARAMS BOOST_PP_DIV(BOOST_MPL_STRING_MAX_LENGTH, 4) #define BOOST_MPL_MULTICHAR_LENGTH(c) ((std::size_t)((c>0xffffff)+(c>0xffff)+(c>0xff)+1)) #define BOOST_MPL_MULTICHAR_AT(c,i) (char)((c)>>(8*(BOOST_MPL_MULTICHAR_LENGTH(c)-((std::size_t)(i))-1))) struct string_tag; struct string_iterator_tag; template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C, 0)> struct string; template<typename Sequence, long N> struct string_iterator; template<typename Sequence> struct sequence_tag; template<typename Tag> struct size_impl; template<> struct size_impl<string_tag> { template<typename Sequence> struct apply : mpl::size_t<Sequence::size> {}; }; template<typename Tag> struct at_impl; template<> struct at_impl<string_tag> { template<typename Sequence, typename N> struct apply : Sequence::template at<N::value> {}; }; template<typename Tag> struct begin_impl; template<> struct begin_impl<string_tag> { template<typename Sequence> struct apply { typedef string_iterator<Sequence, 0> type; }; }; template<typename Tag> struct end_impl; template<> struct end_impl<string_tag> { template<typename Sequence> struct apply { typedef string_iterator<Sequence, Sequence::size> type; }; }; template<typename Tag> struct push_back_impl; template<> struct push_back_impl<string_tag> { template<typename Sequence, typename Value> struct apply; template<typename Value> struct apply<string<>, Value> { typedef string<(char)Value::value> type; }; #define M0(z,n,data) \ template<BOOST_PP_ENUM_PARAMS_Z(z, n, unsigned int C), typename Value> \ struct apply<string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, Value> \ { \ typedef string< \ BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_DEC(n), C) \ BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) \ (BOOST_PP_CAT(C,BOOST_PP_DEC(n))>0xffffff) \ ?BOOST_PP_CAT(C,BOOST_PP_DEC(n)) \ :(BOOST_PP_CAT(C,BOOST_PP_DEC(n))<<8)|(unsigned char)Value::value \ , (BOOST_PP_CAT(C,BOOST_PP_DEC(n))>0xffffff) \ ?(char)Value::value \ :0 \ > type; \ }; BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS), M0, ~) #undef M0 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C), typename Value> struct apply<string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, Value> { BOOST_MPL_ASSERT_RELATION(BOOST_PP_CAT(C,BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS)), <=, 0xffffff); typedef string< BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS), C) , (BOOST_PP_CAT(C,BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS))<<8)|(unsigned char)Value::value > type; }; }; template<typename Tag> struct push_front_impl; template<> struct push_front_impl<string_tag> { template<typename Sequence, typename Value, std::size_t N = BOOST_MPL_MULTICHAR_LENGTH(Sequence::head_)> struct apply; template<typename Value> struct apply<string<>, Value, 1> { typedef string<(char)Value::value> type; }; #define M0(z,n,data) \ template<BOOST_PP_ENUM_PARAMS_Z(z, n, unsigned int C), typename Value, std::size_t N> \ struct apply<string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, Value, N> \ { \ typedef string< \ ((((unsigned char)Value::value)<<(N*8))|C0) \ BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) \ BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, C) \ > type; \ }; \ template<BOOST_PP_ENUM_PARAMS_Z(z, n, unsigned int C), typename Value> \ struct apply<string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, Value, 4> \ { \ typedef string< \ (char)Value::value \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, C) \ > type; \ }; BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS), M0, ~) #undef M0 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C), typename Value, std::size_t N> struct apply<string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, Value, N> { BOOST_MPL_ASSERT_RELATION(C0, <=, 0xffffff); typedef string< (((unsigned char)Value::value)<<(N*8))|C0 , BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C) > type; }; }; template<typename Tag> struct insert_range_impl; template<> struct insert_range_impl<string_tag> { template<typename Sequence, typename Pos, typename Range> struct apply : copy< joint_view< iterator_range< string_iterator<Sequence, 0> , Pos > , joint_view< Range , iterator_range< Pos , string_iterator<Sequence, Sequence::size> > > > , back_inserter<string<> > > {}; }; template<typename Tag> struct insert_impl; template<> struct insert_impl<string_tag> { template<typename Sequence, typename Pos, typename Value> struct apply : insert_range<Sequence, Pos, string<(char)Value::value> > {}; }; template<typename Tag> struct erase_impl; template<> struct erase_impl<string_tag> { template<typename Sequence, typename First, typename Last> struct apply : copy< joint_view< iterator_range< string_iterator<Sequence, 0> , First > , iterator_range< typename if_na<Last, typename next<First>::type>::type , string_iterator<Sequence, Sequence::size> > > , back_inserter<string<> > > {}; }; template<typename Tag> struct clear_impl; template<> struct clear_impl<string_tag> { template<typename> struct apply { typedef string<> type; }; }; template<typename Tag> struct advance_impl; template<> struct advance_impl<string_iterator_tag> { template<typename Iterator, typename N> struct apply { typedef string_iterator< typename Iterator::string_type , Iterator::index + N::value > type; }; }; template<typename Tag> struct distance_impl; template<> struct distance_impl<string_iterator_tag> { template<typename First, typename Last> struct apply { typedef mpl::long_<Last::index - First::index> type; }; }; template<typename Sequence, long N> struct string_iterator : Sequence::template at<N> { typedef string_iterator_tag tag; typedef std::random_access_iterator_tag category; typedef Sequence string_type; static long const index = N; typedef string_iterator<Sequence, N+1> next; typedef string_iterator<Sequence, N-1> prior; }; template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C)> struct string { /// INTERNAL ONLY static unsigned int const head_ = C0; /// INTERNAL ONLY typedef string<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)> tail_; typedef string_tag tag; static std::size_t const size = BOOST_MPL_MULTICHAR_LENGTH(C0) + tail_::size; template<long Pos, bool B = (Pos < BOOST_MPL_MULTICHAR_LENGTH(C0))> struct at : boost::mpl::char_<BOOST_MPL_MULTICHAR_AT(C0,Pos)> {}; template<long Pos> struct at<Pos, false> : tail_::template at<Pos-BOOST_MPL_MULTICHAR_LENGTH(C0)> {}; static char const c_str[]; }; template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C)> char const string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>::c_str[] = { #define M0(z, n, data) at<n>::value BOOST_PP_ENUM(BOOST_MPL_STRING_MAX_LENGTH, M0, ~) #undef M0 , '\0' // to ensure the string is null-terminated }; template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C)> std::size_t const string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>::size; template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned int C)> unsigned int const string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>::head_; template<> struct string<> { /// INTERNAL ONLY static unsigned int const head_ = 0; /// INTERNAL ONLY typedef string tail_; typedef string_tag tag; static std::size_t const size = 0; template<unsigned int> struct at : boost::mpl::char_<'\0'> {}; static char const c_str[]; }; char const string<>::c_str[] = {'\0'}; std::size_t const string<>::size; unsigned int const string<>::head_; }} // namespace boost using namespace boost; // Accept a string as a template parameter! template<char const *sz> struct greeting { std::string say_hello() const { return sz; } }; struct push_char { push_char(std::string &str) : str_(str) {} void operator()(char ch) const { this->str_.push_back(ch); } std::string &str_; }; int main() { BOOST_TEST(0 == std::strcmp(mpl::string<'Hell','o wo','rld!'>::c_str, "Hello world!")); BOOST_TEST((12 == mpl::size<mpl::string<'Hell','o wo','rld!'> >::type::value)); BOOST_TEST(('w' == mpl::at_c<mpl::string<'Hell','o wo','rld!'>, 6>::type::value)); // test using a string as a template parameter greeting<mpl::string<'Hell','o wo','rld!'>::c_str> g; BOOST_TEST("Hello world!" == g.say_hello()); BOOST_TEST(0 == std::strcmp("", mpl::string<>::c_str)); std::string result; mpl::for_each<mpl::string<'Hell','o wo','rld!'> >(push_char(result)); BOOST_TEST("Hello world!" == result); BOOST_MPL_ASSERT((mpl::empty<mpl::string<> >)); BOOST_MPL_ASSERT_NOT((mpl::empty<mpl::string<'hi!'> >)); BOOST_TEST(('h' == mpl::front<mpl::string<'hi!'> >::type())); BOOST_TEST(('!' == mpl::back<mpl::string<'hi!'> >::type())); // testing push_back { typedef mpl::push_back<mpl::string<>, mpl::char_<'a'> >::type t1; BOOST_TEST(0 == std::strcmp("a", t1::c_str)); typedef mpl::push_back<t1, mpl::char_<'b'> >::type t2; BOOST_TEST(0 == std::strcmp("ab", t2::c_str)); typedef mpl::push_back<t2, mpl::char_<'c'> >::type t3; BOOST_TEST(0 == std::strcmp("abc", t3::c_str)); typedef mpl::push_back<t3, mpl::char_<'d'> >::type t4; BOOST_TEST(0 == std::strcmp("abcd", t4::c_str)); typedef mpl::push_back<t4, mpl::char_<'e'> >::type t5; BOOST_TEST(0 == std::strcmp("abcde", t5::c_str)); typedef mpl::string<'aaaa','aaaa','aaaa','aaaa','aaaa','aaaa','aaaa','aaa'> almost_full; BOOST_TEST(0 == std::strcmp("aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaa", almost_full::c_str)); typedef mpl::push_back<almost_full, mpl::char_<'X'> >::type t6; BOOST_TEST(0 == std::strcmp("aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaX", t6::c_str)); } // testing push_front { typedef mpl::push_front<mpl::string<>, mpl::char_<'a'> >::type t1; BOOST_TEST(0 == std::strcmp("a", t1::c_str)); typedef mpl::push_front<t1, mpl::char_<'b'> >::type t2; BOOST_TEST(0 == std::strcmp("ba", t2::c_str)); typedef mpl::push_front<t2, mpl::char_<'c'> >::type t3; BOOST_TEST(0 == std::strcmp("cba", t3::c_str)); typedef mpl::push_front<t3, mpl::char_<'d'> >::type t4; BOOST_TEST(0 == std::strcmp("dcba", t4::c_str)); typedef mpl::push_front<t4, mpl::char_<'e'> >::type t5; BOOST_TEST(0 == std::strcmp("edcba", t5::c_str)); typedef mpl::string<'aaa','aaaa','aaaa','aaaa','aaaa','aaaa','aaaa','aaaa'> almost_full; BOOST_TEST(0 == std::strcmp("aaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa", almost_full::c_str)); typedef mpl::push_front<almost_full, mpl::char_<'X'> >::type t6; BOOST_TEST(0 == std::strcmp("Xaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa" "aaaa", t6::c_str)); } // back-inserter with copy typedef mpl::vector_c<char, 'a','b','c','d','e'> rgc; typedef mpl::copy<rgc, mpl::back_inserter<mpl::string<> > >::type str; BOOST_TEST(0 == std::strcmp("abcde", str::c_str)); // test insert_range and erase { typedef mpl::string<'Hell','o wo','rld!'> hello; typedef mpl::advance_c<mpl::begin<hello>::type, 5>::type where; typedef mpl::string<' cru','el'> cruel; typedef mpl::insert_range<hello, where, cruel>::type hello_cruel; BOOST_TEST(0 == std::strcmp("Hello cruel world!", hello_cruel::c_str)); typedef mpl::erase<hello, mpl::begin<hello>::type, where>::type erased1; BOOST_TEST(0 == std::strcmp(" world!", erased1::c_str)); } return report_errors(); }