ruby-qt6-rice 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4803 @@
1
+ // This file is part of [rice](https://github.com/ruby-rice/rice).
2
+ //
3
+ // Copyright (C) 2025 Jason Roelofs <jasongroelofs@gmail.com>
4
+ // Paul Brannan <curlypaul924@gmail.com>,
5
+ // Charlie Savage
6
+ //
7
+ // Redistribution and use in source and binary forms, with or without
8
+ // modification, are permitted provided that the following conditions
9
+ // are met:
10
+ //
11
+ // 1. Redistributions of source code must retain the above copyright
12
+ // notice, this list of conditions and the following disclaimer.
13
+ // 2. Redistributions in binary form must reproduce the above copyright
14
+ // notice, this list of conditions and the following disclaimer in the
15
+ // documentation and/or other materials provided with the distribution.
16
+ //
17
+ // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
+ // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
+ // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
+ // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
+ // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ #ifndef Rice__stl__hpp_
29
+ #define Rice__stl__hpp_
30
+
31
+
32
+ // ========= exception.hpp =========
33
+
34
+ namespace Rice::stl
35
+ {
36
+ extern Class rb_cStlException;
37
+ }
38
+
39
+
40
+ // --------- exception.ipp ---------
41
+ #include <exception>
42
+
43
+ // Libraries sometime inherit custom exception objects from std::exception,
44
+ // so define it for Ruby if necessary
45
+ namespace Rice::stl
46
+ {
47
+ inline void define_stl_exceptions()
48
+ {
49
+ Module rb_mStd = define_module("Std");
50
+
51
+ define_class_under<std::exception>(rb_mStd, "Exception", rb_eStandardError).
52
+ define_constructor(Constructor<std::exception>()).
53
+ define_method("message", &std::exception::what);
54
+
55
+ define_class_under<std::runtime_error>(rb_mStd, "RuntimeError", rb_eRuntimeError).
56
+ define_constructor(Constructor<std::runtime_error, const char*>()).
57
+ define_method("message", &std::runtime_error::what);
58
+ }
59
+ }
60
+
61
+ namespace Rice::detail
62
+ {
63
+ template<>
64
+ struct Type<std::exception>
65
+ {
66
+ static bool verify()
67
+ {
68
+ Rice::stl::define_stl_exceptions();
69
+ return true;
70
+ }
71
+ };
72
+
73
+ template<>
74
+ struct Type<std::runtime_error>
75
+ {
76
+ static bool verify()
77
+ {
78
+ Rice::stl::define_stl_exceptions();
79
+ return true;
80
+ }
81
+ };
82
+ }
83
+
84
+
85
+ // ========= exception_ptr.hpp =========
86
+
87
+
88
+ // --------- exception_ptr.ipp ---------
89
+ #include <exception>
90
+
91
+ namespace Rice::stl
92
+ {
93
+ inline Data_Type<std::exception_ptr> define_exception_ptr()
94
+ {
95
+ Module rb_mStd = define_module("Std");
96
+ return define_class_under<std::exception_ptr>(rb_mStd, "ExceptionPtr");
97
+ }
98
+ }
99
+
100
+ namespace Rice::detail
101
+ {
102
+ template<>
103
+ struct Type<std::exception_ptr>
104
+ {
105
+ static bool verify()
106
+ {
107
+ if (!Data_Type<std::exception_ptr>::is_defined())
108
+ {
109
+ stl::define_exception_ptr();
110
+ }
111
+
112
+ return true;
113
+ }
114
+ };
115
+ }
116
+
117
+
118
+ // ========= string.hpp =========
119
+
120
+
121
+ // --------- string.ipp ---------
122
+ #include <string>
123
+
124
+ namespace Rice::detail
125
+ {
126
+ template<>
127
+ struct Type<std::string>
128
+ {
129
+ static bool verify()
130
+ {
131
+ return true;
132
+ }
133
+
134
+ static VALUE rubyKlass()
135
+ {
136
+ return rb_cString;
137
+ }
138
+ };
139
+
140
+ template<int N>
141
+ struct Type<std::string[N]>
142
+ {
143
+ static bool verify()
144
+ {
145
+ return true;
146
+ }
147
+
148
+ static VALUE rubyKlass()
149
+ {
150
+ return rb_cString;
151
+ }
152
+ };
153
+
154
+ template<>
155
+ struct Type<std::string*>
156
+ {
157
+ static bool verify()
158
+ {
159
+ return true;
160
+ }
161
+
162
+ static VALUE rubyKlass()
163
+ {
164
+ using Pointer_T = Pointer<std::string>;
165
+ std::pair<VALUE, rb_data_type_t*> pair = Registries::instance.types.getType<Pointer_T>();
166
+ return pair.first;
167
+ }
168
+ };
169
+
170
+ template<>
171
+ struct Type<std::string**>
172
+ {
173
+ static bool verify()
174
+ {
175
+ return true;
176
+ }
177
+
178
+ static VALUE rubyKlass()
179
+ {
180
+ using Pointer_T = Pointer<std::string*>;
181
+ std::pair<VALUE, rb_data_type_t*> pair = Registries::instance.types.getType<Pointer_T>();
182
+ return pair.first;
183
+ }
184
+ };
185
+
186
+ template<>
187
+ class To_Ruby<std::string>
188
+ {
189
+ public:
190
+ To_Ruby() = default;
191
+
192
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
193
+ {
194
+ }
195
+
196
+ VALUE convert(const std::string& x)
197
+ {
198
+ return detail::protect(rb_external_str_new, x.data(), (long)x.size());
199
+ }
200
+
201
+ private:
202
+ Return* returnInfo_ = nullptr;
203
+ };
204
+
205
+ template<>
206
+ class To_Ruby<std::string&>
207
+ {
208
+ public:
209
+ To_Ruby() = default;
210
+
211
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
212
+ {
213
+ }
214
+
215
+ VALUE convert(const std::string& x)
216
+ {
217
+ return detail::protect(rb_external_str_new, x.data(), (long)x.size());
218
+ }
219
+
220
+ private:
221
+ Return* returnInfo_ = nullptr;
222
+ };
223
+
224
+ template<int N>
225
+ class To_Ruby<std::string[N]>
226
+ {
227
+ public:
228
+ To_Ruby() = default;
229
+
230
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
231
+ {
232
+ }
233
+
234
+ VALUE convert(std::string data[N])
235
+ {
236
+ Buffer<std::string> buffer(data, N);
237
+ Data_Object<Buffer<std::string>> dataObject(std::move(buffer));
238
+ return dataObject.value();
239
+ }
240
+ private:
241
+ Return* returnInfo_ = nullptr;
242
+ };
243
+
244
+ template<>
245
+ class To_Ruby<std::string*>
246
+ {
247
+ public:
248
+ To_Ruby() = default;
249
+
250
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
251
+ {
252
+ }
253
+
254
+ VALUE convert(const std::string* value)
255
+ {
256
+ bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner();
257
+ bool isBuffer = this->returnInfo_ && this->returnInfo_->isBuffer();
258
+
259
+ if (isBuffer)
260
+ {
261
+ using Pointer_T = Pointer<std::string>;
262
+ return detail::wrap(Data_Type<Pointer_T>::klass(), Data_Type<Pointer_T>::ruby_data_type(), value, isOwner);
263
+ }
264
+ else
265
+ {
266
+ return detail::protect(rb_external_str_new, value->data(), (long)value->size());
267
+ }
268
+ }
269
+
270
+ private:
271
+ Return* returnInfo_ = nullptr;
272
+ };
273
+
274
+ template<>
275
+ class To_Ruby<std::string*&>
276
+ {
277
+ public:
278
+ To_Ruby() = default;
279
+
280
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
281
+ {
282
+ }
283
+
284
+ VALUE convert(const std::string* x)
285
+ {
286
+ return detail::protect(rb_external_str_new, x->data(), (long)x->size());
287
+ }
288
+
289
+ private:
290
+ Return* returnInfo_ = nullptr;
291
+ };
292
+
293
+ /*template<>
294
+ class To_Ruby<std::string**>
295
+ {
296
+ public:
297
+ To_Ruby() = default;
298
+
299
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
300
+ {
301
+ }
302
+
303
+ VALUE convert(std::string** data)
304
+ {
305
+ Buffer<std::string*> buffer(data);
306
+ Data_Object<Buffer<std::string*>> dataObject(std::move(buffer));
307
+ return dataObject.value();
308
+ }
309
+
310
+ private:
311
+ Return* returnInfo_ = nullptr;
312
+ };*/
313
+
314
+ template<>
315
+ class From_Ruby<std::string>
316
+ {
317
+ public:
318
+ From_Ruby() = default;
319
+
320
+ explicit From_Ruby(Arg* arg) : arg_(arg)
321
+ {
322
+ }
323
+
324
+ Convertible is_convertible(VALUE value)
325
+ {
326
+ switch (rb_type(value))
327
+ {
328
+ case RUBY_T_STRING:
329
+ return Convertible::Exact;
330
+ break;
331
+ default:
332
+ return Convertible::None;
333
+ }
334
+ }
335
+
336
+ std::string convert(VALUE value)
337
+ {
338
+ detail::protect(rb_check_type, value, (int)RUBY_T_STRING);
339
+ return std::string(RSTRING_PTR(value), RSTRING_LEN(value));
340
+ }
341
+
342
+ private:
343
+ Arg* arg_ = nullptr;
344
+ };
345
+
346
+ template<>
347
+ class From_Ruby<std::string&>
348
+ {
349
+ public:
350
+ From_Ruby() = default;
351
+
352
+ explicit From_Ruby(Arg* arg) : arg_(arg)
353
+ {
354
+ }
355
+
356
+ Convertible is_convertible(VALUE value)
357
+ {
358
+ switch (rb_type(value))
359
+ {
360
+ case RUBY_T_STRING:
361
+ return Convertible::Exact;
362
+ break;
363
+ default:
364
+ return Convertible::None;
365
+ }
366
+ }
367
+
368
+ std::string& convert(VALUE value)
369
+ {
370
+ detail::protect(rb_check_type, value, (int)RUBY_T_STRING);
371
+ this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
372
+ return this->converted_;
373
+ }
374
+
375
+ private:
376
+ Arg* arg_ = nullptr;
377
+ std::string converted_ = "";
378
+ };
379
+
380
+ template<>
381
+ class From_Ruby<std::string&&>
382
+ {
383
+ public:
384
+ From_Ruby() = default;
385
+
386
+ explicit From_Ruby(Arg* arg) : arg_(arg)
387
+ {
388
+ }
389
+
390
+ Convertible is_convertible(VALUE value)
391
+ {
392
+ switch (rb_type(value))
393
+ {
394
+ case RUBY_T_STRING:
395
+ return Convertible::Exact;
396
+ break;
397
+ default:
398
+ return Convertible::None;
399
+ }
400
+ }
401
+
402
+ std::string&& convert(VALUE value)
403
+ {
404
+ detail::protect(rb_check_type, value, (int)T_STRING);
405
+ this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
406
+ return std::move(this->converted_);
407
+ }
408
+
409
+ private:
410
+ Arg* arg_ = nullptr;
411
+ std::string converted_ = "";
412
+ };
413
+
414
+ template<>
415
+ class From_Ruby<std::string*>
416
+ {
417
+ public:
418
+ From_Ruby() = default;
419
+
420
+ explicit From_Ruby(Arg* arg) : arg_(arg)
421
+ {
422
+ }
423
+
424
+ Convertible is_convertible(VALUE value)
425
+ {
426
+ switch (rb_type(value))
427
+ {
428
+ case RUBY_T_STRING:
429
+ return Convertible::Exact;
430
+ break;
431
+ default:
432
+ return Convertible::None;
433
+ }
434
+ }
435
+
436
+ std::string* convert(VALUE value)
437
+ {
438
+ detail::protect(rb_check_type, value, (int)RUBY_T_STRING);
439
+ this->converted_ = std::string(RSTRING_PTR(value), RSTRING_LEN(value));
440
+ return &this->converted_;
441
+ }
442
+
443
+ private:
444
+ Arg* arg_ = nullptr;
445
+ std::string converted_;
446
+ };
447
+ }
448
+
449
+ // ========= string_view.hpp =========
450
+
451
+
452
+ // --------- string_view.ipp ---------
453
+ #include <string_view>
454
+
455
+ namespace Rice::detail
456
+ {
457
+ template<>
458
+ struct Type<std::string_view>
459
+ {
460
+ static bool verify()
461
+ {
462
+ return true;
463
+ }
464
+
465
+ static VALUE rubyKlass()
466
+ {
467
+ return rb_cString;
468
+ }
469
+ };
470
+
471
+ template<>
472
+ class To_Ruby<std::string_view>
473
+ {
474
+ public:
475
+ To_Ruby() = default;
476
+
477
+ explicit To_Ruby(Arg* arg) : arg_(arg)
478
+ {
479
+ }
480
+
481
+ VALUE convert(std::string_view const& x)
482
+ {
483
+ return detail::protect(rb_external_str_new, x.data(), (long)x.size());
484
+ }
485
+
486
+ private:
487
+ Arg* arg_ = nullptr;
488
+ };
489
+
490
+ template<>
491
+ class To_Ruby<std::string_view&>
492
+ {
493
+ public:
494
+ To_Ruby() = default;
495
+
496
+ explicit To_Ruby(Arg* arg) : arg_(arg)
497
+ {
498
+ }
499
+
500
+ VALUE convert(std::string_view const& x)
501
+ {
502
+ return detail::protect(rb_external_str_new, x.data(), (long)x.size());
503
+ }
504
+
505
+ private:
506
+ Arg* arg_ = nullptr;
507
+ };
508
+
509
+ template<>
510
+ class From_Ruby<std::string_view>
511
+ {
512
+ public:
513
+ From_Ruby() = default;
514
+
515
+ explicit From_Ruby(Arg* arg) : arg_(arg)
516
+ {
517
+ }
518
+
519
+ Convertible is_convertible(VALUE value)
520
+ {
521
+ switch (rb_type(value))
522
+ {
523
+ case RUBY_T_STRING:
524
+ return Convertible::Exact;
525
+ break;
526
+ default:
527
+ return Convertible::None;
528
+ }
529
+ }
530
+
531
+ std::string_view convert(VALUE value)
532
+ {
533
+ detail::protect(rb_check_type, value, (int)T_STRING);
534
+ return std::string_view(RSTRING_PTR(value), RSTRING_LEN(value));
535
+ }
536
+
537
+ private:
538
+ Arg* arg_ = nullptr;
539
+ };
540
+ }
541
+
542
+ // ========= complex.hpp =========
543
+
544
+
545
+ // --------- complex.ipp ---------
546
+ #include <complex>
547
+
548
+ namespace Rice::detail
549
+ {
550
+ template<typename T>
551
+ struct Type<std::complex<T>>
552
+ {
553
+ static bool verify()
554
+ {
555
+ return true;
556
+ }
557
+
558
+ static VALUE rubyKlass()
559
+ {
560
+ return rb_cComplex;
561
+ }
562
+ };
563
+
564
+ template<typename T>
565
+ class To_Ruby<std::complex<T>>
566
+ {
567
+ public:
568
+ To_Ruby() = default;
569
+
570
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
571
+ {
572
+ }
573
+
574
+ VALUE convert(const std::complex<T>& data)
575
+ {
576
+ std::vector<VALUE> args(2);
577
+ args[0] = To_Ruby<T>().convert(data.real());
578
+ args[1] = To_Ruby<T>().convert(data.imag());
579
+ return protect(rb_funcallv, rb_mKernel, rb_intern("Complex"), (int)args.size(), (const VALUE*)args.data());
580
+ }
581
+
582
+ private:
583
+ Return* returnInfo_ = nullptr;
584
+ };
585
+
586
+ template<typename T>
587
+ class To_Ruby<std::complex<T>&>
588
+ {
589
+ public:
590
+ To_Ruby() = default;
591
+
592
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
593
+ {
594
+ }
595
+
596
+ VALUE convert(const std::complex<T>& data)
597
+ {
598
+ std::vector<VALUE> args(2);
599
+ args[0] = To_Ruby<T>().convert(data.real());
600
+ args[1] = To_Ruby<T>().convert(data.imag());
601
+ return protect(rb_funcallv, rb_mKernel, rb_intern("Complex"), (int)args.size(), (const VALUE*)args.data());
602
+ }
603
+
604
+ private:
605
+ Return* returnInfo_ = nullptr;
606
+ };
607
+
608
+ template<typename T>
609
+ class From_Ruby<std::complex<T>>
610
+ {
611
+ public:
612
+ From_Ruby() = default;
613
+
614
+ explicit From_Ruby(Arg* arg)
615
+ {
616
+ }
617
+
618
+ Convertible is_convertible(VALUE value)
619
+ {
620
+ switch (rb_type(value))
621
+ {
622
+ case RUBY_T_COMPLEX:
623
+ return Convertible::Exact;
624
+ break;
625
+ default:
626
+ return Convertible::None;
627
+ }
628
+ }
629
+
630
+ std::complex<T> convert(VALUE value)
631
+ {
632
+ VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
633
+ VALUE imaginary = protect(rb_funcallv, value, rb_intern("imaginary"), 0, (const VALUE*)nullptr);
634
+
635
+ return std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
636
+ }
637
+ };
638
+
639
+ template<typename T>
640
+ class From_Ruby<std::complex<T>&>
641
+ {
642
+ public:
643
+ From_Ruby() = default;
644
+
645
+ explicit From_Ruby(Arg* arg)
646
+ {
647
+ }
648
+
649
+ Convertible is_convertible(VALUE value)
650
+ {
651
+ switch (rb_type(value))
652
+ {
653
+ case RUBY_T_COMPLEX:
654
+ return Convertible::Exact;
655
+ break;
656
+ default:
657
+ return Convertible::None;
658
+ }
659
+ }
660
+
661
+ std::complex<T>& convert(VALUE value)
662
+ {
663
+ VALUE real = protect(rb_funcallv, value, rb_intern("real"), 0, (const VALUE*)nullptr);
664
+ VALUE imaginary = protect(rb_funcallv, value, rb_intern("imaginary"), 0, (const VALUE*)nullptr);
665
+ this->converted_ = std::complex<T>(From_Ruby<T>().convert(real), From_Ruby<T>().convert(imaginary));
666
+
667
+ return this->converted_;
668
+ }
669
+
670
+ private:
671
+ std::complex<T> converted_;
672
+ };
673
+ }
674
+
675
+
676
+ // ========= filesystem.hpp =========
677
+
678
+
679
+ // --------- filesystem.ipp ---------
680
+ #include <filesystem>
681
+
682
+ namespace Rice
683
+ {
684
+ namespace stl
685
+ {
686
+ inline void define_filesystem_path()
687
+ {
688
+ Module rb_mStd = define_module("Std");
689
+ Module rb_mFileSystem = define_module_under(rb_mStd, "Filesystem");
690
+
691
+ define_class_under<std::filesystem::path>(rb_mFileSystem, "Path").
692
+ define_constructor(Constructor<std::filesystem::path>()).
693
+ define_constructor(Constructor<std::filesystem::path, std::string>());
694
+ }
695
+ }
696
+ }
697
+
698
+ namespace Rice::detail
699
+ {
700
+ template<>
701
+ struct Type<std::filesystem::path>
702
+ {
703
+ static bool verify()
704
+ {
705
+ if (!Data_Type<std::filesystem::path>::is_defined())
706
+ {
707
+ Rice::stl::define_filesystem_path();
708
+ }
709
+
710
+ return true;
711
+ }
712
+ };
713
+ }
714
+
715
+
716
+ // ========= optional.hpp =========
717
+
718
+
719
+ // --------- optional.ipp ---------
720
+ #include <optional>
721
+
722
+ namespace Rice::detail
723
+ {
724
+ template<typename T>
725
+ struct Type<std::optional<T>>
726
+ {
727
+ constexpr static bool verify()
728
+ {
729
+ return Type<intrinsic_type<T>>::verify();
730
+ }
731
+
732
+ static VALUE rubyKlass()
733
+ {
734
+ TypeMapper<T> typeMapper;
735
+ return typeMapper.rubyKlass();
736
+ }
737
+ };
738
+
739
+ template<>
740
+ class To_Ruby<std::nullopt_t>
741
+ {
742
+ public:
743
+ To_Ruby() = default;
744
+
745
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
746
+ {
747
+ }
748
+
749
+ VALUE convert(const std::nullopt_t& _)
750
+ {
751
+ return Qnil;
752
+ }
753
+
754
+ private:
755
+ Return* returnInfo_ = nullptr;
756
+ };
757
+
758
+ template<typename T>
759
+ class To_Ruby<std::optional<T>>
760
+ {
761
+ public:
762
+ To_Ruby() = default;
763
+
764
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
765
+ {
766
+ }
767
+
768
+ VALUE convert(std::optional<T>& data)
769
+ {
770
+ if (data.has_value())
771
+ {
772
+ return To_Ruby<T>().convert(data.value());
773
+ }
774
+ else
775
+ {
776
+ return Qnil;
777
+ }
778
+ }
779
+
780
+ private:
781
+ Return* returnInfo_ = nullptr;
782
+ };
783
+
784
+ template<typename T>
785
+ class To_Ruby<std::optional<T>&>
786
+ {
787
+ public:
788
+ To_Ruby() = default;
789
+
790
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
791
+ {
792
+ }
793
+
794
+ VALUE convert(const std::optional<T>& data)
795
+ {
796
+ if (data.has_value())
797
+ {
798
+ return To_Ruby<T>().convert(data.value());
799
+ }
800
+ else
801
+ {
802
+ return Qnil;
803
+ }
804
+ }
805
+
806
+ private:
807
+ Return* returnInfo_ = nullptr;
808
+ };
809
+
810
+ template<typename T>
811
+ class From_Ruby<std::optional<T>>
812
+ {
813
+ public:
814
+ From_Ruby() = default;
815
+
816
+ explicit From_Ruby(Arg* arg)
817
+ {
818
+ }
819
+
820
+ Convertible is_convertible(VALUE value)
821
+ {
822
+ switch (rb_type(value))
823
+ {
824
+ case RUBY_T_NIL:
825
+ return Convertible::Exact;
826
+ break;
827
+ default:
828
+ return From_Ruby<T>().is_convertible(value);
829
+ }
830
+ }
831
+
832
+ std::optional<T> convert(VALUE value)
833
+ {
834
+ if (value == Qnil)
835
+ {
836
+ return std::nullopt;
837
+ }
838
+ else
839
+ {
840
+ return From_Ruby<T>().convert(value);
841
+ }
842
+ }
843
+ };
844
+
845
+ template<typename T>
846
+ class From_Ruby<std::optional<T>&>
847
+ {
848
+ public:
849
+ From_Ruby() = default;
850
+
851
+ explicit From_Ruby(Arg* arg)
852
+ {
853
+ }
854
+
855
+ Convertible is_convertible(VALUE value)
856
+ {
857
+ switch (rb_type(value))
858
+ {
859
+ case RUBY_T_NIL:
860
+ return Convertible::Exact;
861
+ break;
862
+ default:
863
+ return From_Ruby<T>().is_convertible(value);
864
+ }
865
+ }
866
+
867
+ std::optional<T>& convert(VALUE value)
868
+ {
869
+ if (value == Qnil)
870
+ {
871
+ this->converted_ = std::nullopt;
872
+ }
873
+ else
874
+ {
875
+ this->converted_ = From_Ruby<T>().convert(value);
876
+ }
877
+ return this->converted_;
878
+ }
879
+ private:
880
+ std::optional<T> converted_;
881
+ };
882
+ }
883
+
884
+
885
+ // ========= reference_wrapper.hpp =========
886
+
887
+
888
+ // --------- reference_wrapper.ipp ---------
889
+ #include <functional>
890
+
891
+ namespace Rice::detail
892
+ {
893
+ template<typename T>
894
+ struct Type<std::reference_wrapper<T>>
895
+ {
896
+ constexpr static bool verify()
897
+ {
898
+ return Type<T>::verify();
899
+ }
900
+
901
+ static VALUE rubyKlass()
902
+ {
903
+ TypeMapper<T> typeMapper;
904
+ return typeMapper.rubyKlass();
905
+ }
906
+ };
907
+
908
+ template<typename T>
909
+ class To_Ruby<std::reference_wrapper<T>>
910
+ {
911
+ public:
912
+ To_Ruby() = default;
913
+
914
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
915
+ {
916
+ }
917
+
918
+ VALUE convert(const std::reference_wrapper<T>& data)
919
+ {
920
+ return To_Ruby<T&>().convert(data.get());
921
+ }
922
+
923
+ private:
924
+ Return* returnInfo_ = nullptr;
925
+ };
926
+
927
+ template<typename T>
928
+ class From_Ruby<std::reference_wrapper<T>>
929
+ {
930
+ public:
931
+ From_Ruby() = default;
932
+
933
+ explicit From_Ruby(Arg* arg)
934
+ {
935
+ }
936
+
937
+ Convertible is_convertible(VALUE value)
938
+ {
939
+ return this->converter_.is_convertible(value);
940
+ }
941
+
942
+ std::reference_wrapper<T> convert(VALUE value)
943
+ {
944
+ return this->converter_.convert(value);
945
+ }
946
+
947
+ private:
948
+ From_Ruby<T&> converter_;
949
+ };
950
+ }
951
+
952
+
953
+ // ========= pair.hpp =========
954
+
955
+ namespace Rice
956
+ {
957
+ template<typename T1, typename T2>
958
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName = "");
959
+ }
960
+
961
+
962
+ // --------- pair.ipp ---------
963
+ #include <utility>
964
+
965
+ namespace Rice
966
+ {
967
+ namespace stl
968
+ {
969
+ template<typename T>
970
+ class PairHelper
971
+ {
972
+ public:
973
+ PairHelper(Data_Type<T> klass) : klass_(klass)
974
+ {
975
+ this->define_constructors();
976
+ this->define_attributes();
977
+ this->define_to_s();
978
+ }
979
+
980
+ private:
981
+ void define_constructors()
982
+ {
983
+ klass_.define_constructor(Constructor<T>())
984
+ .define_constructor(Constructor<T, typename T::first_type&, typename T::second_type&>());
985
+
986
+ if constexpr (std::is_copy_constructible_v<typename T::first_type> && std::is_copy_constructible_v<typename T::second_type>)
987
+ {
988
+ klass_.define_constructor(Constructor<T, const T&>());
989
+ }
990
+ }
991
+
992
+ void define_attributes()
993
+ {
994
+ // Access methods
995
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::first_type>>>)
996
+ {
997
+ klass_.define_attr("first", &T::first, Rice::AttrAccess::Read);
998
+ }
999
+ else
1000
+ {
1001
+ klass_.define_attr("first", &T::first, Rice::AttrAccess::ReadWrite);
1002
+ }
1003
+
1004
+ if constexpr (std::is_const_v<std::remove_reference_t<std::remove_pointer_t<typename T::second_type>>>)
1005
+ {
1006
+ klass_.define_attr("second", &T::second, Rice::AttrAccess::Read);
1007
+ }
1008
+ else
1009
+ {
1010
+ klass_.define_attr("second", &T::second, Rice::AttrAccess::ReadWrite);
1011
+ }
1012
+ }
1013
+
1014
+ void define_to_s()
1015
+ {
1016
+ if constexpr (detail::is_ostreamable_v<typename T::first_type> && detail::is_ostreamable_v<typename T::second_type>)
1017
+ {
1018
+ klass_.define_method("to_s", [](const T& pair)
1019
+ {
1020
+ std::stringstream stream;
1021
+ stream << "[" << pair.first << ", " << pair.second << "]";
1022
+ return stream.str();
1023
+ });
1024
+ }
1025
+ else
1026
+ {
1027
+ klass_.define_method("to_s", [](const T& pair)
1028
+ {
1029
+ return "[Not printable]";
1030
+ });
1031
+ }
1032
+ }
1033
+
1034
+ private:
1035
+ Data_Type<T> klass_;
1036
+ };
1037
+ } // namespace
1038
+
1039
+ template<typename T1, typename T2>
1040
+ Data_Type<std::pair<T1, T2>> define_pair(std::string klassName)
1041
+ {
1042
+ using Pair_T = std::pair<T1, T2>;
1043
+ using Data_Type_T = Data_Type<Pair_T>;
1044
+
1045
+ if (klassName.empty())
1046
+ {
1047
+ detail::TypeMapper<Pair_T> typeMapper;
1048
+ klassName = typeMapper.rubyName();
1049
+ }
1050
+
1051
+ Module rb_mStd = define_module("Std");
1052
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1053
+ {
1054
+ return Data_Type_T();
1055
+ }
1056
+
1057
+ Identifier id(klassName);
1058
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Pair_T>>(rb_mStd, id);
1059
+ stl::PairHelper helper(result);
1060
+ return result;
1061
+ }
1062
+
1063
+ namespace detail
1064
+ {
1065
+ template<typename T1, typename T2>
1066
+ struct Type<std::pair<T1, T2>>
1067
+ {
1068
+ static bool verify()
1069
+ {
1070
+ detail::verifyType<T1>();
1071
+ detail::verifyType<T2>();
1072
+
1073
+ if (!Data_Type<std::pair<T1, T2>>::is_defined())
1074
+ {
1075
+ define_pair<T1, T2>();
1076
+ }
1077
+
1078
+ return true;
1079
+ }
1080
+ };
1081
+ }
1082
+ }
1083
+
1084
+
1085
+
1086
+ // ========= map.hpp =========
1087
+
1088
+ namespace Rice
1089
+ {
1090
+ template<typename K, typename T>
1091
+ Data_Type<std::map<K, T>> define_map(std::string name = "");
1092
+ }
1093
+
1094
+
1095
+ // --------- map.ipp ---------
1096
+ #include <map>
1097
+
1098
+ namespace Rice
1099
+ {
1100
+ namespace stl
1101
+ {
1102
+ template<typename T>
1103
+ class MapHelper
1104
+ {
1105
+ using Key_T = typename T::key_type;
1106
+ using Mapped_T = typename T::mapped_type;
1107
+ using Value_T = typename T::value_type;
1108
+ using Reference_T = typename T::reference;
1109
+ using Size_T = typename T::size_type;
1110
+ using Difference_T = typename T::difference_type;
1111
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1112
+
1113
+ public:
1114
+ MapHelper(Data_Type<T> klass) : klass_(klass)
1115
+ {
1116
+ this->register_pair();
1117
+ this->define_constructors();
1118
+ this->define_capacity_methods();
1119
+ this->define_access_methods();
1120
+ this->define_comparable_methods();
1121
+ this->define_modify_methods();
1122
+ this->define_enumerable();
1123
+ this->define_to_s();
1124
+ this->define_to_hash();
1125
+ }
1126
+
1127
+ private:
1128
+
1129
+ void register_pair()
1130
+ {
1131
+ define_pair<const Key_T, Mapped_T>();
1132
+ }
1133
+
1134
+ void define_constructors()
1135
+ {
1136
+ klass_.define_constructor(Constructor<T>());
1137
+
1138
+ if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
1139
+ {
1140
+ klass_.define_constructor(Constructor<T, const T&>());
1141
+ }
1142
+ }
1143
+
1144
+ void define_capacity_methods()
1145
+ {
1146
+ klass_.define_method("empty?", &T::empty)
1147
+ .define_method("max_size", &T::max_size)
1148
+ .define_method("size", &T::size);
1149
+
1150
+ rb_define_alias(klass_, "count", "size");
1151
+ rb_define_alias(klass_, "length", "size");
1152
+ }
1153
+
1154
+ void define_access_methods()
1155
+ {
1156
+ // Access methods
1157
+ klass_.define_method("[]", [](const T& map, const Key_T& key) -> std::optional<Mapped_T>
1158
+ {
1159
+ auto iter = map.find(key);
1160
+
1161
+ if (iter != map.end())
1162
+ {
1163
+ return iter->second;
1164
+ }
1165
+ else
1166
+ {
1167
+ return std::nullopt;
1168
+ }
1169
+ })
1170
+ .define_method("include?", [](T& map, Key_T& key) -> bool
1171
+ {
1172
+ return map.find(key) != map.end();
1173
+ })
1174
+ .define_method("keys", [](T& map) -> std::vector<Key_T>
1175
+ {
1176
+ std::vector<Key_T> result;
1177
+ std::transform(map.begin(), map.end(), std::back_inserter(result),
1178
+ [](const auto& pair)
1179
+ {
1180
+ return pair.first;
1181
+ });
1182
+
1183
+ return result;
1184
+ })
1185
+ .define_method("values", [](T& map) -> std::vector<Mapped_T>
1186
+ {
1187
+ std::vector<Mapped_T> result;
1188
+ std::transform(map.begin(), map.end(), std::back_inserter(result),
1189
+ [](const auto& pair)
1190
+ {
1191
+ return pair.second;
1192
+ });
1193
+
1194
+ return result;
1195
+ });
1196
+
1197
+ rb_define_alias(klass_, "has_key", "include?");
1198
+ }
1199
+
1200
+ // Methods that require Value_T to support operator==
1201
+ void define_comparable_methods()
1202
+ {
1203
+ if constexpr (detail::is_comparable_v<Mapped_T>)
1204
+ {
1205
+ klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1206
+ {
1207
+ auto it = std::find_if(map.begin(), map.end(),
1208
+ [&value](auto& pair)
1209
+ {
1210
+ return pair.second == value;
1211
+ });
1212
+
1213
+ return it != map.end();
1214
+ });
1215
+ }
1216
+ else
1217
+ {
1218
+ klass_.define_method("value?", [](T& map, Mapped_T& value) -> bool
1219
+ {
1220
+ return false;
1221
+ });
1222
+ }
1223
+
1224
+ rb_define_alias(klass_, "has_value", "value?");
1225
+ }
1226
+
1227
+ void define_modify_methods()
1228
+ {
1229
+ klass_.define_method("clear", &T::clear)
1230
+ .define_method("delete", [](T& map, Key_T& key) -> std::optional<Mapped_T>
1231
+ {
1232
+ auto iter = map.find(key);
1233
+
1234
+ if (iter != map.end())
1235
+ {
1236
+ Mapped_T result = iter->second;
1237
+ map.erase(iter);
1238
+ return result;
1239
+ }
1240
+ else
1241
+ {
1242
+ return std::nullopt;
1243
+ }
1244
+ })
1245
+ .define_method("[]=", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1246
+ {
1247
+ map[key] = value;
1248
+ return value;
1249
+ });
1250
+
1251
+ rb_define_alias(klass_, "store", "[]=");
1252
+ }
1253
+
1254
+ void define_enumerable()
1255
+ {
1256
+ // Add enumerable support
1257
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1258
+ }
1259
+
1260
+ void define_to_hash()
1261
+ {
1262
+ // Add enumerable support
1263
+ klass_.define_method("to_h", [](T& map)
1264
+ {
1265
+ VALUE result = rb_hash_new();
1266
+ std::for_each(map.begin(), map.end(), [&result](const Reference_T pair)
1267
+ {
1268
+ VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
1269
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
1270
+ rb_hash_aset(result, key, value);
1271
+ });
1272
+
1273
+ return result;
1274
+ }, Return().setValue());
1275
+ }
1276
+
1277
+ void define_to_s()
1278
+ {
1279
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1280
+ {
1281
+ klass_.define_method("to_s", [](const T& map)
1282
+ {
1283
+ auto iter = map.begin();
1284
+
1285
+ std::stringstream stream;
1286
+ stream << "{";
1287
+
1288
+ for (; iter != map.end(); iter++)
1289
+ {
1290
+ if (iter != map.begin())
1291
+ {
1292
+ stream << ", ";
1293
+ }
1294
+ stream << iter->first << " => " << iter->second;
1295
+ }
1296
+
1297
+ stream << "}";
1298
+ return stream.str();
1299
+ });
1300
+ }
1301
+ else
1302
+ {
1303
+ klass_.define_method("to_s", [](const T& map)
1304
+ {
1305
+ return "[Not printable]";
1306
+ });
1307
+ }
1308
+ }
1309
+
1310
+ private:
1311
+ Data_Type<T> klass_;
1312
+ };
1313
+ } // namespace
1314
+
1315
+ template<typename Key, typename T>
1316
+ Data_Type<std::map<Key, T>> define_map(std::string klassName)
1317
+ {
1318
+ using Map_T = std::map<Key, T>;
1319
+ using Data_Type_T = Data_Type<Map_T>;
1320
+
1321
+ if (klassName.empty())
1322
+ {
1323
+ detail::TypeMapper<Map_T> typeMapper;
1324
+ klassName = typeMapper.rubyName();
1325
+ }
1326
+
1327
+ Module rb_mStd = define_module("Std");
1328
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1329
+ {
1330
+ return Data_Type_T();
1331
+ }
1332
+
1333
+ Identifier id(klassName);
1334
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Map_T>>(rb_mStd, id);
1335
+ stl::MapHelper helper(result);
1336
+ return result;
1337
+ }
1338
+
1339
+ namespace detail
1340
+ {
1341
+ template<typename Key_T, typename T>
1342
+ struct Type<std::map<Key_T, T>>
1343
+ {
1344
+ static bool verify()
1345
+ {
1346
+ Type<Key_T>::verify();
1347
+ Type<T>::verify();
1348
+
1349
+ if (!Data_Type<std::map<Key_T, T>>::is_defined())
1350
+ {
1351
+ define_map<Key_T, T>();
1352
+ }
1353
+
1354
+ return true;
1355
+ }
1356
+ };
1357
+
1358
+ template<typename T, typename U>
1359
+ struct MapFromHash
1360
+ {
1361
+ static int convertPair(VALUE key, VALUE value, VALUE user_data)
1362
+ {
1363
+ std::map<T, U>* result = (std::map<T, U>*)(user_data);
1364
+
1365
+ // This method is being called from Ruby so we cannot let any C++
1366
+ // exceptions propogate back to Ruby
1367
+ return cpp_protect([&]
1368
+ {
1369
+ result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
1370
+ return ST_CONTINUE;
1371
+ });
1372
+ }
1373
+
1374
+ static std::map<T, U> convert(VALUE value)
1375
+ {
1376
+ std::map<T, U> result;
1377
+ VALUE user_data = (VALUE)(&result);
1378
+
1379
+ // MSVC needs help here, but g++ does not
1380
+ using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1381
+ detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
1382
+
1383
+ return result;
1384
+ }
1385
+ };
1386
+
1387
+ template<typename T, typename U>
1388
+ class From_Ruby<std::map<T, U>>
1389
+ {
1390
+ public:
1391
+ From_Ruby() = default;
1392
+
1393
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1394
+ {
1395
+ }
1396
+
1397
+ Convertible is_convertible(VALUE value)
1398
+ {
1399
+ switch (rb_type(value))
1400
+ {
1401
+ case RUBY_T_DATA:
1402
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1403
+ break;
1404
+ case RUBY_T_HASH:
1405
+ return Convertible::Cast;
1406
+ break;
1407
+ default:
1408
+ return Convertible::None;
1409
+ }
1410
+ }
1411
+
1412
+ std::map<T, U> convert(VALUE value)
1413
+ {
1414
+ switch (rb_type(value))
1415
+ {
1416
+ case RUBY_T_DATA:
1417
+ {
1418
+ // This is a wrapped map (hopefully!)
1419
+ return *detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1420
+ }
1421
+ case RUBY_T_HASH:
1422
+ {
1423
+ // If this an Ruby hash and the mapped type is copyable
1424
+ if constexpr (std::is_default_constructible_v<U>)
1425
+ {
1426
+ return MapFromHash<T, U>::convert(value);
1427
+ }
1428
+ }
1429
+ default:
1430
+ {
1431
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1432
+ detail::protect(rb_obj_classname, value), "std::map");
1433
+ }
1434
+ }
1435
+ }
1436
+
1437
+ private:
1438
+ Arg* arg_ = nullptr;
1439
+ };
1440
+
1441
+ template<typename T, typename U>
1442
+ class From_Ruby<std::map<T, U>&>
1443
+ {
1444
+ public:
1445
+ From_Ruby() = default;
1446
+
1447
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1448
+ {
1449
+ }
1450
+
1451
+ Convertible is_convertible(VALUE value)
1452
+ {
1453
+ switch (rb_type(value))
1454
+ {
1455
+ case RUBY_T_DATA:
1456
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1457
+ break;
1458
+ case RUBY_T_HASH:
1459
+ return Convertible::Cast;
1460
+ break;
1461
+ default:
1462
+ return Convertible::None;
1463
+ }
1464
+ }
1465
+
1466
+ std::map<T, U>& convert(VALUE value)
1467
+ {
1468
+ switch (rb_type(value))
1469
+ {
1470
+ case RUBY_T_DATA:
1471
+ {
1472
+ // This is a wrapped map (hopefully!)
1473
+ return *detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1474
+ }
1475
+ case RUBY_T_HASH:
1476
+ {
1477
+ // If this an Ruby array and the map type is copyable
1478
+ if constexpr (std::is_default_constructible_v<std::map<T, U>>)
1479
+ {
1480
+ this->converted_ = MapFromHash<T, U>::convert(value);
1481
+ return this->converted_;
1482
+ }
1483
+ }
1484
+ default:
1485
+ {
1486
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1487
+ detail::protect(rb_obj_classname, value), "std::map");
1488
+ }
1489
+ }
1490
+ }
1491
+
1492
+ private:
1493
+ Arg* arg_ = nullptr;
1494
+ std::map<T, U> converted_;
1495
+ };
1496
+
1497
+ template<typename T, typename U>
1498
+ class From_Ruby<std::map<T, U>*>
1499
+ {
1500
+ public:
1501
+ From_Ruby() = default;
1502
+
1503
+ explicit From_Ruby(Arg* arg) : arg_(arg)
1504
+ {
1505
+ }
1506
+
1507
+ Convertible is_convertible(VALUE value)
1508
+ {
1509
+ switch (rb_type(value))
1510
+ {
1511
+ case RUBY_T_DATA:
1512
+ return Data_Type<std::map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1513
+ break;
1514
+ case RUBY_T_NIL:
1515
+ return Convertible::Exact;
1516
+ break;
1517
+ case RUBY_T_HASH:
1518
+ return Convertible::Cast;
1519
+ break;
1520
+ default:
1521
+ return Convertible::None;
1522
+ }
1523
+ }
1524
+
1525
+ std::map<T, U>* convert(VALUE value)
1526
+ {
1527
+ switch (rb_type(value))
1528
+ {
1529
+ case RUBY_T_DATA:
1530
+ {
1531
+ // This is a wrapped map (hopefully!)
1532
+ return detail::unwrap<std::map<T, U>>(value, Data_Type<std::map<T, U>>::ruby_data_type(), false);
1533
+ }
1534
+ case RUBY_T_HASH:
1535
+ {
1536
+ // If this an Ruby array and the map type is copyable
1537
+ if constexpr (std::is_default_constructible_v<U>)
1538
+ {
1539
+ this->converted_ = MapFromHash<T, U>::convert(value);
1540
+ return &this->converted_;
1541
+ }
1542
+ }
1543
+ default:
1544
+ {
1545
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
1546
+ detail::protect(rb_obj_classname, value), "std::map");
1547
+ }
1548
+ }
1549
+ }
1550
+
1551
+ private:
1552
+ Arg* arg_;
1553
+ std::map<T, U> converted_;
1554
+ };
1555
+ }
1556
+ }
1557
+
1558
+ // ========= monostate.hpp =========
1559
+
1560
+
1561
+ // --------- monostate.ipp ---------
1562
+ #include <variant>
1563
+
1564
+ namespace Rice::detail
1565
+ {
1566
+ template<>
1567
+ struct Type<std::monostate>
1568
+ {
1569
+ constexpr static bool verify()
1570
+ {
1571
+ return true;
1572
+ }
1573
+
1574
+ static VALUE rubyKlass()
1575
+ {
1576
+ return rb_cNilClass;
1577
+ }
1578
+ };
1579
+
1580
+ template<>
1581
+ class To_Ruby<std::monostate>
1582
+ {
1583
+ public:
1584
+ To_Ruby() = default;
1585
+
1586
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
1587
+ {
1588
+ }
1589
+
1590
+ VALUE convert(const std::monostate& _)
1591
+ {
1592
+ return Qnil;
1593
+ }
1594
+
1595
+
1596
+ private:
1597
+ Return* returnInfo_ = nullptr;
1598
+ };
1599
+
1600
+ template<>
1601
+ class To_Ruby<std::monostate&>
1602
+ {
1603
+ public:
1604
+ To_Ruby() = default;
1605
+
1606
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
1607
+ {
1608
+ }
1609
+
1610
+ VALUE convert(const std::monostate& data)
1611
+ {
1612
+ return Qnil;
1613
+ }
1614
+
1615
+ private:
1616
+ Return* returnInfo_ = nullptr;
1617
+ };
1618
+
1619
+ template<>
1620
+ class From_Ruby<std::monostate>
1621
+ {
1622
+ public:
1623
+ From_Ruby() = default;
1624
+
1625
+ explicit From_Ruby(Arg* arg)
1626
+ {
1627
+ }
1628
+
1629
+ Convertible is_convertible(VALUE value)
1630
+ {
1631
+ return value == Qnil ? Convertible::Exact : Convertible::None;
1632
+ }
1633
+
1634
+ std::monostate convert(VALUE value)
1635
+ {
1636
+ if (value == Qnil)
1637
+ {
1638
+ return std::monostate();
1639
+ }
1640
+ else
1641
+ {
1642
+ throw std::runtime_error("Can only convert nil values to std::monostate");
1643
+ }
1644
+ }
1645
+ };
1646
+
1647
+ template<>
1648
+ class From_Ruby<std::monostate&>
1649
+ {
1650
+ public:
1651
+ From_Ruby() = default;
1652
+
1653
+ explicit From_Ruby(Arg* arg)
1654
+ {
1655
+ }
1656
+
1657
+ Convertible is_convertible(VALUE value)
1658
+ {
1659
+ return value == Qnil ? Convertible::Exact : Convertible::None;
1660
+ }
1661
+
1662
+ std::monostate& convert(VALUE value)
1663
+ {
1664
+ if (value == Qnil)
1665
+ {
1666
+ return this->converted_;
1667
+ }
1668
+ else
1669
+ {
1670
+ throw std::runtime_error("Can only convert nil values to std::monostate");
1671
+ }
1672
+ }
1673
+
1674
+ private:
1675
+ std::monostate converted_ = std::monostate();
1676
+ };
1677
+ }
1678
+
1679
+
1680
+ // ========= multimap.hpp =========
1681
+
1682
+ #include <map>
1683
+
1684
+ namespace Rice
1685
+ {
1686
+ template<typename K, typename T>
1687
+ Data_Type<std::multimap<K, T>> define_multimap(std::string name = "");
1688
+ }
1689
+
1690
+
1691
+ // --------- multimap.ipp ---------
1692
+ #include <map>
1693
+
1694
+ namespace Rice
1695
+ {
1696
+ namespace stl
1697
+ {
1698
+ template<typename T>
1699
+ class MultimapHelper
1700
+ {
1701
+ using Key_T = typename T::key_type;
1702
+ using Mapped_T = typename T::mapped_type;
1703
+ using Value_T = typename T::value_type;
1704
+ using Reference_T = typename T::reference;
1705
+ using Size_T = typename T::size_type;
1706
+ using Difference_T = typename T::difference_type;
1707
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
1708
+
1709
+ public:
1710
+ MultimapHelper(Data_Type<T> klass) : klass_(klass)
1711
+ {
1712
+ this->register_pair();
1713
+ this->define_constructors();
1714
+ this->define_capacity_methods();
1715
+ this->define_access_methods();
1716
+ this->define_comparable_methods();
1717
+ this->define_modify_methods();
1718
+ this->define_enumerable();
1719
+ this->define_to_s();
1720
+ }
1721
+
1722
+ private:
1723
+
1724
+ void register_pair()
1725
+ {
1726
+ define_pair<const Key_T, Mapped_T>();
1727
+ }
1728
+
1729
+ void define_constructors()
1730
+ {
1731
+ klass_.define_constructor(Constructor<T>());
1732
+
1733
+ if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
1734
+ {
1735
+ klass_.define_constructor(Constructor<T, const T&>());
1736
+ }
1737
+ }
1738
+
1739
+ void define_capacity_methods()
1740
+ {
1741
+ klass_.define_method("empty?", &T::empty)
1742
+ .define_method("max_size", &T::max_size)
1743
+ .define_method("size", &T::size);
1744
+
1745
+ rb_define_alias(klass_, "count", "size");
1746
+ rb_define_alias(klass_, "length", "size");
1747
+ }
1748
+
1749
+ void define_access_methods()
1750
+ {
1751
+ // Access methods
1752
+ klass_.
1753
+ define_method("[]", [](T& multimap, const Key_T& key) -> Array
1754
+ {
1755
+ Array result;
1756
+ auto range = multimap.equal_range(key);
1757
+
1758
+ for (auto iter = range.first; iter != range.second; iter++)
1759
+ {
1760
+ result.push(iter->second, false);
1761
+ }
1762
+
1763
+ return result;
1764
+ })
1765
+ .define_method("include?", [](T& multimap, Key_T& key) -> bool
1766
+ {
1767
+ return multimap.find(key) != multimap.end();
1768
+ })
1769
+ .define_method("keys", [](T& multimap) -> std::vector<Key_T>
1770
+ {
1771
+ std::vector<Key_T> result;
1772
+ std::transform(multimap.begin(), multimap.end(), std::back_inserter(result),
1773
+ [](const auto& pair)
1774
+ {
1775
+ return pair.first;
1776
+ });
1777
+
1778
+ return result;
1779
+ })
1780
+ .define_method("values", [](T& multimap) -> std::vector<Mapped_T>
1781
+ {
1782
+ std::vector<Mapped_T> result;
1783
+ std::transform(multimap.begin(), multimap.end(), std::back_inserter(result),
1784
+ [](const auto& pair)
1785
+ {
1786
+ return pair.second;
1787
+ });
1788
+
1789
+ return result;
1790
+ });
1791
+
1792
+ rb_define_alias(klass_, "has_key", "include?");
1793
+ }
1794
+
1795
+ // Methods that require Value_T to support operator==
1796
+ void define_comparable_methods()
1797
+ {
1798
+ if constexpr (detail::is_comparable_v<Mapped_T>)
1799
+ {
1800
+ klass_.define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1801
+ {
1802
+ auto it = std::find_if(multimap.begin(), multimap.end(),
1803
+ [&value](auto& pair)
1804
+ {
1805
+ return pair.second == value;
1806
+ });
1807
+
1808
+ return it != multimap.end();
1809
+ });
1810
+ }
1811
+ else
1812
+ {
1813
+ klass_.define_method("value?", [](T& multimap, Mapped_T& value) -> bool
1814
+ {
1815
+ return false;
1816
+ });
1817
+ }
1818
+
1819
+ rb_define_alias(klass_, "has_value", "value?");
1820
+ }
1821
+
1822
+ void define_modify_methods()
1823
+ {
1824
+ klass_.define_method("clear", &T::clear)
1825
+ .define_method("delete", [](T& multimap, Key_T& key) -> std::optional<Mapped_T>
1826
+ {
1827
+ auto iter = multimap.find(key);
1828
+
1829
+ if (iter != multimap.end())
1830
+ {
1831
+ Mapped_T result = iter->second;
1832
+ multimap.erase(iter);
1833
+ return result;
1834
+ }
1835
+ else
1836
+ {
1837
+ return std::nullopt;
1838
+ }
1839
+ })
1840
+ .define_method("insert", [](T& map, Key_T key, Mapped_T& value) -> Mapped_T
1841
+ {
1842
+ Value_T element{ key, value };
1843
+ map.insert(element);
1844
+ return value;
1845
+ });
1846
+ }
1847
+
1848
+ void define_enumerable()
1849
+ {
1850
+ // Add enumerable support
1851
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
1852
+ }
1853
+
1854
+ void define_to_s()
1855
+ {
1856
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
1857
+ {
1858
+ klass_.define_method("to_s", [](const T& multimap)
1859
+ {
1860
+ auto iter = multimap.begin();
1861
+
1862
+ std::stringstream stream;
1863
+ detail::TypeMapper<T> typeMapper;
1864
+ stream << "<" << typeMapper.rubyName() << ":";
1865
+ stream << "{";
1866
+
1867
+ for (; iter != multimap.end(); iter++)
1868
+ {
1869
+ if (iter != multimap.begin())
1870
+ {
1871
+ stream << ", ";
1872
+ }
1873
+ stream << iter->first << " => " << iter->second;
1874
+ }
1875
+
1876
+ stream << "}>";
1877
+ return stream.str();
1878
+ });
1879
+ }
1880
+ else
1881
+ {
1882
+ klass_.define_method("to_s", [](const T& multimap)
1883
+ {
1884
+ return "[Not printable]";
1885
+ });
1886
+ }
1887
+ }
1888
+
1889
+ private:
1890
+ Data_Type<T> klass_;
1891
+ };
1892
+ } // namespace
1893
+
1894
+ template<typename Key, typename T>
1895
+ Data_Type<std::multimap<Key, T>> define_multimap(std::string klassName)
1896
+ {
1897
+ using MultiMap_T = std::multimap<Key, T>;
1898
+ using Data_Type_T = Data_Type<MultiMap_T>;
1899
+
1900
+ if (klassName.empty())
1901
+ {
1902
+ detail::TypeMapper<MultiMap_T> typeMapper;
1903
+ klassName = typeMapper.rubyName();
1904
+ }
1905
+
1906
+ Module rb_mStd = define_module("Std");
1907
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
1908
+ {
1909
+ return Data_Type_T();
1910
+ }
1911
+
1912
+ Identifier id(klassName);
1913
+ Data_Type_T result = define_class_under<detail::intrinsic_type<MultiMap_T>>(rb_mStd, id);
1914
+ stl::MultimapHelper helper(result);
1915
+ return result;
1916
+ }
1917
+
1918
+ namespace detail
1919
+ {
1920
+ // Helper method - maybe someday create a C++ Ruby set wrapper
1921
+ template<typename T, typename U>
1922
+ std::multimap<T, U> toMultimap(VALUE rubyHash)
1923
+ {
1924
+ using Function_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
1925
+
1926
+ auto block = [](VALUE key, VALUE value, VALUE user_data) -> int
1927
+ {
1928
+ using Key_T = typename std::multimap<T, U>::key_type;
1929
+ using Mapped_T = typename std::multimap<T, U>::mapped_type;
1930
+ using Value_T = typename std::multimap<T, U>::value_type;
1931
+
1932
+ return cpp_protect([&]
1933
+ {
1934
+ Value_T pair = { From_Ruby<Key_T>().convert(key), From_Ruby<Mapped_T>().convert(value) };
1935
+ std::multimap<T, U>* result = (std::multimap<T, U>*)user_data;
1936
+ result->insert(pair);
1937
+ return ST_CONTINUE;
1938
+ });
1939
+ };
1940
+
1941
+ std::multimap<T, U> result;
1942
+ detail::protect<Function_T>(rb_hash_foreach, rubyHash, block, (VALUE)&result);
1943
+ return result;
1944
+ }
1945
+
1946
+ template<typename Key_T, typename T>
1947
+ struct Type<std::multimap<Key_T, T>>
1948
+ {
1949
+ static bool verify()
1950
+ {
1951
+ Type<Key_T>::verify();
1952
+ Type<Key_T>::verify();
1953
+
1954
+ if (!Data_Type<std::multimap<Key_T, T>>::is_defined())
1955
+ {
1956
+ define_multimap<Key_T, T>();
1957
+ }
1958
+
1959
+ return true;
1960
+ }
1961
+ };
1962
+
1963
+ template<typename T, typename U>
1964
+ class From_Ruby<std::multimap<T, U>>
1965
+ {
1966
+ public:
1967
+ From_Ruby() = default;
1968
+
1969
+ explicit From_Ruby(Arg * arg) : arg_(arg)
1970
+ {
1971
+ }
1972
+
1973
+ Convertible is_convertible(VALUE value)
1974
+ {
1975
+ switch (rb_type(value))
1976
+ {
1977
+ case RUBY_T_DATA:
1978
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
1979
+ break;
1980
+ case RUBY_T_HASH:
1981
+ return Convertible::Cast;
1982
+ break;
1983
+ default:
1984
+ return Convertible::None;
1985
+ }
1986
+ }
1987
+
1988
+ std::multimap<T, U> convert(VALUE value)
1989
+ {
1990
+ switch (rb_type(value))
1991
+ {
1992
+ case RUBY_T_DATA:
1993
+ {
1994
+ // This is a wrapped multimap (hopefully!)
1995
+ return *detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
1996
+ }
1997
+ case RUBY_T_HASH:
1998
+ {
1999
+ // If this an Ruby hash and the multimapped type is copyable
2000
+ if constexpr (std::is_default_constructible_v<U>)
2001
+ {
2002
+ return toMultimap<T, U>(value);
2003
+ }
2004
+ }
2005
+ default:
2006
+ {
2007
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2008
+ detail::protect(rb_obj_classname, value), "std::multimap");
2009
+ }
2010
+ }
2011
+ }
2012
+
2013
+ private:
2014
+ Arg* arg_ = nullptr;
2015
+ };
2016
+
2017
+ template<typename T, typename U>
2018
+ class From_Ruby<std::multimap<T, U>&>
2019
+ {
2020
+ public:
2021
+ From_Ruby() = default;
2022
+
2023
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2024
+ {
2025
+ }
2026
+
2027
+ Convertible is_convertible(VALUE value)
2028
+ {
2029
+ switch (rb_type(value))
2030
+ {
2031
+ case RUBY_T_DATA:
2032
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2033
+ break;
2034
+ case RUBY_T_HASH:
2035
+ return Convertible::Cast;
2036
+ break;
2037
+ default:
2038
+ return Convertible::None;
2039
+ }
2040
+ }
2041
+
2042
+ std::multimap<T, U>& convert(VALUE value)
2043
+ {
2044
+ switch (rb_type(value))
2045
+ {
2046
+ case RUBY_T_DATA:
2047
+ {
2048
+ // This is a wrapped multimap (hopefully!)
2049
+ return *detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
2050
+ }
2051
+ case RUBY_T_HASH:
2052
+ {
2053
+ // If this an Ruby array and the multimap type is copyable
2054
+ if constexpr (std::is_default_constructible_v<std::multimap<T, U>>)
2055
+ {
2056
+ this->converted_ = toMultimap<T, U>(value);
2057
+ return this->converted_;
2058
+ }
2059
+ }
2060
+ default:
2061
+ {
2062
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2063
+ detail::protect(rb_obj_classname, value), "std::multimap");
2064
+ }
2065
+ }
2066
+ }
2067
+
2068
+ private:
2069
+ Arg* arg_ = nullptr;
2070
+ std::multimap<T, U> converted_;
2071
+ };
2072
+
2073
+ template<typename T, typename U>
2074
+ class From_Ruby<std::multimap<T, U>*>
2075
+ {
2076
+ public:
2077
+ From_Ruby() = default;
2078
+
2079
+ explicit From_Ruby(Arg* arg) : arg_(arg)
2080
+ {
2081
+ }
2082
+
2083
+ Convertible is_convertible(VALUE value)
2084
+ {
2085
+ switch (rb_type(value))
2086
+ {
2087
+ case RUBY_T_DATA:
2088
+ return Data_Type<std::multimap<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2089
+ break;
2090
+ case RUBY_T_NIL:
2091
+ return Convertible::Exact;
2092
+ break;
2093
+ case RUBY_T_HASH:
2094
+ return Convertible::Cast;
2095
+ break;
2096
+ default:
2097
+ return Convertible::None;
2098
+ }
2099
+ }
2100
+
2101
+ std::multimap<T, U>* convert(VALUE value)
2102
+ {
2103
+ switch (rb_type(value))
2104
+ {
2105
+ case RUBY_T_DATA:
2106
+ {
2107
+ // This is a wrapped multimap (hopefully!)
2108
+ return detail::unwrap<std::multimap<T, U>>(value, Data_Type<std::multimap<T, U>>::ruby_data_type(), false);
2109
+ }
2110
+ case RUBY_T_HASH:
2111
+ {
2112
+ // If this an Ruby array and the multimap type is copyable
2113
+ if constexpr (std::is_default_constructible_v<U>)
2114
+ {
2115
+ this->converted_ = toMultimap<T, U>(value);
2116
+ return &this->converted_;
2117
+ }
2118
+ }
2119
+ default:
2120
+ {
2121
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2122
+ detail::protect(rb_obj_classname, value), "std::multimap");
2123
+ }
2124
+ }
2125
+ }
2126
+
2127
+ private:
2128
+ Arg* arg_;
2129
+ std::multimap<T, U> converted_;
2130
+ };
2131
+ }
2132
+ }
2133
+
2134
+ // ========= set.hpp =========
2135
+
2136
+ namespace Rice
2137
+ {
2138
+ template<typename T>
2139
+ Data_Type<std::set<T>> define_set(std::string klassName = "");
2140
+ }
2141
+
2142
+
2143
+ // --------- set.ipp ---------
2144
+ #include <set>
2145
+
2146
+ namespace Rice
2147
+ {
2148
+ namespace stl
2149
+ {
2150
+ template<typename T>
2151
+ class SetHelper
2152
+ {
2153
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
2154
+ // of std::set<bool>. Reference_T is actually a proxy class that we do not
2155
+ // want to have to register with Rice nor do we want to pass it around.
2156
+ using Key_T = typename T::key_type;
2157
+ using Value_T = typename T::value_type;
2158
+ using Size_T = typename T::size_type;
2159
+ using Difference_T = typename T::difference_type;
2160
+ // For To_Ruby_T however we do need to use reference type because this is what
2161
+ // will be passed by an interator to To_Ruby#convert
2162
+ using Reference_T = typename T::reference;
2163
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
2164
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
2165
+
2166
+ public:
2167
+ SetHelper(Data_Type<T> klass) : klass_(klass)
2168
+ {
2169
+ this->define_constructors();
2170
+ this->define_capacity_methods();
2171
+ this->define_comparable_methods();
2172
+ this->define_modify_methods();
2173
+ this->define_operators();
2174
+ this->define_enumerable();
2175
+ this->define_to_array();
2176
+ this->define_to_s();
2177
+ }
2178
+
2179
+ private:
2180
+
2181
+ void define_constructors()
2182
+ {
2183
+ klass_.define_constructor(Constructor<T>())
2184
+ .define_constructor(Constructor<T, const T&>());
2185
+ }
2186
+
2187
+ void define_capacity_methods()
2188
+ {
2189
+ klass_.define_method("empty?", &T::empty)
2190
+ .define_method("max_size", &T::max_size)
2191
+ .define_method("size", &T::size);
2192
+
2193
+ rb_define_alias(klass_, "count", "size");
2194
+ rb_define_alias(klass_, "length", "size");
2195
+ }
2196
+
2197
+ void define_comparable_methods()
2198
+ {
2199
+ klass_
2200
+ .define_method("include?", [](T& self, const Key_T element) -> bool
2201
+ {
2202
+ auto iter = self.find(element);
2203
+ return iter != self.end();
2204
+ })
2205
+ .define_method("count", [](T& self, const Key_T element) -> Size_T
2206
+ {
2207
+ return self.count(element);
2208
+ });
2209
+ }
2210
+
2211
+ void define_modify_methods()
2212
+ {
2213
+ klass_
2214
+ .define_method("clear", &T::clear)
2215
+ .define_method("delete", [](T& self, const Key_T key) -> T&
2216
+ {
2217
+ self.erase(key);
2218
+ return self;
2219
+ })
2220
+ .define_method("insert", [](T& self, const Value_T value) -> T&
2221
+ {
2222
+ self.insert(value);
2223
+ return self;
2224
+ })
2225
+ .define_method("merge", [](T& self, T& other) -> T&
2226
+ {
2227
+ self.merge(other);
2228
+ return self;
2229
+ });
2230
+
2231
+ rb_define_alias(klass_, "erase", "delete");
2232
+ }
2233
+
2234
+ void define_operators()
2235
+ {
2236
+ klass_
2237
+ .define_method("<<", [](T& self, const Value_T value) -> T&
2238
+ {
2239
+ self.insert(value);
2240
+ return self;
2241
+ })
2242
+ .define_method("==", [](const T& self, const T& other) -> bool
2243
+ {
2244
+ if constexpr (detail::is_comparable_v<Value_T>)
2245
+ {
2246
+ return self == other;
2247
+ }
2248
+ else
2249
+ {
2250
+ return false;
2251
+ }
2252
+ })
2253
+ .define_method("&", [](const T& self, const T& other) -> T
2254
+ {
2255
+ T result;
2256
+ std::set_intersection(self.begin(), self.end(),
2257
+ other.begin(), other.end(),
2258
+ std::inserter(result, result.begin()));
2259
+
2260
+ return result;
2261
+ })
2262
+ .define_method("|", [](const T& self, const T& other) -> T
2263
+ {
2264
+ T result;
2265
+ std::set_union(self.begin(), self.end(),
2266
+ other.begin(), other.end(),
2267
+ std::inserter(result, result.begin()));
2268
+
2269
+ return result;
2270
+ })
2271
+ .define_method("-", [](const T& self, const T& other) -> T
2272
+ {
2273
+ T result;
2274
+ std::set_difference(self.begin(), self.end(),
2275
+ other.begin(), other.end(),
2276
+ std::inserter(result, result.begin()));
2277
+
2278
+ return result;
2279
+ })
2280
+ .define_method("^", [](const T& self, const T& other) -> T
2281
+ {
2282
+ T result;
2283
+ std::set_symmetric_difference(self.begin(), self.end(),
2284
+ other.begin(), other.end(),
2285
+ std::inserter(result, result.begin()));
2286
+
2287
+ return result;
2288
+ })
2289
+ .define_method("<", [](const T& self, const T& other) -> bool
2290
+ {
2291
+ return std::includes(other.begin(), other.end(),
2292
+ self.begin(), self.end());
2293
+ })
2294
+ .define_method(">", [](const T& self, const T& other) -> bool
2295
+ {
2296
+ return std::includes(self.begin(), self.end(),
2297
+ other.begin(), other.end());
2298
+ });
2299
+
2300
+ rb_define_alias(klass_, "eql?", "==");
2301
+ rb_define_alias(klass_, "intersection", "&");
2302
+ rb_define_alias(klass_, "union", "|");
2303
+ rb_define_alias(klass_, "difference", "-");
2304
+ rb_define_alias(klass_, "proper_subset?", "<");
2305
+ rb_define_alias(klass_, "subset?", "<");
2306
+ rb_define_alias(klass_, "proper_superset?", ">");
2307
+ rb_define_alias(klass_, "superset?", ">");
2308
+ }
2309
+
2310
+ void define_enumerable()
2311
+ {
2312
+ // Add enumerable support
2313
+ klass_.template define_iterator<typename T::iterator(T::*)() const>(&T::begin, &T::end);
2314
+ }
2315
+
2316
+ void define_to_array()
2317
+ {
2318
+ // Add enumerable support
2319
+ klass_.define_method("to_a", [](T& self) -> VALUE
2320
+ {
2321
+ Array array;
2322
+ for (auto element: self)
2323
+ {
2324
+ array.push(element, false);
2325
+ }
2326
+
2327
+ return array.value();
2328
+ }, Return().setValue());
2329
+ }
2330
+
2331
+ void define_to_s()
2332
+ {
2333
+ if constexpr (detail::is_ostreamable_v<Value_T>)
2334
+ {
2335
+ klass_.define_method("to_s", [](const T& self)
2336
+ {
2337
+ auto iter = self.begin();
2338
+ auto finish = self.end();
2339
+
2340
+ std::stringstream stream;
2341
+ detail::TypeMapper<T> typeMapper;
2342
+ stream << "<" << typeMapper.rubyName() << ":";
2343
+ stream << "{";
2344
+
2345
+ for (; iter != finish; iter++)
2346
+ {
2347
+ if (iter == self.begin())
2348
+ {
2349
+ stream << *iter;
2350
+ }
2351
+ else
2352
+ {
2353
+ stream << ", " << *iter;
2354
+ }
2355
+ }
2356
+
2357
+ stream << "}>";
2358
+ return stream.str();
2359
+ });
2360
+ }
2361
+ else
2362
+ {
2363
+ klass_.define_method("to_s", [](const T& self)
2364
+ {
2365
+ return "[Not printable]";
2366
+ });
2367
+ }
2368
+ }
2369
+
2370
+ private:
2371
+ Data_Type<T> klass_;
2372
+ };
2373
+ } // namespace
2374
+
2375
+ template<typename T>
2376
+ Data_Type<std::set<T>> define_set(std::string klassName)
2377
+ {
2378
+ using Set_T = std::set<T>;
2379
+ using Data_Type_T = Data_Type<Set_T>;
2380
+
2381
+ if (klassName.empty())
2382
+ {
2383
+ detail::TypeMapper<Set_T> typeMapper;
2384
+ klassName = typeMapper.rubyName();
2385
+ }
2386
+
2387
+ Module rb_mStd = define_module("Std");
2388
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2389
+ {
2390
+ return Data_Type_T();
2391
+ }
2392
+
2393
+ Identifier id(klassName);
2394
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Set_T>>(rb_mStd, id);
2395
+ stl::SetHelper helper(result);
2396
+ return result;
2397
+ }
2398
+
2399
+ namespace detail
2400
+ {
2401
+ // Helper method - maybe someday create a C++ Ruby set wrapper
2402
+ template<typename T>
2403
+ std::set<T> toSet(VALUE rubySet)
2404
+ {
2405
+ using Function_T = VALUE(*)(VALUE, ID, int, const VALUE*, rb_block_call_func_t, VALUE);
2406
+ static Identifier identifier("each");
2407
+
2408
+ std::set<T> result;
2409
+ auto block = [&result](const typename std::set<T>::value_type element) -> VALUE
2410
+ {
2411
+ result.insert(element);
2412
+ return Qnil;
2413
+ };
2414
+
2415
+ using Proc_T = decltype(block);
2416
+ using NativeProc_T = NativeProc<Proc_T>;
2417
+ std::unique_ptr<NativeProc_T> proc(NativeProc_T::define(std::forward<Proc_T>(block)));
2418
+
2419
+ detail::protect<Function_T>(rb_block_call, rubySet, identifier.id(), 0, nullptr, NativeProc_T::resolve, (VALUE)proc.get());
2420
+
2421
+ return result;
2422
+ }
2423
+
2424
+ template<typename T>
2425
+ struct Type<std::set<T>>
2426
+ {
2427
+ static bool verify()
2428
+ {
2429
+ Type<intrinsic_type<T>>::verify();
2430
+
2431
+ if (!Data_Type<std::set<T>>::is_defined())
2432
+ {
2433
+ define_set<T>();
2434
+ }
2435
+
2436
+ return true;
2437
+ }
2438
+ };
2439
+
2440
+ template<typename T>
2441
+ class From_Ruby<std::set<T>>
2442
+ {
2443
+ private:
2444
+ static inline std::string setName = "Set";
2445
+
2446
+ public:
2447
+ From_Ruby() = default;
2448
+
2449
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2450
+ {
2451
+ }
2452
+
2453
+ Convertible is_convertible(VALUE value)
2454
+ {
2455
+ switch (rb_type(value))
2456
+ {
2457
+ case RUBY_T_DATA:
2458
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2459
+ break;
2460
+ case RUBY_T_OBJECT:
2461
+ {
2462
+ Object object(value);
2463
+ if (object.class_name().str() == setName)
2464
+ {
2465
+ return Convertible::Cast;
2466
+ }
2467
+ }
2468
+ default:
2469
+ return Convertible::None;
2470
+ }
2471
+ }
2472
+
2473
+ std::set<T> convert(VALUE value)
2474
+ {
2475
+ switch (rb_type(value))
2476
+ {
2477
+ case RUBY_T_DATA:
2478
+ {
2479
+ // This is a wrapped self (hopefully!)
2480
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2481
+ }
2482
+ case RUBY_T_OBJECT:
2483
+ {
2484
+ Object object(value);
2485
+ if (object.class_name().str() == setName)
2486
+ {
2487
+ return toSet<T>(value);
2488
+ }
2489
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2490
+ detail::protect(rb_obj_classname, value), "std::set");
2491
+ }
2492
+ default:
2493
+ {
2494
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2495
+ detail::protect(rb_obj_classname, value), "std::set");
2496
+ }
2497
+ }
2498
+ }
2499
+
2500
+ private:
2501
+ Arg* arg_ = nullptr;
2502
+ };
2503
+
2504
+ template<typename T>
2505
+ class From_Ruby<std::set<T>&>
2506
+ {
2507
+ private:
2508
+ static inline std::string setName = "Set";
2509
+
2510
+ public:
2511
+ From_Ruby() = default;
2512
+
2513
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2514
+ {
2515
+ }
2516
+
2517
+ Convertible is_convertible(VALUE value)
2518
+ {
2519
+ switch (rb_type(value))
2520
+ {
2521
+ case RUBY_T_DATA:
2522
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2523
+ break;
2524
+ case RUBY_T_OBJECT:
2525
+ {
2526
+ Object object(value);
2527
+ if (object.class_name().str() == setName)
2528
+ {
2529
+ return Convertible::Cast;
2530
+ }
2531
+ }
2532
+ default:
2533
+ return Convertible::None;
2534
+ }
2535
+ }
2536
+
2537
+ std::set<T>& convert(VALUE value)
2538
+ {
2539
+ switch (rb_type(value))
2540
+ {
2541
+ case RUBY_T_DATA:
2542
+ {
2543
+ // This is a wrapped self (hopefully!)
2544
+ return *detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2545
+ }
2546
+ case RUBY_T_OBJECT:
2547
+ {
2548
+ Object object(value);
2549
+ if (object.class_name().str() == setName)
2550
+ {
2551
+ // If this an Ruby array and the vector type is copyable
2552
+ if constexpr (std::is_default_constructible_v<T>)
2553
+ {
2554
+ this->converted_ = toSet<T>(value);
2555
+ return this->converted_;
2556
+ }
2557
+ }
2558
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2559
+ detail::protect(rb_obj_classname, value), "std::set");
2560
+ }
2561
+ default:
2562
+ {
2563
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2564
+ detail::protect(rb_obj_classname, value), "std::set");
2565
+ }
2566
+ }
2567
+ }
2568
+
2569
+ private:
2570
+ Arg* arg_ = nullptr;
2571
+ std::set<T> converted_;
2572
+ };
2573
+
2574
+ template<typename T>
2575
+ class From_Ruby<std::set<T>*>
2576
+ {
2577
+ private:
2578
+ static inline std::string setName = "Set";
2579
+ public:
2580
+ From_Ruby() = default;
2581
+
2582
+ explicit From_Ruby(Arg* arg) : arg_(arg)
2583
+ {
2584
+ }
2585
+
2586
+ Convertible is_convertible(VALUE value)
2587
+ {
2588
+ switch (rb_type(value))
2589
+ {
2590
+ case RUBY_T_DATA:
2591
+ return Data_Type<std::set<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
2592
+ break;
2593
+ case RUBY_T_NIL:
2594
+ return Convertible::Exact;
2595
+ break;
2596
+ case RUBY_T_OBJECT:
2597
+ {
2598
+ Object object(value);
2599
+ if (object.class_name().str() == setName)
2600
+ {
2601
+ return Convertible::Cast;
2602
+ }
2603
+ }
2604
+ default:
2605
+ return Convertible::None;
2606
+ }
2607
+ }
2608
+
2609
+ std::set<T>* convert(VALUE value)
2610
+ {
2611
+ switch (rb_type(value))
2612
+ {
2613
+ case RUBY_T_DATA:
2614
+ {
2615
+ // This is a wrapped self (hopefully!)
2616
+ return detail::unwrap<std::set<T>>(value, Data_Type<std::set<T>>::ruby_data_type(), false);
2617
+ }
2618
+ case RUBY_T_OBJECT:
2619
+ {
2620
+ Object object(value);
2621
+ if (object.class_name().str() == setName)
2622
+ {
2623
+ // If this an Ruby array and the vector type is copyable
2624
+ if constexpr (std::is_default_constructible_v<T>)
2625
+ {
2626
+ this->converted_ = toSet<T>(value);
2627
+ return &this->converted_;
2628
+ }
2629
+ }
2630
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2631
+ detail::protect(rb_obj_classname, value), "std::set");
2632
+ }
2633
+ default:
2634
+ {
2635
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
2636
+ detail::protect(rb_obj_classname, value), "std::set");
2637
+ }
2638
+ }
2639
+ }
2640
+
2641
+ private:
2642
+ Arg* arg_;
2643
+ std::set<T> converted_;
2644
+ };
2645
+ }
2646
+ }
2647
+
2648
+
2649
+ // ========= shared_ptr.hpp =========
2650
+
2651
+ namespace Rice::detail
2652
+ {
2653
+ template<typename T>
2654
+ class Wrapper<std::shared_ptr<T>> : public WrapperBase
2655
+ {
2656
+ public:
2657
+ Wrapper(const std::shared_ptr<T>& data);
2658
+ ~Wrapper();
2659
+ void* get() override;
2660
+ std::shared_ptr<T>& data();
2661
+
2662
+ private:
2663
+ std::shared_ptr<T> data_;
2664
+ };
2665
+ }
2666
+
2667
+ namespace Rice
2668
+ {
2669
+ template<typename T>
2670
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName = "");
2671
+ }
2672
+
2673
+
2674
+ // --------- shared_ptr.ipp ---------
2675
+ #include <memory>
2676
+
2677
+ // --------- Enable creation of std::shared_ptr from Ruby ---------
2678
+ namespace Rice
2679
+ {
2680
+ template<typename T>
2681
+ Data_Type<std::shared_ptr<T>> define_shared_ptr(std::string klassName)
2682
+ {
2683
+ using SharedPtr_T = std::shared_ptr<T>;
2684
+ using Data_Type_T = Data_Type<SharedPtr_T>;
2685
+
2686
+ if (klassName.empty())
2687
+ {
2688
+ detail::TypeMapper<SharedPtr_T> typeMapper;
2689
+ klassName = typeMapper.rubyName();
2690
+ }
2691
+
2692
+ Module rb_mStd = define_module("Std");
2693
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
2694
+ {
2695
+ return Data_Type_T();
2696
+ }
2697
+
2698
+ Identifier id(klassName);
2699
+ Data_Type_T result = define_class_under<detail::intrinsic_type<SharedPtr_T>>(rb_mStd, id).
2700
+ define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
2701
+
2702
+ return result;
2703
+ }
2704
+ }
2705
+
2706
+ // --------- Wrapper ---------
2707
+ namespace Rice::detail
2708
+ {
2709
+ template<typename T>
2710
+ inline Wrapper<std::shared_ptr<T>>::Wrapper(const std::shared_ptr<T>& data)
2711
+ : data_(data)
2712
+ {
2713
+ }
2714
+
2715
+ template<typename T>
2716
+ inline Wrapper<std::shared_ptr<T>>::~Wrapper()
2717
+ {
2718
+ Registries::instance.instances.remove(this->get());
2719
+ }
2720
+
2721
+ template<typename T>
2722
+ inline void* Wrapper<std::shared_ptr<T>>::get()
2723
+ {
2724
+ return (void*)this->data_.get();
2725
+ }
2726
+
2727
+ template<typename T>
2728
+ inline std::shared_ptr<T>& Wrapper<std::shared_ptr<T>>::data()
2729
+ {
2730
+ return data_;
2731
+ }
2732
+ }
2733
+
2734
+ // --------- Type/To_Ruby/From_Ruby ---------
2735
+ namespace Rice::detail
2736
+ {
2737
+ template<typename T>
2738
+ struct Type<std::shared_ptr<T>>
2739
+ {
2740
+ static bool verify()
2741
+ {
2742
+ if constexpr (std::is_fundamental_v<T>)
2743
+ {
2744
+ return Type<Pointer<T>>::verify();
2745
+ return Type<Buffer<T>>::verify();
2746
+ }
2747
+ else
2748
+ {
2749
+ return Type<T>::verify();
2750
+ }
2751
+ }
2752
+
2753
+ static VALUE rubyKlass()
2754
+ {
2755
+ if (Data_Type<std::shared_ptr<T>>::is_defined())
2756
+ {
2757
+ std::pair<VALUE, rb_data_type_t*> pair = Registries::instance.types.getType<std::shared_ptr<T>>();
2758
+ return pair.first;
2759
+ }
2760
+ else
2761
+ {
2762
+ TypeMapper<T> typeMapper;
2763
+ return typeMapper.rubyKlass();
2764
+ }
2765
+ }
2766
+ };
2767
+
2768
+ template <typename T>
2769
+ class To_Ruby<std::shared_ptr<T>>
2770
+ {
2771
+ public:
2772
+ To_Ruby() = default;
2773
+
2774
+ explicit To_Ruby(Arg* arv)
2775
+ {
2776
+ }
2777
+
2778
+ VALUE convert(std::shared_ptr<T>& data)
2779
+ {
2780
+ if constexpr (std::is_fundamental_v<T>)
2781
+ {
2782
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<Pointer<T>>::klass(), Data_Type<Pointer<T>>::ruby_data_type(), data, true);
2783
+ }
2784
+ else
2785
+ {
2786
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2787
+ }
2788
+ }
2789
+
2790
+ VALUE convert(std::shared_ptr<T>&& data)
2791
+ {
2792
+ if constexpr (std::is_fundamental_v<T>)
2793
+ {
2794
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<Pointer<T>>::klass(), Data_Type<Pointer<T>>::ruby_data_type(), data, true);
2795
+ }
2796
+ else
2797
+ {
2798
+ return detail::wrap<std::shared_ptr<T>>(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2799
+ }
2800
+ }
2801
+ };
2802
+
2803
+ template <typename T>
2804
+ class From_Ruby<std::shared_ptr<T>>
2805
+ {
2806
+ public:
2807
+ From_Ruby() = default;
2808
+
2809
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2810
+ {
2811
+ }
2812
+
2813
+ Convertible is_convertible(VALUE value)
2814
+ {
2815
+ switch (rb_type(value))
2816
+ {
2817
+ case RUBY_T_DATA:
2818
+ return Convertible::Exact;
2819
+ break;
2820
+ default:
2821
+ return Convertible::None;
2822
+ }
2823
+ }
2824
+
2825
+ std::shared_ptr<T> convert(VALUE value)
2826
+ {
2827
+ // Get the wrapper
2828
+ WrapperBase* wrapperBase = detail::getWrapper(value);
2829
+
2830
+ // Was this shared_ptr created by the user from Ruby? If so it will
2831
+ // be wrapped as a pointer, std::shared_ptr<T>*. In the case just
2832
+ // return the shared pointer
2833
+ if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
2834
+ {
2835
+ // Use unwrap to validate the underlying wrapper is the correct type
2836
+ std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
2837
+ return *ptr;
2838
+ }
2839
+ else if (std::is_fundamental_v<T>)
2840
+ {
2841
+ // Get the wrapper again to validate T's type
2842
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<Pointer<T>>::ruby_data_type());
2843
+ return wrapper->data();
2844
+ }
2845
+ else
2846
+ {
2847
+ // Get the wrapper again to validate T's type
2848
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2849
+ return wrapper->data();
2850
+ }
2851
+ }
2852
+ private:
2853
+ Arg* arg_ = nullptr;
2854
+ };
2855
+
2856
+ template <typename T>
2857
+ class To_Ruby<std::shared_ptr<T>&>
2858
+ {
2859
+ public:
2860
+ To_Ruby() = default;
2861
+
2862
+ explicit To_Ruby(Arg* arg)
2863
+ {
2864
+ }
2865
+
2866
+ VALUE convert(std::shared_ptr<T>& data)
2867
+ {
2868
+ return detail::wrap(Data_Type<T>::klass(), Data_Type<T>::ruby_data_type(), data, true);
2869
+ }
2870
+ };
2871
+
2872
+ template <typename T>
2873
+ class From_Ruby<std::shared_ptr<T>&>
2874
+ {
2875
+ public:
2876
+ From_Ruby() = default;
2877
+
2878
+ explicit From_Ruby(Arg * arg) : arg_(arg)
2879
+ {
2880
+ }
2881
+
2882
+ Convertible is_convertible(VALUE value)
2883
+ {
2884
+ switch (rb_type(value))
2885
+ {
2886
+ case RUBY_T_DATA:
2887
+ return Convertible::Exact;
2888
+ break;
2889
+ default:
2890
+ return Convertible::None;
2891
+ }
2892
+ }
2893
+
2894
+ std::shared_ptr<T>& convert(VALUE value)
2895
+ {
2896
+ // Get the wrapper
2897
+ WrapperBase* wrapperBase = detail::getWrapper(value);
2898
+
2899
+ // Was this shared_ptr created by the user from Ruby? If so it will
2900
+ // be wrapped as a pointer, std::shared_ptr<T>*. In the case just
2901
+ // return the shared pointer
2902
+ if (dynamic_cast<Wrapper<std::shared_ptr<T>*>*>(wrapperBase))
2903
+ {
2904
+ // Use unwrap to validate the underlying wrapper is the correct type
2905
+ std::shared_ptr<T>* ptr = unwrap<std::shared_ptr<T>>(value, Data_Type<std::shared_ptr<T>>::ruby_data_type(), false);
2906
+ return *ptr;
2907
+ }
2908
+ else if (std::is_fundamental_v<T>)
2909
+ {
2910
+ // Get the wrapper again to validate T's type
2911
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<Pointer<T>>::ruby_data_type());
2912
+ return wrapper->data();
2913
+ }
2914
+ else
2915
+ {
2916
+ // Get the wrapper again to validate T's type
2917
+ Wrapper<std::shared_ptr<T>>* wrapper = getWrapper<Wrapper<std::shared_ptr<T>>>(value, Data_Type<T>::ruby_data_type());
2918
+ return wrapper->data();
2919
+ }
2920
+ }
2921
+
2922
+ private:
2923
+ Arg* arg_ = nullptr;
2924
+ };
2925
+ }
2926
+
2927
+
2928
+ // ========= tuple.hpp =========
2929
+
2930
+
2931
+ // --------- tuple.ipp ---------
2932
+ #include <tuple>
2933
+
2934
+ namespace Rice::detail
2935
+ {
2936
+ template<typename...Types>
2937
+ struct Type<std::tuple<Types...>>
2938
+ {
2939
+ using Tuple_T = std::tuple<Types...>;
2940
+
2941
+ template<std::size_t... I>
2942
+ constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
2943
+ {
2944
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
2945
+ }
2946
+
2947
+ template<std::size_t... I>
2948
+ constexpr static bool verify()
2949
+ {
2950
+ auto indices = std::make_index_sequence<std::tuple_size_v<std::tuple<Types...>>>{};
2951
+ return verifyTypes(indices);
2952
+ }
2953
+
2954
+ static VALUE rubyKlass()
2955
+ {
2956
+ return rb_cArray;
2957
+ }
2958
+ };
2959
+
2960
+ template<typename...Types>
2961
+ class To_Ruby<std::tuple<Types...>>
2962
+ {
2963
+ public:
2964
+ To_Ruby() = default;
2965
+
2966
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
2967
+ {
2968
+ }
2969
+
2970
+ VALUE convert(const std::tuple<Types...>& data)
2971
+ {
2972
+ Array result;
2973
+
2974
+ for_each_tuple(data, [&](auto element)
2975
+ {
2976
+ result.push(element, true);
2977
+ });
2978
+
2979
+ return result.value();
2980
+ }
2981
+
2982
+ private:
2983
+ Return* returnInfo_ = nullptr;
2984
+ };
2985
+
2986
+ template<typename...Types>
2987
+ class To_Ruby<std::tuple<Types...>&>
2988
+ {
2989
+ public:
2990
+ To_Ruby() = default;
2991
+
2992
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
2993
+ {
2994
+ }
2995
+
2996
+ VALUE convert(const std::tuple<Types...>& data)
2997
+ {
2998
+ Array result;
2999
+
3000
+ bool isOwner = (this->returnInfo_ && this->returnInfo_->isOwner());
3001
+
3002
+ for_each_tuple(data, [&](auto& element)
3003
+ {
3004
+ result.push(element, isOwner);
3005
+ });
3006
+
3007
+ return result.value();
3008
+ }
3009
+
3010
+ private:
3011
+ Return* returnInfo_ = nullptr;
3012
+ };
3013
+
3014
+ template<typename...Types>
3015
+ class From_Ruby<std::tuple<Types...>>
3016
+ {
3017
+ public:
3018
+ using Tuple_T = std::tuple<Types...>;
3019
+
3020
+ template<std::size_t... I>
3021
+ constexpr static bool verifyTypes(Array& array, std::index_sequence<I...>& indices)
3022
+ {
3023
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
3024
+ }
3025
+
3026
+ From_Ruby() = default;
3027
+
3028
+ explicit From_Ruby(Arg* arg)
3029
+ {
3030
+ }
3031
+
3032
+ Convertible is_convertible(VALUE value)
3033
+ {
3034
+ Convertible result = Convertible::None;
3035
+
3036
+ // The ruby value must be an array of the correct size
3037
+ if (rb_type(value) != RUBY_T_ARRAY || Array(value).size() != std::tuple_size_v<Tuple_T>)
3038
+ {
3039
+ return result;
3040
+ }
3041
+
3042
+ // Now check that each tuple type is convertible
3043
+ Array array(value);
3044
+ int i = 0;
3045
+ for_each_tuple(this->fromRubys_,
3046
+ [&](auto& fromRuby)
3047
+ {
3048
+ result = result | fromRuby.is_convertible(array[i].value());
3049
+ i++;
3050
+ });
3051
+
3052
+ return result;
3053
+ }
3054
+
3055
+ template <std::size_t... I>
3056
+ std::tuple<Types...> convertInternal(Array array, std::index_sequence<I...>& indices)
3057
+ {
3058
+ return std::forward_as_tuple(std::get<I>(this->fromRubys_).convert(array[I].value())...);
3059
+ }
3060
+
3061
+ std::tuple<Types...> convert(VALUE value)
3062
+ {
3063
+ Array array(value);
3064
+ auto indices = std::make_index_sequence<std::tuple_size_v<Tuple_T>>{};
3065
+ return convertInternal(array, indices);
3066
+ }
3067
+
3068
+ private:
3069
+ // Possible converters we could use for this variant
3070
+ using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
3071
+ From_Ruby_Ts fromRubys_;
3072
+ };
3073
+
3074
+ /* template<typename...Types>
3075
+ class From_Ruby<std::tuple<Types...>&> : public From_Ruby<std::tuple<Types...>>
3076
+ {
3077
+ public:
3078
+ std::tuple<Types...>& convert(VALUE value)
3079
+ {
3080
+ int index = this->figureIndex(value);
3081
+ this->converted_ = this->convertInternal(value, index);
3082
+ return this->converted_;
3083
+ }
3084
+
3085
+ private:
3086
+ std::tuple<Types...> converted_;
3087
+ };*/
3088
+ }
3089
+
3090
+
3091
+ // ========= type_index.hpp =========
3092
+
3093
+
3094
+ // --------- type_index.ipp ---------
3095
+ #include <typeindex>
3096
+
3097
+ namespace Rice::stl
3098
+ {
3099
+ inline Data_Type<std::type_index> define_type_index()
3100
+ {
3101
+ Module rb_mStd = define_module("Std");
3102
+ return define_class_under<std::type_index>(rb_mStd, "TypeIndex").
3103
+ define_constructor(Constructor<std::type_index, const std::type_info&>()).
3104
+ define_method("hash_code", &std::type_index::hash_code).
3105
+ define_method("name", &std::type_index::name);
3106
+ }
3107
+ }
3108
+
3109
+ namespace Rice::detail
3110
+ {
3111
+ template<>
3112
+ struct Type<std::type_index>
3113
+ {
3114
+ static bool verify()
3115
+ {
3116
+ if (!detail::Registries::instance.types.isDefined<std::type_index>())
3117
+ {
3118
+ stl::define_type_index();
3119
+ }
3120
+
3121
+ return true;
3122
+ }
3123
+ };
3124
+ }
3125
+
3126
+
3127
+ // ========= type_info.hpp =========
3128
+
3129
+
3130
+ // --------- type_info.ipp ---------
3131
+ #include <typeinfo>
3132
+
3133
+ namespace Rice::stl
3134
+ {
3135
+ inline Data_Type<std::type_info> define_type_info()
3136
+ {
3137
+ Module rb_mStd = define_module("Std");
3138
+ return define_class_under<std::type_info>(rb_mStd, "TypeInfo").
3139
+ define_method("hash_code", &std::type_info::hash_code).
3140
+ define_method("name", &std::type_info::name);
3141
+ }
3142
+ }
3143
+
3144
+ namespace Rice::detail
3145
+ {
3146
+ template<>
3147
+ struct Type<std::type_info>
3148
+ {
3149
+ static inline bool verify()
3150
+ {
3151
+ if (!detail::Registries::instance.types.isDefined<std::type_info>())
3152
+ {
3153
+ stl::define_type_info();
3154
+ }
3155
+
3156
+ return true;
3157
+ }
3158
+ };
3159
+ }
3160
+
3161
+
3162
+ // ========= variant.hpp =========
3163
+
3164
+
3165
+ // --------- variant.ipp ---------
3166
+ #include <variant>
3167
+
3168
+ namespace Rice::detail
3169
+ {
3170
+ template<typename...Types>
3171
+ struct Type<std::variant<Types...>>
3172
+ {
3173
+ using Tuple_T = std::tuple<Types...>;
3174
+
3175
+ template<std::size_t... I>
3176
+ constexpr static bool verifyTypes(std::index_sequence<I...>& indices)
3177
+ {
3178
+ return (Type<std::tuple_element_t<I, Tuple_T>>::verify() && ...);
3179
+ }
3180
+
3181
+ constexpr static bool verify()
3182
+ {
3183
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
3184
+ return verifyTypes(indices);
3185
+ }
3186
+
3187
+ static VALUE rubyKlass()
3188
+ {
3189
+ // There is no direct mapping to Ruby, so just return Object
3190
+ return rb_cObject;
3191
+ }
3192
+ };
3193
+
3194
+ template<typename...Types>
3195
+ class To_Ruby<std::variant<Types...>>
3196
+ {
3197
+ public:
3198
+ To_Ruby() = default;
3199
+
3200
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
3201
+ {
3202
+ }
3203
+
3204
+ template<typename U, typename V>
3205
+ VALUE convertElement(U& data, bool takeOwnership)
3206
+ {
3207
+ return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
3208
+ }
3209
+
3210
+ template<typename U, std::size_t... I>
3211
+ VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
3212
+ {
3213
+ // Create a tuple of the variant types so we can look over the tuple's types
3214
+ using Tuple_T = std::tuple<Types...>;
3215
+
3216
+ /* This is a fold expression. In pseudo code:
3217
+
3218
+ for (type in variant.types)
3219
+ {
3220
+ if (variant.has_value<type>())
3221
+ return ToRuby<type>().convert(variant.getValue<type>)
3222
+ }
3223
+
3224
+ The list of variant types is stored in Tuple_T. The number of types is stored in I.
3225
+ Starting with index 0, get the variant type using td::tuple_element_t<I, Tuple_T>>.
3226
+ Next check if the variant has a value for that type using std::holds_alternative<T>.
3227
+ If yes, then call convertElement and save the return value to result. Then use the
3228
+ comma operator to return true to the fold expression. If the variant does not have
3229
+ a value for the type then return false.
3230
+
3231
+ The fold operator is or (||). If an index returns false, then the next index is evaluated
3232
+ up until I.
3233
+
3234
+ Code inspired by https://www.foonathan.net/2020/05/fold-tricks/ */
3235
+
3236
+ VALUE result = Qnil;
3237
+
3238
+ #if defined(__GNUC__) || defined(__clang__)
3239
+ #pragma GCC diagnostic push
3240
+ #pragma GCC diagnostic ignored "-Wunused-value"
3241
+ #endif
3242
+
3243
+ ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
3244
+ (result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
3245
+
3246
+ #if defined(__GNUC__) || defined(__clang__)
3247
+ #pragma GCC diagnostic pop
3248
+ #endif
3249
+
3250
+ return result;
3251
+ }
3252
+
3253
+ template<typename U>
3254
+ VALUE convert(U& data)
3255
+ {
3256
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
3257
+ return convertIterator(data, true, indices);
3258
+ }
3259
+
3260
+ template<typename U>
3261
+ VALUE convert(U&& data)
3262
+ {
3263
+ bool isOwner = true;
3264
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
3265
+ return convertIterator(data, isOwner, indices);
3266
+ }
3267
+
3268
+ private:
3269
+ Return* returnInfo_ = nullptr;
3270
+ };
3271
+
3272
+ template<typename...Types>
3273
+ class To_Ruby<std::variant<Types...>&>
3274
+ {
3275
+ public:
3276
+ To_Ruby() = default;
3277
+
3278
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
3279
+ {
3280
+ }
3281
+
3282
+ template<typename U, typename V>
3283
+ VALUE convertElement(U& data, bool takeOwnership)
3284
+ {
3285
+ if constexpr (std::is_const_v<U>)
3286
+ {
3287
+ return To_Ruby<V>().convert(std::get<V>(data));
3288
+ }
3289
+ else
3290
+ {
3291
+ return To_Ruby<V>().convert(std::forward<V>(std::get<V>(data)));
3292
+ }
3293
+ }
3294
+
3295
+ template<typename U, std::size_t... I>
3296
+ VALUE convertIterator(U& data, bool takeOwnership, std::index_sequence<I...>& indices)
3297
+ {
3298
+ // Create a tuple of the variant types so we can look over the tuple's types
3299
+ using Tuple_T = std::tuple<Types...>;
3300
+
3301
+ // See comments above for explanation of this code
3302
+ VALUE result = Qnil;
3303
+
3304
+ #if defined(__GNUC__) || defined(__clang__)
3305
+ #pragma GCC diagnostic push
3306
+ #pragma GCC diagnostic ignored "-Wunused-value"
3307
+ #endif
3308
+
3309
+ ((std::holds_alternative<std::tuple_element_t<I, Tuple_T>>(data) ?
3310
+ (result = convertElement<U, std::tuple_element_t<I, Tuple_T>>(data, takeOwnership), true) : false) || ...);
3311
+
3312
+ #if defined(__GNUC__) || defined(__clang__)
3313
+ #pragma GCC diagnostic pop
3314
+ #endif
3315
+
3316
+ return result;
3317
+ }
3318
+
3319
+ template<typename U>
3320
+ VALUE convert(U& data)
3321
+ {
3322
+ bool isOwner = (this->returnInfo_ && this->returnInfo_->isOwner());
3323
+ auto indices = std::make_index_sequence<std::variant_size_v<std::variant<Types...>>>{};
3324
+ return convertIterator(data, isOwner, indices);
3325
+ }
3326
+
3327
+ private:
3328
+ Return* returnInfo_ = nullptr;
3329
+ };
3330
+
3331
+ template<typename...Types>
3332
+ class From_Ruby<std::variant<Types...>>
3333
+ {
3334
+ public:
3335
+ From_Ruby() = default;
3336
+
3337
+ explicit From_Ruby(Arg* arg)
3338
+ {
3339
+ }
3340
+
3341
+ Convertible is_convertible(VALUE value)
3342
+ {
3343
+ Convertible result = Convertible::None;
3344
+
3345
+ for_each_tuple(this->fromRubys_,
3346
+ [&](auto& fromRuby)
3347
+ {
3348
+ result = result | fromRuby.is_convertible(value);
3349
+ });
3350
+
3351
+ return result;
3352
+ }
3353
+
3354
+ // This method search through a variant's types to figure out which one the
3355
+ // currently Ruby value best matches. It then returns the index of the type.
3356
+ int figureIndex(VALUE value)
3357
+ {
3358
+ int i = 0;
3359
+ int index = -1;
3360
+ Convertible foundConversion = Convertible::None;
3361
+
3362
+ for_each_tuple(this->fromRubys_,
3363
+ [&](auto& fromRuby)
3364
+ {
3365
+ Convertible isConvertible = fromRuby.is_convertible(value);
3366
+
3367
+ if (isConvertible > foundConversion)
3368
+ {
3369
+ index = i;
3370
+ foundConversion = isConvertible;
3371
+ }
3372
+ i++;
3373
+ });
3374
+
3375
+ if (index == -1)
3376
+ {
3377
+ rb_raise(rb_eArgError, "Could not find converter for variant");
3378
+ }
3379
+
3380
+ return index;
3381
+ }
3382
+
3383
+ /* This method loops over each type in the variant, creates a From_Ruby converter,
3384
+ and then check if the converter can work with the provided Rby value (it checks
3385
+ the type of the Ruby object to see if it matches the variant type).
3386
+ If yes, then the converter runs. If no, then the method recursively calls itself
3387
+ increasing the index.
3388
+
3389
+ We use recursion, with a constexpr, to avoid having to instantiate an instance
3390
+ of the variant to store results from a fold expression like the To_Ruby code
3391
+ does above. That allows us to process variants with non default constructible
3392
+ arguments like std::reference_wrapper. */
3393
+ template <std::size_t I = 0>
3394
+ std::variant<Types...> convertInternal(VALUE value, int index)
3395
+ {
3396
+ if constexpr (I < std::variant_size_v<std::variant<Types...>>)
3397
+ {
3398
+ if (I == index)
3399
+ {
3400
+ auto fromRuby = std::get<I>(this->fromRubys_);
3401
+ return fromRuby.convert(value);
3402
+ }
3403
+ else
3404
+ {
3405
+ return convertInternal<I + 1>(value, index);
3406
+ }
3407
+ }
3408
+ rb_raise(rb_eArgError, "Could not find converter for variant");
3409
+ }
3410
+
3411
+ std::variant<Types...> convert(VALUE value)
3412
+ {
3413
+ int index = this->figureIndex(value);
3414
+ return this->convertInternal(value, index);
3415
+ }
3416
+
3417
+ private:
3418
+ // Possible converters we could use for this variant
3419
+ using From_Ruby_Ts = std::tuple<From_Ruby<Types>...>;
3420
+ From_Ruby_Ts fromRubys_;
3421
+ };
3422
+
3423
+ template<typename...Types>
3424
+ class From_Ruby<std::variant<Types...>&> : public From_Ruby<std::variant<Types...>>
3425
+ {
3426
+ public:
3427
+ From_Ruby() = default;
3428
+
3429
+ explicit From_Ruby(Arg* arg)
3430
+ {
3431
+ }
3432
+
3433
+ std::variant<Types...>& convert(VALUE value)
3434
+ {
3435
+ int index = this->figureIndex(value);
3436
+ this->converted_ = this->convertInternal(value, index);
3437
+ return this->converted_;
3438
+ }
3439
+
3440
+ private:
3441
+ std::variant<Types...> converted_;
3442
+ };
3443
+ }
3444
+
3445
+
3446
+ // ========= unique_ptr.hpp =========
3447
+
3448
+ namespace Rice::detail
3449
+ {
3450
+ template<typename T>
3451
+ class Wrapper<std::unique_ptr<T>> : public WrapperBase
3452
+ {
3453
+ public:
3454
+ Wrapper(std::unique_ptr<T>&& data);
3455
+ ~Wrapper();
3456
+ void* get() override;
3457
+ std::unique_ptr<T>& data();
3458
+
3459
+ private:
3460
+ std::unique_ptr<T> data_;
3461
+ };
3462
+ }
3463
+
3464
+
3465
+ // --------- unique_ptr.ipp ---------
3466
+ #include <memory>
3467
+
3468
+ namespace Rice::detail
3469
+ {
3470
+ template<typename T>
3471
+ inline Wrapper<std::unique_ptr<T>>::Wrapper(std::unique_ptr<T>&& data)
3472
+ : data_(std::move(data))
3473
+ {
3474
+ }
3475
+
3476
+ template<typename T>
3477
+ inline Wrapper<std::unique_ptr<T>>::~Wrapper()
3478
+ {
3479
+ Registries::instance.instances.remove(this->get());
3480
+ }
3481
+
3482
+ template<typename T>
3483
+ inline void* Wrapper<std::unique_ptr<T>>::get()
3484
+ {
3485
+ return (void*)this->data_.get();
3486
+ }
3487
+
3488
+ template<typename T>
3489
+ inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
3490
+ {
3491
+ return data_;
3492
+ }
3493
+
3494
+ template <typename T>
3495
+ class To_Ruby<std::unique_ptr<T>>
3496
+ {
3497
+ public:
3498
+ To_Ruby() = default;
3499
+
3500
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
3501
+ {
3502
+ }
3503
+
3504
+ VALUE convert(std::unique_ptr<T>& data)
3505
+ {
3506
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3507
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3508
+ }
3509
+
3510
+ VALUE convert(std::unique_ptr<T>&& data)
3511
+ {
3512
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3513
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3514
+ }
3515
+
3516
+ private:
3517
+ Return* returnInfo_ = nullptr;
3518
+ };
3519
+
3520
+ template <typename T>
3521
+ class To_Ruby<std::unique_ptr<T>&>
3522
+ {
3523
+ public:
3524
+ To_Ruby() = default;
3525
+
3526
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
3527
+ {
3528
+ }
3529
+
3530
+ VALUE convert(std::unique_ptr<T>& data)
3531
+ {
3532
+ std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
3533
+ return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
3534
+ }
3535
+
3536
+ private:
3537
+ Return* returnInfo_ = nullptr;
3538
+ };
3539
+
3540
+ template <typename T>
3541
+ class From_Ruby<std::unique_ptr<T>>
3542
+ {
3543
+ public:
3544
+ Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3545
+ {
3546
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3547
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3548
+ }
3549
+
3550
+ From_Ruby() = default;
3551
+
3552
+ explicit From_Ruby(Arg* arg)
3553
+ {
3554
+ }
3555
+
3556
+ Convertible is_convertible(VALUE value)
3557
+ {
3558
+ if (!is_same_smart_ptr(value))
3559
+ return Convertible::None;
3560
+
3561
+ switch (rb_type(value))
3562
+ {
3563
+ case RUBY_T_DATA:
3564
+ return Convertible::Exact;
3565
+ break;
3566
+ default:
3567
+ return Convertible::None;
3568
+ }
3569
+ }
3570
+
3571
+ std::unique_ptr<T> convert(VALUE value)
3572
+ {
3573
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3574
+ if (!wrapper)
3575
+ {
3576
+ std::string message = "Invalid smart pointer wrapper";
3577
+ throw std::runtime_error(message.c_str());
3578
+ }
3579
+ return std::move(wrapper->data());
3580
+ }
3581
+ };
3582
+
3583
+ template <typename T>
3584
+ class From_Ruby<std::unique_ptr<T>&>
3585
+ {
3586
+ public:
3587
+ Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
3588
+ {
3589
+ WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
3590
+ return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
3591
+ }
3592
+
3593
+ From_Ruby() = default;
3594
+
3595
+ explicit From_Ruby(Arg* arg)
3596
+ {
3597
+ }
3598
+
3599
+ Convertible is_convertible(VALUE value)
3600
+ {
3601
+ if (!is_same_smart_ptr(value))
3602
+ return Convertible::None;
3603
+
3604
+ switch (rb_type(value))
3605
+ {
3606
+ case RUBY_T_DATA:
3607
+ return Convertible::Exact;
3608
+ break;
3609
+ default:
3610
+ return Convertible::None;
3611
+ }
3612
+ }
3613
+
3614
+ std::unique_ptr<T>& convert(VALUE value)
3615
+ {
3616
+ Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
3617
+ if (!wrapper)
3618
+ {
3619
+ std::string message = "Invalid smart pointer wrapper";
3620
+ throw std::runtime_error(message.c_str());
3621
+ }
3622
+ return wrapper->data();
3623
+ }
3624
+ };
3625
+
3626
+ template<typename T>
3627
+ struct Type<std::unique_ptr<T>>
3628
+ {
3629
+ static bool verify()
3630
+ {
3631
+ if constexpr (std::is_fundamental_v<T>)
3632
+ {
3633
+ return Type<Pointer<T>>::verify();
3634
+ return Type<Buffer<T>>::verify();
3635
+ }
3636
+ else
3637
+ {
3638
+ return Type<T>::verify();
3639
+ }
3640
+ }
3641
+
3642
+ static VALUE rubyKlass()
3643
+ {
3644
+ TypeMapper<T> typeMapper;
3645
+ return typeMapper.rubyKlass();
3646
+ }
3647
+ };
3648
+ }
3649
+
3650
+
3651
+ // ========= unordered_map.hpp =========
3652
+
3653
+ namespace Rice
3654
+ {
3655
+ template<typename Key, typename T>
3656
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string name = "");
3657
+ }
3658
+
3659
+
3660
+ // --------- unordered_map.ipp ---------
3661
+ #include <unordered_map>
3662
+
3663
+ namespace Rice
3664
+ {
3665
+ namespace stl
3666
+ {
3667
+ template<typename T>
3668
+ class UnorderedMapHelper
3669
+ {
3670
+ using Key_T = typename T::key_type;
3671
+ using Mapped_T = typename T::mapped_type;
3672
+ using Value_T = typename T::value_type;
3673
+ using Reference_T = typename T::reference;
3674
+ using Size_T = typename T::size_type;
3675
+ using Difference_T = typename T::difference_type;
3676
+ using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
3677
+
3678
+ public:
3679
+ UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
3680
+ {
3681
+ this->register_pair();
3682
+ this->define_constructors();
3683
+ this->define_capacity_methods();
3684
+ this->define_access_methods();
3685
+ this->define_comparable_methods();
3686
+ this->define_modify_methods();
3687
+ this->define_enumerable();
3688
+ this->define_to_s();
3689
+ this->define_to_hash();
3690
+ }
3691
+
3692
+ private:
3693
+
3694
+ void register_pair()
3695
+ {
3696
+ define_pair<const Key_T, T>();
3697
+ }
3698
+
3699
+ void define_constructors()
3700
+ {
3701
+ klass_.define_constructor(Constructor<T>());
3702
+
3703
+ if constexpr (std::is_copy_constructible_v<Key_T> && std::is_copy_constructible_v<Value_T>)
3704
+ {
3705
+ klass_.define_constructor(Constructor<T, const T&>());
3706
+ }
3707
+ }
3708
+
3709
+ void define_capacity_methods()
3710
+ {
3711
+ klass_.define_method("empty?", &T::empty)
3712
+ .define_method("max_size", &T::max_size)
3713
+ .define_method("size", &T::size);
3714
+
3715
+ rb_define_alias(klass_, "count", "size");
3716
+ rb_define_alias(klass_, "length", "size");
3717
+ }
3718
+
3719
+ void define_access_methods()
3720
+ {
3721
+ // Access methods
3722
+ klass_.define_method("[]", [](const T& unordered_map, const Key_T& key) -> std::optional<Mapped_T>
3723
+ {
3724
+ auto iter = unordered_map.find(key);
3725
+
3726
+ if (iter != unordered_map.end())
3727
+ {
3728
+ return iter->second;
3729
+ }
3730
+ else
3731
+ {
3732
+ return std::nullopt;
3733
+ }
3734
+ })
3735
+ .define_method("include?", [](T& unordered_map, Key_T& key) -> bool
3736
+ {
3737
+ return unordered_map.find(key) != unordered_map.end();
3738
+ })
3739
+ .define_method("keys", [](T& unordered_map) -> std::vector<Key_T>
3740
+ {
3741
+ std::vector<Key_T> result;
3742
+ std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
3743
+ [](const auto& pair)
3744
+ {
3745
+ return pair.first;
3746
+ });
3747
+
3748
+ return result;
3749
+ })
3750
+ .define_method("values", [](T& unordered_map) -> std::vector<Mapped_T>
3751
+ {
3752
+ std::vector<Mapped_T> result;
3753
+ std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
3754
+ [](const auto& pair)
3755
+ {
3756
+ return pair.second;
3757
+ });
3758
+
3759
+ return result;
3760
+ });
3761
+
3762
+ rb_define_alias(klass_, "has_key", "include?");
3763
+ }
3764
+
3765
+ // Methods that require Value_T to support operator==
3766
+ void define_comparable_methods()
3767
+ {
3768
+ if constexpr (detail::is_comparable_v<Mapped_T>)
3769
+ {
3770
+ klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
3771
+ {
3772
+ auto it = std::find_if(unordered_map.begin(), unordered_map.end(),
3773
+ [&value](auto& pair)
3774
+ {
3775
+ return pair.second == value;
3776
+ });
3777
+
3778
+ return it != unordered_map.end();
3779
+ });
3780
+ }
3781
+ else
3782
+ {
3783
+ klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
3784
+ {
3785
+ return false;
3786
+ });
3787
+ }
3788
+
3789
+ rb_define_alias(klass_, "has_value", "value?");
3790
+ }
3791
+
3792
+ void define_modify_methods()
3793
+ {
3794
+ klass_.define_method("clear", &T::clear)
3795
+ .define_method("delete", [](T& unordered_map, Key_T& key) -> std::optional<Mapped_T>
3796
+ {
3797
+ auto iter = unordered_map.find(key);
3798
+
3799
+ if (iter != unordered_map.end())
3800
+ {
3801
+ Mapped_T result = iter->second;
3802
+ unordered_map.erase(iter);
3803
+ return result;
3804
+ }
3805
+ else
3806
+ {
3807
+ return std::nullopt;
3808
+ }
3809
+ })
3810
+ .define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T& value) -> Mapped_T
3811
+ {
3812
+ unordered_map[key] = value;
3813
+ return value;
3814
+ });
3815
+
3816
+ rb_define_alias(klass_, "store", "[]=");
3817
+ }
3818
+
3819
+ void define_enumerable()
3820
+ {
3821
+ // Add enumerable support
3822
+ klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
3823
+ }
3824
+
3825
+ void define_to_hash()
3826
+ {
3827
+ // Add enumerable support
3828
+ klass_.define_method("to_h", [](T& unordered_map)
3829
+ {
3830
+ VALUE result = rb_hash_new();
3831
+ std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const Reference_T& pair)
3832
+ {
3833
+ VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
3834
+ VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
3835
+ rb_hash_aset(result, key, value);
3836
+ });
3837
+
3838
+ return result;
3839
+ }, Return().setValue());
3840
+ }
3841
+
3842
+ void define_to_s()
3843
+ {
3844
+ if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
3845
+ {
3846
+ klass_.define_method("to_s", [](const T& unordered_map)
3847
+ {
3848
+ auto iter = unordered_map.begin();
3849
+
3850
+ std::stringstream stream;
3851
+ stream << "{";
3852
+
3853
+ for (; iter != unordered_map.end(); iter++)
3854
+ {
3855
+ if (iter != unordered_map.begin())
3856
+ {
3857
+ stream << ", ";
3858
+ }
3859
+ stream << iter->first << " => " << iter->second;
3860
+ }
3861
+
3862
+ stream << "}";
3863
+ return stream.str();
3864
+ });
3865
+ }
3866
+ else
3867
+ {
3868
+ klass_.define_method("to_s", [](const T& unordered_map)
3869
+ {
3870
+ return "[Not printable]";
3871
+ });
3872
+ }
3873
+ }
3874
+
3875
+ private:
3876
+ Data_Type<T> klass_;
3877
+ };
3878
+ } // namespace
3879
+
3880
+ template<typename Key, typename T>
3881
+ Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string klassName)
3882
+ {
3883
+ using UnorderedMap_T = std::unordered_map<Key, T>;
3884
+ using Data_Type_T = Data_Type<UnorderedMap_T>;
3885
+
3886
+ if (klassName.empty())
3887
+ {
3888
+ detail::TypeMapper<UnorderedMap_T> typeMapper;
3889
+ klassName = typeMapper.rubyName();
3890
+ }
3891
+
3892
+ Module rb_mStd = define_module("Std");
3893
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
3894
+ {
3895
+ return Data_Type_T();
3896
+ }
3897
+
3898
+ Identifier id(klassName);
3899
+ Data_Type_T result = define_class_under<detail::intrinsic_type<UnorderedMap_T>>(rb_mStd, id);
3900
+ stl::UnorderedMapHelper helper(result);
3901
+ return result;
3902
+ }
3903
+
3904
+ namespace detail
3905
+ {
3906
+ template<typename Key_T, typename T>
3907
+ struct Type<std::unordered_map<Key_T, T>>
3908
+ {
3909
+ static bool verify()
3910
+ {
3911
+ Type<Key_T>::verify();
3912
+ Type<T>::verify();
3913
+
3914
+ if (!Data_Type<std::unordered_map<Key_T, T>>::is_defined())
3915
+ {
3916
+ define_unordered_map<Key_T, T>();
3917
+ }
3918
+
3919
+ return true;
3920
+ }
3921
+ };
3922
+
3923
+ template<typename T, typename U>
3924
+ struct UnorderedMapFromHash
3925
+ {
3926
+ static int convertPair(VALUE key, VALUE value, VALUE user_data)
3927
+ {
3928
+ std::unordered_map<T, U>* result = (std::unordered_map<T, U>*)(user_data);
3929
+
3930
+ // This method is being called from Ruby so we cannot let any C++
3931
+ // exceptions propogate back to Ruby
3932
+ return cpp_protect([&]
3933
+ {
3934
+ result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
3935
+ return ST_CONTINUE;
3936
+ });
3937
+ }
3938
+
3939
+ static std::unordered_map<T, U> convert(VALUE value)
3940
+ {
3941
+ std::unordered_map<T, U> result;
3942
+ VALUE user_data = (VALUE)(&result);
3943
+
3944
+ // MSVC needs help here, but g++ does not
3945
+ using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
3946
+ detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
3947
+
3948
+ return result;
3949
+ }
3950
+ };
3951
+
3952
+ template<typename T, typename U>
3953
+ class From_Ruby<std::unordered_map<T, U>>
3954
+ {
3955
+ public:
3956
+ From_Ruby() = default;
3957
+
3958
+ explicit From_Ruby(Arg * arg) : arg_(arg)
3959
+ {
3960
+ }
3961
+
3962
+ Convertible is_convertible(VALUE value)
3963
+ {
3964
+ switch (rb_type(value))
3965
+ {
3966
+ case RUBY_T_DATA:
3967
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
3968
+ break;
3969
+ case RUBY_T_HASH:
3970
+ return Convertible::Cast;
3971
+ break;
3972
+ default:
3973
+ return Convertible::None;
3974
+ }
3975
+ }
3976
+
3977
+ std::unordered_map<T, U> convert(VALUE value)
3978
+ {
3979
+ switch (rb_type(value))
3980
+ {
3981
+ case RUBY_T_DATA:
3982
+ {
3983
+ // This is a wrapped unordered_map (hopefully!)
3984
+ return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
3985
+ }
3986
+ case RUBY_T_HASH:
3987
+ {
3988
+ // If this an Ruby hash and the unordered_mapped type is copyable
3989
+ if constexpr (std::is_default_constructible_v<U>)
3990
+ {
3991
+ return UnorderedMapFromHash<T, U>::convert(value);
3992
+ }
3993
+ }
3994
+ default:
3995
+ {
3996
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
3997
+ detail::protect(rb_obj_classname, value), "std::unordered_map");
3998
+ }
3999
+ }
4000
+ }
4001
+
4002
+ private:
4003
+ Arg* arg_ = nullptr;
4004
+ };
4005
+
4006
+ template<typename T, typename U>
4007
+ class From_Ruby<std::unordered_map<T, U>&>
4008
+ {
4009
+ public:
4010
+ From_Ruby() = default;
4011
+
4012
+ explicit From_Ruby(Arg * arg) : arg_(arg)
4013
+ {
4014
+ }
4015
+
4016
+ Convertible is_convertible(VALUE value)
4017
+ {
4018
+ switch (rb_type(value))
4019
+ {
4020
+ case RUBY_T_DATA:
4021
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4022
+ break;
4023
+ case RUBY_T_HASH:
4024
+ return Convertible::Cast;
4025
+ break;
4026
+ default:
4027
+ return Convertible::None;
4028
+ }
4029
+ }
4030
+
4031
+ std::unordered_map<T, U>& convert(VALUE value)
4032
+ {
4033
+ switch (rb_type(value))
4034
+ {
4035
+ case RUBY_T_DATA:
4036
+ {
4037
+ // This is a wrapped unordered_map (hopefully!)
4038
+ return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
4039
+ }
4040
+ case RUBY_T_HASH:
4041
+ {
4042
+ // If this an Ruby array and the unordered_map type is copyable
4043
+ if constexpr (std::is_default_constructible_v<std::unordered_map<T, U>>)
4044
+ {
4045
+ this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
4046
+ return this->converted_;
4047
+ }
4048
+ }
4049
+ default:
4050
+ {
4051
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
4052
+ detail::protect(rb_obj_classname, value), "std::unordered_map");
4053
+ }
4054
+ }
4055
+ }
4056
+
4057
+ private:
4058
+ Arg* arg_ = nullptr;
4059
+ std::unordered_map<T, U> converted_;
4060
+ };
4061
+
4062
+ template<typename T, typename U>
4063
+ class From_Ruby<std::unordered_map<T, U>*>
4064
+ {
4065
+ public:
4066
+ From_Ruby() = default;
4067
+
4068
+ explicit From_Ruby(Arg* arg) : arg_(arg)
4069
+ {
4070
+ }
4071
+
4072
+ Convertible is_convertible(VALUE value)
4073
+ {
4074
+ switch (rb_type(value))
4075
+ {
4076
+ case RUBY_T_DATA:
4077
+ return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4078
+ break;
4079
+ case RUBY_T_NIL:
4080
+ return Convertible::Exact;
4081
+ break;
4082
+ case RUBY_T_HASH:
4083
+ return Convertible::Cast;
4084
+ break;
4085
+ default:
4086
+ return Convertible::None;
4087
+ }
4088
+ }
4089
+
4090
+ std::unordered_map<T, U>* convert(VALUE value)
4091
+ {
4092
+ switch (rb_type(value))
4093
+ {
4094
+ case RUBY_T_DATA:
4095
+ {
4096
+ // This is a wrapped unordered_map (hopefully!)
4097
+ return detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
4098
+ }
4099
+ case RUBY_T_HASH:
4100
+ {
4101
+ // If this an Ruby array and the unordered_map type is copyable
4102
+ if constexpr (std::is_default_constructible_v<U>)
4103
+ {
4104
+ this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
4105
+ return &this->converted_;
4106
+ }
4107
+ }
4108
+ default:
4109
+ {
4110
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
4111
+ detail::protect(rb_obj_classname, value), "std::unordered_map");
4112
+ }
4113
+ }
4114
+ }
4115
+
4116
+ private:
4117
+ Arg* arg_;
4118
+ std::unordered_map<T, U> converted_;
4119
+ };
4120
+ }
4121
+ }
4122
+
4123
+ // ========= vector.hpp =========
4124
+
4125
+ namespace Rice
4126
+ {
4127
+ template<typename T>
4128
+ Data_Type<std::vector<T>> define_vector(std::string name = "" );
4129
+ }
4130
+
4131
+
4132
+ // --------- vector.ipp ---------
4133
+ #include <vector>
4134
+
4135
+ namespace Rice
4136
+ {
4137
+ namespace stl
4138
+ {
4139
+ template<typename T>
4140
+ class VectorHelper
4141
+ {
4142
+ // We do NOT use Reference_T and instead use Parameter_T to avoid the weirdness
4143
+ // of std::vector<bool>. Reference_T is actually a proxy class that we do not
4144
+ // want to have to register with Rice nor do we want to pass it around.
4145
+ using Value_T = typename T::value_type;
4146
+ using Size_T = typename T::size_type;
4147
+ using Difference_T = typename T::difference_type;
4148
+ // For To_Ruby_T however we do need to use reference type because this is what
4149
+ // will be passed by an interator to To_Ruby#convert
4150
+ using Reference_T = typename T::reference;
4151
+ using Parameter_T = std::conditional_t<std::is_pointer_v<Value_T>, Value_T, Value_T&>;
4152
+ using To_Ruby_T = detail::remove_cv_recursive_t<typename T::reference>;
4153
+
4154
+ public:
4155
+ VectorHelper(Data_Type<T> klass) : klass_(klass)
4156
+ {
4157
+ this->define_constructors();
4158
+ this->define_constructable_methods();
4159
+ this->define_capacity_methods();
4160
+ this->define_access_methods();
4161
+ this->define_comparable_methods();
4162
+ this->define_modify_methods();
4163
+ this->define_enumerable();
4164
+ this->define_to_array();
4165
+ this->define_to_s();
4166
+ }
4167
+
4168
+ private:
4169
+
4170
+ // Helper method to translate Ruby indices to vector indices
4171
+ Difference_T normalizeIndex(Size_T size, Difference_T index, bool enforceBounds = false)
4172
+ {
4173
+ // Negative indices mean count from the right
4174
+ if (index < 0 && (-index <= size))
4175
+ {
4176
+ index = size + index;
4177
+ }
4178
+
4179
+ if (enforceBounds && (index < 0 || index >= (Difference_T)size))
4180
+ {
4181
+ throw std::out_of_range("Invalid index: " + std::to_string(index));
4182
+ }
4183
+
4184
+ return index;
4185
+ };
4186
+
4187
+ void define_constructors()
4188
+ {
4189
+ klass_.define_constructor(Constructor<T>());
4190
+
4191
+ if constexpr (std::is_copy_constructible_v<Value_T>)
4192
+ {
4193
+ klass_.define_constructor(Constructor<T, const T&>())
4194
+ .define_constructor(Constructor<T, Size_T, const Parameter_T>());
4195
+ }
4196
+
4197
+ if constexpr (std::is_default_constructible_v<Value_T>)
4198
+ {
4199
+ klass_.define_constructor(Constructor<T, Size_T>());
4200
+ }
4201
+
4202
+ // Allow creation of a vector from a Ruby Array
4203
+ klass_.define_method("initialize", [](VALUE self, Array array) -> void
4204
+ {
4205
+ // Create a new vector from the array
4206
+ T* data = new T();
4207
+ data->reserve(array.size());
4208
+
4209
+ detail::From_Ruby<Value_T> fromRuby;
4210
+
4211
+ for (long i = 0; i < array.size(); i++)
4212
+ {
4213
+ VALUE element = detail::protect(rb_ary_entry, array, i);
4214
+ data->push_back(fromRuby.convert(element));
4215
+ }
4216
+
4217
+ // Wrap the vector
4218
+ detail::wrapConstructed<T>(self, Data_Type<T>::ruby_data_type(), data, true);
4219
+ });
4220
+ }
4221
+
4222
+ void define_constructable_methods()
4223
+ {
4224
+ if constexpr (std::is_default_constructible_v<Value_T> && std::is_same_v<Value_T, bool>)
4225
+ {
4226
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t, bool)>(&T::resize));
4227
+ }
4228
+ else if constexpr (std::is_default_constructible_v<Value_T>)
4229
+ {
4230
+ klass_.define_method("resize", static_cast<void (T::*)(const size_t)>(&T::resize));
4231
+ }
4232
+ else
4233
+ {
4234
+ klass_.define_method("resize", [](const T& vector, Size_T newSize)
4235
+ {
4236
+ // Do nothing
4237
+ });
4238
+ }
4239
+ }
4240
+
4241
+ void define_capacity_methods()
4242
+ {
4243
+ klass_.define_method("empty?", &T::empty)
4244
+ .define_method("capacity", &T::capacity)
4245
+ .define_method("max_size", &T::max_size)
4246
+ .define_method("reserve", &T::reserve)
4247
+ .define_method("size", &T::size);
4248
+
4249
+ rb_define_alias(klass_, "count", "size");
4250
+ rb_define_alias(klass_, "length", "size");
4251
+ //detail::protect(rb_define_alias, klass_, "count", "size");
4252
+ //detail::protect(rb_define_alias, klass_, "length", "size");
4253
+ }
4254
+
4255
+ void define_access_methods()
4256
+ {
4257
+ if constexpr (!std::is_same_v<Value_T, bool>)
4258
+ {
4259
+ // Access methods
4260
+ klass_.define_method("first", [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4261
+ {
4262
+ if (vector.size() > 0)
4263
+ {
4264
+ return vector.front();
4265
+ }
4266
+ else
4267
+ {
4268
+ return std::nullopt;
4269
+ }
4270
+ })
4271
+ .define_method("last", [](T& vector) -> std::optional<std::reference_wrapper<Value_T>>
4272
+ {
4273
+ if (vector.size() > 0)
4274
+ {
4275
+ return vector.back();
4276
+ }
4277
+ else
4278
+ {
4279
+ return std::nullopt;
4280
+ }
4281
+ })
4282
+ .define_method("[]", [this](T& vector, Difference_T index) -> std::optional<std::reference_wrapper<Value_T>>
4283
+ {
4284
+ index = normalizeIndex(vector.size(), index);
4285
+ if (index < 0 || index >= (Difference_T)vector.size())
4286
+ {
4287
+ return std::nullopt;
4288
+ }
4289
+ else
4290
+ {
4291
+ return vector[index];
4292
+ }
4293
+ })
4294
+ .template define_method<Value_T*(T::*)()>("data", &T::data, Return().setBuffer());
4295
+ }
4296
+ else
4297
+ {
4298
+ // Access methods
4299
+ klass_.define_method("first", [](T& vector) -> std::optional<Value_T>
4300
+ {
4301
+ if (vector.size() > 0)
4302
+ {
4303
+ return vector.front();
4304
+ }
4305
+ else
4306
+ {
4307
+ return std::nullopt;
4308
+ }
4309
+ })
4310
+ .define_method("last", [](T& vector) -> std::optional<Value_T>
4311
+ {
4312
+ if (vector.size() > 0)
4313
+ {
4314
+ return vector.back();
4315
+ }
4316
+ else
4317
+ {
4318
+ return std::nullopt;
4319
+ }
4320
+ })
4321
+ .define_method("[]", [this](T& vector, Difference_T index) -> std::optional<Value_T>
4322
+ {
4323
+ index = normalizeIndex(vector.size(), index);
4324
+ if (index < 0 || index >= (Difference_T)vector.size())
4325
+ {
4326
+ return std::nullopt;
4327
+ }
4328
+ else
4329
+ {
4330
+ return vector[index];
4331
+ }
4332
+ });
4333
+ }
4334
+
4335
+ klass_.define_method("[]", [this](T& vector, Difference_T start, Difference_T length) -> VALUE
4336
+ {
4337
+ start = normalizeIndex(vector.size(), start);
4338
+ if (start < 0 || start >= (Difference_T)vector.size())
4339
+ {
4340
+ return rb_ary_new();
4341
+ }
4342
+ else
4343
+ {
4344
+ auto begin = vector.begin() + start;
4345
+
4346
+ // Ruby does not throw an exception when the length is too long
4347
+ Difference_T size = (Difference_T)vector.size();
4348
+ if (start + length > size)
4349
+ {
4350
+ length = size - start;
4351
+ }
4352
+
4353
+ auto finish = vector.begin() + start + length;
4354
+
4355
+ VALUE result = rb_ary_new();
4356
+ for (auto iter = begin; iter != finish; iter++)
4357
+ {
4358
+ const Reference_T element = *iter;
4359
+ VALUE value = detail::To_Ruby<Reference_T>().convert(element);
4360
+ rb_ary_push(result, value);
4361
+ }
4362
+
4363
+ return result;
4364
+ }
4365
+ }, Return().setValue());
4366
+
4367
+ rb_define_alias(klass_, "at", "[]");
4368
+ }
4369
+
4370
+ // Methods that require Value_T to support operator==
4371
+ void define_comparable_methods()
4372
+ {
4373
+ if constexpr (detail::is_comparable_v<T>)
4374
+ {
4375
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
4376
+ {
4377
+ auto iter = std::find(vector.begin(), vector.end(), element);
4378
+ if (iter == vector.end())
4379
+ {
4380
+ return std::nullopt;
4381
+ }
4382
+ else if constexpr (std::is_copy_assignable_v<Value_T>)
4383
+ {
4384
+ Value_T result = *iter;
4385
+ vector.erase(iter);
4386
+ return result;
4387
+ }
4388
+ else
4389
+ {
4390
+ return std::nullopt;
4391
+ }
4392
+ })
4393
+ .define_method("include?", [](T& vector, Parameter_T element)
4394
+ {
4395
+ return std::find(vector.begin(), vector.end(), element) != vector.end();
4396
+ })
4397
+ .define_method("index", [](T& vector, Parameter_T element) -> std::optional<Difference_T>
4398
+ {
4399
+ auto iter = std::find(vector.begin(), vector.end(), element);
4400
+ if (iter == vector.end())
4401
+ {
4402
+ return std::nullopt;
4403
+ }
4404
+ else
4405
+ {
4406
+ return iter - vector.begin();
4407
+ }
4408
+ });
4409
+ }
4410
+ else
4411
+ {
4412
+ klass_.define_method("delete", [](T& vector, Parameter_T element) -> std::optional<Value_T>
4413
+ {
4414
+ return std::nullopt;
4415
+ })
4416
+ .define_method("include?", [](const T& vector, Parameter_T element)
4417
+ {
4418
+ return false;
4419
+ })
4420
+ .define_method("index", [](const T& vector, Parameter_T element) -> std::optional<Difference_T>
4421
+ {
4422
+ return std::nullopt;
4423
+ });
4424
+ }
4425
+ }
4426
+
4427
+ void define_modify_methods()
4428
+ {
4429
+ klass_.define_method("clear", &T::clear)
4430
+ .define_method("delete_at", [](T& vector, const size_t& pos) -> std::optional<Value_T>
4431
+ {
4432
+ auto iter = vector.begin() + pos;
4433
+
4434
+ if constexpr (std::is_copy_assignable_v<Value_T>)
4435
+ {
4436
+ Value_T result = *iter;
4437
+ vector.erase(iter);
4438
+ return result;
4439
+ }
4440
+ else
4441
+ {
4442
+ vector.erase(iter);
4443
+ return std::nullopt;
4444
+ }
4445
+ })
4446
+ .define_method("insert", [this](T& vector, Difference_T index, Parameter_T element) -> T&
4447
+ {
4448
+ int normalized = normalizeIndex(vector.size(), index, true);
4449
+ // For a Ruby array a positive index means insert the element before the index. But
4450
+ // a negative index means insert the element *after* the index. std::vector
4451
+ // inserts *before* the index. So add 1 if this is a negative index.
4452
+ if (index < 0)
4453
+ {
4454
+ normalized++;
4455
+ }
4456
+ auto iter = vector.begin() + normalized;
4457
+ vector.insert(iter, std::move(element));
4458
+ return vector;
4459
+ })
4460
+ .define_method("pop", [](T& vector) -> std::optional<Value_T>
4461
+ {
4462
+ if constexpr (!std::is_copy_assignable_v<Value_T>)
4463
+ {
4464
+ vector.pop_back();
4465
+ return std::nullopt;
4466
+ }
4467
+ else if (vector.empty())
4468
+ {
4469
+ return std::nullopt;
4470
+ }
4471
+ else
4472
+ {
4473
+ Value_T result = vector.back();
4474
+ vector.pop_back();
4475
+ return result;
4476
+ }
4477
+ })
4478
+ .define_method("push", [](T& vector, Parameter_T element) -> T&
4479
+ {
4480
+ vector.push_back(std::move(element));
4481
+ return vector;
4482
+ })
4483
+ .define_method("shrink_to_fit", &T::shrink_to_fit)
4484
+ .define_method("[]=", [this](T& vector, Difference_T index, Parameter_T element) -> void
4485
+ {
4486
+ index = normalizeIndex(vector.size(), index, true);
4487
+ vector[index] = std::move(element);
4488
+ });
4489
+
4490
+ rb_define_alias(klass_, "push_back", "push");
4491
+ rb_define_alias(klass_, "<<", "push");
4492
+ rb_define_alias(klass_, "append", "push");
4493
+ }
4494
+
4495
+ void define_enumerable()
4496
+ {
4497
+ // Add enumerable support
4498
+ klass_.template define_iterator<typename T::iterator(T::*)()>(&T::begin, &T::end);
4499
+ }
4500
+
4501
+ void define_to_array()
4502
+ {
4503
+ // Add enumerable support
4504
+ klass_.define_method("to_a", [](T& vector)
4505
+ {
4506
+ VALUE result = rb_ary_new();
4507
+ std::for_each(vector.begin(), vector.end(), [&result](const Reference_T element)
4508
+ {
4509
+ VALUE value = detail::To_Ruby<Reference_T>().convert(element);
4510
+ rb_ary_push(result, value);
4511
+ });
4512
+
4513
+ return result;
4514
+ }, Return().setValue());
4515
+ }
4516
+
4517
+ void define_to_s()
4518
+ {
4519
+ if constexpr (detail::is_ostreamable_v<Value_T>)
4520
+ {
4521
+ klass_.define_method("to_s", [](const T& vector)
4522
+ {
4523
+ auto iter = vector.begin();
4524
+ auto finish = vector.size() > 1000 ? vector.begin() + 1000 : vector.end();
4525
+
4526
+ std::stringstream stream;
4527
+ stream << "[";
4528
+
4529
+ for (; iter != finish; iter++)
4530
+ {
4531
+ if (iter == vector.begin())
4532
+ {
4533
+ stream << *iter;
4534
+ }
4535
+ else
4536
+ {
4537
+ stream << ", " << *iter;
4538
+ }
4539
+ }
4540
+
4541
+ stream << "]";
4542
+ return stream.str();
4543
+ });
4544
+ }
4545
+ else
4546
+ {
4547
+ klass_.define_method("to_s", [](const T& vector)
4548
+ {
4549
+ return "[Not printable]";
4550
+ });
4551
+ }
4552
+ }
4553
+
4554
+ private:
4555
+ Data_Type<T> klass_;
4556
+ };
4557
+ } // namespace
4558
+
4559
+ template<typename T>
4560
+ Data_Type<std::vector<T>> define_vector(std::string klassName)
4561
+ {
4562
+ using Vector_T = std::vector<T>;
4563
+ using Data_Type_T = Data_Type<Vector_T>;
4564
+
4565
+ if (klassName.empty())
4566
+ {
4567
+ detail::TypeMapper<Vector_T> typeMapper;
4568
+ klassName = typeMapper.rubyName();
4569
+ }
4570
+
4571
+ Module rb_mStd = define_module("Std");
4572
+ if (Data_Type_T::check_defined(klassName, rb_mStd))
4573
+ {
4574
+ return Data_Type_T();
4575
+ }
4576
+
4577
+ Identifier id(klassName);
4578
+ Data_Type_T result = define_class_under<detail::intrinsic_type<Vector_T>>(rb_mStd, id);
4579
+ stl::VectorHelper helper(result);
4580
+ return result;
4581
+ }
4582
+
4583
+
4584
+ namespace detail
4585
+ {
4586
+ template<typename T>
4587
+ struct Type<std::vector<T>>
4588
+ {
4589
+ static bool verify()
4590
+ {
4591
+ Type<intrinsic_type<T>>::verify();
4592
+
4593
+ if (!Data_Type<std::vector<T>>::is_defined())
4594
+ {
4595
+ define_vector<T>();
4596
+ }
4597
+
4598
+ return true;
4599
+ }
4600
+ };
4601
+
4602
+ template<typename T>
4603
+ class From_Ruby<std::vector<T>>
4604
+ {
4605
+ public:
4606
+ From_Ruby() = default;
4607
+
4608
+ explicit From_Ruby(Arg * arg) : arg_(arg)
4609
+ {
4610
+ }
4611
+
4612
+ Convertible is_convertible(VALUE value)
4613
+ {
4614
+ switch (rb_type(value))
4615
+ {
4616
+ case RUBY_T_DATA:
4617
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4618
+ break;
4619
+ case RUBY_T_ARRAY:
4620
+ if constexpr (std::is_default_constructible_v<T>)
4621
+ {
4622
+ return Convertible::Cast;
4623
+ }
4624
+ default:
4625
+ return Convertible::None;
4626
+ }
4627
+ }
4628
+
4629
+ std::vector<T> convert(VALUE value)
4630
+ {
4631
+ switch (rb_type(value))
4632
+ {
4633
+ case RUBY_T_DATA:
4634
+ {
4635
+ // This is a wrapped vector (hopefully!)
4636
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
4637
+ }
4638
+ case RUBY_T_ARRAY:
4639
+ {
4640
+ // If this an Ruby array and the vector type is copyable
4641
+ if constexpr (std::is_default_constructible_v<T>)
4642
+ {
4643
+ return Array(value).to_vector<T>();
4644
+ }
4645
+ }
4646
+ default:
4647
+ {
4648
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
4649
+ detail::protect(rb_obj_classname, value), "std::vector");
4650
+ }
4651
+ }
4652
+ }
4653
+
4654
+ private:
4655
+ Arg* arg_ = nullptr;
4656
+ };
4657
+
4658
+ template<typename T>
4659
+ class From_Ruby<std::vector<T>&>
4660
+ {
4661
+ public:
4662
+ From_Ruby() = default;
4663
+
4664
+ explicit From_Ruby(Arg * arg) : arg_(arg)
4665
+ {
4666
+ }
4667
+
4668
+ Convertible is_convertible(VALUE value)
4669
+ {
4670
+ switch (rb_type(value))
4671
+ {
4672
+ case RUBY_T_DATA:
4673
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4674
+ break;
4675
+ case RUBY_T_ARRAY:
4676
+ if constexpr (std::is_default_constructible_v<T>)
4677
+ {
4678
+ return Convertible::Cast;
4679
+ }
4680
+ default:
4681
+ return Convertible::None;
4682
+ }
4683
+ }
4684
+
4685
+ std::vector<T>& convert(VALUE value)
4686
+ {
4687
+ switch (rb_type(value))
4688
+ {
4689
+ case RUBY_T_DATA:
4690
+ {
4691
+ // This is a wrapped vector (hopefully!)
4692
+ return *detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
4693
+ }
4694
+ case RUBY_T_ARRAY:
4695
+ {
4696
+ // If this an Ruby array and the vector type is copyable
4697
+ if constexpr (std::is_default_constructible_v<T>)
4698
+ {
4699
+ this->converted_ = Array(value).to_vector<T>();
4700
+ return this->converted_;
4701
+ }
4702
+ }
4703
+ default:
4704
+ {
4705
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
4706
+ detail::protect(rb_obj_classname, value), "std::vector");
4707
+ }
4708
+ }
4709
+ }
4710
+
4711
+ private:
4712
+ Arg* arg_ = nullptr;
4713
+ std::vector<T> converted_;
4714
+ };
4715
+
4716
+ template<typename T>
4717
+ class From_Ruby<std::vector<T>*>
4718
+ {
4719
+ public:
4720
+ From_Ruby() = default;
4721
+
4722
+ explicit From_Ruby(Arg* arg) : arg_(arg)
4723
+ {
4724
+ }
4725
+
4726
+ Convertible is_convertible(VALUE value)
4727
+ {
4728
+ switch (rb_type(value))
4729
+ {
4730
+ case RUBY_T_DATA:
4731
+ return Data_Type<std::vector<T>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
4732
+ break;
4733
+ case RUBY_T_NIL:
4734
+ return Convertible::Exact;
4735
+ break;
4736
+ case RUBY_T_ARRAY:
4737
+ if constexpr (std::is_default_constructible_v<T>)
4738
+ {
4739
+ return Convertible::Cast;
4740
+ }
4741
+ default:
4742
+ return Convertible::None;
4743
+ }
4744
+ }
4745
+
4746
+ std::vector<T>* convert(VALUE value)
4747
+ {
4748
+ switch (rb_type(value))
4749
+ {
4750
+ case RUBY_T_DATA:
4751
+ {
4752
+ // This is a wrapped vector (hopefully!)
4753
+ return detail::unwrap<std::vector<T>>(value, Data_Type<std::vector<T>>::ruby_data_type(), false);
4754
+ }
4755
+ case RUBY_T_ARRAY:
4756
+ {
4757
+ // If this a Ruby array and the vector type is copyable
4758
+ if constexpr (std::is_default_constructible_v<T>)
4759
+ {
4760
+ this->converted_ = Array(value).to_vector<T>();
4761
+ return &this->converted_;
4762
+ }
4763
+ }
4764
+ default:
4765
+ {
4766
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
4767
+ detail::protect(rb_obj_classname, value), "std::vector");
4768
+ }
4769
+ }
4770
+ }
4771
+
4772
+ private:
4773
+ Arg* arg_;
4774
+ std::vector<T> converted_;
4775
+ };
4776
+ }
4777
+
4778
+ // Special handling for std::vector<bool>
4779
+ namespace detail
4780
+ {
4781
+ template<>
4782
+ class To_Ruby<std::vector<bool>::reference>
4783
+ {
4784
+ public:
4785
+ To_Ruby() = default;
4786
+
4787
+ explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo)
4788
+ {
4789
+ }
4790
+
4791
+ VALUE convert(const std::vector<bool>::reference& value)
4792
+ {
4793
+ return value ? Qtrue : Qfalse;
4794
+ }
4795
+
4796
+ private:
4797
+ Return* returnInfo_ = nullptr;
4798
+ };
4799
+ }
4800
+ }
4801
+
4802
+
4803
+ #endif // Rice__stl__hpp_