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.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +15 -0
- data/LICENSE +185 -0
- data/README.md +3 -0
- data/Rakefile +12 -0
- data/include/bando/common.hpp +232 -0
- data/include/bando/qobject/qdbusabstractadaptor.hpp +102 -0
- data/include/bando/qobject/qdbusabstractinterface.hpp +89 -0
- data/include/bando/qobject/qitemdelegate.hpp +138 -0
- data/include/bando/qobject/qlayout.hpp +175 -0
- data/include/bando/qobject.hpp +89 -0
- data/include/bando/qwidget/qspinbox.hpp +207 -0
- data/include/bando/qwidget.hpp +187 -0
- data/include/rice/qt6/qdbusreply.hpp +53 -0
- data/include/rice/qt6/qenum.hpp +51 -0
- data/include/rice/qt6/qflags.hpp +58 -0
- data/include/rice/qt6/qlist.hpp +238 -0
- data/include/rice/rice.hpp +15154 -0
- data/include/rice/stl.hpp +4803 -0
- data/lib/mkmf-rice.rb +101 -0
- data/lib/mkmf-rubyqt6.rb +28 -0
- data/lib/qt6/rice/version.rb +7 -0
- data/lib/qt6/rice.rb +3 -0
- data/lib/qt6/rspec/bando_file_parser.rb +102 -0
- data/lib/qt6/rspec/qlass_file_parser.rb +255 -0
- data/lib/qt6/rspec.rb +275 -0
- metadata +68 -0
|
@@ -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_
|