Skip to content

Commit dd6b38c

Browse files
committed
Merge branch 'release-5.x' into develop
2 parents f7b52f6 + 1e62eb4 commit dd6b38c

8 files changed

Lines changed: 156 additions & 26 deletions

File tree

cheatsheet.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,28 @@ chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with an
163163
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
164164
```
165165

166+
### Conversion Caveats
167+
168+
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
169+
170+
```cpp
171+
// ok this is supported, you can register it with chaiscript engine
172+
void nullify_shared_ptr(std::shared_ptr<int> &t) {
173+
t == nullptr
174+
}
175+
```
176+
177+
```cpp
178+
int main()
179+
{
180+
// do some stuff and create a chaiscript instance
181+
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
182+
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
183+
// supported and causes undefined behavior in the chaiscript engine
184+
}
185+
```
186+
187+
166188
## Sharing Values
167189

168190
```

include/chaiscript/dispatchkit/boxed_cast_helper.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,21 @@ namespace chaiscript
173173
{
174174
};
175175

176+
template<typename Result>
177+
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
178+
{
179+
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
180+
181+
typedef Boxed_Value::Sentinel<Result> Result_Type;
182+
183+
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
184+
{
185+
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
186+
return ob.pointer_sentinel(res);
187+
}
188+
};
189+
190+
176191
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
177192
template<typename Result>
178193
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >

include/chaiscript/dispatchkit/boxed_value.hpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,50 @@ namespace chaiscript
226226
return m_data->m_type_info.bare_equal(ti);
227227
}
228228

229+
template<typename T>
230+
struct Sentinel {
231+
Sentinel(std::shared_ptr<T> &ptr, Data &data)
232+
: m_ptr(ptr), m_data(data)
233+
{
234+
}
235+
236+
~Sentinel()
237+
{
238+
// save new pointer data
239+
m_data.get().m_data_ptr = m_ptr.get().get();
240+
m_data.get().m_const_data_ptr = m_ptr.get().get();
241+
}
242+
243+
Sentinel& operator=(Sentinel&&s) {
244+
m_ptr = std::move(s.m_ptr);
245+
m_data = std::move(s.m_data);
246+
}
247+
248+
Sentinel(Sentinel &&s)
249+
: m_ptr(std::move(s.m_ptr)),
250+
m_data(std::move(s.m_data))
251+
{
252+
}
253+
254+
operator std::shared_ptr<T>&() const
255+
{
256+
return m_ptr.get();
257+
}
258+
259+
Sentinel &operator=(const Sentinel &) = delete;
260+
Sentinel(Sentinel&) = delete;
261+
262+
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
263+
std::reference_wrapper<Data> m_data;
264+
};
265+
266+
267+
template<typename T>
268+
Sentinel<T> pointer_sentinel(std::shared_ptr<T> &ptr) const
269+
{
270+
return Sentinel<T>(ptr, *(m_data.get()));
271+
}
272+
229273
bool is_null() const noexcept
230274
{
231275
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);

include/chaiscript/dispatchkit/type_info.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ namespace chaiscript
150150
}
151151
};
152152

153+
template<typename T>
154+
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
155+
{
156+
};
157+
153158
template<typename T>
154159
struct Get_Type_Info<const std::shared_ptr<T> &>
155160
{

releasenotes.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Notes:
22
=======
3-
Current Version: 5.8.1
3+
Current Version: 5.8.2
4+
5+
### Changes since 5.8.1
6+
* Allow casting to non-const & std::shared_ptr<T>
7+
48

59
### Changes since 5.8.0
610
* Fix parsing of floats to be locale independent #250

src/test_module.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ std::shared_ptr<TestBaseType> null_factory()
111111
return std::shared_ptr<TestBaseType>();
112112
}
113113

114+
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
115+
{
116+
ptr = std::make_shared<TestDerivedType>();
117+
}
118+
119+
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
120+
{
121+
ptr = nullptr;
122+
}
123+
114124
std::string hello_world()
115125
{
116126
return "Hello World";
@@ -202,6 +212,10 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
202212
m->add(chaiscript::type_conversion<const char *, std::string>());
203213
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
204214

215+
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
216+
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
217+
218+
205219
return m;
206220
}
207221

unittests/boxed_cast_test.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,13 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
5454
}
5555

5656
template<typename Type>
57-
bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, bool ConstTPtr, bool TPtrConst,
58-
bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
59-
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
60-
bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef,
61-
bool ConstWrappedRefRef, bool ConstWrappedConstRefRef, bool Number,
62-
bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, bool ConstTPtrConstRef)
57+
bool do_test(const Boxed_Value &bv,
58+
bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr,
59+
bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
60+
bool SharedPtrTRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
61+
bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef, bool ConstWrappedRefRef,
62+
bool ConstWrappedConstRefRef, bool Number, bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef,
63+
bool ConstTPtrConstRef)
6364
{
6465
bool passed = true;
6566
passed &= test_type_conversion<Type>(bv, T);
@@ -72,8 +73,8 @@ bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTR
7273
passed &= test_type_conversion<const Type * const>(bv, ConstTPtrConst);
7374
passed &= test_type_conversion<std::shared_ptr<Type> >(bv, SharedPtrT);
7475
passed &= test_type_conversion<std::shared_ptr<const Type> >(bv, SharedConstPtrT);
75-
passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, false);
76-
passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false);
76+
passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, SharedPtrTRef);
77+
//passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false);
7778
passed &= test_type_conversion<const std::shared_ptr<Type> >(bv, ConstSharedPtrT);
7879
passed &= test_type_conversion<const std::shared_ptr<const Type> >(bv, ConstSharedConstPtrT);
7980
passed &= test_type_conversion<const std::shared_ptr<Type> &>(bv, ConstSharedPtrTRef);
@@ -115,37 +116,37 @@ bool built_in_type_test(const T &initial, bool ispod)
115116
T i = T(initial);
116117
passed &= do_test<T>(var(i), true, true, true, true, true,
117118
true, true, true, true, true,
118-
true, true, true, true, true,
119+
true, true, true, true, true, true,
119120
true, true, true, true, true,
120121
ispod, ispod, ispod, true, true);
121122

122123
passed &= do_test<T>(const_var(i), true, true, false, true, false,
123124
true, false, true, false, true,
124-
false, true, false, true, false,
125+
false, false, true, false, true, false,
125126
true, false, true, false, true,
126127
ispod, ispod, ispod, false, true);
127128

128129
passed &= do_test<T>(var(&i), true, true, true, true, true,
129130
true, true, true, false, false,
130-
false, false, false, false, true,
131+
false, false, false, false, false, true,
131132
true, true, true, true, true,
132133
ispod, ispod, ispod, true, true);
133134

134135
passed &= do_test<T>(const_var(&i), true, true, false, true, false,
135136
true, false, true, false, false,
136-
false, false, false, false, false,
137+
false, false, false, false, false, false,
137138
true, false, true, false, true,
138139
ispod, ispod, ispod, false, true);
139140

140141
passed &= do_test<T>(var(std::ref(i)), true, true, true, true, true,
141142
true, true, true, false, false,
142-
false, false, false, false, true,
143+
false, false, false, false, false, true,
143144
true, true, true, true, true,
144145
ispod, ispod, ispod, true, true);
145146

146147
passed &= do_test<T>(var(std::cref(i)), true, true, false, true, false,
147148
true, false, true, false, false,
148-
false, false, false, false, false,
149+
false, false, false, false, false, false,
149150
true, false, true, false, true,
150151
ispod, ispod, ispod, false, true);
151152

@@ -156,33 +157,33 @@ bool built_in_type_test(const T &initial, bool ispod)
156157

157158
passed &= do_test<T>(var(i), true, true, true, true, true,
158159
true, true, true, true, true,
159-
true, true, true, true, true,
160+
true, true, true, true, true, true,
160161
true, true, true, true, true,
161162
ispod, ispod, ispod, true, true);
162163

163164
// But a pointer or reference to it should be necessarily const
164165
passed &= do_test<T>(var(&ir), true, true, false, true, false,
165166
true, false, true, false, false,
166-
false, false, false, false, false,
167+
false, false, false, false, false, false,
167168
true, false, true, false, true,
168169
ispod, ispod, ispod, false, true);
169170

170171
passed &= do_test<T>(var(std::ref(ir)), true, true, false, true, false,
171172
true, false, true, false, false,
172-
false, false, false, false, false,
173+
false, false, false, false, false, false,
173174
true, false, true, false, true,
174175
ispod, ispod, ispod, false, true);
175176

176177
// Make sure const of const works too
177178
passed &= do_test<T>(const_var(&ir), true, true, false, true, false,
178179
true, false, true, false, false,
179-
false, false, false, false, false,
180+
false, false, false, false, false, false,
180181
true, false, true, false, true,
181182
ispod, ispod, ispod, false, true);
182183

183184
passed &= do_test<T>(const_var(std::ref(ir)), true, true, false, true, false,
184185
true, false, true, false, false,
185-
false, false, false, false, false,
186+
false, false, false, false, false, false,
186187
true, false, true, false, true,
187188
ispod, ispod, ispod, false, true);
188189

@@ -192,14 +193,14 @@ bool built_in_type_test(const T &initial, bool ispod)
192193
const T*cip = &i;
193194
passed &= do_test<T>(var(cip), true, true, false, true, false,
194195
true, false, true, false, false,
195-
false, false, false, false, false,
196+
false, false, false, false, false, false,
196197
true, false, true, false, true,
197198
ispod, ispod, ispod, false, true);
198199

199200
// make sure const of const works
200201
passed &= do_test<T>(const_var(cip), true, true, false, true, false,
201202
true, false, true, false, false,
202-
false, false, false, false, false,
203+
false, false, false, false, false, false,
203204
true, false, true, false, true,
204205
ispod, ispod, ispod, false, true);
205206

@@ -209,13 +210,13 @@ bool built_in_type_test(const T &initial, bool ispod)
209210

210211
passed &= do_test<T>(var(ip), true, true, true, true, true,
211212
true, true, true, true, true,
212-
true, true, true, true, true,
213+
true, true, true, true, true, true,
213214
true, true, true, true, true,
214215
ispod, ispod, ispod, true, true);
215216

216217
passed &= do_test<T>(const_var(ip), true, true, false, true, false,
217218
true, false, true, false, true,
218-
false, true, false, true, false,
219+
false, false, true, false, true, false,
219220
true, false, true, false, true,
220221
ispod, ispod, ispod, false, true);
221222

@@ -224,14 +225,14 @@ bool built_in_type_test(const T &initial, bool ispod)
224225

225226
passed &= do_test<T>(var(ipc), true, true, false, true, false,
226227
true, false, true, false, true,
227-
false, true, false, true, false,
228+
false, false, true, false, true, false,
228229
true, false, true, false, true,
229230
ispod, ispod, ispod, false, true);
230231

231232
// const of this should be the same, making sure it compiles
232233
passed &= do_test<T>(const_var(ipc), true, true, false, true, false,
233234
true, false, true, false, true,
234-
false, true, false, true, false,
235+
false, false, true, false, true, false,
235236
true, false, true, false, true,
236237
ispod, ispod, ispod, false, true);
237238

unittests/shared_ptr_update.chai

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
load_module("test_module")
2+
3+
auto o := null_factory();
4+
5+
assert_true(o.is_var_null());
6+
7+
update_shared_ptr(o);
8+
9+
assert_false(o.is_var_null());
10+
assert_true(o.base_only_func() == -9);
11+
12+
nullify_shared_ptr(o);
13+
o.nullify_shared_ptr();
14+
15+
assert_true(o.is_var_null());
16+
17+
try {
18+
o.func();
19+
} catch (e) {
20+
exit(0);
21+
}
22+
23+
assert_true(false);
24+
25+

0 commit comments

Comments
 (0)