1 2 #ifndef BOOST_MPL_STRING_HPP_INCLUDED 3 #define BOOST_MPL_STRING_HPP_INCLUDED 4 5 // Copyright Eric Niebler 2009 6 // 7 // Distributed under the Boost Software License, Version 1.0. 8 // (See accompanying file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 // 11 // See http://www.boost.org/libs/mpl for documentation. 12 13 // $Id: string.hpp 49239 2009-04-01 09:10:26Z eric_niebler $ 14 // $Date: 2009-04-01 02:10:26 -0700 (Wed, 1 Apr 2009) $ 15 // $Revision: 49239 $ 16 // 17 // Thanks to: 18 // Dmitry Goncharov for porting this to the Sun compiler 19 20 #include <boost/config.hpp> 21 #include <boost/detail/workaround.hpp> 22 #include <boost/predef/other/endian.h> 23 #include <boost/mpl/limits/string.hpp> 24 #include <boost/mpl/if.hpp> 25 #include <boost/mpl/char.hpp> 26 #include <boost/mpl/copy.hpp> 27 #include <boost/mpl/size.hpp> 28 #include <boost/mpl/empty.hpp> 29 #include <boost/mpl/assert.hpp> 30 #include <boost/mpl/size_t.hpp> 31 #include <boost/mpl/begin_end.hpp> 32 #include <boost/mpl/joint_view.hpp> 33 #include <boost/mpl/insert_range.hpp> 34 #include <boost/mpl/back_inserter.hpp> 35 #include <boost/mpl/front_inserter.hpp> 36 #include <boost/mpl/iterator_range.hpp> 37 #include <boost/preprocessor/arithmetic/dec.hpp> 38 #include <boost/preprocessor/arithmetic/add.hpp> 39 #include <boost/preprocessor/arithmetic/div.hpp> 40 #include <boost/preprocessor/punctuation/comma_if.hpp> 41 #include <boost/preprocessor/repetition/repeat.hpp> 42 #include <boost/preprocessor/repetition/enum_params.hpp> 43 #include <boost/preprocessor/repetition/repeat_from_to.hpp> 44 #include <boost/preprocessor/repetition/enum_shifted_params.hpp> 45 #include <boost/preprocessor/repetition/enum_trailing_params.hpp> 46 #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> 47 48 #include <iterator> // for bidirectional_iterator_tag 49 #include <climits> 50 51 namespace boost { namespace mpl 52 { 53 #define BOOST_MPL_STRING_MAX_PARAMS \ 54 BOOST_PP_DIV(BOOST_PP_ADD(BOOST_MPL_LIMIT_STRING_SIZE, 3), 4) 55 56 // Low-level bit-twiddling is done by macros. Any implementation-defined behavior of 57 // multi-character literals should be localized to these macros. 58 59 #define BOOST_MPL_MULTICHAR_LENGTH(c) \ 60 (std::size_t)((c<CHAR_MIN) ? 4 : ((c>0xffffff)+(c>0xffff)+(c>0xff)+1)) 61 62 #if BOOST_ENDIAN_LITTLE_BYTE && defined(__SUNPRO_CC) 63 64 #define BOOST_MPL_MULTICHAR_AT(c,i) \ 65 (char)(0xff&((unsigned)(c)>>(8*(std::size_t)(i)))) 66 67 #define BOOST_MPL_MULTICHAR_PUSH_BACK(c,i) \ 68 ((((unsigned char)(i))<<(BOOST_MPL_MULTICHAR_LENGTH(c)*8))|(unsigned)(c)) 69 70 #define BOOST_MPL_MULTICHAR_PUSH_FRONT(c,i) \ 71 (((unsigned)(c)<<8)|(unsigned char)(i)) 72 73 #define BOOST_MPL_MULTICHAR_POP_BACK(c) \ 74 (((1<<((BOOST_MPL_MULTICHAR_LENGTH(c)-1)*8))-1)&(unsigned)(c)) 75 76 #define BOOST_MPL_MULTICHAR_POP_FRONT(c) \ 77 ((unsigned)(c)>>8) 78 79 #else 80 81 #define BOOST_MPL_MULTICHAR_AT(c,i) \ 82 (char)(0xff&((unsigned)(c)>>(8*(BOOST_MPL_MULTICHAR_LENGTH(c)-(std::size_t)(i)-1)))) 83 84 #define BOOST_MPL_MULTICHAR_PUSH_BACK(c,i) \ 85 (((unsigned)(c)<<8)|(unsigned char)(i)) 86 87 #define BOOST_MPL_MULTICHAR_PUSH_FRONT(c,i) \ 88 ((((unsigned char)(i))<<(BOOST_MPL_MULTICHAR_LENGTH(c)*8))|(unsigned)(c)) 89 90 #define BOOST_MPL_MULTICHAR_POP_BACK(c) \ 91 ((unsigned)(c)>>8) 92 93 #define BOOST_MPL_MULTICHAR_POP_FRONT(c) \ 94 (((1<<((BOOST_MPL_MULTICHAR_LENGTH(c)-1)*8))-1)&(unsigned)(c)) 95 96 #endif 97 98 struct string_tag; 99 struct string_iterator_tag; 100 101 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_MPL_STRING_MAX_PARAMS, int C, 0)> 102 struct string; 103 104 template<typename Sequence, int I, int J> 105 struct string_iterator; 106 107 template<typename Sequence> 108 struct sequence_tag; 109 110 template<typename Tag> 111 struct size_impl; 112 113 template<> 114 struct size_impl<mpl::string_tag> 115 { 116 template<typename Sequence> 117 struct apply; 118 119 #define M0(z, n, data) \ 120 + BOOST_MPL_MULTICHAR_LENGTH(BOOST_PP_CAT(C,n)) 121 122 #define M1(z, n, data) \ 123 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C)> \ 124 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)> > \ 125 : mpl::size_t<(0 BOOST_PP_REPEAT_ ## z(n, M0, ~))> \ 126 {}; 127 128 BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_MPL_STRING_MAX_PARAMS), M1, ~) 129 #undef M0 130 #undef M1 131 }; 132 133 template<> 134 struct size_impl<mpl::string_tag>::apply<mpl::string<> > 135 : mpl::size_t<0> 136 {}; 137 138 template<typename Tag> 139 struct begin_impl; 140 141 template<> 142 struct begin_impl<mpl::string_tag> 143 { 144 template<typename Sequence> 145 struct apply 146 { 147 typedef mpl::string_iterator<Sequence, 0, 0> type; 148 }; 149 }; 150 151 template<typename Tag> 152 struct end_impl; 153 154 template<> 155 struct end_impl<mpl::string_tag> 156 { 157 template<typename Sequence> 158 struct apply; 159 160 #define M0(z,n,data) \ 161 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C)> \ 162 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)> > \ 163 { \ 164 typedef mpl::string_iterator<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, n, 0> type; \ 165 }; 166 167 BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_MPL_STRING_MAX_PARAMS), M0, ~) 168 #undef M0 169 }; 170 171 template<> 172 struct end_impl<mpl::string_tag>::apply<mpl::string<> > 173 { 174 typedef mpl::string_iterator<mpl::string<>, 0, 0> type; 175 }; 176 177 template<typename Tag> 178 struct push_back_impl; 179 180 template<> 181 struct push_back_impl<mpl::string_tag> 182 { 183 template<typename Sequence, typename Value, bool B = (4==BOOST_MPL_MULTICHAR_LENGTH(Sequence::back_))> 184 struct apply 185 { 186 BOOST_MPL_ASSERT_MSG( 187 (BOOST_MPL_LIMIT_STRING_SIZE != mpl::size<Sequence>::type::value) 188 , PUSH_BACK_FAILED_MPL_STRING_IS_FULL 189 , (Sequence) 190 ); 191 // If the above assertion didn't fire, then the string is sparse. 192 // Repack the string and retry the push_back 193 typedef 194 typename mpl::push_back< 195 typename mpl::copy< 196 Sequence 197 , mpl::back_inserter<mpl::string<> > 198 >::type 199 , Value 200 >::type 201 type; 202 }; 203 204 template<typename Value> 205 struct apply<mpl::string<>, Value, false> 206 { 207 typedef mpl::string<(char)Value::value> type; 208 }; 209 210 #define M0(z,n,data) \ 211 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C), typename Value> \ 212 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, Value, false> \ 213 { \ 214 typedef \ 215 mpl::string< \ 216 BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_DEC(n), C) \ 217 BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) \ 218 ((unsigned)BOOST_PP_CAT(C,BOOST_PP_DEC(n))>0xffffff) \ 219 ?BOOST_PP_CAT(C,BOOST_PP_DEC(n)) \ 220 :BOOST_MPL_MULTICHAR_PUSH_BACK(BOOST_PP_CAT(C,BOOST_PP_DEC(n)), Value::value) \ 221 , ((unsigned)BOOST_PP_CAT(C,BOOST_PP_DEC(n))>0xffffff) \ 222 ?(char)Value::value \ 223 :0 \ 224 > \ 225 type; \ 226 }; 227 228 BOOST_PP_REPEAT_FROM_TO(1, BOOST_MPL_STRING_MAX_PARAMS, M0, ~) 229 #undef M0 230 231 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C), typename Value> 232 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, Value, false> 233 { 234 typedef 235 mpl::string< 236 BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS), C) 237 , BOOST_MPL_MULTICHAR_PUSH_BACK(BOOST_PP_CAT(C,BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS)), Value::value) 238 > 239 type; 240 }; 241 }; 242 243 template<typename Tag> 244 struct has_push_back_impl; 245 246 template<> 247 struct has_push_back_impl<mpl::string_tag> 248 { 249 template<typename Sequence> 250 struct apply 251 : mpl::true_ 252 {}; 253 }; 254 255 template<typename Tag> 256 struct pop_back_impl; 257 258 template<> 259 struct pop_back_impl<mpl::string_tag> 260 { 261 template<typename Sequence> 262 struct apply; 263 264 #define M0(z,n,data) \ 265 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C)> \ 266 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)> > \ 267 { \ 268 BOOST_MPL_ASSERT_MSG((C0 != 0), POP_BACK_FAILED_MPL_STRING_IS_EMPTY, (mpl::string<>)); \ 269 typedef \ 270 mpl::string< \ 271 BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_DEC(n), C) \ 272 BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) \ 273 BOOST_MPL_MULTICHAR_POP_BACK(BOOST_PP_CAT(C,BOOST_PP_DEC(n))) \ 274 > \ 275 type; \ 276 }; 277 278 BOOST_PP_REPEAT_FROM_TO(1, BOOST_PP_INC(BOOST_MPL_STRING_MAX_PARAMS), M0, ~) 279 #undef M0 280 }; 281 282 template<typename Tag> 283 struct has_pop_back_impl; 284 285 template<> 286 struct has_pop_back_impl<mpl::string_tag> 287 { 288 template<typename Sequence> 289 struct apply 290 : mpl::true_ 291 {}; 292 }; 293 294 template<typename Tag> 295 struct push_front_impl; 296 297 template<> 298 struct push_front_impl<mpl::string_tag> 299 { 300 template<typename Sequence, typename Value, bool B = (4==BOOST_MPL_MULTICHAR_LENGTH(Sequence::front_))> 301 struct apply 302 { 303 BOOST_MPL_ASSERT_MSG( 304 (BOOST_MPL_LIMIT_STRING_SIZE != mpl::size<Sequence>::type::value) 305 , PUSH_FRONT_FAILED_MPL_STRING_IS_FULL 306 , (Sequence) 307 ); 308 // If the above assertion didn't fire, then the string is sparse. 309 // Repack the string and retry the push_front. 310 typedef 311 typename mpl::push_front< 312 typename mpl::reverse_copy< 313 Sequence 314 , mpl::front_inserter<string<> > 315 >::type 316 , Value 317 >::type 318 type; 319 }; 320 321 #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) 322 template<typename Value> 323 struct apply<mpl::string<>, Value, false> 324 { 325 typedef mpl::string<(char)Value::value> type; 326 }; 327 #endif 328 329 #define M0(z,n,data) \ 330 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C), typename Value> \ 331 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, Value, true> \ 332 { \ 333 typedef \ 334 mpl::string< \ 335 (char)Value::value \ 336 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, C) \ 337 > \ 338 type; \ 339 }; 340 341 BOOST_PP_REPEAT_FROM_TO(1, BOOST_MPL_STRING_MAX_PARAMS, M0, ~) 342 #undef M0 343 344 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C), typename Value> 345 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, Value, false> 346 { 347 typedef 348 mpl::string< 349 BOOST_MPL_MULTICHAR_PUSH_FRONT(C0, Value::value) 350 , BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C) 351 > 352 type0; 353 354 #if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) 355 typedef 356 typename mpl::if_< 357 mpl::empty<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)> > 358 , mpl::string<(char)Value::value> 359 , type0 360 >::type 361 type; 362 #else 363 typedef type0 type; 364 #endif 365 }; 366 }; 367 368 template<typename Tag> 369 struct has_push_front_impl; 370 371 template<> 372 struct has_push_front_impl<mpl::string_tag> 373 { 374 template<typename Sequence> 375 struct apply 376 : mpl::true_ 377 {}; 378 }; 379 380 template<typename Tag> 381 struct pop_front_impl; 382 383 template<> 384 struct pop_front_impl<mpl::string_tag> 385 { 386 template<typename Sequence, bool B = (1==BOOST_MPL_MULTICHAR_LENGTH(Sequence::front_))> 387 struct apply; 388 389 #define M0(z,n,data) \ 390 template<BOOST_PP_ENUM_PARAMS_Z(z, n, int C)> \ 391 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS_Z(z, n, C)>, true> \ 392 { \ 393 BOOST_MPL_ASSERT_MSG((C0 != 0), POP_FRONT_FAILED_MPL_STRING_IS_EMPTY, (mpl::string<>)); \ 394 typedef \ 395 mpl::string<BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, C)> \ 396 type; \ 397 }; 398 399 BOOST_PP_REPEAT_FROM_TO(1, BOOST_MPL_STRING_MAX_PARAMS, M0, ~) 400 #undef M0 401 402 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C)> 403 struct apply<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, false> 404 { 405 typedef 406 mpl::string< 407 BOOST_MPL_MULTICHAR_POP_FRONT(C0) 408 , BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C) 409 > 410 type; 411 }; 412 }; 413 414 template<typename Tag> 415 struct has_pop_front_impl; 416 417 template<> 418 struct has_pop_front_impl<mpl::string_tag> 419 { 420 template<typename Sequence> 421 struct apply 422 : mpl::true_ 423 {}; 424 }; 425 426 template<typename Tag> 427 struct insert_range_impl; 428 429 template<> 430 struct insert_range_impl<mpl::string_tag> 431 { 432 template<typename Sequence, typename Pos, typename Range> 433 struct apply 434 : mpl::copy< 435 mpl::joint_view< 436 mpl::iterator_range< 437 mpl::string_iterator<Sequence, 0, 0> 438 , Pos 439 > 440 , mpl::joint_view< 441 Range 442 , mpl::iterator_range< 443 Pos 444 , typename mpl::end<Sequence>::type 445 > 446 > 447 > 448 , mpl::back_inserter<mpl::string<> > 449 > 450 {}; 451 }; 452 453 template<typename Tag> 454 struct insert_impl; 455 456 template<> 457 struct insert_impl<mpl::string_tag> 458 { 459 template<typename Sequence, typename Pos, typename Value> 460 struct apply 461 : mpl::insert_range<Sequence, Pos, mpl::string<(char)Value::value> > 462 {}; 463 }; 464 465 template<typename Tag> 466 struct erase_impl; 467 468 template<> 469 struct erase_impl<mpl::string_tag> 470 { 471 template<typename Sequence, typename First, typename Last> 472 struct apply 473 : mpl::copy< 474 mpl::joint_view< 475 mpl::iterator_range< 476 mpl::string_iterator<Sequence, 0, 0> 477 , First 478 > 479 , mpl::iterator_range< 480 typename mpl::if_na<Last, typename mpl::next<First>::type>::type 481 , typename mpl::end<Sequence>::type 482 > 483 > 484 , mpl::back_inserter<mpl::string<> > 485 > 486 {}; 487 }; 488 489 template<typename Tag> 490 struct clear_impl; 491 492 template<> 493 struct clear_impl<mpl::string_tag> 494 { 495 template<typename> 496 struct apply 497 { 498 typedef mpl::string<> type; 499 }; 500 }; 501 502 #define M0(z, n, data) \ 503 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C), int J> \ 504 struct string_iterator<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, n, J> \ 505 { \ 506 enum { eomc_ = (BOOST_MPL_MULTICHAR_LENGTH(BOOST_PP_CAT(C, n)) == J + 1) }; \ 507 typedef mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)> string; \ 508 typedef std::bidirectional_iterator_tag category; \ 509 typedef \ 510 mpl::string_iterator<string, n + eomc_, eomc_ ? 0 : J + 1> \ 511 next; \ 512 typedef \ 513 mpl::string_iterator<string, n, J - 1> \ 514 prior; \ 515 typedef mpl::char_<BOOST_MPL_MULTICHAR_AT(BOOST_PP_CAT(C, n), J)> type; \ 516 }; \ 517 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C)> \ 518 struct string_iterator<mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)>, n, 0> \ 519 { \ 520 enum { eomc_ = (BOOST_MPL_MULTICHAR_LENGTH(BOOST_PP_CAT(C, n)) == 1) }; \ 521 typedef mpl::string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, C)> string; \ 522 typedef std::bidirectional_iterator_tag category; \ 523 typedef \ 524 mpl::string_iterator<string, n + eomc_, !eomc_> \ 525 next; \ 526 typedef \ 527 mpl::string_iterator< \ 528 string \ 529 , n - 1 \ 530 , BOOST_MPL_MULTICHAR_LENGTH(BOOST_PP_CAT(C, BOOST_PP_DEC(n))) - 1 \ 531 > \ 532 prior; \ 533 typedef mpl::char_<BOOST_MPL_MULTICHAR_AT(BOOST_PP_CAT(C, n), 0)> type; \ 534 }; 535 536 BOOST_PP_REPEAT(BOOST_MPL_STRING_MAX_PARAMS, M0, ~) 537 #undef M0 538 539 template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, int C)> 540 struct string 541 { 542 /// INTERNAL ONLY 543 enum 544 { 545 front_ = C0 546 , back_ = BOOST_PP_CAT(C, BOOST_PP_DEC(BOOST_MPL_STRING_MAX_PARAMS)) 547 }; 548 549 typedef char value_type; 550 typedef string type; 551 typedef string_tag tag; 552 }; 553 554 namespace aux_ 555 { 556 template<typename It, typename End> 557 struct next_unless 558 : mpl::next<It> 559 {}; 560 561 template<typename End> 562 struct next_unless<End, End> 563 { 564 typedef End type; 565 }; 566 567 template<typename It, typename End> 568 struct deref_unless 569 : mpl::deref<It> 570 {}; 571 572 template<typename End> 573 struct deref_unless<End, End> 574 { 575 typedef mpl::char_<'\0'> type; 576 }; 577 } 578 579 template<typename Sequence> 580 struct c_str 581 { 582 typedef typename mpl::end<Sequence>::type iend; 583 typedef typename mpl::begin<Sequence>::type i0; 584 #define M0(z, n, data) \ 585 typedef \ 586 typename mpl::aux_::next_unless<BOOST_PP_CAT(i, n), iend>::type \ 587 BOOST_PP_CAT(i, BOOST_PP_INC(n)); 588 BOOST_PP_REPEAT(BOOST_MPL_LIMIT_STRING_SIZE, M0, ~) 589 #undef M0 590 591 typedef c_str type; 592 static typename Sequence::value_type const value[BOOST_MPL_LIMIT_STRING_SIZE+1]; 593 }; 594 595 template<typename Sequence> 596 typename Sequence::value_type const c_str<Sequence>::value[BOOST_MPL_LIMIT_STRING_SIZE+1] = 597 { 598 #define M0(z, n, data) \ 599 mpl::aux_::deref_unless<BOOST_PP_CAT(i, n), iend>::type::value, 600 BOOST_PP_REPEAT(BOOST_MPL_LIMIT_STRING_SIZE, M0, ~) 601 #undef M0 602 '\0' 603 }; 604 605 }} // namespace boost 606 607 #endif // BOOST_MPL_STRING_HPP_INCLUDED 608