xbasic_fixed_string.hpp 99 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436
  1. /***************************************************************************
  2. * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTL_BASIC_FIXED_STRING_HPP
  10. #define XTL_BASIC_FIXED_STRING_HPP
  11. #include <cstddef>
  12. #include <exception>
  13. #include <functional>
  14. #include <iterator>
  15. #include <sstream>
  16. #include <stdexcept>
  17. #include <string>
  18. #include <cassert>
  19. #include <algorithm>
  20. #include <type_traits>
  21. #ifdef __CLING__
  22. #include <nlohmann/json.hpp>
  23. #endif
  24. #include "xhash.hpp"
  25. #include "xtl_config.hpp"
  26. namespace xtl
  27. {
  28. namespace string_policy
  29. {
  30. template <std::size_t>
  31. struct silent_error;
  32. template <std::size_t>
  33. struct throwing_error;
  34. }
  35. /***********************
  36. * xbasic_fixed_string *
  37. ***********************/
  38. enum storage_options
  39. {
  40. buffer = 1 << 0,
  41. pointer = 1 << 1,
  42. store_size = 1 << 2,
  43. is_const = 1 << 3
  44. };
  45. template <class CT, std::size_t N = 55, int ST = buffer | store_size, template <std::size_t> class EP = string_policy::silent_error, class TR = std::char_traits<CT>>
  46. class xbasic_fixed_string;
  47. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  48. std::basic_ostream<CT, TR>& operator<<(std::basic_ostream<CT, TR>& os,
  49. const xbasic_fixed_string<CT, N, ST, EP, TR>& str);
  50. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  51. std::basic_istream<CT, TR>& operator>>(std::basic_istream<CT, TR>& is,
  52. xbasic_fixed_string<CT, N, ST, EP, TR>& str);
  53. template <class CT>
  54. using xbasic_string_view = xbasic_fixed_string<const CT, 0, pointer | store_size | is_const>;
  55. namespace detail
  56. {
  57. template <int selector>
  58. struct select_storage;
  59. template <typename T>
  60. struct fixed_small_string_storage_impl;
  61. template <class T, std::size_t N>
  62. struct fixed_small_string_storage_impl<T[N]>
  63. {
  64. static_assert(N <= (1u << (8 * sizeof(T))), "small string");
  65. fixed_small_string_storage_impl()
  66. {
  67. set_size(0);
  68. }
  69. fixed_small_string_storage_impl(T ptr[N], std::size_t size)
  70. : m_buffer(ptr)
  71. {
  72. m_buffer[N - 1] = N - size;
  73. }
  74. T* buffer()
  75. {
  76. return m_buffer;
  77. }
  78. const T* buffer() const
  79. {
  80. return m_buffer;
  81. }
  82. std::size_t size() const
  83. {
  84. // Don't use std::make_unsinged_t here, this should remain C++11 compatible
  85. using unsigned_type = typename std::make_unsigned<T>::type;
  86. return N - reinterpret_cast<unsigned_type const*>(m_buffer)[N - 1];
  87. }
  88. void set_size(std::size_t sz)
  89. {
  90. assert(sz < N && "setting a small size");
  91. // Don't use std::make_unsinged_t here, this should remain C++11 compatible
  92. using unsigned_type = typename std::make_unsigned<T>::type;
  93. reinterpret_cast<unsigned_type*>(m_buffer)[N - 1] = static_cast<unsigned_type>(N - sz);
  94. m_buffer[sz] = '\0';
  95. }
  96. void adjust_size(std::ptrdiff_t val)
  97. {
  98. assert(size() + val >= 0 && "adjusting to positive size");
  99. set_size(static_cast<std::size_t>(static_cast<std::ptrdiff_t>(size()) + val));
  100. }
  101. T m_buffer[N];
  102. };
  103. template <class T>
  104. struct fixed_string_storage_impl
  105. {
  106. fixed_string_storage_impl() = default;
  107. fixed_string_storage_impl(T ptr, std::size_t size)
  108. : m_buffer(ptr), m_size(size)
  109. {
  110. }
  111. T& buffer()
  112. {
  113. return m_buffer;
  114. }
  115. const T& buffer() const
  116. {
  117. return m_buffer;
  118. }
  119. std::size_t size() const
  120. {
  121. return m_size;
  122. }
  123. void set_size(std::size_t sz)
  124. {
  125. m_size = sz;
  126. m_buffer[sz] = '\0';
  127. }
  128. void adjust_size(std::ptrdiff_t val)
  129. {
  130. m_size += std::size_t(val);
  131. m_buffer[m_size] = '\0';
  132. }
  133. T m_buffer;
  134. std::size_t m_size;
  135. };
  136. template <class T>
  137. struct fixed_string_external_storage_impl
  138. {
  139. fixed_string_external_storage_impl() = default;
  140. fixed_string_external_storage_impl(T ptr, std::ptrdiff_t/*size*/)
  141. {
  142. m_buffer = ptr;
  143. }
  144. T& buffer()
  145. {
  146. return m_buffer;
  147. }
  148. const T& buffer() const
  149. {
  150. return m_buffer;
  151. }
  152. void set_size(std::size_t sz)
  153. {
  154. m_buffer[sz] = '\0';
  155. }
  156. void adjust_size(std::ptrdiff_t val)
  157. {
  158. m_buffer[size() + val] = '\0';
  159. }
  160. std::size_t size() const
  161. {
  162. return std::strlen(m_buffer);
  163. }
  164. T m_buffer;
  165. };
  166. template <class T, bool Small>
  167. struct select_fixed_storage {
  168. using type = fixed_string_storage_impl<T>;
  169. };
  170. template <class T>
  171. struct select_fixed_storage<T, true> {
  172. using type = fixed_small_string_storage_impl<T>;
  173. };
  174. template <>
  175. struct select_storage<buffer | store_size>
  176. {
  177. template <class T, std::size_t N>
  178. using type = typename select_fixed_storage<T[N + 1], N < (1u << (8 * sizeof(T)))>::type;
  179. };
  180. template <>
  181. struct select_storage<buffer>
  182. {
  183. template <class T, std::size_t N>
  184. using type = fixed_string_external_storage_impl<T[N + 1]>;
  185. };
  186. }
  187. template <class CT,
  188. std::size_t N,
  189. int ST,
  190. template <std::size_t> class EP,
  191. class TR>
  192. class xbasic_fixed_string
  193. {
  194. public:
  195. using traits_type = TR;
  196. using value_type = CT;
  197. using size_type = std::size_t;
  198. using difference_type = std::ptrdiff_t;
  199. using storage_type = typename detail::select_storage<ST>::template type<CT, N>;
  200. using reference = value_type&;
  201. using const_reference = const value_type&;
  202. using pointer = value_type*;
  203. using const_pointer = const value_type*;
  204. using iterator = pointer;
  205. using const_iterator = const_pointer;
  206. using reverse_iterator = std::reverse_iterator<iterator>;
  207. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  208. static const size_type npos;
  209. using self_type = xbasic_fixed_string;
  210. using initializer_type = std::initializer_list<value_type>;
  211. using string_type = std::basic_string<value_type, traits_type>;
  212. using error_policy = EP<N>;
  213. xbasic_fixed_string();
  214. explicit xbasic_fixed_string(size_type count, value_type ch);
  215. explicit xbasic_fixed_string(const self_type& other,
  216. size_type pos,
  217. size_type count = npos);
  218. explicit xbasic_fixed_string(const string_type& other);
  219. explicit xbasic_fixed_string(const string_type& other,
  220. size_type pos,
  221. size_type count = npos);
  222. xbasic_fixed_string(const_pointer s, size_type count);
  223. xbasic_fixed_string(const_pointer s);
  224. xbasic_fixed_string(initializer_type ilist);
  225. template <class InputIt>
  226. xbasic_fixed_string(InputIt first, InputIt last);
  227. operator string_type() const;
  228. ~xbasic_fixed_string() = default;
  229. xbasic_fixed_string(const self_type&) = default;
  230. xbasic_fixed_string(self_type&&) = default;
  231. self_type& operator=(const self_type&) = default;
  232. self_type& operator=(self_type&&) = default;
  233. self_type& operator=(const_pointer s);
  234. self_type& operator=(value_type ch);
  235. self_type& operator=(initializer_type ilist);
  236. self_type& operator=(const string_type& str);
  237. self_type& assign(size_type count, value_type ch);
  238. self_type& assign(const self_type& other,
  239. size_type pos,
  240. size_type count = npos);
  241. self_type& assign(const_pointer s, size_type count);
  242. self_type& assign(const_pointer s);
  243. self_type& assign(initializer_type ilist);
  244. template <class InputIt>
  245. self_type& assign(InputIt first, InputIt last);
  246. self_type& assign(const self_type& rhs);
  247. self_type& assign(self_type&& rhs);
  248. self_type& assign(const string_type& str);
  249. self_type& assign(const string_type& other,
  250. size_type pos,
  251. size_type count = npos);
  252. reference at(size_type pos);
  253. const_reference at(size_type pos) const;
  254. reference operator[](size_type pos);
  255. const_reference operator[](size_type pos) const;
  256. reference front();
  257. const_reference front() const;
  258. reference back();
  259. const_reference back() const;
  260. pointer data() noexcept;
  261. const_pointer data() const noexcept;
  262. const_pointer c_str() const noexcept;
  263. iterator begin() noexcept;
  264. iterator end() noexcept;
  265. const_iterator begin() const noexcept;
  266. const_iterator end() const noexcept;
  267. const_iterator cbegin() const noexcept;
  268. const_iterator cend() const noexcept;
  269. reverse_iterator rbegin() noexcept;
  270. reverse_iterator rend() noexcept;
  271. const_reverse_iterator rbegin() const noexcept;
  272. const_reverse_iterator rend() const noexcept;
  273. const_reverse_iterator crbegin() const noexcept;
  274. const_reverse_iterator crend() const noexcept;
  275. bool empty() const noexcept;
  276. size_type size() const noexcept;
  277. size_type length() const noexcept;
  278. size_type max_size() const noexcept;
  279. void clear() noexcept;
  280. void push_back(value_type ch);
  281. void pop_back();
  282. self_type substr(size_type pos = 0, size_type count = npos) const;
  283. size_type copy(pointer dest, size_type count, size_type pos = 0) const;
  284. void resize(size_type count);
  285. void resize(size_type count, value_type ch);
  286. void swap(self_type& rhs) noexcept;
  287. self_type& insert(size_type index, size_type count, value_type ch);
  288. self_type& insert(size_type index, const_pointer s);
  289. self_type& insert(size_type index, const_pointer s, size_type count);
  290. self_type& insert(size_type index, const self_type& str);
  291. self_type& insert(size_type index, const self_type& str,
  292. size_type index_str, size_type count = npos);
  293. self_type& insert(size_type index, const string_type& str);
  294. self_type& insert(size_type index, const string_type& str,
  295. size_type index_str, size_type count = npos);
  296. iterator insert(const_iterator pos, value_type ch);
  297. iterator insert(const_iterator pos, size_type count, value_type ch);
  298. iterator insert(const_iterator pos, initializer_type ilist);
  299. template <class InputIt>
  300. iterator insert(const_iterator pos, InputIt first, InputIt last);
  301. self_type& erase(size_type index = 0, size_type count = npos);
  302. iterator erase(const_iterator position);
  303. iterator erase(const_iterator first, const_iterator last);
  304. self_type& append(size_type count, value_type ch);
  305. self_type& append(const self_type& str);
  306. self_type& append(const self_type& str,
  307. size_type pos, size_type count = npos);
  308. self_type& append(const string_type& str);
  309. self_type& append(const string_type& str,
  310. size_type pos, size_type count = npos);
  311. self_type& append(const_pointer s, size_type count);
  312. self_type& append(const_pointer s);
  313. self_type& append(initializer_type ilist);
  314. template <class InputIt>
  315. self_type& append(InputIt first, InputIt last);
  316. self_type& operator+=(const self_type& str);
  317. self_type& operator+=(const string_type& str);
  318. self_type& operator+=(value_type ch);
  319. self_type& operator+=(const_pointer s);
  320. self_type& operator+=(initializer_type ilist);
  321. int compare(const self_type& str) const noexcept;
  322. int compare(size_type pos1, size_type count1, const self_type& str) const;
  323. int compare(size_type pos1, size_type count1, const self_type& str,
  324. size_type pos2, size_type count2 = npos) const;
  325. int compare(const string_type& str) const noexcept;
  326. int compare(size_type pos1, size_type count1, const string_type& str) const;
  327. int compare(size_type pos1, size_type count1, const string_type& str,
  328. size_type pos2, size_type count2 = npos) const;
  329. int compare(const_pointer s) const noexcept;
  330. int compare(size_type pos1, size_type count1, const_pointer s) const;
  331. int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const;
  332. self_type& replace(size_type pos, size_type count, const self_type& str);
  333. self_type& replace(const_iterator first, const_iterator last, const self_type& str);
  334. self_type& replace(size_type pos1, size_type count1, const self_type& str,
  335. size_type pos2, size_type count2 = npos);
  336. self_type& replace(size_type pos, size_type count, const string_type& str);
  337. self_type& replace(const_iterator first, const_iterator last, const string_type& str);
  338. self_type& replace(size_type pos1, size_type count1, const string_type& str,
  339. size_type pos2, size_type count2 = npos);
  340. self_type& replace(size_type pos, size_type count, const_pointer cstr, size_type count2);
  341. self_type& replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count2);
  342. self_type& replace(size_type pos, size_type count, const_pointer cstr);
  343. self_type& replace(const_iterator first, const_iterator last, const_pointer cstr);
  344. self_type& replace(size_type pos, size_type count, size_type count2, value_type ch);
  345. self_type& replace(const_iterator first, const_iterator last, size_type count2, value_type ch);
  346. self_type& replace(const_iterator first, const_iterator last, initializer_type ilist);
  347. template <class InputIt>
  348. self_type& replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2);
  349. size_type find(const self_type& str, size_type pos = 0) const noexcept;
  350. size_type find(const string_type& str, size_type pos = 0) const noexcept;
  351. size_type find(const_pointer s, size_type pos, size_type count) const;
  352. size_type find(const_pointer s, size_type pos = 0) const;
  353. size_type find(value_type ch, size_type pos = 0) const;
  354. size_type rfind(const self_type& str, size_type pos = npos) const noexcept;
  355. size_type rfind(const string_type& str, size_type pos = npos) const noexcept;
  356. size_type rfind(const_pointer s, size_type pos, size_type count) const;
  357. size_type rfind(const_pointer s, size_type pos = npos) const;
  358. size_type rfind(value_type ch, size_type pos = npos) const;
  359. size_type find_first_of(const self_type& str, size_type pos = 0) const noexcept;
  360. size_type find_first_of(const string_type& str, size_type pos = 0) const noexcept;
  361. size_type find_first_of(const_pointer s, size_type pos, size_type count) const;
  362. size_type find_first_of(const_pointer s, size_type pos = 0) const;
  363. size_type find_first_of(value_type ch, size_type pos = 0) const;
  364. size_type find_first_not_of(const self_type& str, size_type pos = 0) const noexcept;
  365. size_type find_first_not_of(const string_type& str, size_type pos = 0) const noexcept;
  366. size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const;
  367. size_type find_first_not_of(const_pointer s, size_type pos = 0) const;
  368. size_type find_first_not_of(value_type ch, size_type pos = 0) const;
  369. size_type find_last_of(const self_type& str, size_type pos = 0) const noexcept;
  370. size_type find_last_of(const string_type& str, size_type pos = 0) const noexcept;
  371. size_type find_last_of(const_pointer s, size_type pos, size_type count) const;
  372. size_type find_last_of(const_pointer s, size_type pos = 0) const;
  373. size_type find_last_of(value_type ch, size_type pos = 0) const;
  374. size_type find_last_not_of(const self_type& str, size_type pos = npos) const noexcept;
  375. size_type find_last_not_of(const string_type& str, size_type pos = npos) const noexcept;
  376. size_type find_last_not_of(const_pointer s, size_type pos, size_type count) const;
  377. size_type find_last_not_of(const_pointer s, size_type pos = npos) const;
  378. size_type find_last_not_of(value_type ch, size_type pos = npos) const;
  379. private:
  380. int compare_impl(const_pointer s1, size_type count1, const_pointer s2, size_type count2) const noexcept;
  381. void update_null_termination() noexcept;
  382. void check_index(size_type pos, size_type size, const char* what) const;
  383. void check_index_strict(size_type pos, size_type size, const char* what) const;
  384. storage_type m_storage;
  385. };
  386. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  387. const typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type xbasic_fixed_string<CT, N, ST, EP, TR>::npos
  388. = std::basic_string<value_type, traits_type>::npos;
  389. template <std::size_t N>
  390. using xfixed_string = xbasic_fixed_string<char, N>;
  391. template <std::size_t N>
  392. using xwfixed_string = xbasic_fixed_string<wchar_t, N>;
  393. template <std::size_t N>
  394. using xu16fixed_string = xbasic_fixed_string<char16_t, N>;
  395. template <std::size_t N>
  396. using xu32fixed_string = xbasic_fixed_string<char32_t, N>;
  397. /**************************
  398. * Concatenation operator *
  399. **************************/
  400. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  401. xbasic_fixed_string<CT, N, ST, EP, TR>
  402. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  403. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
  404. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  405. xbasic_fixed_string<CT, N, ST, EP, TR>
  406. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  407. const CT* rhs);
  408. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  409. xbasic_fixed_string<CT, N, ST, EP, TR>
  410. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  411. CT rhs);
  412. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  413. xbasic_fixed_string<CT, N, ST, EP, TR>
  414. operator+(const CT* lhs,
  415. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
  416. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  417. xbasic_fixed_string<CT, N, ST, EP, TR>
  418. operator+(CT lhs,
  419. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
  420. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  421. xbasic_fixed_string<CT, N, ST, EP, TR>
  422. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  423. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
  424. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  425. xbasic_fixed_string<CT, N, ST, EP, TR>
  426. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  427. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
  428. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  429. xbasic_fixed_string<CT, N, ST, EP, TR>
  430. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  431. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
  432. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  433. xbasic_fixed_string<CT, N, ST, EP, TR>
  434. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  435. const CT* rhs);
  436. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  437. xbasic_fixed_string<CT, N, ST, EP, TR>
  438. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  439. CT rhs);
  440. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  441. xbasic_fixed_string<CT, N, ST, EP, TR>
  442. operator+(const CT* lhs,
  443. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
  444. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  445. xbasic_fixed_string<CT, N, ST, EP, TR>
  446. operator+(CT lhs,
  447. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs);
  448. /************************
  449. * Comparison operators *
  450. ************************/
  451. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  452. bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  453. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  454. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  455. bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  456. const CT* rhs) noexcept;
  457. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  458. bool operator==(const CT* lhs,
  459. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  460. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  461. bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  462. const std::basic_string<CT, TR>& rhs) noexcept;
  463. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  464. bool operator==(const std::basic_string<CT, TR>& lhs,
  465. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  466. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  467. bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  468. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  469. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  470. bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  471. const CT* rhs) noexcept;
  472. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  473. bool operator!=(const CT* lhs,
  474. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  475. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  476. bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  477. const std::basic_string<CT, TR>& rhs) noexcept;
  478. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  479. bool operator!=(const std::basic_string<CT, TR>& lhs,
  480. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  481. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  482. bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  483. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  484. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  485. bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  486. const CT* rhs) noexcept;
  487. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  488. bool operator<(const CT* lhs,
  489. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  490. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  491. bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  492. const std::basic_string<CT, TR>& rhs) noexcept;
  493. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  494. bool operator<(const std::basic_string<CT, TR>& lhs,
  495. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  496. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  497. bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  498. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  499. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  500. bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  501. const CT* rhs) noexcept;
  502. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  503. bool operator<=(const CT* lhs,
  504. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  505. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  506. bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  507. const std::basic_string<CT, TR>& rhs) noexcept;
  508. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  509. bool operator<=(const std::basic_string<CT, TR>& lhs,
  510. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  511. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  512. bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  513. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  514. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  515. bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  516. const CT* rhs) noexcept;
  517. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  518. bool operator>(const CT* lhs,
  519. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  520. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  521. bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  522. const std::basic_string<CT, TR>& rhs) noexcept;
  523. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  524. bool operator>(const std::basic_string<CT, TR>& lhs,
  525. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  526. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  527. bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  528. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  529. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  530. bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  531. const CT* rhs) noexcept;
  532. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  533. bool operator>=(const CT* lhs,
  534. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  535. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  536. bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  537. const std::basic_string<CT, TR>& rhs) noexcept;
  538. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  539. bool operator>=(const std::basic_string<CT, TR>& lhs,
  540. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept;
  541. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  542. void swap(xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  543. xbasic_fixed_string<CT, N, ST, EP, TR>& rhs);
  544. /******************************
  545. * Input / output declaration *
  546. ******************************/
  547. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  548. std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
  549. xbasic_fixed_string<CT, N, ST, EP, TR>& str,
  550. CT delim);
  551. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  552. std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
  553. xbasic_fixed_string<CT, N, ST, EP, TR>& str,
  554. CT delim);
  555. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  556. std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
  557. xbasic_fixed_string<CT, N, ST, EP, TR>& str);
  558. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  559. std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
  560. xbasic_fixed_string<CT, N, ST, EP, TR>& str);
  561. } // namespace xtl
  562. namespace std
  563. {
  564. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  565. struct hash<::xtl::xbasic_fixed_string<CT, N, ST, EP, TR>>
  566. {
  567. using argument_type = ::xtl::xbasic_fixed_string<CT, N, ST, EP, TR>;
  568. using result_type = std::size_t;
  569. inline result_type operator()(const argument_type& arg) const
  570. {
  571. return ::xtl::hash_bytes(arg.data(), arg.size(), static_cast<std::size_t>(0xc70f6907UL));
  572. }
  573. };
  574. } // namespace std
  575. namespace xtl
  576. {
  577. /********************************
  578. * xbasic_fixed_string policies *
  579. ********************************/
  580. namespace string_policy
  581. {
  582. template <std::size_t N>
  583. struct silent_error
  584. {
  585. inline static std::size_t check_size(std::size_t size)
  586. {
  587. return size;
  588. }
  589. inline static std::size_t check_add(std::size_t size1, std::size_t size2)
  590. {
  591. return size1 + size2;
  592. }
  593. };
  594. template <std::size_t N>
  595. struct throwing_error
  596. {
  597. inline static std::size_t check_size(std::size_t size)
  598. {
  599. if (size > N)
  600. {
  601. std::ostringstream oss;
  602. oss << "Invalid size (" << size << ") for xbasic_fixed_string - maximal size: " << N;
  603. #if defined(XTL_NO_EXCEPTIONS)
  604. std::fprintf(stderr, "%s\n", oss.str().c_str());
  605. std::terminate();
  606. #else
  607. throw std::length_error(oss.str());
  608. #endif
  609. }
  610. return size;
  611. }
  612. inline static std::size_t check_add(std::size_t size1, std::size_t size2)
  613. {
  614. return check_size(size1 + size2);
  615. }
  616. };
  617. } // string_policy
  618. /**************************************
  619. * xbasic_fixed_string implementation *
  620. **************************************/
  621. /****************
  622. * Constructors *
  623. ****************/
  624. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  625. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string()
  626. : m_storage()
  627. {
  628. }
  629. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  630. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(size_type count, value_type ch)
  631. : m_storage()
  632. {
  633. assign(count, ch);
  634. }
  635. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  636. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const self_type& other,
  637. size_type pos,
  638. size_type count)
  639. : m_storage()
  640. {
  641. assign(other, pos, count);
  642. }
  643. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  644. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const string_type& other)
  645. : m_storage()
  646. {
  647. assign(other);
  648. }
  649. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  650. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const string_type& other,
  651. size_type pos,
  652. size_type count)
  653. : m_storage()
  654. {
  655. assign(other, pos, count);
  656. }
  657. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  658. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const_pointer s, size_type count)
  659. : m_storage()
  660. {
  661. assign(s, count);
  662. }
  663. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  664. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(const_pointer s)
  665. : m_storage()
  666. {
  667. assign(s);
  668. }
  669. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  670. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(initializer_type ilist)
  671. : m_storage()
  672. {
  673. assign(ilist);
  674. }
  675. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  676. template <class InputIt>
  677. inline xbasic_fixed_string<CT, N, ST, EP, TR>::xbasic_fixed_string(InputIt first, InputIt last)
  678. : m_storage()
  679. {
  680. assign(first, last);
  681. }
  682. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  683. inline xbasic_fixed_string<CT, N, ST, EP, TR>::operator string_type() const
  684. {
  685. return string_type(data());
  686. }
  687. /**************
  688. * Assignment *
  689. **************/
  690. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  691. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(const_pointer s) -> self_type&
  692. {
  693. return assign(s);
  694. }
  695. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  696. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(value_type ch) -> self_type&
  697. {
  698. return assign(size_type(1), ch);
  699. }
  700. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  701. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(initializer_type ilist) -> self_type&
  702. {
  703. return assign(ilist);
  704. }
  705. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  706. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator=(const string_type& str) -> self_type&
  707. {
  708. return assign(str);
  709. }
  710. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  711. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(size_type count, value_type ch) -> self_type&
  712. {
  713. m_storage.set_size(error_policy::check_size(count));
  714. traits_type::assign(data(), count, ch);
  715. return *this;
  716. }
  717. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  718. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const self_type& other,
  719. size_type pos,
  720. size_type count) -> self_type&
  721. {
  722. check_index_strict(pos, other.size(), "xbasic_fixed_string::assign");
  723. size_type copy_count = std::min(other.size() - pos, count);
  724. m_storage.set_size(error_policy::check_size(copy_count));
  725. traits_type::copy(data(), other.data() + pos, copy_count);
  726. return *this;
  727. }
  728. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  729. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const_pointer s, size_type count) -> self_type&
  730. {
  731. m_storage.set_size(error_policy::check_size(count));
  732. traits_type::copy(data(), s, count);
  733. return *this;
  734. }
  735. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  736. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const_pointer s) -> self_type&
  737. {
  738. std::size_t ssize = traits_type::length(s);
  739. return assign(s, ssize);
  740. }
  741. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  742. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(initializer_type ilist) -> self_type&
  743. {
  744. return assign(ilist.begin(), ilist.end());
  745. }
  746. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  747. template <class InputIt>
  748. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(InputIt first, InputIt last) -> self_type&
  749. {
  750. m_storage.set_size(error_policy::check_size(static_cast<size_type>(std::distance(first, last))));
  751. std::copy(first, last, data());
  752. return *this;
  753. }
  754. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  755. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const self_type& rhs) -> self_type&
  756. {
  757. if (this != &rhs)
  758. {
  759. m_storage.set_size(rhs.size());
  760. traits_type::copy(data(), rhs.data(), rhs.size());
  761. }
  762. return *this;
  763. }
  764. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  765. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(self_type&& rhs) -> self_type&
  766. {
  767. if (this != &rhs)
  768. {
  769. m_storage.set_size(rhs.size());
  770. traits_type::copy(data(), rhs.data(), rhs.size());
  771. }
  772. return *this;
  773. }
  774. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  775. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const string_type& other) -> self_type&
  776. {
  777. return assign(other.c_str());
  778. }
  779. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  780. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::assign(const string_type& other,
  781. size_type pos,
  782. size_type count) -> self_type&
  783. {
  784. return assign(other.c_str() + pos, std::min(count, other.size() - pos));
  785. }
  786. /******************
  787. * Element access *
  788. ******************/
  789. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  790. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::at(size_type pos) -> reference
  791. {
  792. check_index(pos, size(), "basic_fixed_string::at");
  793. return this->operator[](pos);
  794. }
  795. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  796. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::at(size_type pos) const -> const_reference
  797. {
  798. check_index(pos, size(), "basic_fixed_string::at");
  799. return this->operator[](pos);
  800. }
  801. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  802. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator[](size_type pos) -> reference
  803. {
  804. return data()[pos];
  805. }
  806. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  807. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator[](size_type pos) const -> const_reference
  808. {
  809. return data()[pos];
  810. }
  811. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  812. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::front() -> reference
  813. {
  814. return this->operator[](0);
  815. }
  816. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  817. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::front() const -> const_reference
  818. {
  819. return this->operator[](0);
  820. }
  821. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  822. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::back() -> reference
  823. {
  824. return this->operator[](size() - 1);
  825. }
  826. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  827. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::back() const -> const_reference
  828. {
  829. return this->operator[](size() - 1);
  830. }
  831. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  832. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::data() noexcept -> pointer
  833. {
  834. return m_storage.buffer();
  835. }
  836. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  837. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::data() const noexcept -> const_pointer
  838. {
  839. return m_storage.buffer();
  840. }
  841. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  842. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::c_str() const noexcept -> const_pointer
  843. {
  844. return m_storage.buffer();
  845. }
  846. /*************
  847. * Iterators *
  848. *************/
  849. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  850. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::begin() noexcept -> iterator
  851. {
  852. return data();
  853. }
  854. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  855. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::end() noexcept -> iterator
  856. {
  857. return data() + size();
  858. }
  859. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  860. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::begin() const noexcept -> const_iterator
  861. {
  862. return cbegin();
  863. }
  864. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  865. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::end() const noexcept -> const_iterator
  866. {
  867. return cend();
  868. }
  869. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  870. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::cbegin() const noexcept -> const_iterator
  871. {
  872. return data();
  873. }
  874. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  875. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::cend() const noexcept -> const_iterator
  876. {
  877. return data() + size();
  878. }
  879. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  880. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rbegin() noexcept -> reverse_iterator
  881. {
  882. return reverse_iterator(end());
  883. }
  884. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  885. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rend() noexcept -> reverse_iterator
  886. {
  887. return reverse_iterator(begin());
  888. }
  889. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  890. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rbegin() const noexcept -> const_reverse_iterator
  891. {
  892. return const_reverse_iterator(end());
  893. }
  894. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  895. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rend() const noexcept -> const_reverse_iterator
  896. {
  897. return const_reverse_iterator(begin());
  898. }
  899. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  900. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::crbegin() const noexcept -> const_reverse_iterator
  901. {
  902. return const_reverse_iterator(end());
  903. }
  904. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  905. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::crend() const noexcept -> const_reverse_iterator
  906. {
  907. return const_reverse_iterator(begin());
  908. }
  909. /************
  910. * Capacity *
  911. ************/
  912. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  913. inline bool xbasic_fixed_string<CT, N, ST, EP, TR>::empty() const noexcept
  914. {
  915. return size() == 0;
  916. }
  917. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  918. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::size() const noexcept -> size_type
  919. {
  920. return m_storage.size();
  921. }
  922. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  923. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::length() const noexcept -> size_type
  924. {
  925. return m_storage.size();
  926. }
  927. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  928. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::max_size() const noexcept -> size_type
  929. {
  930. return N;
  931. }
  932. /**************
  933. * Operations *
  934. **************/
  935. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  936. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::clear() noexcept
  937. {
  938. m_storage.set_size(0);
  939. }
  940. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  941. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::push_back(value_type ch)
  942. {
  943. error_policy::check_add(size(), size_type(1));
  944. data()[size()] = ch;
  945. m_storage.adjust_size(+1);
  946. }
  947. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  948. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::pop_back()
  949. {
  950. m_storage.adjust_size(-1);
  951. }
  952. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  953. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::substr(size_type pos, size_type count) const -> self_type
  954. {
  955. return self_type(*this, pos, count);
  956. }
  957. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  958. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::copy(pointer dest, size_type count, size_type pos) const -> size_type
  959. {
  960. check_index_strict(pos, size(), "xbasic_fixed_string::copy");
  961. size_type nb_copied = std::min(count, size() - pos);
  962. traits_type::copy(dest, data() + pos, nb_copied);
  963. return nb_copied;
  964. }
  965. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  966. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::resize(size_type count)
  967. {
  968. resize(count, value_type(' ')); // need to initialize with some value != \0
  969. }
  970. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  971. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::resize(size_type count, value_type ch)
  972. {
  973. size_type old_size = size();
  974. m_storage.set_size(error_policy::check_size(count));
  975. if (old_size < size())
  976. {
  977. traits_type::assign(data() + old_size, size() - old_size, ch);
  978. }
  979. }
  980. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  981. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::swap(self_type& rhs) noexcept
  982. {
  983. self_type tmp(std::move(rhs));
  984. rhs = std::move(*this);
  985. *this = std::move(tmp);
  986. }
  987. /**********
  988. * insert *
  989. **********/
  990. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  991. auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, size_type count, value_type ch) -> self_type&
  992. {
  993. check_index_strict(index, size(), "xbasic_fixed_string::insert");
  994. size_type old_size = size();
  995. m_storage.set_size(error_policy::check_add(size(), count));
  996. std::copy_backward(data() + index, data() + old_size, end());
  997. traits_type::assign(data() + index, count, ch);
  998. return *this;
  999. }
  1000. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1001. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const_pointer s) -> self_type&
  1002. {
  1003. return insert(index, s, traits_type::length(s));
  1004. }
  1005. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1006. auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const_pointer s, size_type count) -> self_type&
  1007. {
  1008. check_index_strict(index, size(), "xbasic_fixed_string::insert");
  1009. size_type old_size = size();
  1010. m_storage.set_size(error_policy::check_add(size(), count));
  1011. std::copy_backward(data() + index, data() + old_size, end());
  1012. traits_type::copy(data() + index, s, count);
  1013. return *this;
  1014. }
  1015. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1016. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const self_type& str) -> self_type&
  1017. {
  1018. return insert(index, str.data(), str.size());
  1019. }
  1020. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1021. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const self_type& str,
  1022. size_type index_str, size_type count) -> self_type&
  1023. {
  1024. check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert");
  1025. return insert(index, str.data() + index_str, std::min(count, str.size() - index_str));
  1026. }
  1027. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1028. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const string_type& str) -> self_type&
  1029. {
  1030. return insert(index, str.c_str(), str.size());
  1031. }
  1032. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1033. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(size_type index, const string_type& str,
  1034. size_type index_str, size_type count) -> self_type&
  1035. {
  1036. check_index_strict(index_str, str.size(), "xbasic_fixed_string::insert");
  1037. return insert(index, str.c_str() + index_str, std::min(count, str.size() - index_str));
  1038. }
  1039. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1040. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, value_type ch) -> iterator
  1041. {
  1042. return insert(pos, size_type(1), ch);
  1043. }
  1044. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1045. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, size_type count, value_type ch) -> iterator
  1046. {
  1047. if (cbegin() <= pos && pos < cend())
  1048. {
  1049. size_type index = static_cast<size_type>(pos - cbegin());
  1050. insert(index, count, ch);
  1051. return const_cast<iterator>(pos);
  1052. }
  1053. return end();
  1054. }
  1055. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1056. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, initializer_type ilist) -> iterator
  1057. {
  1058. return insert(pos, ilist.begin(), ilist.end());
  1059. }
  1060. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1061. template <class InputIt>
  1062. auto xbasic_fixed_string<CT, N, ST, EP, TR>::insert(const_iterator pos, InputIt first, InputIt last) -> iterator
  1063. {
  1064. if (cbegin() <= pos && pos < cend())
  1065. {
  1066. size_type index = static_cast<size_type>(pos - cbegin());
  1067. size_type count = static_cast<size_type>(std::distance(first, last));
  1068. size_type old_size = size();
  1069. m_storage.set_size(error_policy::check_add(size(), count));
  1070. std::copy_backward(data() + index, data() + old_size, end());
  1071. std::copy(first, last, data() + index);
  1072. return begin() + index;
  1073. }
  1074. return end();
  1075. }
  1076. /*********
  1077. * erase *
  1078. *********/
  1079. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1080. auto xbasic_fixed_string<CT, N, ST, EP, TR>::erase(size_type index, size_type count) -> self_type&
  1081. {
  1082. check_index_strict(index, size(), "xbasic_fixed_string::erase");
  1083. size_type erase_count = std::min(count, size() - index);
  1084. // cannot use traits_type::copy because of overlapping
  1085. std::copy(data() + index + erase_count, data() + size(), data() + index);
  1086. m_storage.adjust_size(-static_cast<std::ptrdiff_t>(erase_count));
  1087. return *this;
  1088. }
  1089. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1090. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::erase(const_iterator position) -> iterator
  1091. {
  1092. return erase(position, position + 1);
  1093. }
  1094. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1095. auto xbasic_fixed_string<CT, N, ST, EP, TR>::erase(const_iterator first, const_iterator last) -> iterator
  1096. {
  1097. if (cbegin() <= first && first < cend())
  1098. {
  1099. const_iterator adapted_last = std::min(last, cend());
  1100. size_type erase_count = static_cast<size_type>(adapted_last - first);
  1101. // cannot use traits_type::copy because of overlapping
  1102. std::copy(adapted_last, cend(), iterator(first));
  1103. m_storage.adjust_size(-static_cast<std::ptrdiff_t>(erase_count));
  1104. return const_cast<iterator>(first);
  1105. }
  1106. return end();
  1107. }
  1108. /**********
  1109. * append *
  1110. **********/
  1111. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1112. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(size_type count, value_type ch) -> self_type&
  1113. {
  1114. size_type old_size = m_storage.size();
  1115. m_storage.set_size(error_policy::check_add(size(), count));
  1116. traits_type::assign(data() + old_size, count, ch);
  1117. return *this;
  1118. }
  1119. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1120. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const self_type& str) -> self_type&
  1121. {
  1122. return append(str.data(), str.size());
  1123. }
  1124. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1125. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const self_type& str,
  1126. size_type pos, size_type count) -> self_type&
  1127. {
  1128. check_index_strict(pos, str.size(), "xbasic_fixed_string::append");
  1129. return append(str.data() + pos, std::min(count, str.size() - pos));
  1130. }
  1131. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1132. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const string_type& str) -> self_type&
  1133. {
  1134. return append(str.c_str(), str.size());
  1135. }
  1136. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1137. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const string_type& str,
  1138. size_type pos, size_type count) -> self_type&
  1139. {
  1140. check_index_strict(pos, str.size(), "xbasic_fixed_string::append");
  1141. return append(str.c_str() + pos, std::min(count, str.size() - pos));
  1142. }
  1143. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1144. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const_pointer s, size_type count) -> self_type&
  1145. {
  1146. size_type old_size = m_storage.size();
  1147. m_storage.set_size(error_policy::check_add(size(), count));
  1148. traits_type::copy(data() + old_size, s, count);
  1149. return *this;
  1150. }
  1151. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1152. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(const_pointer s) -> self_type&
  1153. {
  1154. return append(s, traits_type::length(s));
  1155. }
  1156. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1157. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(initializer_type ilist) -> self_type&
  1158. {
  1159. return append(ilist.begin(), ilist.end());
  1160. }
  1161. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1162. template <class InputIt>
  1163. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::append(InputIt first, InputIt last) -> self_type&
  1164. {
  1165. size_type count = static_cast<size_type>(std::distance(first, last));
  1166. size_type old_size = m_storage.size();
  1167. m_storage.set_size(error_policy::check_add(size(), count));
  1168. std::copy(first, last, data() + old_size);
  1169. return *this;
  1170. }
  1171. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1172. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const self_type& str) -> self_type&
  1173. {
  1174. return append(str);
  1175. }
  1176. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1177. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const string_type& str) -> self_type&
  1178. {
  1179. return append(str);
  1180. }
  1181. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1182. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(value_type ch) -> self_type&
  1183. {
  1184. return append(size_type(1), ch);
  1185. }
  1186. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1187. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(const_pointer s) -> self_type&
  1188. {
  1189. return append(s);
  1190. }
  1191. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1192. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::operator+=(initializer_type ilist) -> self_type&
  1193. {
  1194. return append(ilist);
  1195. }
  1196. /***********
  1197. * compare *
  1198. ***********/
  1199. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1200. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const self_type& str) const noexcept
  1201. {
  1202. return compare_impl(data(), size(), str.data(), str.size());
  1203. }
  1204. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1205. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const self_type& str) const
  1206. {
  1207. check_index_strict(pos1, size(), "xbasic_fixed_string::compare");
  1208. return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size());
  1209. }
  1210. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1211. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const self_type& str,
  1212. size_type pos2, size_type count2) const
  1213. {
  1214. check_index_strict(pos1, size(), "xbasic_fixed_string::compare");
  1215. check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare");
  1216. return compare_impl(data() + pos1, std::min(count1, size() - pos1),
  1217. str.data() + pos2, std::min(count2, str.size() - pos2));
  1218. }
  1219. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1220. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const string_type& str) const noexcept
  1221. {
  1222. return compare_impl(data(), size(), str.data(), str.size());
  1223. }
  1224. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1225. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const string_type& str) const
  1226. {
  1227. check_index_strict(pos1, size(), "xbasic_fixed_string::compare");
  1228. return compare_impl(data() + pos1, std::min(count1, size() - pos1), str.data(), str.size());
  1229. }
  1230. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1231. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const string_type& str,
  1232. size_type pos2, size_type count2) const
  1233. {
  1234. check_index_strict(pos1, size(), "xbasic_fixed_string::compare");
  1235. check_index_strict(pos2, str.size(), "xbasic_fixed_string::compare");
  1236. return compare_impl(data() + pos1, std::min(count1, size() - pos1),
  1237. str.data() + pos2, std::min(count2, str.size() - pos2));
  1238. }
  1239. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1240. inline int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(const_pointer s) const noexcept
  1241. {
  1242. return compare_impl(data(), size(), s, traits_type::length(s));
  1243. }
  1244. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1245. int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const_pointer s) const
  1246. {
  1247. return compare(pos1, count1, s, traits_type::length(s));
  1248. }
  1249. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1250. int xbasic_fixed_string<CT, N, ST, EP, TR>::compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const
  1251. {
  1252. check_index_strict(pos1, size(), "xbasic_fixed_string::compare");
  1253. return compare_impl(data() + pos1, std::min(count1, size() - pos1),
  1254. s, count2);
  1255. }
  1256. /***********
  1257. * replace *
  1258. ***********/
  1259. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1260. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count, const self_type& str) -> self_type&
  1261. {
  1262. return replace(pos, count, str.data(), str.size());
  1263. }
  1264. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1265. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1266. const self_type& str) -> self_type&
  1267. {
  1268. return replace(first, last, str.data(), str.size());
  1269. }
  1270. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1271. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos1, size_type count1, const self_type& str,
  1272. size_type pos2, size_type count2) -> self_type&
  1273. {
  1274. check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace");
  1275. return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2));
  1276. }
  1277. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1278. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count, const string_type& str) -> self_type&
  1279. {
  1280. return replace(pos, count, str.data(), str.size());
  1281. }
  1282. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1283. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1284. const string_type& str) -> self_type&
  1285. {
  1286. return replace(first, last, str.data(), str.size());
  1287. }
  1288. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1289. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos1, size_type count1, const string_type& str,
  1290. size_type pos2, size_type count2) -> self_type&
  1291. {
  1292. check_index_strict(pos2, str.size(), "xbasic_fixed_string::replace");
  1293. return replace(pos1, count1, str.data() + pos2, std::min(count2, str.size() - pos2));
  1294. }
  1295. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1296. auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count,
  1297. const_pointer cstr, size_type count2) -> self_type&
  1298. {
  1299. check_index_strict(pos, size(), "xbasic_fixed_string::replace");
  1300. size_type erase_count = std::min(count, size() - pos);
  1301. size_type new_size = error_policy::check_add(size() - erase_count, count2);
  1302. if (erase_count > count2)
  1303. {
  1304. traits_type::copy(data() + pos, cstr, count2);
  1305. std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2);
  1306. m_storage.set_size(new_size);
  1307. }
  1308. else if (erase_count < count2)
  1309. {
  1310. std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size);
  1311. traits_type::copy(data() + pos, cstr, count2);
  1312. m_storage.set_size(new_size);
  1313. }
  1314. else
  1315. {
  1316. traits_type::copy(data() + pos, cstr, count2);
  1317. }
  1318. return *this;
  1319. }
  1320. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1321. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1322. const_pointer cstr, size_type count2) -> self_type&
  1323. {
  1324. if (cbegin() <= first && first < last && last <= cend())
  1325. {
  1326. size_type pos = static_cast<size_type>(first - cbegin());
  1327. size_type count = static_cast<size_type>(last - first);
  1328. return replace(pos, count, cstr, count2);
  1329. }
  1330. return *this;
  1331. }
  1332. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1333. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count,
  1334. const_pointer cstr) -> self_type&
  1335. {
  1336. return replace(pos, count, cstr, traits_type::length(cstr));
  1337. }
  1338. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1339. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1340. const_pointer cstr) -> self_type&
  1341. {
  1342. return replace(first, last, cstr, traits_type::length(cstr));
  1343. }
  1344. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1345. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(size_type pos, size_type count,
  1346. size_type count2, value_type ch) -> self_type&
  1347. {
  1348. check_index_strict(pos, size(), "xbasic_fixed_string::replace");
  1349. size_type erase_count = std::min(count, size() - pos);
  1350. size_type new_size = error_policy::check_add(size() - erase_count, count2);
  1351. if (erase_count > count2)
  1352. {
  1353. traits_type::assign(data() + pos, count2, ch);
  1354. std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2);
  1355. m_storage.set_size(new_size);
  1356. }
  1357. else if (erase_count < count2)
  1358. {
  1359. std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size);
  1360. traits_type::assign(data() + pos, count2, ch);
  1361. m_storage.set_size(new_size);
  1362. }
  1363. else
  1364. {
  1365. traits_type::assign(data() + pos, count2, ch);
  1366. }
  1367. return *this;
  1368. }
  1369. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1370. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1371. size_type count2, value_type ch) -> self_type&
  1372. {
  1373. if (cbegin() <= first && first < last && last <= cend())
  1374. {
  1375. size_type pos = static_cast<size_type>(first - cbegin());
  1376. size_type count = static_cast<size_type>(last - first);
  1377. return replace(pos, count, count2, ch);
  1378. }
  1379. return *this;
  1380. }
  1381. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1382. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1383. initializer_type ilist) -> self_type&
  1384. {
  1385. return replace(first, last, ilist.begin(), ilist.end());
  1386. }
  1387. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1388. template <class InputIt>
  1389. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::replace(const_iterator first, const_iterator last,
  1390. InputIt first2, InputIt last2) -> self_type&
  1391. {
  1392. if (cbegin() <= first && first < last && last <= cend())
  1393. {
  1394. size_type pos = static_cast<size_type>(first - cbegin());
  1395. size_type erase_count = static_cast<size_type>(last - first);
  1396. size_type count2 = static_cast<size_type>(std::distance(first2, last2));
  1397. size_type new_size = error_policy::check_add(size() - erase_count, count2);
  1398. if (erase_count > count2)
  1399. {
  1400. std::copy(first2, last2, data() + pos);
  1401. std::copy(cbegin() + pos + erase_count, cend(), data() + pos + count2);
  1402. m_storage.set_size(new_size);
  1403. }
  1404. else if (erase_count < count2)
  1405. {
  1406. std::copy_backward(cbegin() + pos + erase_count, cend(), data() + new_size);
  1407. std::copy(first2, last2, data() + pos);
  1408. m_storage.set_size(new_size);
  1409. }
  1410. else
  1411. {
  1412. std::copy(first2, last2, data() + pos);
  1413. }
  1414. }
  1415. return *this;
  1416. }
  1417. /********
  1418. * find *
  1419. ********/
  1420. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1421. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const self_type& str, size_type pos) const noexcept -> size_type
  1422. {
  1423. return find(str.data(), pos, str.size());
  1424. }
  1425. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1426. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const string_type& str, size_type pos) const noexcept -> size_type
  1427. {
  1428. return find(str.data(), pos, str.size());
  1429. }
  1430. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1431. auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const_pointer s, size_type pos, size_type count) const -> size_type
  1432. {
  1433. if (count == size_type(0) && pos <= size())
  1434. {
  1435. return pos;
  1436. }
  1437. size_type nm;
  1438. if (pos < size() && count <= (nm = size() - pos))
  1439. {
  1440. const_pointer uptr, vptr;
  1441. for (nm -= count - 1, vptr = data() + pos;
  1442. (uptr = traits_type::find(vptr, nm, *s)) != 0;
  1443. nm -= size_type(uptr - vptr) + 1ul, vptr = uptr + 1ul)
  1444. {
  1445. if (traits_type::compare(uptr, s, count) == 0)
  1446. {
  1447. return size_type(uptr - data());
  1448. }
  1449. }
  1450. }
  1451. return npos;
  1452. }
  1453. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1454. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(const_pointer s, size_type pos) const -> size_type
  1455. {
  1456. return find(s, pos, traits_type::length(s));
  1457. }
  1458. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1459. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find(value_type ch, size_type pos) const -> size_type
  1460. {
  1461. return find((const_pointer)(&ch), pos, size_type(1));
  1462. }
  1463. /*********
  1464. * rfind *
  1465. *********/
  1466. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1467. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const self_type& str, size_type pos) const noexcept -> size_type
  1468. {
  1469. return rfind(str.data(), pos, str.size());
  1470. }
  1471. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1472. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const string_type& str, size_type pos) const noexcept -> size_type
  1473. {
  1474. return rfind(str.data(), pos, str.size());
  1475. }
  1476. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1477. auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const_pointer s, size_type pos, size_type count) const -> size_type
  1478. {
  1479. if (count == 0)
  1480. {
  1481. return std::min(pos, size());
  1482. }
  1483. if (count <= size())
  1484. {
  1485. const_pointer uptr = data() + std::min(pos, size() - count);
  1486. for (;; --uptr)
  1487. {
  1488. if (traits_type::eq(*uptr, *s) && traits_type::compare(uptr, s, count) == 0)
  1489. {
  1490. return size_type(uptr - data());
  1491. }
  1492. else if (uptr == data())
  1493. {
  1494. break;
  1495. }
  1496. }
  1497. }
  1498. return npos;
  1499. }
  1500. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1501. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(const_pointer s, size_type pos) const -> size_type
  1502. {
  1503. return rfind(s, pos, traits_type::length(s));
  1504. }
  1505. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1506. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::rfind(value_type ch, size_type pos) const -> size_type
  1507. {
  1508. return rfind((const_pointer)(&ch), pos, size_type(1));
  1509. }
  1510. /*****************
  1511. * find_first_of *
  1512. *****************/
  1513. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1514. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(const self_type& str, size_type pos) const noexcept -> size_type
  1515. {
  1516. return find_first_of(str.data(), pos, str.size());
  1517. }
  1518. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1519. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(const string_type& str, size_type pos) const noexcept -> size_type
  1520. {
  1521. return find_first_of(str.data(), pos, str.size());
  1522. }
  1523. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1524. auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(const_pointer s, size_type pos, size_type count) const -> size_type
  1525. {
  1526. if (size_type(0) < count && pos < size())
  1527. {
  1528. const_pointer vptr = data() + size();
  1529. for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr)
  1530. {
  1531. if (traits_type::find(s, count, *uptr) != 0)
  1532. {
  1533. return size_type(uptr - data());
  1534. }
  1535. }
  1536. }
  1537. return npos;
  1538. }
  1539. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1540. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(const_pointer s, size_type pos) const -> size_type
  1541. {
  1542. return find_first_of(s, pos, traits_type::length(s));
  1543. }
  1544. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1545. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_of(value_type ch, size_type pos) const -> size_type
  1546. {
  1547. return find_first_of((const_pointer)(&ch), pos, size_type(1));
  1548. }
  1549. /*********************
  1550. * find_first_not_of *
  1551. *********************/
  1552. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1553. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_not_of(const self_type& str, size_type pos) const noexcept -> size_type
  1554. {
  1555. return find_first_not_of(str.data(), pos, str.size());
  1556. }
  1557. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1558. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_not_of(const string_type& str, size_type pos) const noexcept -> size_type
  1559. {
  1560. return find_first_not_of(str.data(), pos, str.size());
  1561. }
  1562. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1563. auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_not_of(const_pointer s, size_type pos, size_type count) const -> size_type
  1564. {
  1565. if (pos < size())
  1566. {
  1567. const_pointer vptr = data() + size();
  1568. for (const_pointer uptr = data() + pos; uptr < vptr; ++uptr)
  1569. {
  1570. if (traits_type::find(s, count, *uptr) == 0)
  1571. {
  1572. return size_type(uptr - data());
  1573. }
  1574. }
  1575. }
  1576. return npos;
  1577. }
  1578. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1579. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_not_of(const_pointer s, size_type pos) const -> size_type
  1580. {
  1581. return find_first_not_of(s, pos, traits_type::length(s));
  1582. }
  1583. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1584. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_first_not_of(value_type ch, size_type pos) const -> size_type
  1585. {
  1586. return find_first_not_of((const_pointer)(&ch), pos, size_type(1));
  1587. }
  1588. /****************
  1589. * find_last_of *
  1590. ****************/
  1591. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1592. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(const self_type& str, size_type pos) const noexcept -> size_type
  1593. {
  1594. return find_last_of(str.data(), pos, str.size());
  1595. }
  1596. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1597. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(const string_type& str, size_type pos) const noexcept -> size_type
  1598. {
  1599. return find_last_of(str.data(), pos, str.size());
  1600. }
  1601. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1602. auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(const_pointer s, size_type pos, size_type count) const -> size_type
  1603. {
  1604. if (size_type(0) < count && size_type(0) < size())
  1605. {
  1606. const_pointer uptr = data() + std::min(pos, size() - 1);
  1607. for (;; --uptr)
  1608. {
  1609. if (traits_type::find(s, count, *uptr) != 0)
  1610. {
  1611. return size_type(uptr - data());
  1612. }
  1613. else if (uptr == data())
  1614. {
  1615. break;
  1616. }
  1617. }
  1618. }
  1619. return npos;
  1620. }
  1621. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1622. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(const_pointer s, size_type pos) const -> size_type
  1623. {
  1624. return find_last_of(s, pos, traits_type::length(s));
  1625. }
  1626. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1627. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_of(value_type ch, size_type pos) const -> size_type
  1628. {
  1629. return find_last_of((const_pointer)(&ch), pos, size_type(1));
  1630. }
  1631. /********************
  1632. * find_last_not_of *
  1633. ********************/
  1634. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1635. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_not_of(const self_type& str, size_type pos) const noexcept -> size_type
  1636. {
  1637. return find_last_not_of(str.data(), pos, str.size());
  1638. }
  1639. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1640. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_not_of(const string_type& str, size_type pos) const noexcept -> size_type
  1641. {
  1642. return find_last_not_of(str.data(), pos, str.size());
  1643. }
  1644. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1645. auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_not_of(const_pointer s, size_type pos, size_type count) const -> size_type
  1646. {
  1647. if (size_type(0) < size())
  1648. {
  1649. const_pointer uptr = data() + std::min(pos, size() - 1);
  1650. for (;; --uptr)
  1651. {
  1652. if (traits_type::find(s, count, *uptr) == 0)
  1653. {
  1654. return size_type(uptr - data());
  1655. }
  1656. else if (uptr == data())
  1657. {
  1658. break;
  1659. }
  1660. }
  1661. }
  1662. return npos;
  1663. }
  1664. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1665. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_not_of(const_pointer s, size_type pos) const -> size_type
  1666. {
  1667. return find_last_not_of(s, pos, traits_type::length(s));
  1668. }
  1669. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1670. inline auto xbasic_fixed_string<CT, N, ST, EP, TR>::find_last_not_of(value_type ch, size_type pos) const -> size_type
  1671. {
  1672. return find_last_not_of((const_pointer)(&ch), pos, size_type(1));
  1673. }
  1674. /*******************
  1675. * Private methods *
  1676. *******************/
  1677. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1678. int xbasic_fixed_string<CT, N, ST, EP, TR>::compare_impl(const_pointer s1, size_type count1,
  1679. const_pointer s2, size_type count2) const noexcept
  1680. {
  1681. size_type rlen = std::min(count1, count2);
  1682. int res = traits_type::compare(s1, s2, rlen);
  1683. if (res == 0)
  1684. {
  1685. return count1 < count2 ? -1 : (count1 > count2 ? 1 : 0);
  1686. }
  1687. else
  1688. {
  1689. return res;
  1690. }
  1691. }
  1692. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1693. inline void xbasic_fixed_string<CT, N, ST, EP, TR>::update_null_termination() noexcept
  1694. {
  1695. data()[size()] = '\0';
  1696. }
  1697. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1698. void xbasic_fixed_string<CT, N, ST, EP, TR>::check_index(size_type pos, size_type size, const char* what) const
  1699. {
  1700. if (pos >= size)
  1701. {
  1702. #if defined(XTL_NO_EXCEPTIONS)
  1703. std::fprintf(stderr, "%s\n", what);
  1704. std::terminate();
  1705. #else
  1706. throw std::out_of_range(what);
  1707. #endif
  1708. }
  1709. }
  1710. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1711. void xbasic_fixed_string<CT, N, ST, EP, TR>::check_index_strict(size_type pos, size_type size, const char* what) const
  1712. {
  1713. check_index(pos, size + 1, what);
  1714. }
  1715. /**************************
  1716. * Concatenation operator *
  1717. **************************/
  1718. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1719. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1720. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1721. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
  1722. {
  1723. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1724. return res += rhs;
  1725. }
  1726. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1727. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1728. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1729. const CT* rhs)
  1730. {
  1731. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1732. return res += rhs;
  1733. }
  1734. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1735. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1736. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1737. CT rhs)
  1738. {
  1739. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1740. return res += rhs;
  1741. }
  1742. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1743. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1744. operator+(const CT* lhs,
  1745. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
  1746. {
  1747. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1748. return res += rhs;
  1749. }
  1750. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1751. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1752. operator+(CT lhs,
  1753. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
  1754. {
  1755. using size_type = typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type;
  1756. xbasic_fixed_string<CT, N, ST, EP, TR> res(size_type(1), lhs);
  1757. return res += rhs;
  1758. }
  1759. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1760. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1761. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  1762. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
  1763. {
  1764. xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
  1765. return res += rhs;
  1766. }
  1767. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1768. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1769. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1770. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
  1771. {
  1772. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1773. return res += std::move(rhs);
  1774. }
  1775. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1776. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1777. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  1778. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
  1779. {
  1780. xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
  1781. return res += std::move(rhs);
  1782. }
  1783. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1784. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1785. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  1786. const CT* rhs)
  1787. {
  1788. xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
  1789. return res += rhs;
  1790. }
  1791. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1792. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1793. operator+(const xbasic_fixed_string<CT, N, ST, EP, TR>&& lhs,
  1794. CT rhs)
  1795. {
  1796. xbasic_fixed_string<CT, N, ST, EP, TR> res(std::move(lhs));
  1797. return res += rhs;
  1798. }
  1799. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1800. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1801. operator+(const CT* lhs,
  1802. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
  1803. {
  1804. xbasic_fixed_string<CT, N, ST, EP, TR> res(lhs);
  1805. return res += std::move(rhs);
  1806. }
  1807. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1808. inline xbasic_fixed_string<CT, N, ST, EP, TR>
  1809. operator+(CT lhs,
  1810. const xbasic_fixed_string<CT, N, ST, EP, TR>&& rhs)
  1811. {
  1812. using size_type = typename xbasic_fixed_string<CT, N, ST, EP, TR>::size_type;
  1813. xbasic_fixed_string<CT, N, ST, EP, TR> res(size_type(1), lhs);
  1814. return res += std::move(rhs);
  1815. }
  1816. /************************
  1817. * Comparison operators *
  1818. ************************/
  1819. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1820. inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1821. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1822. {
  1823. return lhs.compare(rhs) == 0;
  1824. }
  1825. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1826. inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1827. const CT* rhs) noexcept
  1828. {
  1829. return lhs.compare(rhs) == 0;
  1830. }
  1831. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1832. inline bool operator==(const CT* lhs,
  1833. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1834. {
  1835. return rhs == lhs;
  1836. }
  1837. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1838. inline bool operator==(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1839. const std::basic_string<CT, TR>& rhs) noexcept
  1840. {
  1841. return lhs == rhs.c_str();
  1842. }
  1843. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1844. inline bool operator==(const std::basic_string<CT, TR>& lhs,
  1845. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1846. {
  1847. return lhs.c_str() == rhs;
  1848. }
  1849. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1850. inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1851. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1852. {
  1853. return lhs.compare(rhs) != 0;
  1854. }
  1855. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1856. inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1857. const CT* rhs) noexcept
  1858. {
  1859. return lhs.compare(rhs) != 0;
  1860. }
  1861. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1862. inline bool operator!=(const CT* lhs,
  1863. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1864. {
  1865. return rhs != lhs;
  1866. }
  1867. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1868. inline bool operator!=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1869. const std::basic_string<CT, TR>& rhs) noexcept
  1870. {
  1871. return lhs != rhs.c_str();
  1872. }
  1873. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1874. inline bool operator!=(const std::basic_string<CT, TR>& lhs,
  1875. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1876. {
  1877. return lhs.c_str() != rhs;
  1878. }
  1879. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1880. inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1881. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1882. {
  1883. return lhs.compare(rhs) < 0;
  1884. }
  1885. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1886. inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1887. const CT* rhs) noexcept
  1888. {
  1889. return lhs.compare(rhs) < 0;
  1890. }
  1891. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1892. inline bool operator<(const CT* lhs,
  1893. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1894. {
  1895. return rhs > lhs;
  1896. }
  1897. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1898. inline bool operator<(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1899. const std::basic_string<CT, TR>& rhs) noexcept
  1900. {
  1901. return lhs < rhs.c_str();
  1902. }
  1903. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1904. inline bool operator<(const std::basic_string<CT, TR>& lhs,
  1905. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1906. {
  1907. return lhs.c_str() < rhs;
  1908. }
  1909. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1910. inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1911. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1912. {
  1913. return lhs.compare(rhs) <= 0;
  1914. }
  1915. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1916. inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1917. const CT* rhs) noexcept
  1918. {
  1919. return lhs.compare(rhs) <= 0;
  1920. }
  1921. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1922. inline bool operator<=(const CT* lhs,
  1923. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1924. {
  1925. return rhs >= lhs;
  1926. }
  1927. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1928. inline bool operator<=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1929. const std::basic_string<CT, TR>& rhs) noexcept
  1930. {
  1931. return lhs <= rhs.c_str();
  1932. }
  1933. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1934. inline bool operator<=(const std::basic_string<CT, TR>& lhs,
  1935. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1936. {
  1937. return lhs.c_str() <= rhs;
  1938. }
  1939. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1940. inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1941. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1942. {
  1943. return lhs.compare(rhs) > 0;
  1944. }
  1945. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1946. inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1947. const CT* rhs) noexcept
  1948. {
  1949. return lhs.compare(rhs) > 0;
  1950. }
  1951. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1952. inline bool operator>(const CT* lhs,
  1953. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1954. {
  1955. return rhs < lhs;
  1956. }
  1957. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1958. inline bool operator>(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1959. const std::basic_string<CT, TR>& rhs) noexcept
  1960. {
  1961. return lhs > rhs.c_str();
  1962. }
  1963. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1964. inline bool operator>(const std::basic_string<CT, TR>& lhs,
  1965. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1966. {
  1967. return lhs.c_str() > rhs;
  1968. }
  1969. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1970. inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1971. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1972. {
  1973. return lhs.compare(rhs) >= 0;
  1974. }
  1975. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1976. inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1977. const CT* rhs) noexcept
  1978. {
  1979. return lhs.compare(rhs) >= 0;
  1980. }
  1981. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1982. inline bool operator>=(const CT* lhs,
  1983. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1984. {
  1985. return rhs <= lhs;
  1986. }
  1987. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1988. inline bool operator>=(const xbasic_fixed_string<CT, N, ST, EP, TR>& lhs,
  1989. const std::basic_string<CT, TR>& rhs) noexcept
  1990. {
  1991. return lhs >= rhs.c_str();
  1992. }
  1993. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  1994. inline bool operator>=(const std::basic_string<CT, TR>& lhs,
  1995. const xbasic_fixed_string<CT, N, ST, EP, TR>& rhs) noexcept
  1996. {
  1997. return lhs.c_str() >= rhs;
  1998. }
  1999. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2000. inline void swap(xbasic_fixed_string<CT, N, ST, EP, TR>& lhs, xbasic_fixed_string<CT, N, ST, EP, TR>& rhs)
  2001. {
  2002. lhs.swap(rhs);
  2003. }
  2004. /******************
  2005. * Input / output *
  2006. ******************/
  2007. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2008. inline std::basic_ostream<CT, TR>& operator<<(std::basic_ostream<CT, TR>& os,
  2009. const xbasic_fixed_string<CT, N, ST, EP, TR>& str)
  2010. {
  2011. os << str.c_str();
  2012. return os;
  2013. }
  2014. #ifdef __CLING__
  2015. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2016. nlohmann::json mime_bundle_repr(const xbasic_fixed_string<CT, N, ST, EP, TR>& str)
  2017. {
  2018. auto bundle = nlohmann::json::object();
  2019. bundle["text/plain"] = str.c_str();
  2020. return bundle;
  2021. }
  2022. #endif
  2023. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2024. inline std::basic_istream<CT, TR>& operator>>(std::basic_istream<CT, TR>& is,
  2025. xbasic_fixed_string<CT, N, ST, EP, TR>& str)
  2026. {
  2027. // Not optimal
  2028. std::string tmp;
  2029. is >> tmp;
  2030. str = tmp.c_str();
  2031. return is;
  2032. }
  2033. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2034. inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
  2035. xbasic_fixed_string<CT, N, ST, EP, TR>& str,
  2036. CT delim)
  2037. {
  2038. std::string tmp;
  2039. auto& ret = std::getline(input, tmp, delim);
  2040. str = tmp;
  2041. return ret;
  2042. }
  2043. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2044. inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
  2045. xbasic_fixed_string<CT, N, ST, EP, TR>& str,
  2046. CT delim)
  2047. {
  2048. std::string tmp;
  2049. auto& ret = std::getline(std::move(input), tmp, delim);
  2050. str = tmp;
  2051. return ret;
  2052. }
  2053. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2054. inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>& input,
  2055. xbasic_fixed_string<CT, N, ST, EP, TR>& str)
  2056. {
  2057. std::string tmp;
  2058. auto& ret = std::getline(input, tmp);
  2059. str = tmp;
  2060. return ret;
  2061. }
  2062. template <class CT, std::size_t N, int ST, template <std::size_t> class EP, class TR>
  2063. inline std::basic_istream<CT, TR>& getline(std::basic_istream<CT, TR>&& input,
  2064. xbasic_fixed_string<CT, N, ST, EP, TR>& str)
  2065. {
  2066. std::string tmp;
  2067. auto& ret = std::getline(std::move(input), tmp);
  2068. str = tmp;
  2069. return ret;
  2070. }
  2071. }
  2072. #endif // xtl