container.hpp 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964
  1. #ifndef GI_CONTAINER_HPP
  2. #define GI_CONTAINER_HPP
  3. #include "base.hpp"
  4. #include "wrap.hpp"
  5. #include <iterator>
  6. #include <map>
  7. #include <vector>
  8. #include <assert.h>
  9. #include <string.h>
  10. namespace gi
  11. {
  12. namespace detail
  13. {
  14. // helpers
  15. // element unwrap cast helper;
  16. // element reference type depends on container reference type
  17. // lvalue
  18. template<typename T>
  19. T
  20. cast_ref(T &&el, std::true_type)
  21. {
  22. return el;
  23. }
  24. // rvalue
  25. template<typename T>
  26. typename std::remove_reference<T>::type &&
  27. cast_ref(T &&el, std::false_type)
  28. {
  29. return std::move(el);
  30. }
  31. // std::iterator may be deprecated, but it is still handy
  32. // so replicate it here to avoid deprecation warnings
  33. template<typename Category, typename T, typename Distance = std::ptrdiff_t,
  34. typename Pointer = T *, typename Reference = T &>
  35. struct iterator
  36. {
  37. using iterator_category = Category;
  38. using value_type = T;
  39. using difference_type = Distance;
  40. using pointer = Pointer;
  41. using reference = Reference;
  42. };
  43. namespace _traits
  44. {
  45. template<typename T>
  46. struct hash
  47. {};
  48. template<typename T>
  49. struct equal
  50. {};
  51. template<typename CType>
  52. void
  53. _destroy(CType v)
  54. {
  55. // destroy by wrapping a temporary with full transfer
  56. // and then simply dropping that temporary
  57. wrap(v, transfer_full);
  58. }
  59. // C type case
  60. template<typename CType, typename Enable = void>
  61. struct destroy
  62. {
  63. static constexpr auto func = _destroy<CType>;
  64. };
  65. // Cpp type case
  66. template<typename CppType>
  67. struct destroy<CppType, typename traits::if_valid_type<typename traits::ctype<
  68. typename std::decay<CppType>::type>::type>::type>
  69. {
  70. using CType =
  71. typename traits::ctype<typename std::decay<CppType>::type>::type;
  72. static constexpr auto func = _destroy<CType>;
  73. };
  74. // let's simply stick to the following for now
  75. // since others are not so likely and not always clear semantics
  76. template<>
  77. struct hash<std::string>
  78. {
  79. static constexpr GHashFunc func = g_str_hash;
  80. };
  81. template<>
  82. struct hash<gi::cstring>
  83. {
  84. static constexpr GHashFunc func = g_str_hash;
  85. };
  86. template<>
  87. struct hash<gi::cstring_v>
  88. {
  89. static constexpr GHashFunc func = g_str_hash;
  90. };
  91. template<>
  92. struct equal<std::string>
  93. {
  94. static constexpr GEqualFunc func = g_str_equal;
  95. };
  96. template<>
  97. struct equal<gi::cstring>
  98. {
  99. static constexpr GEqualFunc func = g_str_equal;
  100. };
  101. template<>
  102. struct equal<gi::cstring_v>
  103. {
  104. static constexpr GEqualFunc func = g_str_equal;
  105. };
  106. } // namespace _traits
  107. /////////////////
  108. //
  109. ////////////////
  110. // helper check/trait
  111. namespace trait
  112. {
  113. std::false_type is_initializer_list_dispatch(...);
  114. template<typename T>
  115. std::true_type is_initializer_list_dispatch(std::initializer_list<T> *);
  116. template<typename T>
  117. struct is_initializer_list
  118. : decltype(is_initializer_list_dispatch(static_cast<T *>(nullptr)))
  119. {};
  120. } // namespace trait
  121. // helper; combine some traits
  122. template<typename T, typename Transfer>
  123. using elcpptype = traits::cpptype<T, typename element_transfer<Transfer>::type>;
  124. // hard convert/cast of a pointer to a C type to its wrapper type
  125. // (which is expected of same size)
  126. template<typename Transfer, typename CType,
  127. typename CppType = typename elcpptype<CType, Transfer>::type>
  128. CppType *
  129. wrap_cast(CType *c)
  130. {
  131. static_assert(sizeof(*c) == sizeof(std::declval<CppType>()), "");
  132. return reinterpret_cast<CppType *>(c);
  133. }
  134. // snippet to disable a method for transfer none case
  135. #define GI_DISABLE_METHOD_NONE \
  136. template<typename Enable = void, \
  137. typename Check = typename std::enable_if< \
  138. std::is_void<Enable>::value && \
  139. !std::is_same<Transfer, transfer_none_t>::value>::type>
  140. template<typename ListType, typename ElType, typename Transfer,
  141. typename Enable = void>
  142. class CollectionBase
  143. {};
  144. template<typename ListType, typename ElCType, typename Transfer>
  145. struct list_ops;
  146. struct GPtrArrayFuncs
  147. {
  148. constexpr static bool refcnt = true;
  149. using value_type = gpointer;
  150. static GType get_type_() { return G_TYPE_PTR_ARRAY; }
  151. static ::GPtrArray *ref(::GPtrArray *data)
  152. {
  153. return data ? g_ptr_array_ref(data) : data;
  154. }
  155. static ::GPtrArray *sink(::GPtrArray *data)
  156. {
  157. return data ? g_ptr_array_ref(data) : data;
  158. }
  159. static void free(::GPtrArray *&data)
  160. {
  161. if (data) {
  162. g_ptr_array_unref(data);
  163. data = nullptr;
  164. }
  165. }
  166. static ::GPtrArray *float_(::GPtrArray *data) { return data; }
  167. };
  168. template<typename ElCType, typename Transfer>
  169. struct list_ops<::GPtrArray, ElCType, Transfer> : public GPtrArrayFuncs
  170. {};
  171. template<typename ElCType, typename Transfer>
  172. class CollectionBase<::GPtrArray, ElCType, Transfer>
  173. : public Wrapper<GPtrArrayFuncs, ::GPtrArray>
  174. {
  175. protected:
  176. using list_ops = GPtrArrayFuncs;
  177. using state_type = int; // dummy
  178. state_type _create()
  179. {
  180. if (!this->data_) {
  181. auto &l = this->data_;
  182. l = g_ptr_array_new();
  183. if (std::is_same<Transfer, transfer_full_t>::value)
  184. g_ptr_array_set_free_func(
  185. l, (GDestroyNotify)_traits::destroy<ElCType>::func);
  186. }
  187. return 0;
  188. }
  189. void _finish() {}
  190. state_type _push(state_type s, list_ops::value_type item)
  191. {
  192. g_ptr_array_add(this->data_, item);
  193. return s;
  194. }
  195. struct iterator_type
  196. {
  197. CollectionBase *self;
  198. int index;
  199. bool next(list_ops::value_type &val)
  200. {
  201. if (self->data_ && (index < (int)self->data_->len)) {
  202. val = g_ptr_array_index(self->data_, index++);
  203. return true;
  204. }
  205. return false;
  206. }
  207. };
  208. iterator_type _iterator() { return iterator_type{this, 0}; }
  209. void _steal()
  210. {
  211. g_free(g_ptr_array_steal(this->data_, nullptr));
  212. g_ptr_array_unref(this->data_);
  213. this->data_ = nullptr;
  214. }
  215. public:
  216. using value_type = typename elcpptype<ElCType, Transfer>::type;
  217. protected:
  218. value_type *_cast() const
  219. {
  220. return wrap_cast<Transfer>((ElCType *)(this->data_->pdata));
  221. }
  222. GI_DISABLE_METHOD_NONE
  223. void _ensure_array() { _create(); }
  224. public:
  225. // assume same layout of wrapper and wrappee
  226. static_assert(sizeof(value_type) == sizeof(gpointer), "");
  227. static_assert(sizeof(value_type[2]) == sizeof(gpointer[2]), "");
  228. using iterator = value_type *;
  229. using const_iterator = const value_type *;
  230. const_iterator cbegin() const { return this->data_ ? _cast() : nullptr; }
  231. const_iterator cend() const
  232. {
  233. return this->data_ ? begin() + this->data_->len : nullptr;
  234. }
  235. const_iterator begin() const { return cbegin(); }
  236. const_iterator end() const { return cend(); }
  237. GI_DISABLE_METHOD_NONE
  238. iterator begin() { return this->data_ ? _cast() : nullptr; }
  239. GI_DISABLE_METHOD_NONE iterator end()
  240. {
  241. return this->data_ ? begin() + this->data_->len : nullptr;
  242. }
  243. size_t size() const noexcept { return this->data_ ? this->data_->len : 0; }
  244. bool empty() const noexcept { return size() == 0; }
  245. GI_DISABLE_METHOD_NONE
  246. void push_front(const value_type &v) { insert(begin(), v); }
  247. GI_DISABLE_METHOD_NONE
  248. void push_front(value_type &&v) { insert(begin(), std::move(v)); }
  249. GI_DISABLE_METHOD_NONE
  250. void pop_front() { erase(begin()); }
  251. GI_DISABLE_METHOD_NONE
  252. void push_back(const value_type &v) { insert(end(), v); }
  253. GI_DISABLE_METHOD_NONE
  254. void push_back(value_type &&v) { insert(end(), std::move(v)); }
  255. GI_DISABLE_METHOD_NONE
  256. void pop_back()
  257. {
  258. if (!empty())
  259. erase(end() - 1);
  260. }
  261. GI_DISABLE_METHOD_NONE
  262. iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
  263. GI_DISABLE_METHOD_NONE
  264. iterator erase(const_iterator first, const_iterator last)
  265. {
  266. if (this->data_ && first < last) {
  267. auto index = first - begin();
  268. auto cnt = last - first;
  269. // erase from back to front to minimize (or even avoid) data moves
  270. while (cnt) {
  271. --cnt;
  272. auto v = g_ptr_array_steal_index(this->data_, index + cnt);
  273. _traits::destroy<ElCType>::func(ElCType(v));
  274. }
  275. return begin() + index;
  276. }
  277. return begin();
  278. }
  279. GI_DISABLE_METHOD_NONE
  280. iterator insert(const_iterator pos, const value_type &v)
  281. {
  282. auto cv = unwrap(v, Transfer());
  283. return _insert(pos, cv);
  284. }
  285. GI_DISABLE_METHOD_NONE
  286. iterator insert(const_iterator pos, value_type &&v)
  287. {
  288. auto cv = unwrap(std::move(v), Transfer());
  289. return _insert(pos, cv);
  290. }
  291. // erase to avoid memory free
  292. GI_DISABLE_METHOD_NONE
  293. void clear() { erase(begin(), end()); }
  294. protected:
  295. iterator _insert(const_iterator pos, gpointer v)
  296. {
  297. // establish index before potential create
  298. auto index = pos - begin();
  299. _ensure_array();
  300. g_ptr_array_insert(this->data_, index, v);
  301. return begin() + index;
  302. }
  303. };
  304. struct GHashTableFuncs
  305. {
  306. constexpr static bool refcnt = true;
  307. using value_type = std::pair<gpointer, gpointer>;
  308. static GType get_type_() { return G_TYPE_HASH_TABLE; }
  309. static ::GHashTable *ref(::GHashTable *data)
  310. {
  311. return data ? g_hash_table_ref(data) : data;
  312. }
  313. static ::GHashTable *sink(::GHashTable *data)
  314. {
  315. return data ? g_hash_table_ref(data) : data;
  316. }
  317. static void free(::GHashTable *&data)
  318. {
  319. if (data) {
  320. g_hash_table_unref(data);
  321. data = nullptr;
  322. }
  323. }
  324. static ::GHashTable *float_(::GHashTable *data) { return data; }
  325. };
  326. template<typename ElCType, typename Transfer>
  327. struct list_ops<::GHashTable, ElCType, Transfer> : public GHashTableFuncs
  328. {};
  329. template<typename ElCType, typename Transfer>
  330. class CollectionBase<::GHashTable, ElCType, Transfer>
  331. : public Wrapper<GHashTableFuncs, ::GHashTable>
  332. {
  333. protected:
  334. using list_ops = GHashTableFuncs;
  335. using ElCKeyType = typename std::tuple_element<0, ElCType>::type;
  336. using ElCMappedType = typename std::tuple_element<1, ElCType>::type;
  337. using ElCppKeyType = typename elcpptype<ElCKeyType, Transfer>::type;
  338. using ElCppMappedType = typename elcpptype<ElCMappedType, Transfer>::type;
  339. static_assert(sizeof(ElCKeyType) == sizeof(gpointer), "");
  340. static_assert(sizeof(ElCMappedType) == sizeof(gpointer), "");
  341. using key_type = const ElCppKeyType;
  342. using mapped_type = ElCppMappedType;
  343. using value_type = std::pair<ElCppKeyType, mapped_type>;
  344. using const_value_type = std::pair<const ElCppKeyType, const mapped_type>;
  345. using state_type = int; // dummy
  346. state_type _create()
  347. {
  348. if (!this->data_) {
  349. if (std::is_same<Transfer, transfer_full_t>::value) {
  350. this->data_ = g_hash_table_new_full(_traits::hash<ElCppKeyType>::func,
  351. _traits::equal<ElCppKeyType>::func,
  352. GDestroyNotify(_traits::destroy<ElCppKeyType>::func),
  353. GDestroyNotify(_traits::destroy<ElCppMappedType>::func));
  354. } else {
  355. this->data_ = g_hash_table_new(_traits::hash<ElCppKeyType>::func,
  356. _traits::equal<ElCppKeyType>::func);
  357. }
  358. }
  359. return 0;
  360. }
  361. state_type _push(state_type s, list_ops::value_type item)
  362. {
  363. g_hash_table_replace(this->data_, item.first, item.second);
  364. return s;
  365. }
  366. void _finish() {}
  367. struct iterator_type
  368. {
  369. CollectionBase &self;
  370. GHashTableIter iter;
  371. int index{};
  372. iterator_type(CollectionBase &_self) : self(_self)
  373. {
  374. if (self.data_)
  375. g_hash_table_iter_init(&iter, self.data_);
  376. }
  377. bool next(list_ops::value_type &val)
  378. {
  379. if (!self.data_)
  380. return false;
  381. gpointer key, value;
  382. auto more = g_hash_table_iter_next(&iter, &key, &value);
  383. val = {key, value};
  384. return more;
  385. }
  386. };
  387. iterator_type _iterator() { return iterator_type{*this}; }
  388. void _steal()
  389. {
  390. g_hash_table_steal_all(this->data_);
  391. g_hash_table_unref(this->data_);
  392. this->data_ = nullptr;
  393. }
  394. public:
  395. class const_iterator
  396. : public detail::iterator<std::input_iterator_tag, const_value_type>
  397. {
  398. using self_type = const_iterator;
  399. enum State { NONE, INIT, ITERATING, DONE };
  400. ::GHashTableIter iter;
  401. std::pair<gpointer, gpointer> kv;
  402. State state;
  403. const_value_type *_cast()
  404. {
  405. // sanity check in view of rough cast
  406. static_assert(sizeof(kv) == sizeof(const_value_type), "");
  407. return reinterpret_cast<const_value_type *>(&kv);
  408. }
  409. ::GHashTable *_table() const
  410. {
  411. return state == NONE || state == DONE
  412. ? nullptr
  413. : g_hash_table_iter_get_hash_table(
  414. const_cast<::GHashTableIter *>(&iter));
  415. }
  416. public:
  417. const_iterator(
  418. ::GHashTable *table, gpointer key = nullptr, gpointer value = nullptr)
  419. : state(NONE)
  420. {
  421. if (table) {
  422. g_hash_table_iter_init(&iter, table);
  423. state = INIT;
  424. // if iterator is created as a result of a find,
  425. // then we arrange for lazy sync of hash table iterator
  426. if (G_LIKELY(!key && !value)) {
  427. state = ITERATING;
  428. ++(*this);
  429. } else {
  430. kv = {key, value};
  431. }
  432. }
  433. }
  434. const_value_type &operator*() { return *_cast(); }
  435. const_value_type *operator->() { return _cast(); }
  436. bool operator==(const self_type &other)
  437. {
  438. auto t = _table();
  439. return (t == other._table()) && (!t || (kv.first == other.kv.first));
  440. }
  441. bool operator!=(const self_type &other) { return !(*this == other); }
  442. self_type &operator++()
  443. {
  444. bool has_more = true;
  445. // if needed, sync iterator with key
  446. if (G_UNLIKELY(state != ITERATING)) {
  447. gpointer key{}, value{};
  448. while (has_more && key != kv.first) {
  449. has_more = g_hash_table_iter_next(&iter, &key, &value);
  450. }
  451. }
  452. if (G_LIKELY(has_more))
  453. has_more = g_hash_table_iter_next(&iter, &kv.first, &kv.second);
  454. state = has_more ? ITERATING : DONE;
  455. return *this;
  456. }
  457. };
  458. // consistency
  459. using iterator = const_iterator;
  460. const_iterator cbegin() const { return {this->data_}; }
  461. const_iterator cend() const { return {nullptr}; }
  462. const_iterator begin() const { return cbegin(); };
  463. const_iterator end() const { return cend(); };
  464. size_t size() const
  465. {
  466. return this->data_ ? g_hash_table_size(this->data_) : 0;
  467. }
  468. bool empty() const { return size() == 0; }
  469. GI_DISABLE_METHOD_NONE
  470. void clear()
  471. {
  472. if (this->data_)
  473. g_hash_table_remove_all(this->data_);
  474. };
  475. size_t count(key_type &key) const
  476. {
  477. if (!this->data_)
  478. return 0;
  479. auto v = unwrap(key, transfer_none);
  480. return g_hash_table_contains(this->data_, v) ? 1 : 0;
  481. }
  482. const_iterator find(key_type &key) const
  483. {
  484. if (this->data_) {
  485. auto v = unwrap(key, transfer_none);
  486. gpointer lv;
  487. if (g_hash_table_lookup_extended(this->data_, v, nullptr, &lv))
  488. return {this->data_, gpointer(v), gpointer(lv)};
  489. }
  490. return end();
  491. }
  492. typename elcpptype<ElCMappedType, transfer_none_t>::type lookup(
  493. key_type &key) const
  494. {
  495. auto it = find(key);
  496. if (it == end())
  497. return {};
  498. // decay copy should be possible
  499. return it->second;
  500. }
  501. GI_DISABLE_METHOD_NONE
  502. bool replace(ElCppKeyType &&key, ElCppMappedType &&value)
  503. {
  504. _create();
  505. auto kv = unwrap(std::move(key), Transfer());
  506. auto vv = unwrap(std::move(value), Transfer());
  507. return g_hash_table_replace(this->data_, kv, vv);
  508. }
  509. GI_DISABLE_METHOD_NONE
  510. size_t erase(key_type &key)
  511. {
  512. if (this->data_) {
  513. auto v = unwrap(key, transfer_none);
  514. return g_hash_table_remove(this->data_, gpointer(v)) ? 1 : 0;
  515. }
  516. return 0;
  517. }
  518. };
  519. template<typename ListType>
  520. struct ListFuncs
  521. {
  522. constexpr static bool refcnt = false;
  523. using value_type = gpointer;
  524. // this value type is used in e.g. signal argument
  525. static GType get_type_() { return G_TYPE_POINTER; }
  526. static ListType *ref(ListType *data) { return data; }
  527. };
  528. template<typename ElCType, typename Transfer>
  529. struct list_ops<::GList, ElCType, Transfer> : public ListFuncs<::GList>
  530. {};
  531. template<typename ElCType, typename Transfer>
  532. struct list_ops<::GSList, ElCType, Transfer> : public ListFuncs<::GSList>
  533. {};
  534. template<typename ListType>
  535. struct LinkedListOps;
  536. template<>
  537. struct LinkedListOps<::GSList>
  538. {
  539. static void free(::GSList *l) { g_slist_free(l); }
  540. static void free_full(::GSList *l, GDestroyNotify func)
  541. {
  542. g_slist_free_full(l, func);
  543. }
  544. static ::GSList *append(::GSList *l, gpointer data)
  545. {
  546. return g_slist_append(l, data);
  547. }
  548. static ::GSList *prepend(::GSList *l, gpointer data)
  549. {
  550. return g_slist_prepend(l, data);
  551. }
  552. static ::GSList *last(::GSList *l) { return g_slist_last(l); }
  553. static ::GSList *insert_before(::GSList *l, ::GSList *link, gpointer data)
  554. {
  555. return g_slist_insert_before(l, link, data);
  556. }
  557. static ::GSList *delete_link(::GSList *l, ::GSList *link)
  558. {
  559. return g_slist_delete_link(l, link);
  560. }
  561. static ::GSList *reverse(::GSList *l) { return g_slist_reverse(l); }
  562. };
  563. template<>
  564. struct LinkedListOps<::GList>
  565. {
  566. static void free(::GList *l) { g_list_free(l); }
  567. static void free_full(::GList *l, GDestroyNotify func)
  568. {
  569. return g_list_free_full(l, func);
  570. }
  571. static ::GList *append(::GList *l, gpointer data)
  572. {
  573. return g_list_append(l, data);
  574. }
  575. static ::GList *prepend(::GList *l, gpointer data)
  576. {
  577. return g_list_prepend(l, data);
  578. }
  579. static ::GList *last(::GList *l) { return g_list_last(l); }
  580. static ::GList *insert_before(::GList *l, ::GList *link, gpointer data)
  581. {
  582. return g_list_insert_before(l, link, data);
  583. }
  584. static ::GList *delete_link(::GList *l, ::GList *link)
  585. {
  586. return g_list_delete_link(l, link);
  587. }
  588. static ::GList *reverse(::GList *l) { return g_list_reverse(l); }
  589. };
  590. template<typename ListType, typename ElType, typename Transfer>
  591. struct LinkedListBase;
  592. template<typename ListType, typename ElCType>
  593. struct LinkedListBase<ListType, ElCType, transfer_none_t>
  594. : public SharedWrapper<ListType>
  595. {
  596. protected:
  597. static void _deleter(ListType *&d, ...) { d = nullptr; }
  598. static ListType *_copy(ListType *d) { return d; }
  599. };
  600. template<typename ListType, typename ElCType>
  601. struct LinkedListBase<ListType, ElCType, transfer_container_t>
  602. : public SharedWrapper<ListType>
  603. {
  604. protected:
  605. static void _deleter(ListType *&l, ...)
  606. {
  607. LinkedListOps<ListType>::free(l);
  608. l = nullptr;
  609. }
  610. };
  611. template<typename ListType, typename ElCType>
  612. struct LinkedListBase<ListType, ElCType, transfer_full_t>
  613. : public SharedWrapper<ListType>
  614. {
  615. protected:
  616. static void _deleter(ListType *&l, ...)
  617. {
  618. LinkedListOps<ListType>::free_full(
  619. l, (GDestroyNotify)_traits::destroy<ElCType>::func);
  620. l = nullptr;
  621. }
  622. };
  623. // enable copy constructor on none transfer cases
  624. // compiler otherwise always selects the deleted one, even if other options
  625. template<typename Transfer, typename Base>
  626. using SelectBaseWrapper =
  627. typename std::conditional<std::is_same<Transfer, transfer_none_t>::value,
  628. CopyWrapper<Base>, MoveWrapper<Base>>::type;
  629. template<typename ListType, typename ElCType, typename Transfer>
  630. class CollectionBase<ListType, ElCType, Transfer,
  631. typename std::enable_if<std::is_same<ListType, ::GSList>::value ||
  632. std::is_same<ListType, ::GList>::value>::type>
  633. : public SelectBaseWrapper<Transfer,
  634. LinkedListBase<ListType, ElCType, Transfer>>
  635. {
  636. protected:
  637. using list_ops = ListFuncs<ListType>;
  638. using state_type = ListType *;
  639. state_type _create() { return nullptr; }
  640. state_type _push(state_type, typename list_ops::value_type item)
  641. {
  642. this->data_ = LinkedListOps<ListType>::prepend(this->data_, item);
  643. return nullptr;
  644. }
  645. void _finish()
  646. {
  647. this->data_ = LinkedListOps<ListType>::reverse(this->data_);
  648. }
  649. struct iterator_type
  650. {
  651. ListType *it;
  652. bool next(typename list_ops::value_type &val)
  653. {
  654. if (it) {
  655. val = it->data;
  656. it = it->next;
  657. return true;
  658. }
  659. return false;
  660. }
  661. };
  662. iterator_type _iterator() { return {this->data_}; }
  663. void _steal()
  664. {
  665. LinkedListOps<ListType>::free(this->data_);
  666. this->data_ = nullptr;
  667. }
  668. static void _destroy(gpointer value)
  669. {
  670. _traits::destroy<ElCType>::func(ElCType(value));
  671. }
  672. public:
  673. using value_type = typename elcpptype<ElCType, Transfer>::type;
  674. static constexpr bool is_glist = std::is_same<ListType, ::GList>::value;
  675. template<typename value_t>
  676. class iterator_t : public detail::iterator<std::forward_iterator_tag, value_t>
  677. {
  678. using self_type = iterator_t;
  679. friend class CollectionBase;
  680. ListType *it = nullptr;
  681. public:
  682. iterator_t(ListType *l = nullptr) : it(l){};
  683. // construct const from non-const
  684. template<typename other_value_t,
  685. typename Enable = typename std::enable_if<
  686. std::is_convertible<other_value_t *, value_t *>::value>::type>
  687. iterator_t(const iterator_t<other_value_t> &oi) : iterator_t(oi.it)
  688. {}
  689. value_t &operator*() { return *operator->(); }
  690. value_t *operator->()
  691. {
  692. return wrap_cast<Transfer>((ElCType *)(&it->data));
  693. }
  694. bool operator==(const self_type &other) { return it == other.it; }
  695. bool operator!=(const self_type &other) { return !(*this == other); }
  696. self_type &operator++()
  697. {
  698. if (it)
  699. it = it->next;
  700. return *this;
  701. }
  702. self_type operator++(int)
  703. {
  704. auto ret = *this;
  705. ++(*this);
  706. return ret;
  707. }
  708. };
  709. using const_iterator = iterator_t<const value_type>;
  710. using iterator = iterator_t<value_type>;
  711. const_iterator begin() const { return cbegin(); }
  712. const_iterator end() const { return cend(); }
  713. const_iterator cbegin() const { return {this->data_}; }
  714. const_iterator cend() const { return {}; }
  715. GI_DISABLE_METHOD_NONE
  716. iterator begin() { return {this->data_}; }
  717. GI_DISABLE_METHOD_NONE
  718. iterator end() { return {}; }
  719. bool empty() const noexcept { return !this->data_; }
  720. GI_DISABLE_METHOD_NONE
  721. void push_front(const value_type &v)
  722. {
  723. auto cv = unwrap(v, Transfer());
  724. this->data_ = LinkedListOps<ListType>::prepend(this->data_, cv);
  725. }
  726. GI_DISABLE_METHOD_NONE
  727. void push_front(value_type &&v)
  728. {
  729. auto cv = unwrap(std::move(v), Transfer());
  730. this->data_ = LinkedListOps<ListType>::prepend(this->data_, cv);
  731. }
  732. GI_DISABLE_METHOD_NONE
  733. void pop_front()
  734. {
  735. if (this->data_)
  736. _destroy(this->data_->data);
  737. this->data_ =
  738. LinkedListOps<ListType>::delete_link(this->data_, this->data_);
  739. }
  740. GI_DISABLE_METHOD_NONE
  741. void push_back(const value_type &v)
  742. {
  743. auto cv = unwrap(v, Transfer());
  744. this->data_ = LinkedListOps<ListType>::append(this->data_, cv);
  745. }
  746. GI_DISABLE_METHOD_NONE
  747. void push_back(value_type &&v)
  748. {
  749. auto cv = unwrap(std::move(v), Transfer());
  750. this->data_ = LinkedListOps<ListType>::append(this->data_, cv);
  751. }
  752. GI_DISABLE_METHOD_NONE
  753. void pop_back()
  754. {
  755. auto last = LinkedListOps<ListType>::last(this->data_);
  756. if (last)
  757. _destroy(last->data);
  758. this->data_ = LinkedListOps<ListType>::delete_link(this->data_, last);
  759. }
  760. GI_DISABLE_METHOD_NONE
  761. iterator erase(const_iterator pos)
  762. {
  763. ListType *next = nullptr;
  764. if (pos.it) {
  765. next = pos.it->next;
  766. _destroy(pos.it->data);
  767. }
  768. this->data_ = LinkedListOps<ListType>::delete_link(this->data_, pos.it);
  769. return {next};
  770. }
  771. template<typename Enable = void,
  772. typename Check = typename std::enable_if<
  773. std::is_void<Enable>::value && Transfer().value && is_glist>::type>
  774. iterator insert(const_iterator pos, const value_type &v)
  775. {
  776. auto cv = unwrap(v, Transfer());
  777. return _insert(pos, cv);
  778. }
  779. template<typename Enable = void,
  780. typename Check = typename std::enable_if<
  781. std::is_void<Enable>::value && Transfer().value && is_glist>::type>
  782. iterator insert(const_iterator pos, value_type &&v)
  783. {
  784. auto cv = unwrap(std::move(v), Transfer());
  785. return _insert(pos, cv);
  786. }
  787. GI_DISABLE_METHOD_NONE
  788. void reverse()
  789. {
  790. this->data_ = LinkedListOps<ListType>::reverse(this->data_);
  791. }
  792. GI_DISABLE_METHOD_NONE
  793. void clear()
  794. {
  795. this->_deleter(this->data_);
  796. this->data_ = nullptr;
  797. }
  798. protected:
  799. iterator _insert(const_iterator pos, gpointer v)
  800. {
  801. this->data_ =
  802. LinkedListOps<ListType>::insert_before(this->data_, pos.it, v);
  803. return {pos.it ? pos.it->prev : LinkedListOps<ListType>::last(this->data_)};
  804. }
  805. };
  806. enum SpanType {
  807. DYNAMIC = -1,
  808. ZT = 0,
  809. };
  810. template<int SIZE>
  811. struct Span
  812. {};
  813. template<typename ElCType, typename Transfer, int SIZE>
  814. struct SpanBase : public SharedWrapper<ElCType>
  815. {
  816. protected:
  817. // extra members needed in this case
  818. // only > 0 if data locally allocated (as opposed to from elsewhere)
  819. size_t capacity_ = 0;
  820. size_t size_ = 0;
  821. static void _deleter(decltype(SpanBase::data_) &d, SpanBase *self)
  822. {
  823. assert(self);
  824. if (std::is_same<Transfer, transfer_full_t>::value && d) {
  825. auto end = d + self->size_;
  826. for (auto p = d; p != end; ++p) {
  827. _traits::destroy<ElCType>::func(*p);
  828. }
  829. }
  830. if (!std::is_same<Transfer, transfer_none_t>::value)
  831. g_free(d);
  832. d = nullptr;
  833. }
  834. template<typename Enable = void>
  835. static decltype(SpanBase::data_) _copy(decltype(SpanBase::data_) d)
  836. {
  837. // should only end up used in none case
  838. static_assert(std::is_same<Transfer, transfer_none_t>::value, "");
  839. return d;
  840. }
  841. };
  842. template<typename ElCType, typename Transfer, int SIZE>
  843. struct list_ops<Span<SIZE>, ElCType, Transfer> : public ListFuncs<ElCType>
  844. {};
  845. template<typename ElCType, typename Transfer, int SIZE>
  846. class CollectionBase<Span<SIZE>, ElCType, Transfer>
  847. : public SelectBaseWrapper<Transfer, SpanBase<ElCType, Transfer, SIZE>>
  848. {
  849. protected:
  850. static auto constexpr SPAN_SIZE = SIZE;
  851. struct list_ops : public ListFuncs<ElCType>
  852. {
  853. using value_type = ElCType;
  854. };
  855. using state_type = ElCType *;
  856. // used by wrap
  857. CollectionBase(ElCType *p = nullptr, int s = 0)
  858. {
  859. // NOTE no copy needed;
  860. // either transfer is full/container (and ownership is assumed)
  861. // either transfer is none (and will never free/release)
  862. this->data_ = p;
  863. this->capacity_ = 0;
  864. // normalize -1 from C side to avoid potential surprises elsewhere
  865. if (s < 0 || SIZE == ZT) {
  866. s = 0;
  867. if (p) {
  868. while (*p) {
  869. ++s;
  870. ++p;
  871. }
  872. }
  873. }
  874. this->size_ = s;
  875. }
  876. ElCType *_create()
  877. {
  878. if (!this->data_) {
  879. this->capacity_ = SIZE > 0 ? SIZE : 2;
  880. this->data_ = (ElCType *)g_malloc0(this->capacity_ * sizeof(ElCType));
  881. this->size_ = 0;
  882. }
  883. return this->data_;
  884. }
  885. void _create_from(ElCType *d, size_t lsize)
  886. {
  887. using T = ElCType;
  888. // try to re-use incoming data
  889. // otherwise fall back to plain copy
  890. // (if transfer or zero-termination fiddling is needed)
  891. bool allocate = (Transfer().value != transfer_none.value) || (SIZE == ZT);
  892. auto size = SIZE == ZT ? lsize + 1 : lsize;
  893. auto *data = d;
  894. if (allocate) {
  895. data = (T *)g_malloc(size * sizeof(T));
  896. this->capacity_ = size;
  897. memcpy(data, d, lsize * sizeof(T));
  898. if (SIZE == ZT)
  899. data[lsize] = T{};
  900. }
  901. // track data
  902. assert(!this->data_);
  903. g_free(this->data_);
  904. this->data_ = data;
  905. this->size_ = lsize;
  906. }
  907. void _reserve(size_t capacity)
  908. {
  909. if (this->capacity_ < capacity + (SIZE == ZT)) {
  910. this->capacity_ =
  911. std::max(std::max(2 * this->capacity_, size_t(2)), capacity);
  912. this->data_ =
  913. (ElCType *)g_realloc_n(this->data_, this->capacity_, sizeof(ElCType));
  914. }
  915. }
  916. state_type _push(state_type s, ElCType item)
  917. {
  918. // should only get here if previously allocated
  919. assert(this->capacity_ > 0);
  920. auto offset = s - this->data_;
  921. _reserve(offset + 1);
  922. s = this->data_ + offset;
  923. *s = item;
  924. ++this->size_;
  925. ++s;
  926. // ensure ZT if applicable
  927. if (SIZE == ZT) {
  928. assert(size_t(s - this->data_) < this->capacity_);
  929. *s = ElCType{};
  930. }
  931. return s;
  932. }
  933. void _finish()
  934. {
  935. if ((SIZE > 0) && (this->size_ != (size_t)SIZE))
  936. g_error("fixed list size mismatch");
  937. }
  938. struct iterator_type
  939. {
  940. CollectionBase &self;
  941. ElCType *p;
  942. iterator_type(CollectionBase &s) : self(s), p(self.data_) {}
  943. explicit operator bool()
  944. {
  945. return p && (ZT ? !!*p : (p != self.data_ + self.size_));
  946. };
  947. bool next(ElCType &val)
  948. {
  949. if (*this) {
  950. val = *(p++);
  951. return true;
  952. }
  953. return false;
  954. }
  955. };
  956. iterator_type _iterator() { return {*this}; }
  957. void _steal()
  958. {
  959. // if Holder is trying to destroy, check if we really allocated
  960. // (may have optimized array case)
  961. if (!std::is_same<Transfer, transfer_none_t>::value || this->capacity_)
  962. g_free(this->data_);
  963. this->data_ = nullptr;
  964. this->size_ = this->capacity_ = 0;
  965. };
  966. public:
  967. // this one is used by code generation (the unwrap size part)
  968. // so it should only be used in specific situations
  969. // let's add checks to make it so
  970. size_t _size() const
  971. {
  972. static_assert(SIZE != ZT, "");
  973. return this->size_;
  974. }
  975. using value_type = typename elcpptype<ElCType, Transfer>::type;
  976. // assume same layout of wrapper and wrappee
  977. static_assert(sizeof(value_type) == sizeof(ElCType), "");
  978. static_assert(sizeof(value_type[2]) == sizeof(ElCType[2]), "");
  979. using iterator = value_type *;
  980. using const_iterator = const value_type *;
  981. const_iterator cbegin() const
  982. {
  983. return this->data_ ? wrap_cast<Transfer>(this->data_) : nullptr;
  984. }
  985. const_iterator cend() const
  986. {
  987. return this->data_ ? begin() + this->size_ : nullptr;
  988. }
  989. const_iterator begin() const { return cbegin(); }
  990. const_iterator end() const { return cend(); }
  991. GI_DISABLE_METHOD_NONE
  992. iterator begin()
  993. {
  994. return this->data_ ? wrap_cast<Transfer>(this->data_) : nullptr;
  995. }
  996. GI_DISABLE_METHOD_NONE
  997. iterator end() { return this->data_ ? begin() + this->size_ : nullptr; }
  998. size_t size() const { return this->size_; }
  999. bool empty() const { return size() == 0; }
  1000. GI_DISABLE_METHOD_NONE
  1001. void push_front(const value_type &v) { insert(begin(), v); }
  1002. GI_DISABLE_METHOD_NONE
  1003. void push_front(value_type &&v) { insert(begin(), std::move(v)); }
  1004. GI_DISABLE_METHOD_NONE
  1005. void pop_front() { erase(begin()); }
  1006. GI_DISABLE_METHOD_NONE
  1007. void push_back(const value_type &v) { insert(end(), v); }
  1008. GI_DISABLE_METHOD_NONE
  1009. void push_back(value_type &&v) { insert(end(), std::move(v)); }
  1010. GI_DISABLE_METHOD_NONE
  1011. void pop_back()
  1012. {
  1013. if (!empty())
  1014. erase(end() - 1);
  1015. }
  1016. GI_DISABLE_METHOD_NONE
  1017. iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
  1018. GI_DISABLE_METHOD_NONE
  1019. iterator erase(const_iterator first, const_iterator last)
  1020. {
  1021. if (this->data_ && this->size_ > 0 && first < last) {
  1022. size_t index = first - begin();
  1023. size_t cnt = last - first;
  1024. size_t lindex = std::min(index + cnt, this->size_);
  1025. for (auto i = index; i < lindex; ++i)
  1026. _traits::destroy<ElCType>::func(this->data_[index]);
  1027. if (lindex < this->size_)
  1028. memmove(this->data_ + index, this->data_ + lindex,
  1029. sizeof(*this->data_) * (this->size_ - lindex));
  1030. this->size_ -= cnt;
  1031. if (SIZE == ZT)
  1032. this->data_[this->size_] = ElCType{};
  1033. return begin() + index;
  1034. }
  1035. return begin();
  1036. }
  1037. GI_DISABLE_METHOD_NONE
  1038. iterator insert(const_iterator pos, const value_type &v)
  1039. {
  1040. auto cv = unwrap(v, Transfer());
  1041. return _insert(pos, cv);
  1042. }
  1043. GI_DISABLE_METHOD_NONE
  1044. iterator insert(const_iterator pos, value_type &&v)
  1045. {
  1046. auto cv = unwrap(std::move(v), Transfer());
  1047. return _insert(pos, cv);
  1048. }
  1049. size_t capacity() const { return this->capacity_; }
  1050. GI_DISABLE_METHOD_NONE
  1051. void reserve(size_t capacity) { _reserve(capacity); }
  1052. // erase to avoid memory free
  1053. GI_DISABLE_METHOD_NONE
  1054. void clear() { erase(begin(), end()); }
  1055. protected:
  1056. iterator _insert(const_iterator pos, ElCType v)
  1057. {
  1058. // establish index before potential create
  1059. size_t index = pos - begin();
  1060. // grow if needed
  1061. _reserve(this->size_ + 1);
  1062. // move if needed
  1063. if (index < this->size_)
  1064. memmove(this->data_ + index + 1, this->data_ + index,
  1065. sizeof(*this->data_) * (this->size_ - index));
  1066. // insert
  1067. ++this->size_;
  1068. this->data_[index] = v;
  1069. // ensure ZT if applicable
  1070. if (SIZE == ZT) {
  1071. assert(this->size_ < this->capacity_);
  1072. this->data_[this->size_] = ElCType{};
  1073. }
  1074. return begin() + index;
  1075. }
  1076. };
  1077. // class tag
  1078. class Container
  1079. {};
  1080. // minor helper, essentially compile-time signal/notification
  1081. template<typename T>
  1082. struct Notifier
  1083. {
  1084. static constexpr bool construct_none = false;
  1085. static void _updated(T *, bool /*create*/) {}
  1086. };
  1087. // considered owning for container or full
  1088. // unwrap will have to release_()
  1089. template<typename ListType, typename T, typename Transfer = transfer_full_t,
  1090. typename Notify = Notifier<void>, typename ExtraBase = Container>
  1091. struct Collection : public CollectionBase<ListType, T, Transfer>,
  1092. public ExtraBase
  1093. {
  1094. protected:
  1095. using self_type = Collection;
  1096. using super_type = CollectionBase<ListType, T, Transfer>;
  1097. public:
  1098. using list_ops = typename super_type::list_ops;
  1099. protected:
  1100. using ElTransfer = typename element_transfer<Transfer>::type;
  1101. // decompose pair in case of map
  1102. template<typename G>
  1103. struct get_types
  1104. {
  1105. // map to harmless type if no key applicable
  1106. using key_type = bool;
  1107. using mapped_type = G;
  1108. using cpp_type = typename traits::cpptype<G, ElTransfer>::type;
  1109. };
  1110. template<typename T1, typename T2>
  1111. struct get_types<std::pair<T1, T2>>
  1112. {
  1113. using key_type = T1;
  1114. using mapped_type = T2;
  1115. using cpp_type = std::pair<typename traits::cpptype<T1, ElTransfer>::type,
  1116. typename traits::cpptype<T2, ElTransfer>::type>;
  1117. };
  1118. using KeyCType = typename get_types<T>::key_type;
  1119. using ElCType = typename get_types<T>::mapped_type;
  1120. using KeyCppType = typename traits::cpptype<KeyCType, ElTransfer>::type;
  1121. using ElCppType = typename traits::cpptype<ElCType, ElTransfer>::type;
  1122. using ValueCppType = typename get_types<T>::cpp_type;
  1123. // sanity/consistency checks
  1124. // expect normalized template types
  1125. static_assert(
  1126. std::is_same<ListType, typename std::decay<ListType>::type>::value, "");
  1127. static_assert(
  1128. std::is_same<KeyCppType, typename std::decay<KeyCppType>::type>::value,
  1129. "");
  1130. static_assert(
  1131. std::is_same<ElCppType, typename std::decay<ElCppType>::type>::value, "");
  1132. // internal wrap of list-case
  1133. Collection(ListType *l, bool own)
  1134. {
  1135. this->data_ = ((!own && l) ? list_ops::ref(l) : l);
  1136. }
  1137. // internal wrap of span case
  1138. // (also avoid conflict with a public constructor below)
  1139. template<typename Enable = void>
  1140. Collection(ElCType *d, size_t s, std::nullptr_t) : super_type(d, s)
  1141. {}
  1142. template<typename T1, typename T2, typename LVR>
  1143. std::pair<gpointer, gpointer> unwrap_item(std::pair<T1, T2> &el, LVR)
  1144. {
  1145. // NOTE if compiler error occurs here, perhaps std::move() input
  1146. auto item1 = unwrap(cast_ref(el.first, LVR()), ElTransfer());
  1147. static_assert(std::is_pointer<decltype(item1)>::value, "expected pointer");
  1148. auto item2 = unwrap(cast_ref(el.second, LVR()), ElTransfer());
  1149. static_assert(std::is_pointer<decltype(item2)>::value, "expected pointer");
  1150. return {(gpointer)item1, (gpointer)item2};
  1151. };
  1152. template<typename T1, typename LVR>
  1153. typename list_ops::value_type unwrap_item(T1 &el, LVR)
  1154. {
  1155. // NOTE if compiler error occurs here, perhaps std::move() input
  1156. auto item = unwrap(cast_ref(el, LVR()), ElTransfer());
  1157. // only force pointers or same size to same size
  1158. using item_type = decltype(item);
  1159. static_assert(
  1160. std::is_pointer<item_type>::value ==
  1161. std::is_pointer<typename list_ops::value_type>::value &&
  1162. sizeof(item_type) == sizeof(typename list_ops::value_type),
  1163. "expected pointer or matched size");
  1164. return (typename list_ops::value_type)item;
  1165. }
  1166. template<typename Iterator, typename LVR>
  1167. void create_from(Iterator first, Iterator last, LVR)
  1168. {
  1169. // empty container is not null, so always init/create
  1170. // NOTE should also add leading/initial zero if needed
  1171. Notify::_updated(this, true);
  1172. auto s = this->_create();
  1173. while (first != last) {
  1174. auto &el = *first;
  1175. auto item = unwrap_item(el, LVR());
  1176. s = this->_push(s, item);
  1177. ++first;
  1178. }
  1179. // possible (size) check might be done here
  1180. this->_finish();
  1181. }
  1182. // array as surrogate generic container
  1183. template<typename InputT>
  1184. void create_from_array(InputT *d, size_t s, std::false_type)
  1185. {
  1186. create_from(d, d + s, std::true_type());
  1187. }
  1188. // array shortcut case; from plain array to matching span
  1189. template<typename InputT>
  1190. void create_from_array(InputT *d, size_t s, std::true_type)
  1191. {
  1192. // should be around as this should be Span case
  1193. // add cast to avoid const issues etc
  1194. using v_type = typename list_ops::value_type;
  1195. static_assert(sizeof(v_type) == sizeof(InputT), "");
  1196. Notify::_updated(this, true);
  1197. this->_create_from((v_type *)d, s);
  1198. }
  1199. template<typename Out, typename Enable = void>
  1200. struct get_value_type
  1201. {
  1202. using type = typename Out::container_type::value_type;
  1203. };
  1204. template<typename Tp>
  1205. struct get_value_type<Tp *>
  1206. {
  1207. using type = typename std::decay<Tp>::type;
  1208. };
  1209. template<typename OutIterator, typename T1, typename T2>
  1210. void wrap_item_add(std::pair<T1, T2> &el, OutIterator &out)
  1211. {
  1212. using DestType = typename get_value_type<OutIterator>::type;
  1213. // expected to be a pair
  1214. using DestType1 = typename std::tuple_element<0, DestType>::type;
  1215. using DestType2 = typename std::tuple_element<1, DestType>::type;
  1216. static_assert(!(std::is_same<Transfer, transfer_full_t>::value &&
  1217. (traits::is_reftype<DestType1>::value ||
  1218. traits::is_reftype<DestType2>::value)),
  1219. "full transfer to reftype");
  1220. auto item1 = wrap((KeyCType)el.first, ElTransfer());
  1221. auto item2 = wrap((ElCType)el.second, ElTransfer());
  1222. *out = std::make_pair(std::move(item1), std::move(item2));
  1223. };
  1224. template<typename OutIterator, typename T1>
  1225. void wrap_item_add(T1 &el, OutIterator &out)
  1226. {
  1227. // validation check; no transfer full to a reftype
  1228. using DestType = typename get_value_type<OutIterator>::type;
  1229. // sanity check that we probably got the right type
  1230. static_assert(std::is_convertible<ElCppType, DestType>::value, "");
  1231. static_assert(!(std::is_same<Transfer, transfer_full_t>::value &&
  1232. traits::is_reftype<DestType>::value),
  1233. "full transfer to reftype");
  1234. using item_type = typename std::decay<decltype(el)>::type;
  1235. // would also lead to cast failure below, but make it more expressive
  1236. static_assert(
  1237. std::is_pointer<item_type>::value == std::is_pointer<ElCType>::value &&
  1238. sizeof(item_type) == sizeof(ElCType),
  1239. "expected pointer or matched size");
  1240. // could have const char** or so, so let's (const) cast the hard way
  1241. *out = wrap((ElCType)el, ElTransfer());
  1242. }
  1243. public:
  1244. // some common type blurbs
  1245. using value_type = typename super_type::value_type;
  1246. using size_type = std::size_t;
  1247. using difference_type = std::ptrdiff_t;
  1248. using reference = value_type &;
  1249. using const_reference = const value_type &;
  1250. static GType get_type_() { return list_ops::get_type_(); }
  1251. // used by code generation (for non-plain array case)
  1252. // but could be of general use
  1253. template<typename OutIterator>
  1254. void move_to(OutIterator out) &&
  1255. {
  1256. // NOTE assumption;
  1257. // out creates as it goes (e.g. back_inserter)
  1258. // or there is enough output space
  1259. typename list_ops::value_type item;
  1260. auto it = this->_iterator();
  1261. while (it.next(item)) {
  1262. wrap_item_add(item, out);
  1263. ++out;
  1264. }
  1265. // clear out elements without destroying them if needed
  1266. // (if we pulled their ownership with full transfer)
  1267. constexpr bool steal = std::is_same<ElTransfer, transfer_full_t>::value;
  1268. // provide for equally cleared state in either case
  1269. Notify::_updated(this, false);
  1270. if (steal && this->data_) {
  1271. this->_steal();
  1272. } else if (this->data_) {
  1273. this->~self_type();
  1274. this->data_ = nullptr;
  1275. }
  1276. }
  1277. public:
  1278. // group a few helpers
  1279. struct _detail
  1280. {
  1281. using DataType = decltype(std::declval<super_type>().gobj_());
  1282. // check if it is possible to create a container
  1283. // a none variant does not assume ownership
  1284. // so it is not in a position to create a collection (with no other owner)
  1285. // however, as usual, the ref types can always own
  1286. // also, allow tweaking this restriction (e.g. for holder subclass below)
  1287. static constexpr bool constructible =
  1288. !std::is_same<Transfer, transfer_none_t>::value || list_ops::refcnt ||
  1289. Notify::construct_none;
  1290. static constexpr bool is_span = !std::is_class<typename std::decay<
  1291. decltype(*std::declval<super_type>().gobj_())>::type>::value;
  1292. template<bool B, typename Enable = void>
  1293. struct span_size_impl : public std::integral_constant<int, 0>
  1294. {};
  1295. template<typename Enable>
  1296. struct span_size_impl<true, Enable>
  1297. : public std::integral_constant<int,
  1298. super_type::SPAN_SIZE >= 0 ? super_type::SPAN_SIZE : 0>
  1299. {};
  1300. static constexpr int span_size = span_size_impl<is_span>::value;
  1301. static constexpr bool is_fixed_span = is_span && span_size > 0;
  1302. // check if this is Span<> collection of plain V elements
  1303. // (the deref of data_ is so we only end up matching a Span<> case)
  1304. template<typename V>
  1305. using is_plain = typename std::conditional<
  1306. is_span && traits::is_plain<typename std::decay<V>::type>::value &&
  1307. std::is_same<typename list_ops::value_type,
  1308. typename std::decay<V>::type>::value,
  1309. std::true_type, std::false_type>::type;
  1310. // check Cpp type compatibility
  1311. // this could be triggered on non-complete V, in which case
  1312. // std::is_convertible is undefined, so guard that approach
  1313. template<typename V, bool Complete = false>
  1314. struct is_acceptable_helper : public std::integral_constant<bool, false>
  1315. {};
  1316. template<typename V>
  1317. struct is_acceptable_helper<V, true>
  1318. : public std::is_convertible<V, ValueCppType>
  1319. {};
  1320. template<typename V>
  1321. using is_acceptable = typename is_acceptable_helper<V,
  1322. traits::is_type_complete<V>::value>::type;
  1323. // likewise, deal with const variations on e.g. char**
  1324. // (as char* can be converted to const char*)
  1325. template<typename CType>
  1326. using is_compatible =
  1327. typename std::conditional<std::is_convertible<ElCType, CType>::value,
  1328. std::true_type, std::false_type>::type;
  1329. };
  1330. Collection(std::nullptr_t = nullptr) {}
  1331. // a non-owning accepts from all other types
  1332. // (either the other owns or there is another non-owner already)
  1333. template<typename OtherTransfer,
  1334. typename Enable = typename std::enable_if<
  1335. !std::is_same<void, OtherTransfer>::value &&
  1336. std::is_same<Transfer, transfer_none_t>::value>::type>
  1337. Collection(const Collection<ListType, T, OtherTransfer> &cother)
  1338. {
  1339. // never mind any const, as usual
  1340. auto &other = const_cast<Collection<ListType, T, OtherTransfer> &>(cother);
  1341. this->data_ = other.gobj_() ? list_ops::ref(other.gobj_()) : nullptr;
  1342. }
  1343. // construct from reasonably matching container
  1344. // NOTE may need r-value input for non-movable (content) types
  1345. template<typename Container,
  1346. typename Check = typename std::enable_if<
  1347. _detail::template is_acceptable<
  1348. typename std::decay<Container>::type::value_type>::value &&
  1349. _detail::constructible>::type,
  1350. typename Enable =
  1351. typename detail::disable_if_same_or_derived<Collection, Container>>
  1352. Collection(Container &&c)
  1353. {
  1354. create_from(
  1355. std::begin(c), std::end(c), std::is_lvalue_reference<Container>());
  1356. }
  1357. // construct from initializer list
  1358. template<typename InitElement,
  1359. typename Check = typename std::enable_if<
  1360. _detail::template is_acceptable<InitElement>::value &&
  1361. _detail::constructible>::type,
  1362. typename Enable =
  1363. typename detail::disable_if_same_or_derived<Collection, Container>>
  1364. Collection(std::initializer_list<InitElement> c)
  1365. {
  1366. // initializer_list iterator is a const iterator, so no moving from
  1367. create_from(std::begin(c), std::end(c), std::true_type());
  1368. }
  1369. // construct from array
  1370. // (these arguments could come from a vector, or span, or ...)
  1371. // NOTE no evident way to mark as r-value/movable-from,
  1372. // so it will just have to do and work out
  1373. template<typename InputT,
  1374. typename Check = typename std::enable_if<
  1375. _detail::template is_acceptable<InputT>::value &&
  1376. _detail::constructible>::type>
  1377. Collection(InputT *d, size_t s)
  1378. {
  1379. create_from_array(d, s, typename _detail::template is_plain<InputT>());
  1380. }
  1381. // construct from fixed-size array if this is a fixed-size Span<> case
  1382. // NOTE other notes as above apply
  1383. template<typename InputT,
  1384. typename Check = typename std::enable_if<
  1385. _detail::template is_acceptable<InputT>::value &&
  1386. _detail::constructible>::type,
  1387. typename Enable = typename std::enable_if<
  1388. !std::is_same<InputT, void>::value && _detail::is_fixed_span>::type>
  1389. Collection(InputT (&d)[_detail::span_size])
  1390. {
  1391. create_from_array(d, super_type::SPAN_SIZE,
  1392. typename _detail::template is_plain<InputT>());
  1393. }
  1394. // Avoid std::allocator type; check for const_iterator member.
  1395. // Disable conversion to an std::initializer_list (also has const_iterator).
  1396. // (in C++11 std::vector<T>::operator= is overloaded to take either a
  1397. // std::vector<T> or an std::initializer_list<T>).
  1398. // move to container
  1399. // (clear/empty this one)
  1400. template<typename Container,
  1401. typename Check = typename std::enable_if<
  1402. _detail::template is_acceptable<
  1403. typename std::decay<Container>::type::value_type>::value &&
  1404. sizeof(typename std::decay<Container>::type::const_iterator) &&
  1405. !trait::is_initializer_list<
  1406. typename std::remove_reference<Container>::type>::value>::type>
  1407. operator Container() &&
  1408. {
  1409. Container result;
  1410. std::move(*this).move_to(std::inserter(result, result.end()));
  1411. return result;
  1412. }
  1413. // generic method(s)
  1414. GI_DISABLE_METHOD_NONE
  1415. value_type &front() { return *this->begin(); }
  1416. const value_type &front() const { return *this->begin(); }
  1417. #define GI_ENABLE_METHOD_ARRAY_NOT_NONE \
  1418. template<typename Enable = void, \
  1419. typename Check = typename std::enable_if< \
  1420. std::is_void<Enable>::value && \
  1421. std::is_pointer<typename super_type::const_iterator>::value && \
  1422. !std::is_same<Transfer, transfer_none_t>::value>::type>
  1423. #define GI_ENABLE_METHOD_ARRAY \
  1424. template<typename Enable = void, \
  1425. typename Check = typename std::enable_if< \
  1426. std::is_void<Enable>::value && \
  1427. std::is_pointer<typename super_type::const_iterator>::value>::type>
  1428. GI_ENABLE_METHOD_ARRAY_NOT_NONE
  1429. value_type &back() { return *(this->end() - 1); }
  1430. GI_ENABLE_METHOD_ARRAY
  1431. const value_type &back() const { return *(this->end() - 1); }
  1432. GI_ENABLE_METHOD_ARRAY_NOT_NONE
  1433. value_type *data() { return this->begin(); }
  1434. GI_ENABLE_METHOD_ARRAY
  1435. const value_type *data() const { return this->begin(); }
  1436. GI_ENABLE_METHOD_ARRAY_NOT_NONE
  1437. value_type &operator[](size_type pos) { return *(this->begin() + pos); }
  1438. GI_ENABLE_METHOD_ARRAY
  1439. const value_type &operator[](size_type pos) const
  1440. {
  1441. return *(this->begin() + pos);
  1442. }
  1443. GI_ENABLE_METHOD_ARRAY_NOT_NONE
  1444. value_type &at(size_type pos)
  1445. {
  1446. if (pos >= this->size())
  1447. try_throw(std::out_of_range("Collection::at"));
  1448. return *(this->begin() + pos);
  1449. }
  1450. GI_ENABLE_METHOD_ARRAY
  1451. const value_type &at(size_type pos) const
  1452. {
  1453. if (pos >= this->size())
  1454. try_throw(std::out_of_range("Collection::at"));
  1455. return *(this->begin() + pos);
  1456. }
  1457. GI_ENABLE_METHOD_ARRAY
  1458. void resize(size_type s)
  1459. {
  1460. auto size = this->size();
  1461. if (s < size) {
  1462. this->erase(this->begin() + s, this->end());
  1463. } else if (s > size) {
  1464. auto cnt = s - size;
  1465. while (cnt) {
  1466. this->push_back({});
  1467. --cnt;
  1468. }
  1469. }
  1470. }
  1471. GI_DISABLE_METHOD_NONE
  1472. void swap(Collection &other)
  1473. {
  1474. std::swap((super_type &)*this, (super_type &)other);
  1475. }
  1476. #undef GI_ENABLE_METHOD_ARRAY
  1477. #undef GI_ENABLE_METHOD_ARRAY_NOT_NONE
  1478. // in unwrap below;
  1479. // refcnt based cases support all sorts of transfer,
  1480. // otherwise transfer must match the Transfer encoded in type
  1481. // r-value case; data can be snatched from this instance
  1482. template<typename ReqTransfer,
  1483. typename std::enable_if<std::is_same<Transfer, ReqTransfer>::value ||
  1484. list_ops::refcnt>::type * = nullptr>
  1485. typename _detail::DataType _unwrap(const ReqTransfer &t) &&
  1486. {
  1487. auto l = this->data_;
  1488. // be nice to subtype below
  1489. // avoid yanking away possibly owned value
  1490. if (t.value != transfer_none.value)
  1491. this->data_ = nullptr;
  1492. return l;
  1493. }
  1494. // l-value case; no snatching, so only transfer none (if not refcnt)
  1495. template<typename ReqTransfer,
  1496. typename std::enable_if<
  1497. list_ops::refcnt ||
  1498. (std::is_same<Transfer, ReqTransfer>::value &&
  1499. std::is_same<ReqTransfer, transfer_none_t>::value)>::type * =
  1500. nullptr>
  1501. typename _detail::DataType _unwrap(const ReqTransfer &t) &
  1502. {
  1503. if (list_ops::refcnt)
  1504. return ((t.value != transfer_none.value) && this->data_)
  1505. ? list_ops::ref(this->data_)
  1506. : this->data_;
  1507. // must be none transfer in this case
  1508. return this->data_;
  1509. }
  1510. template<typename CppType, typename ReqTransfer,
  1511. typename std::enable_if<std::is_same<Transfer, ReqTransfer>::value &&
  1512. !_detail::is_span>::type * = nullptr>
  1513. static CppType _wrap(const ListType *obj, const ReqTransfer &t)
  1514. {
  1515. static_assert(sizeof(CppType) == sizeof(self_type), "invalid wrap");
  1516. static_assert(std::is_base_of<self_type, CppType>::value, "invalid wrap");
  1517. self_type w(const_cast<ListType *>(obj), t.value);
  1518. return std::move(*static_cast<CppType *>(&w));
  1519. }
  1520. // special case; wrap of 2 arguments (ptr and size)
  1521. // (could be combined in a single span,
  1522. // but it would have to be unpacked anyway)
  1523. template<typename CppType, typename CType, typename ReqTransfer,
  1524. typename std::enable_if<
  1525. std::is_same<Transfer, ReqTransfer>::value && _detail::is_span &&
  1526. _detail::template is_compatible<CType>::value>::type * = nullptr>
  1527. static CppType _wrap(CType *obj, int s, const ReqTransfer &)
  1528. {
  1529. static_assert(sizeof(CppType) == sizeof(self_type), "invalid wrap");
  1530. static_assert(std::is_base_of<self_type, CppType>::value, "invalid wrap");
  1531. // select internal protected constructor
  1532. self_type w(const_cast<ElCType *>(obj), s, nullptr);
  1533. return std::move(*static_cast<CppType *>(&w));
  1534. }
  1535. // likewise, ZT
  1536. template<typename CppType, typename CType, typename ReqTransfer,
  1537. typename std::enable_if<
  1538. std::is_same<Transfer, ReqTransfer>::value && _detail::is_span &&
  1539. _detail::span_size == SpanType::ZT>::type * = nullptr>
  1540. static CppType _wrap(CType *obj, const ReqTransfer &)
  1541. {
  1542. return _wrap<CppType>(obj, -1, ReqTransfer());
  1543. }
  1544. template<typename CppType,
  1545. typename std::enable_if<!std::is_void<CppType>::value &&
  1546. list_ops::refcnt>::type * = nullptr>
  1547. static CppType _get_value(const GValue *v)
  1548. {
  1549. auto wv = std::is_same<Transfer, transfer_none_t>::value()
  1550. ? g_value_get_boxed(v)
  1551. : g_value_dup_boxed(v);
  1552. return _wrap<CppType>((ListType *)(wv), Transfer());
  1553. }
  1554. template<typename CppType,
  1555. typename std::enable_if<!std::is_void<CppType>::value &&
  1556. !list_ops::refcnt>::type * = nullptr>
  1557. static CppType _get_value(const GValue *v)
  1558. {
  1559. // tracked as raw gpointer
  1560. auto wv = g_value_get_pointer(v);
  1561. return _wrap<CppType>((ElCType *)(wv), Transfer());
  1562. }
  1563. void _set_value(GValue *v)
  1564. {
  1565. if (list_ops::refcnt) {
  1566. g_value_set_boxed(v, this->gobj_());
  1567. } else {
  1568. g_value_set_pointer(v, this->gobj_());
  1569. }
  1570. }
  1571. };
  1572. // add additional owner tracking data
  1573. // (see below for reason of simple/silly separate type)
  1574. struct OwnerData : public Container
  1575. {
  1576. bool own_ = false;
  1577. };
  1578. template<typename... Args>
  1579. struct NotifierThunk;
  1580. // should only end up used with transfer_none
  1581. template<typename ListType, typename T, typename Transfer = transfer_none_t>
  1582. class CollectionHolder : public Collection<ListType, T, Transfer,
  1583. NotifierThunk<ListType, T, Transfer>, OwnerData>
  1584. {
  1585. // ownership tracked by OwnerData
  1586. // as notified by helper which needs access
  1587. friend struct NotifierThunk<ListType, T, Transfer>;
  1588. // to call here
  1589. void _updated(bool create)
  1590. {
  1591. if (create) {
  1592. this->own_ = true;
  1593. } else {
  1594. this->~CollectionHolder();
  1595. }
  1596. }
  1597. public:
  1598. // NOTE OwnerData is inserted as a lower base class to ensure it is
  1599. // initialized soon enough (before the using'ed constructor will notify
  1600. // of creation)
  1601. using super_type = Collection<ListType, T, Transfer,
  1602. NotifierThunk<ListType, T, Transfer>, OwnerData>;
  1603. using super_type::super_type;
  1604. // only allowed (limited) move
  1605. // (even if some parents might allow more)
  1606. CollectionHolder(CollectionHolder &&other) : super_type(other)
  1607. {
  1608. this->own_ = other.own_;
  1609. other.own_ = false;
  1610. }
  1611. CollectionHolder &operator=(CollectionHolder &&other)
  1612. {
  1613. if (this != &other) {
  1614. this->~CollectionHolder();
  1615. (super_type &)(*this) = std::move(other);
  1616. this->own_ = other.own_;
  1617. other.own_ = false;
  1618. }
  1619. return *this;
  1620. }
  1621. ~CollectionHolder()
  1622. {
  1623. // only need to act if super type does not handle (owns) anyway
  1624. // only free/clear list, items not owned
  1625. if (std::is_same<Transfer, transfer_none_t>::value && this->own_ &&
  1626. this->data_) {
  1627. this->_steal();
  1628. this->own_ = false;
  1629. }
  1630. }
  1631. };
  1632. #undef GI_DISABLE_METHOD_NONE
  1633. template<typename... Args>
  1634. struct NotifierThunk
  1635. {
  1636. static constexpr bool construct_none = true;
  1637. static void _updated(Container *c, bool create)
  1638. {
  1639. using CT = CollectionHolder<Args...>;
  1640. return static_cast<CT *>(c)->_updated(create);
  1641. }
  1642. };
  1643. struct glib_deleter
  1644. {
  1645. template<typename T>
  1646. void operator()(T *p)
  1647. {
  1648. g_free(p);
  1649. }
  1650. };
  1651. template<typename T>
  1652. using unique_ptr = std::unique_ptr<T, glib_deleter>;
  1653. template<typename ListType, typename ElType, typename Transfer,
  1654. typename Enable = void>
  1655. struct ListAcceptorImpl
  1656. {
  1657. using type = Collection<ListType, ElType, Transfer>;
  1658. };
  1659. template<typename ListType, typename ElType, typename Transfer>
  1660. struct ListAcceptorImpl<ListType, ElType, Transfer,
  1661. typename std::enable_if<
  1662. (std::is_same<ListType, ::GList>::value ||
  1663. std::is_same<ListType, ::GSList>::value) &&
  1664. std::is_same<Transfer, transfer_none_t>::value>::type>
  1665. {
  1666. using type = CollectionHolder<ListType, ElType, Transfer>;
  1667. };
  1668. } // namespace detail
  1669. using detail::unwrap;
  1670. using ZTSpan = detail::Span<detail::SpanType::ZT>;
  1671. using DSpan = detail::Span<detail::SpanType::DYNAMIC>;
  1672. template<int S>
  1673. using FSpan = detail::Span<S>;
  1674. // only the full_transfer version is really safe for general use
  1675. // but let's export it all
  1676. using detail::Collection;
  1677. // type to use in (input) parameter declaration
  1678. // use basic type for ref-cases, otherwise need Holder subtype
  1679. // NOTE add a workaround hack;
  1680. // use full transfer for a none transfer HashTable parameter
  1681. // (as annotation there might be bogus; looking at add gst_uri_set_query_table)
  1682. // (and if the annotiation is not bogus, the full should work out ok-ish)
  1683. // NOTE list_ops is used directly hereto avoid instantiation of Collection
  1684. // (as that might otherwise occur during declaration)
  1685. template<typename ListType, typename T, typename Transfer>
  1686. using CollectionParameter = typename std::conditional<
  1687. std::is_same<ListType, ::GHashTable>::value &&
  1688. std::is_same<Transfer, transfer_none_t>::value,
  1689. detail::Collection<ListType, T, transfer_full_t>,
  1690. typename std::conditional<detail::list_ops<ListType, T, Transfer>::refcnt,
  1691. detail::Collection<ListType, T, Transfer>,
  1692. detail::CollectionHolder<ListType, T, Transfer>>::type>::type;
  1693. namespace traits
  1694. {
  1695. // (many to one) map from Cpp to C type (so no other way around)
  1696. template<typename ListType, typename El, typename Transfer>
  1697. struct ctype<detail::Collection<ListType, El, Transfer>>
  1698. {
  1699. using type =
  1700. typename detail::Collection<ListType, El, Transfer>::_detail::DataType;
  1701. };
  1702. template<typename ListType, typename El, typename Transfer>
  1703. struct ctype<const detail::Collection<ListType, El, Transfer>>
  1704. {
  1705. using type = const typename detail::Collection<ListType, El,
  1706. Transfer>::_detail::DataType;
  1707. };
  1708. } // namespace traits
  1709. } // namespace gi
  1710. #endif // GI_CONTAINER_HPP