string.hpp 23 KB

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