string.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. #ifndef GI_STRING_HPP
  2. #define GI_STRING_HPP
  3. #include "base.hpp"
  4. // used for hash
  5. #include <functional>
  6. #include <limits>
  7. #include <string>
  8. #if __cplusplus >= 201703L
  9. #include <optional>
  10. #include <string_view>
  11. #endif
  12. // define << operator if not unwanted
  13. #ifndef GI_NO_STRING_IOS
  14. #include <iostream>
  15. #endif
  16. #include "string.h"
  17. #ifdef __has_builtin
  18. #define GI_HAS_BUILTIN(x) __has_builtin(x)
  19. #else
  20. #define GI_HAS_BUILTIN(x) 0
  21. #endif
  22. namespace gi
  23. {
  24. namespace convert
  25. {
  26. // generic template; specialize as needed where appropriate
  27. template<typename From, typename To, class Enable = void>
  28. struct converter
  29. {
  30. // fail in explanatory way if we end up here
  31. static To convert(const From &)
  32. {
  33. static_assert(!std::is_void<Enable>::value, "unknown type conversion");
  34. return To();
  35. }
  36. };
  37. // implementation should provide some types
  38. template<typename From, typename To, class Enable = void>
  39. struct converter_base : public std::true_type
  40. {
  41. typedef From from_type;
  42. typedef To to_type;
  43. };
  44. // check whether conversion possible
  45. template<typename From, typename To, typename Enable = void>
  46. struct is_convertible : public std::false_type
  47. {};
  48. template<typename From, typename To>
  49. struct is_convertible<From, To,
  50. typename std::enable_if<std::is_base_of<To, From>::value>::type>
  51. : public std::false_type
  52. {};
  53. template<typename From, typename To>
  54. struct is_convertible<From, To,
  55. typename std::enable_if<std::is_pointer<
  56. typename converter<From, To>::from_type *>::value>::type>
  57. : public std::true_type
  58. {};
  59. } // namespace convert
  60. namespace detail
  61. {
  62. // tag
  63. struct String
  64. {};
  65. template<typename Transfer>
  66. struct StringFuncs
  67. {
  68. static void _deleter(char *&p)
  69. {
  70. if (Transfer().value)
  71. g_free(p);
  72. p = nullptr;
  73. }
  74. static void _copy(const char *p)
  75. {
  76. return Transfer().value ? g_strdup(p) : p;
  77. }
  78. };
  79. template<typename Transfer>
  80. class cstr : public String
  81. {
  82. using self_type = cstr;
  83. protected:
  84. using _member_type =
  85. typename std::conditional<std::is_same<Transfer, transfer_full_t>::value,
  86. char, const char>::type;
  87. _member_type *data_ = nullptr;
  88. void clear()
  89. {
  90. if (Transfer().value && data_)
  91. g_free((char *)data_);
  92. data_ = nullptr;
  93. }
  94. public:
  95. using traits_type = std::char_traits<char>;
  96. using value_type = char;
  97. using pointer = char *;
  98. using const_pointer = const char *;
  99. using reference = char &;
  100. using const_reference = const char &;
  101. using const_iterator = const char *;
  102. using iterator = const_iterator;
  103. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  104. using reverse_iterator = const_reverse_iterator;
  105. using size_type = size_t;
  106. using difference_type = std::ptrdiff_t;
  107. using view_type = cstr<transfer_none_t>;
  108. static constexpr bool is_view_type =
  109. !std::is_same<Transfer, transfer_full_t>::value;
  110. static constexpr size_type npos = static_cast<size_type>(-1);
  111. constexpr cstr() noexcept : data_(nullptr) {}
  112. constexpr cstr(std::nullptr_t) noexcept : data_(nullptr) {}
  113. // const usually means none, so only on view type
  114. // also, no arbitrary size is accepted here
  115. template<typename Enable = void,
  116. typename std::enable_if<std::is_same<Enable, void>::value &&
  117. is_view_type>::type * = nullptr>
  118. constexpr cstr(const char *data) : data_(data)
  119. {}
  120. // a single pointer, optionally specify ownership
  121. // behave like string by default, assume no ownership of incoming pointer
  122. template<typename LTransfer = transfer_none_t,
  123. typename std::enable_if<
  124. (std::is_same<LTransfer, transfer_full_t>::value ||
  125. std::is_same<LTransfer, transfer_none_t>::value) &&
  126. !is_view_type>::type * = nullptr>
  127. cstr(char *data, const LTransfer &t)
  128. : data_((t.value == transfer_full.value) || !data ? data : g_strdup(data))
  129. {}
  130. // pointer along with size
  131. // always behave like string and make a copy
  132. template<typename Enable = void,
  133. typename std::enable_if<std::is_same<Enable, void>::value &&
  134. !is_view_type>::type * = nullptr>
  135. cstr(const char *data, size_t len = npos)
  136. : data_(!data ? nullptr
  137. : (len == npos ? g_strdup(data) : g_strndup(data, len)))
  138. {}
  139. // construct from any transfer variant
  140. template<typename OTransfer>
  141. cstr(const cstr<OTransfer> &s) : cstr(s.data())
  142. {}
  143. // accept from string, but NOT string_view as that may not be null-terminated
  144. template<typename Allocator>
  145. cstr(const std::basic_string<char, std::char_traits<char>, Allocator>
  146. &s) noexcept
  147. : cstr(s.data())
  148. {}
  149. #if __cplusplus >= 201703L
  150. // some optional variants of above
  151. constexpr cstr(std::nullopt_t) noexcept : data_(nullptr) {}
  152. template<typename Allocator>
  153. cstr(const std::optional<
  154. std::basic_string<char, std::char_traits<char>, Allocator>> &s) noexcept
  155. : cstr(s ? s.value().data() : nullptr)
  156. {}
  157. #endif
  158. // hook extensible conversion
  159. // (avoid instantiation and confusion with self and base types)
  160. template<typename From,
  161. typename NoBase = typename std::enable_if<
  162. !std::is_base_of<self_type, From>::value>::type,
  163. typename Enable = typename std::enable_if<
  164. convert::is_convertible<From, self_type>::value>::type>
  165. cstr(const From &f) : cstr(convert::converter<From, self_type>::convert(f))
  166. {}
  167. // custom
  168. constexpr const_pointer gobj_() const { return data_; }
  169. explicit constexpr operator bool() const { return data_; }
  170. _member_type *release_()
  171. {
  172. auto tmp = this->data_;
  173. this->data_ = nullptr;
  174. return tmp;
  175. }
  176. // destruct / copy / assign
  177. ~cstr() { clear(); }
  178. cstr(const cstr &other) { *this = other; }
  179. cstr(cstr &&other) { *this = std::move(other); }
  180. cstr &operator=(const cstr &other)
  181. {
  182. if (this != &other) {
  183. clear();
  184. data_ = Transfer().value ? g_strdup(other.data_) : other.data_;
  185. }
  186. return *this;
  187. }
  188. cstr &operator=(cstr &&other)
  189. {
  190. if (this != &other) {
  191. clear();
  192. data_ = other.data_;
  193. other.data_ = nullptr;
  194. }
  195. return *this;
  196. }
  197. // deduced conversion to string(_view)
  198. template<typename Destination,
  199. typename Check = typename std::enable_if<
  200. convert::is_convertible<self_type, Destination>::value>::type>
  201. operator Destination() const
  202. {
  203. return convert::converter<self_type, Destination>::convert(*this);
  204. }
  205. #if __cplusplus >= 201703L
  206. // unfortunately, conversion to std::optional picks Destination = std::string
  207. // (which can obviously not be excluded above, or as specialization)
  208. std::optional<std::string> opt_()
  209. {
  210. using To = std::optional<std::string>;
  211. return c_str() ? To({c_str(), size()}) : To(std::nullopt);
  212. }
  213. #endif
  214. // usual string(view) stuff
  215. // iterators
  216. constexpr const_iterator begin() const noexcept { return data_; }
  217. constexpr const_iterator end() const noexcept
  218. {
  219. return data_ ? data_ + size() : nullptr;
  220. }
  221. constexpr const_iterator cbegin() const noexcept { return begin(); }
  222. constexpr const_iterator cend() const noexcept { return end(); }
  223. const_reverse_iterator rbegin() const noexcept
  224. {
  225. return const_reverse_iterator(end());
  226. }
  227. const_reverse_iterator rend() const noexcept
  228. {
  229. return const_reverse_iterator(begin());
  230. }
  231. const_reverse_iterator crbegin() const noexcept { return rbegin(); }
  232. const_reverse_iterator crend() const noexcept { return rend(); }
  233. // capacity
  234. constexpr size_type size() const noexcept
  235. {
  236. #if GI_HAS_BUILTIN(__builtin_strlen) || \
  237. (defined(__GNUC__) && !defined(__clang__))
  238. return __builtin_strlen(data_);
  239. #else
  240. return data_ ? strlen(data_) : 0;
  241. #endif
  242. }
  243. constexpr size_type length() const noexcept { return size(); }
  244. constexpr size_type max_size() const noexcept
  245. {
  246. return std::numeric_limits<size_type>::max();
  247. }
  248. constexpr bool empty() const noexcept { return !data_ || *data_ == 0; }
  249. // access
  250. constexpr const_reference operator[](size_type i) const { return data_[i]; }
  251. constexpr const_reference at(size_type i) const
  252. {
  253. return i < size() ? data_[i]
  254. : (try_throw(std::out_of_range("cstr::at")), data_[i]);
  255. }
  256. constexpr const_reference front() const { return data_[0]; }
  257. constexpr const_reference back() const { return data_[size() - 1]; }
  258. constexpr const_pointer data() const noexcept { return data_; }
  259. constexpr const_pointer c_str() const noexcept { return data_; }
  260. // modifiers
  261. // view only
  262. template<typename Enable = void,
  263. typename std::enable_if<std::is_same<Enable, void>::value &&
  264. is_view_type>::type * = nullptr>
  265. constexpr void remove_prefix(size_type n)
  266. {
  267. data_ += n;
  268. }
  269. constexpr void swap(self_type &s) noexcept
  270. {
  271. std::swap(this->data_, s.data_);
  272. }
  273. // operations
  274. size_type copy(char *buf, size_type n, size_type pos = 0) const
  275. {
  276. auto s = size();
  277. if (pos > s)
  278. try_throw(std::out_of_range("cstr::copy"));
  279. size_type rlen = (std::min)(s - pos, n);
  280. if (rlen > 0) {
  281. const char *start = data_ + pos;
  282. traits_type::copy(buf, start, rlen);
  283. }
  284. return rlen;
  285. }
  286. int compare(view_type x) const noexcept
  287. {
  288. return g_strcmp0(data_, x.c_str());
  289. }
  290. int compare(const char *s) const { return compare(view_type(s)); }
  291. // find
  292. size_type find(view_type n, size_type pos = 0) const noexcept
  293. {
  294. auto s = size();
  295. auto os = n.size();
  296. if (os > s || pos > s - os)
  297. return npos;
  298. if (!os)
  299. return pos <= s ? pos : npos;
  300. auto loc = strstr(data_ + pos, n.data());
  301. return loc ? loc - data_ : npos;
  302. }
  303. size_type find(char c, size_type pos = 0) const noexcept
  304. {
  305. if (pos >= size())
  306. return npos;
  307. auto loc = strchr(data_ + pos, c);
  308. return loc ? loc - data_ : npos;
  309. }
  310. size_type find(const char *s, size_type pos = 0) const
  311. {
  312. return find(view_type(s), pos);
  313. }
  314. size_type rfind(view_type n, size_type pos = npos) const noexcept
  315. {
  316. auto s = size();
  317. if (!s)
  318. return npos;
  319. auto os = n.size();
  320. if (!os)
  321. return pos == npos ? s : pos;
  322. auto loc = g_strrstr_len(c_str(), pos, n.c_str());
  323. return loc ? loc - data_ : npos;
  324. }
  325. size_type rfind(char c, size_type pos = npos) const noexcept
  326. {
  327. // not quite efficient, but anyways
  328. char str[] = {c, 0};
  329. return rfind(str, pos);
  330. }
  331. size_type rfind(const char *s, size_type pos = npos) const
  332. {
  333. return rfind(view_type(s), pos);
  334. }
  335. // find_first_of variants
  336. // only provide those if std helps us out
  337. #if __cplusplus >= 201703L
  338. size_type find_first_of(view_type s, size_type pos = 0) const noexcept
  339. {
  340. return std::string_view(data_).find_first_of(s.data(), pos);
  341. }
  342. size_type find_first_of(char c, size_type pos = 0) const noexcept
  343. {
  344. return find(c, pos);
  345. }
  346. size_type find_first_of(const char *s, size_type pos = 0) const
  347. {
  348. return find_first_of(view_type(s), pos);
  349. }
  350. size_type find_last_of(view_type s, size_type pos = npos) const noexcept
  351. {
  352. return std::string_view(data_).find_last_of(s.data(), pos);
  353. }
  354. size_type find_last_of(char c, size_type pos = npos) const noexcept
  355. {
  356. return rfind(c, pos);
  357. }
  358. size_type find_last_of(const char *s, size_type pos = npos) const
  359. {
  360. return find_last_of(view_type(s), pos);
  361. }
  362. size_type find_first_not_of(view_type s, size_type pos = 0) const noexcept
  363. {
  364. return std::string_view(data_).find_first_not_of(s.data(), pos);
  365. }
  366. size_type find_first_not_of(char c, size_type pos = 0) const noexcept
  367. {
  368. return std::string_view(data_).find_first_not_of(c, pos);
  369. }
  370. size_type find_first_not_of(const char *s, size_type pos = 0) const
  371. {
  372. return find_first_not_of(view_type(s), pos);
  373. }
  374. size_type find_last_not_of(view_type s, size_type pos = npos) const noexcept
  375. {
  376. return std::string_view(data_).find_last_not_of(s.data(), pos);
  377. }
  378. size_type find_last_not_of(char c, size_type pos = npos) const noexcept
  379. {
  380. return std::string_view(data_).find_last_not_of(c, pos);
  381. }
  382. size_type find_last_not_of(const char *s, size_type pos = npos) const
  383. {
  384. return find_last_not_of(view_type(s), pos);
  385. }
  386. #endif
  387. };
  388. using _string_view = cstr<transfer_none_t>;
  389. inline bool
  390. operator==(_string_view x, _string_view y) noexcept
  391. {
  392. return x.compare(y) == 0;
  393. }
  394. inline bool
  395. operator!=(_string_view x, _string_view y) noexcept
  396. {
  397. return !(x == y);
  398. }
  399. inline bool
  400. operator<(_string_view x, _string_view y) noexcept
  401. {
  402. return x.compare(y) < 0;
  403. }
  404. inline bool
  405. operator>(_string_view x, _string_view y) noexcept
  406. {
  407. return y < x;
  408. }
  409. inline bool
  410. operator<=(_string_view x, _string_view y) noexcept
  411. {
  412. return !(y < x);
  413. }
  414. inline bool
  415. operator>=(_string_view x, _string_view y) noexcept
  416. {
  417. return !(x < y);
  418. }
  419. #ifndef GI_NO_STRING_IOS
  420. inline std::ostream &
  421. operator<<(std::ostream &o, _string_view sv)
  422. {
  423. // backwards compatibility; behave similar to empty string
  424. return o << (sv ? sv.c_str() : "");
  425. }
  426. #endif
  427. // purpose of silly Delay is to avoid gcc premature instantiation of converter
  428. // (in the hook constructor of base class with cstring as From ??)
  429. template<typename Delay = void>
  430. class cstring_d : public cstr<transfer_full_t>
  431. {
  432. using self_type = cstring_d;
  433. using super_type = cstr<transfer_full_t>;
  434. public:
  435. using super_type::super_type;
  436. // if all other construction fails, try to pass through string
  437. template<typename... Args,
  438. typename NoConvert = typename std::enable_if<
  439. !std::is_constructible<super_type, Args...>::value>::type,
  440. typename Enable = typename std::enable_if<
  441. std::is_constructible<std::string, Args...>::value>::type>
  442. cstring_d(Args &&...args)
  443. : super_type(std::string(std::forward<Args>(args)...))
  444. {}
  445. constexpr pointer gobj_() { return data_; }
  446. // re-use string
  447. template<typename... Args>
  448. self_type &assign(Args &&...t)
  449. {
  450. return *this = std::string().assign(std::forward<Args>(t)...);
  451. }
  452. // access
  453. using super_type::at;
  454. constexpr reference at(size_type i)
  455. {
  456. return i < size() ? data_[i]
  457. : (try_throw(std::out_of_range("cstr::at")), data_[i]);
  458. }
  459. using super_type::front;
  460. constexpr reference front() { return data_[0]; }
  461. using super_type::back;
  462. constexpr reference back() { return data_[size() - 1]; }
  463. using super_type::data;
  464. constexpr pointer data() noexcept { return data_; }
  465. // iterators
  466. using super_type::begin;
  467. constexpr iterator begin() noexcept { return data_; }
  468. using super_type::end;
  469. constexpr iterator end() noexcept { return data_ ? data_ + size() : nullptr; }
  470. using super_type::rbegin;
  471. reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
  472. using super_type::rend;
  473. reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
  474. // operations
  475. using super_type::clear;
  476. void push_back(char c)
  477. {
  478. char str[] = {c, 0};
  479. self_type n{g_strconcat(c_str() ? c_str() : "", str, NULL), transfer_full};
  480. swap(n);
  481. }
  482. void pop_back()
  483. {
  484. auto s = size();
  485. if (s)
  486. at(s - 1) = 0;
  487. }
  488. self_type &append(const char *str)
  489. {
  490. self_type n{g_strconcat(c_str() ? c_str() : "", str, NULL), transfer_full};
  491. swap(n);
  492. return *this;
  493. }
  494. template<typename Transfer>
  495. self_type &append(const cstr<Transfer> &str)
  496. {
  497. return append(str.data());
  498. }
  499. // otherwise delegate
  500. template<typename... Args>
  501. self_type &append(Args &&...args)
  502. {
  503. std::string s;
  504. s.append(std::forward<Args>(args)...);
  505. // make sure to select the desired variant
  506. return append((const char *)s.c_str());
  507. }
  508. // likewise for +=
  509. self_type &operator+=(char c)
  510. {
  511. push_back(c);
  512. return *this;
  513. }
  514. template<typename T>
  515. self_type &operator+=(const T &o)
  516. {
  517. return append(o);
  518. }
  519. self_type substr(size_type pos = 0, size_type n = npos) const
  520. {
  521. auto l = size();
  522. return (pos > l)
  523. ? (try_throw(std::out_of_range("cstr::substr")), self_type())
  524. : self_type(data_ + pos, std::min(n, l - pos));
  525. }
  526. // indeed some are lacking/skipped
  527. // only minimal compatibility
  528. // custom; align with other cases
  529. self_type copy_() { return substr(0); }
  530. };
  531. using cstring = cstring_d<>;
  532. // likewise; (delayed) view type
  533. template<typename Delay = void>
  534. class cstring_v_d : public cstr<transfer_none_t>
  535. {
  536. using self_type = cstring_v_d;
  537. using super_type = cstr<transfer_none_t>;
  538. public:
  539. using super_type::super_type;
  540. // primary reason for subtype
  541. // provide copy/upgrade to owning variant
  542. cstring copy_() { return {g_strdup(this->data()), transfer_full}; }
  543. };
  544. using cstring_v = cstring_v_d<>;
  545. inline cstring
  546. operator+(const _string_view x, const _string_view y) noexcept
  547. {
  548. if (!x)
  549. return {g_strdup(y.c_str()), transfer_full};
  550. if (!y)
  551. return {g_strdup(x.c_str()), transfer_full};
  552. return {g_strconcat(x.c_str(), y.c_str(), NULL), transfer_full};
  553. }
  554. inline cstring
  555. operator+(const _string_view x, char y) noexcept
  556. {
  557. if (!x)
  558. return {1, y};
  559. char str[] = {y, 0};
  560. return x + str;
  561. }
  562. inline cstring
  563. operator+(char x, const _string_view y) noexcept
  564. {
  565. if (!y)
  566. return {1, x};
  567. char str[] = {x, 0};
  568. return str + y;
  569. }
  570. // add convenient conversions
  571. // local helper traits used below
  572. namespace trait
  573. {
  574. template<typename T, std::size_t SIZE, typename Enable = void>
  575. struct has_data_member : std::false_type
  576. {};
  577. template<typename T, std::size_t SIZE>
  578. struct has_data_member<T, SIZE,
  579. typename std::enable_if<
  580. std::is_pointer<decltype(std::declval<T>().c_str())>::value>::type>
  581. : std::integral_constant<bool, sizeof(*std::declval<T>().c_str()) == SIZE>
  582. {};
  583. template<typename T, typename Enable = void>
  584. struct has_size_member : std::false_type
  585. {};
  586. template<typename T>
  587. struct has_size_member<T, typename std::enable_if<std::is_integral<
  588. decltype(std::declval<T>().size())>::value>::type>
  589. : std::true_type
  590. {};
  591. template<typename T>
  592. struct is_string_type
  593. : public std::integral_constant<bool,
  594. has_data_member<T, 1>::value && has_size_member<T>::value>
  595. {};
  596. } // namespace trait
  597. } // namespace detail
  598. namespace convert
  599. {
  600. template<typename From>
  601. struct converter<From, detail::cstr<transfer_full_t>,
  602. typename std::enable_if<detail::trait::is_string_type<From>::value>::type>
  603. : public converter_base<From, detail::cstr<transfer_full_t>>
  604. {
  605. static detail::cstring convert(const From &v)
  606. {
  607. return {(char *)v.c_str(), v.size()};
  608. }
  609. };
  610. // to a typical string(_view) case
  611. // (avoid conflict with above)
  612. // the traits_type (tries to) restricts this to std::string(_view)
  613. // not doing so might conveniently allow conversion to other types as well.
  614. // however, this would also allow e.g. QByteArray, which comes with an operator+
  615. // in global namespace (also selected by non-ADL lookup),
  616. // which then results in ambiguous overload
  617. // (with the operator+ that is provided above)
  618. template<typename Transfer, typename To>
  619. struct converter<detail::cstr<Transfer>, To,
  620. typename std::enable_if<
  621. !std::is_base_of<detail::String, To>::value &&
  622. !std::is_same<typename To::traits_type, void>::value &&
  623. std::is_constructible<To, const char *, size_t>::value>::type>
  624. : public converter_base<detail::cstr<Transfer>, To>
  625. {
  626. static To convert(const detail::cstr<Transfer> &v)
  627. {
  628. return v.c_str() ? To{(char *)v.c_str(), v.size()} : To();
  629. }
  630. };
  631. #if __cplusplus >= 201703L
  632. // to an std::optional string(_view) case
  633. template<typename Transfer, typename To>
  634. struct converter<detail::cstr<Transfer>, To,
  635. typename std::enable_if<std::is_constructible<To, std::in_place_t,
  636. const char *, size_t>::value>::type>
  637. : public converter_base<detail::cstr<Transfer>, To>
  638. {
  639. static To convert(const detail::cstr<Transfer> &v)
  640. {
  641. abort();
  642. return v.c_str() ? To{std::in_place, (char *)v.c_str(), v.size()} : To();
  643. }
  644. };
  645. #endif
  646. } // namespace convert
  647. using detail::cstring;
  648. using detail::cstring_v;
  649. // sanity check; match C counterpart
  650. static_assert(sizeof(cstring) == sizeof(char *), "");
  651. static_assert(sizeof(cstring_v) == sizeof(char *), "");
  652. namespace traits
  653. {
  654. template<>
  655. struct ctype<const gi::cstring, void>
  656. {
  657. typedef const char *type;
  658. };
  659. template<>
  660. struct ctype<gi::cstring, void>
  661. {
  662. typedef char *type;
  663. };
  664. template<>
  665. struct ctype<const gi::cstring_v, void>
  666. {
  667. typedef const char *type;
  668. };
  669. template<>
  670. struct ctype<gi::cstring_v, void>
  671. {
  672. typedef char *type;
  673. };
  674. template<>
  675. struct cpptype<char *, transfer_full_t>
  676. {
  677. using type = gi::cstring;
  678. };
  679. template<>
  680. struct cpptype<char *, transfer_none_t>
  681. {
  682. using type = gi::cstring_v;
  683. };
  684. } // namespace traits
  685. } // namespace gi
  686. // specialize std::hash for suitable use
  687. namespace std
  688. {
  689. template<>
  690. struct hash<gi::cstring>
  691. {
  692. typedef gi::cstring argument_type;
  693. typedef std::size_t result_type;
  694. result_type operator()(argument_type const &s) const
  695. {
  696. return s.c_str() ? g_str_hash(s.c_str()) : 0;
  697. }
  698. };
  699. template<>
  700. struct hash<gi::cstring_v>
  701. {
  702. typedef gi::cstring_v argument_type;
  703. typedef std::size_t result_type;
  704. result_type operator()(argument_type const &s) const
  705. {
  706. return s.c_str() ? g_str_hash(s.c_str()) : 0;
  707. }
  708. };
  709. } // namespace std
  710. #endif // GI_STRING_HPP