diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-17 15:55:37 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-17 15:55:37 -0400 |
commit | 90aadf3844386824140a20d7fbb847bc16009a94 (patch) | |
tree | 6f83fce90e71abb22b1a8f3e09c79963b2a34d5d /vendor | |
parent | bc63fa57ced1c7329f7fdcfd168eaf7e290158bc (diff) | |
parent | 86f0106d0523825549f1e74b835688c78a10cf6c (diff) | |
download | therapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.gz therapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.bz2 therapy-90aadf3844386824140a20d7fbb847bc16009a94.zip |
Merge pull request #7 from hatkirby/es-rewrite
The ECS rewrite exceeds the original branch in functionality, so it is time to merge it in.
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/sol.hpp | 21575 | ||||
-rw-r--r-- | vendor/stb_image.cpp | 4 | ||||
-rw-r--r-- | vendor/stb_image.h | 6326 |
3 files changed, 27905 insertions, 0 deletions
diff --git a/vendor/sol.hpp b/vendor/sol.hpp new file mode 100644 index 0000000..d033cba --- /dev/null +++ b/vendor/sol.hpp | |||
@@ -0,0 +1,21575 @@ | |||
1 | // The MIT License (MIT) | ||
2 | |||
3 | // Copyright (c) 2013-2018 Rapptz, ThePhD and contributors | ||
4 | |||
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
6 | // this software and associated documentation files (the "Software"), to deal in | ||
7 | // the Software without restriction, including without limitation the rights to | ||
8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
9 | // the Software, and to permit persons to whom the Software is furnished to do so, | ||
10 | // subject to the following conditions: | ||
11 | |||
12 | // The above copyright notice and this permission notice shall be included in all | ||
13 | // copies or substantial portions of the Software. | ||
14 | |||
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
17 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
18 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
19 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
20 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | |||
22 | // This file was generated with a script. | ||
23 | // Generated 2018-04-18 00:12:41.772355 UTC | ||
24 | // This header was generated with sol v2.20.0 (revision 8b77411) | ||
25 | // https://github.com/ThePhD/sol2 | ||
26 | |||
27 | #ifndef SOL_SINGLE_INCLUDE_HPP | ||
28 | #define SOL_SINGLE_INCLUDE_HPP | ||
29 | |||
30 | // beginning of sol.hpp | ||
31 | |||
32 | #ifndef SOL_HPP | ||
33 | #define SOL_HPP | ||
34 | |||
35 | #if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) | ||
36 | #define SOL_INSIDE_UNREAL 1 | ||
37 | #endif // Unreal Engine 4 bullshit | ||
38 | |||
39 | #if defined(SOL_INSIDE_UNREAL) && SOL_INSIDE_UNREAL | ||
40 | #ifdef check | ||
41 | #define SOL_INSIDE_UNREAL_REMOVED_CHECK | ||
42 | #undef check | ||
43 | #endif | ||
44 | #endif // Unreal Engine 4 Bullshit | ||
45 | |||
46 | #if defined(__GNUC__) | ||
47 | #pragma GCC diagnostic push | ||
48 | #pragma GCC diagnostic ignored "-Wshadow" | ||
49 | #pragma GCC diagnostic ignored "-Wconversion" | ||
50 | #if __GNUC__ > 6 | ||
51 | #pragma GCC diagnostic ignored "-Wnoexcept-type" | ||
52 | #endif | ||
53 | #elif defined(__clang__) | ||
54 | #elif defined _MSC_VER | ||
55 | #pragma warning( push ) | ||
56 | #pragma warning( disable : 4324 ) // structure was padded due to alignment specifier | ||
57 | #pragma warning( disable : 4503 ) // decorated name horse shit | ||
58 | #pragma warning( disable : 4702 ) // unreachable code | ||
59 | #pragma warning( disable: 4127 ) // 'conditional expression is constant' yeah that's the point your old compilers don't have `if constexpr` you jerk | ||
60 | #pragma warning( disable: 4505 ) // some other nonsense warning | ||
61 | #endif // clang++ vs. g++ vs. VC++ | ||
62 | |||
63 | // beginning of sol/forward.hpp | ||
64 | |||
65 | // beginning of sol/feature_test.hpp | ||
66 | |||
67 | #if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) | ||
68 | #ifndef SOL_CXX17_FEATURES | ||
69 | #define SOL_CXX17_FEATURES 1 | ||
70 | #endif // C++17 features macro | ||
71 | #endif // C++17 features check | ||
72 | |||
73 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
74 | #if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L)))) | ||
75 | #ifndef SOL_NOEXCEPT_FUNCTION_TYPE | ||
76 | #define SOL_NOEXCEPT_FUNCTION_TYPE 1 | ||
77 | #endif // noexcept is part of a function's type | ||
78 | #endif // compiler-specific checks | ||
79 | #if defined(__clang__) && defined(__APPLE__) | ||
80 | #if defined(__has_include) | ||
81 | #if __has_include(<variant>) | ||
82 | #define SOL_STD_VARIANT 1 | ||
83 | #endif // has include nonsense | ||
84 | #endif // __has_include | ||
85 | #else | ||
86 | #define SOL_STD_VARIANT 1 | ||
87 | #endif // Clang screws up variant | ||
88 | #endif // C++17 only | ||
89 | |||
90 | // beginning of sol/config.hpp | ||
91 | |||
92 | #ifdef _MSC_VER | ||
93 | #if defined(_DEBUG) && !defined(NDEBUG) | ||
94 | |||
95 | #ifndef SOL_IN_DEBUG_DETECTED | ||
96 | #define SOL_IN_DEBUG_DETECTED 1 | ||
97 | #endif | ||
98 | |||
99 | #endif // VC++ Debug macros | ||
100 | |||
101 | #ifndef _CPPUNWIND | ||
102 | #ifndef SOL_NO_EXCEPTIONS | ||
103 | #define SOL_NO_EXCEPTIONS 1 | ||
104 | #endif | ||
105 | #endif // Automatic Exceptions | ||
106 | |||
107 | #ifndef _CPPRTTI | ||
108 | #ifndef SOL_NO_RTTI | ||
109 | #define SOL_NO_RTTI 1 | ||
110 | #endif | ||
111 | #endif // Automatic RTTI | ||
112 | #elif defined(__GNUC__) || defined(__clang__) | ||
113 | |||
114 | #if !defined(NDEBUG) && !defined(__OPTIMIZE__) | ||
115 | |||
116 | #ifndef SOL_IN_DEBUG_DETECTED | ||
117 | #define SOL_IN_DEBUG_DETECTED 1 | ||
118 | #endif | ||
119 | |||
120 | #endif // Not Debug && g++ optimizer flag | ||
121 | |||
122 | #ifndef __EXCEPTIONS | ||
123 | #ifndef SOL_NO_EXCEPTIONS | ||
124 | #define SOL_NO_EXCEPTIONS 1 | ||
125 | #endif | ||
126 | #endif // No Exceptions | ||
127 | |||
128 | #ifndef __GXX_RTTI | ||
129 | #ifndef SOL_NO_RTII | ||
130 | #define SOL_NO_RTTI 1 | ||
131 | #endif | ||
132 | #endif // No RTTI | ||
133 | |||
134 | #endif // vc++ || clang++/g++ | ||
135 | |||
136 | #if defined(SOL_CHECK_ARGUMENTS) && SOL_CHECK_ARGUMENTS | ||
137 | |||
138 | // Checks low-level getter function | ||
139 | // (and thusly, affects nearly entire framework) | ||
140 | #if !defined(SOL_SAFE_GETTER) | ||
141 | #define SOL_SAFE_GETTER 1 | ||
142 | #endif | ||
143 | |||
144 | // Checks access on usertype functions | ||
145 | // local my_obj = my_type.new() | ||
146 | // my_obj.my_member_function() | ||
147 | // -- bad syntax and crash | ||
148 | #if !defined(SOL_SAFE_USERTYPE) | ||
149 | #define SOL_SAFE_USERTYPE 1 | ||
150 | #endif | ||
151 | |||
152 | // Checks sol::reference derived boundaries | ||
153 | // sol::function ref(L, 1); | ||
154 | // sol::userdata sref(L, 2); | ||
155 | #if !defined(SOL_SAFE_REFERENCES) | ||
156 | #define SOL_SAFE_REFERENCES 1 | ||
157 | #endif | ||
158 | |||
159 | // Changes all typedefs of sol::function to point to the | ||
160 | // protected_function version, instead of unsafe_function | ||
161 | #if !defined(SOL_SAFE_FUNCTION) | ||
162 | #define SOL_SAFE_FUNCTION 1 | ||
163 | #endif | ||
164 | |||
165 | // Checks function parameters and | ||
166 | // returns upon call into/from Lua | ||
167 | // local a = 1 | ||
168 | // local b = "woof" | ||
169 | // my_c_function(a, b) | ||
170 | #if !defined(SOL_SAFE_FUNCTION_CALLS) | ||
171 | #define SOL_SAFE_FUNCTION_CALLS 1 | ||
172 | #endif | ||
173 | |||
174 | // Checks conversions | ||
175 | // int v = lua["bark"]; | ||
176 | // int v2 = my_sol_function(); | ||
177 | #if !defined(SOL_SAFE_PROXIES) | ||
178 | #define SOL_SAFE_PROXIES 1 | ||
179 | #endif | ||
180 | |||
181 | // Check overflowing number conversions | ||
182 | // for things like 64 bit integers that don't fit in a typical lua_Number | ||
183 | // for Lua 5.1 and 5.2 | ||
184 | #if !defined(SOL_SAFE_NUMERICS) | ||
185 | #define SOL_SAFE_NUMERICS 1 | ||
186 | #endif | ||
187 | |||
188 | // Turn off Number Precision Checks | ||
189 | // if this is defined, we do not do range | ||
190 | // checks on integers / unsigned integers that might | ||
191 | // be bigger than what Lua can represent | ||
192 | #if !defined(SOL_NO_CHECK_NUMBER_PRECISION) | ||
193 | // off by default | ||
194 | #define SOL_NO_CHECK_NUMBER_PRECISION 0 | ||
195 | #endif | ||
196 | |||
197 | #endif // Turn on Safety for all if top-level macro is defined | ||
198 | |||
199 | #if defined(SOL_IN_DEBUG_DETECTED) && SOL_IN_DEBUG_DETECTED | ||
200 | |||
201 | #if !defined(SOL_SAFE_REFERENCES) | ||
202 | // Ensure that references are forcefully type-checked upon construction | ||
203 | #define SOL_SAFE_REFERENCES 1 | ||
204 | #endif | ||
205 | |||
206 | // Safe usertypes checks for errors such as | ||
207 | // obj = my_type.new() | ||
208 | // obj.f() -- note the '.' instead of ':' | ||
209 | // usertypes should be safe no matter what | ||
210 | #if !defined(SOL_SAFE_USERTYPE) | ||
211 | #define SOL_SAFE_USERTYPE 1 | ||
212 | #endif | ||
213 | |||
214 | #if !defined(SOL_SAFE_FUNCTION_CALLS) | ||
215 | // Function calls from Lua should be automatically safe in debug mode | ||
216 | #define SOL_SAFE_FUNCTION_CALLS 1 | ||
217 | #endif | ||
218 | |||
219 | // Print any exceptions / errors that occur | ||
220 | // in debug mode to the default error stream / console | ||
221 | #if !defined(SOL_PRINT_ERRORS) | ||
222 | #define SOL_PRINT_ERRORS 1 | ||
223 | #endif | ||
224 | |||
225 | #endif // DEBUG: Turn on all debug safety features for VC++ / g++ / clang++ and similar | ||
226 | |||
227 | #if !defined(SOL_PRINT_ERRORS) | ||
228 | #define SOL_PRINT_ERRORS 0 | ||
229 | #endif | ||
230 | |||
231 | #if !defined(SOL_DEFAULT_PASS_ON_ERROR) | ||
232 | #define SOL_DEFAULT_PASS_ON_ERROR 0 | ||
233 | #endif | ||
234 | |||
235 | #if !defined(SOL_ENABLE_INTEROP) | ||
236 | #define SOL_ENABLE_INTEROP 0 | ||
237 | #endif | ||
238 | |||
239 | #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) | ||
240 | #if !defined(SOL_NO_NIL) | ||
241 | #define SOL_NO_NIL 1 | ||
242 | #endif | ||
243 | #endif // avoiding nil defines / keywords | ||
244 | |||
245 | #if defined(SOL_USE_BOOST) && SOL_USE_BOOST | ||
246 | #ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
247 | #define SOL_UNORDERED_MAP_COMPATIBLE_HASH 1 | ||
248 | #endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
249 | #endif | ||
250 | |||
251 | #ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE | ||
252 | #define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024 | ||
253 | #endif // Optimized conversion routines using a KB or so off the stack | ||
254 | |||
255 | // end of sol/config.hpp | ||
256 | |||
257 | // end of sol/feature_test.hpp | ||
258 | |||
259 | namespace sol { | ||
260 | |||
261 | template <bool b> | ||
262 | class basic_reference; | ||
263 | using reference = basic_reference<false>; | ||
264 | using main_reference = basic_reference<true>; | ||
265 | class stack_reference; | ||
266 | |||
267 | struct proxy_base_tag; | ||
268 | template <typename Super> | ||
269 | struct proxy_base; | ||
270 | template <typename Table, typename Key> | ||
271 | struct proxy; | ||
272 | |||
273 | template <typename T> | ||
274 | class usertype; | ||
275 | template <typename T> | ||
276 | class simple_usertype; | ||
277 | template <bool, typename T> | ||
278 | class basic_table_core; | ||
279 | template <bool b> | ||
280 | using table_core = basic_table_core<b, reference>; | ||
281 | template <bool b> | ||
282 | using main_table_core = basic_table_core<b, main_reference>; | ||
283 | template <bool b> | ||
284 | using stack_table_core = basic_table_core<b, stack_reference>; | ||
285 | template <typename T> | ||
286 | using basic_table = basic_table_core<false, T>; | ||
287 | typedef table_core<false> table; | ||
288 | typedef table_core<true> global_table; | ||
289 | typedef main_table_core<false> main_table; | ||
290 | typedef main_table_core<true> main_global_table; | ||
291 | typedef stack_table_core<false> stack_table; | ||
292 | typedef stack_table_core<true> stack_global_table; | ||
293 | template <typename base_t> | ||
294 | struct basic_environment; | ||
295 | using environment = basic_environment<reference>; | ||
296 | using main_environment = basic_environment<main_reference>; | ||
297 | using stack_environment = basic_environment<stack_reference>; | ||
298 | template <typename T, bool> | ||
299 | class basic_function; | ||
300 | template <typename T, bool, typename H> | ||
301 | class basic_protected_function; | ||
302 | using unsafe_function = basic_function<reference, false>; | ||
303 | using safe_function = basic_protected_function<reference, false, reference>; | ||
304 | using main_unsafe_function = basic_function<main_reference, false>; | ||
305 | using main_safe_function = basic_protected_function<main_reference, false, reference>; | ||
306 | using stack_unsafe_function = basic_function<stack_reference, false>; | ||
307 | using stack_safe_function = basic_protected_function<stack_reference, false, reference>; | ||
308 | using stack_aligned_unsafe_function = basic_function<stack_reference, true>; | ||
309 | using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>; | ||
310 | using protected_function = safe_function; | ||
311 | using main_protected_function = main_safe_function; | ||
312 | using stack_protected_function = stack_safe_function; | ||
313 | using stack_aligned_protected_function = stack_aligned_safe_function; | ||
314 | #if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION | ||
315 | using function = protected_function; | ||
316 | using main_function = main_protected_function; | ||
317 | using stack_function = stack_protected_function; | ||
318 | #else | ||
319 | using function = unsafe_function; | ||
320 | using main_function = main_unsafe_function; | ||
321 | using stack_function = stack_unsafe_function; | ||
322 | #endif | ||
323 | using stack_aligned_function = stack_aligned_unsafe_function; | ||
324 | using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>; | ||
325 | |||
326 | struct unsafe_function_result; | ||
327 | struct protected_function_result; | ||
328 | using safe_function_result = protected_function_result; | ||
329 | #if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION | ||
330 | using function_result = safe_function_result; | ||
331 | #else | ||
332 | using function_result = unsafe_function_result; | ||
333 | #endif | ||
334 | |||
335 | template <typename base_t> | ||
336 | class basic_object; | ||
337 | template <typename base_t> | ||
338 | class basic_userdata; | ||
339 | template <typename base_t> | ||
340 | class basic_lightuserdata; | ||
341 | template <typename base_t> | ||
342 | class basic_coroutine; | ||
343 | template <typename base_t> | ||
344 | class basic_thread; | ||
345 | |||
346 | using object = basic_object<reference>; | ||
347 | using userdata = basic_userdata<reference>; | ||
348 | using lightuserdata = basic_lightuserdata<reference>; | ||
349 | using thread = basic_thread<reference>; | ||
350 | using coroutine = basic_coroutine<reference>; | ||
351 | using main_object = basic_object<main_reference>; | ||
352 | using main_userdata = basic_userdata<main_reference>; | ||
353 | using main_lightuserdata = basic_lightuserdata<main_reference>; | ||
354 | using main_coroutine = basic_coroutine<main_reference>; | ||
355 | using stack_object = basic_object<stack_reference>; | ||
356 | using stack_userdata = basic_userdata<stack_reference>; | ||
357 | using stack_lightuserdata = basic_lightuserdata<stack_reference>; | ||
358 | using stack_thread = basic_thread<stack_reference>; | ||
359 | using stack_coroutine = basic_coroutine<stack_reference>; | ||
360 | |||
361 | struct stack_proxy_base; | ||
362 | struct stack_proxy; | ||
363 | struct variadic_args; | ||
364 | struct variadic_results; | ||
365 | struct stack_count; | ||
366 | struct this_state; | ||
367 | struct this_main_state; | ||
368 | struct this_environment; | ||
369 | |||
370 | template <typename T> | ||
371 | struct as_table_t; | ||
372 | template <typename T> | ||
373 | struct as_container_t; | ||
374 | template <typename T> | ||
375 | struct nested; | ||
376 | template <typename T> | ||
377 | struct light; | ||
378 | template <typename T> | ||
379 | struct user; | ||
380 | template <typename T> | ||
381 | struct as_args_t; | ||
382 | template <typename T> | ||
383 | struct protect_t; | ||
384 | template <typename F, typename... Filters> | ||
385 | struct filter_wrapper; | ||
386 | } // namespace sol | ||
387 | |||
388 | // end of sol/forward.hpp | ||
389 | |||
390 | // beginning of sol/state.hpp | ||
391 | |||
392 | // beginning of sol/state_view.hpp | ||
393 | |||
394 | // beginning of sol/error.hpp | ||
395 | |||
396 | #include <stdexcept> | ||
397 | #include <string> | ||
398 | |||
399 | namespace sol { | ||
400 | namespace detail { | ||
401 | struct direct_error_tag {}; | ||
402 | const auto direct_error = direct_error_tag{}; | ||
403 | } // namespace detail | ||
404 | |||
405 | class error : public std::runtime_error { | ||
406 | private: | ||
407 | // Because VC++ is upsetting, most of the time! | ||
408 | std::string w; | ||
409 | |||
410 | public: | ||
411 | error(const std::string& str) | ||
412 | : error(detail::direct_error, "lua: error: " + str) { | ||
413 | } | ||
414 | error(std::string&& str) | ||
415 | : error(detail::direct_error, "lua: error: " + std::move(str)) { | ||
416 | } | ||
417 | error(detail::direct_error_tag, const std::string& str) | ||
418 | : std::runtime_error(""), w(str) { | ||
419 | } | ||
420 | error(detail::direct_error_tag, std::string&& str) | ||
421 | : std::runtime_error(""), w(std::move(str)) { | ||
422 | } | ||
423 | |||
424 | error(const error& e) = default; | ||
425 | error(error&& e) = default; | ||
426 | error& operator=(const error& e) = default; | ||
427 | error& operator=(error&& e) = default; | ||
428 | |||
429 | virtual const char* what() const noexcept override { | ||
430 | return w.c_str(); | ||
431 | } | ||
432 | }; | ||
433 | |||
434 | } // namespace sol | ||
435 | |||
436 | // end of sol/error.hpp | ||
437 | |||
438 | // beginning of sol/table.hpp | ||
439 | |||
440 | // beginning of sol/table_core.hpp | ||
441 | |||
442 | // beginning of sol/proxy.hpp | ||
443 | |||
444 | // beginning of sol/traits.hpp | ||
445 | |||
446 | // beginning of sol/tuple.hpp | ||
447 | |||
448 | #include <tuple> | ||
449 | #include <cstddef> | ||
450 | |||
451 | namespace sol { | ||
452 | namespace detail { | ||
453 | using swallow = std::initializer_list<int>; | ||
454 | } // namespace detail | ||
455 | |||
456 | template <typename... Args> | ||
457 | struct types { | ||
458 | typedef std::make_index_sequence<sizeof...(Args)> indices; | ||
459 | static constexpr std::size_t size() { | ||
460 | return sizeof...(Args); | ||
461 | } | ||
462 | }; | ||
463 | namespace meta { | ||
464 | namespace detail { | ||
465 | template <typename... Args> | ||
466 | struct tuple_types_ { typedef types<Args...> type; }; | ||
467 | |||
468 | template <typename... Args> | ||
469 | struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; }; | ||
470 | } // namespace detail | ||
471 | |||
472 | template <typename T> | ||
473 | using unqualified = std::remove_cv<std::remove_reference_t<T>>; | ||
474 | |||
475 | template <typename T> | ||
476 | using unqualified_t = typename unqualified<T>::type; | ||
477 | |||
478 | template <typename... Args> | ||
479 | using tuple_types = typename detail::tuple_types_<Args...>::type; | ||
480 | |||
481 | template <typename Arg> | ||
482 | struct pop_front_type; | ||
483 | |||
484 | template <typename Arg> | ||
485 | using pop_front_type_t = typename pop_front_type<Arg>::type; | ||
486 | |||
487 | template <typename... Args> | ||
488 | struct pop_front_type<types<Args...>> { | ||
489 | typedef void front_type; | ||
490 | typedef types<Args...> type; | ||
491 | }; | ||
492 | |||
493 | template <typename Arg, typename... Args> | ||
494 | struct pop_front_type<types<Arg, Args...>> { | ||
495 | typedef Arg front_type; | ||
496 | typedef types<Args...> type; | ||
497 | }; | ||
498 | |||
499 | template <std::size_t N, typename Tuple> | ||
500 | using tuple_element = std::tuple_element<N, std::remove_reference_t<Tuple>>; | ||
501 | |||
502 | template <std::size_t N, typename Tuple> | ||
503 | using tuple_element_t = std::tuple_element_t<N, std::remove_reference_t<Tuple>>; | ||
504 | |||
505 | template <std::size_t N, typename Tuple> | ||
506 | using unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>; | ||
507 | |||
508 | template <std::size_t N, typename Tuple> | ||
509 | using unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>; | ||
510 | |||
511 | } // namespace meta | ||
512 | } // namespace sol | ||
513 | |||
514 | // end of sol/tuple.hpp | ||
515 | |||
516 | // beginning of sol/bind_traits.hpp | ||
517 | |||
518 | namespace sol { | ||
519 | namespace meta { | ||
520 | namespace meta_detail { | ||
521 | |||
522 | template <class F> | ||
523 | struct check_deducible_signature { | ||
524 | struct nat {}; | ||
525 | template <class G> | ||
526 | static auto test(int) -> decltype(&G::operator(), void()); | ||
527 | template <class> | ||
528 | static auto test(...) -> nat; | ||
529 | |||
530 | using type = std::is_void<decltype(test<F>(0))>; | ||
531 | }; | ||
532 | } // namespace meta_detail | ||
533 | |||
534 | template <class F> | ||
535 | struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type {}; | ||
536 | |||
537 | namespace meta_detail { | ||
538 | |||
539 | template <std::size_t I, typename T> | ||
540 | struct void_tuple_element : meta::tuple_element<I, T> {}; | ||
541 | |||
542 | template <std::size_t I> | ||
543 | struct void_tuple_element<I, std::tuple<>> { typedef void type; }; | ||
544 | |||
545 | template <std::size_t I, typename T> | ||
546 | using void_tuple_element_t = typename void_tuple_element<I, T>::type; | ||
547 | |||
548 | template <bool it_is_noexcept, bool has_c_variadic, typename T, typename R, typename... Args> | ||
549 | struct basic_traits { | ||
550 | private: | ||
551 | typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type; | ||
552 | |||
553 | public: | ||
554 | static const bool is_noexcept = it_is_noexcept; | ||
555 | static const bool is_member_function = std::is_void<T>::value; | ||
556 | static const bool has_c_var_arg = has_c_variadic; | ||
557 | static const std::size_t arity = sizeof...(Args); | ||
558 | static const std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value); | ||
559 | typedef types<Args...> args_list; | ||
560 | typedef std::tuple<Args...> args_tuple; | ||
561 | typedef T object_type; | ||
562 | typedef R return_type; | ||
563 | typedef tuple_types<R> returns_list; | ||
564 | typedef R(function_type)(Args...); | ||
565 | typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list; | ||
566 | typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type; | ||
567 | typedef std::conditional_t<std::is_void<T>::value, R (*)(Args...), R (*)(first_type, Args...)> free_function_pointer_type; | ||
568 | typedef std::remove_pointer_t<free_function_pointer_type> signature_type; | ||
569 | template <std::size_t i> | ||
570 | using arg_at = void_tuple_element_t<i, args_tuple>; | ||
571 | }; | ||
572 | |||
573 | template <typename Signature, bool b = has_deducible_signature<Signature>::value> | ||
574 | struct fx_traits : basic_traits<false, false, void, void> {}; | ||
575 | |||
576 | // Free Functions | ||
577 | template <typename R, typename... Args> | ||
578 | struct fx_traits<R(Args...), false> : basic_traits<false, false, void, R, Args...> { | ||
579 | typedef R (*function_pointer_type)(Args...); | ||
580 | }; | ||
581 | |||
582 | template <typename R, typename... Args> | ||
583 | struct fx_traits<R (*)(Args...), false> : basic_traits<false, false, void, R, Args...> { | ||
584 | typedef R (*function_pointer_type)(Args...); | ||
585 | }; | ||
586 | |||
587 | template <typename R, typename... Args> | ||
588 | struct fx_traits<R(Args..., ...), false> : basic_traits<false, true, void, R, Args...> { | ||
589 | typedef R (*function_pointer_type)(Args..., ...); | ||
590 | }; | ||
591 | |||
592 | template <typename R, typename... Args> | ||
593 | struct fx_traits<R (*)(Args..., ...), false> : basic_traits<false, true, void, R, Args...> { | ||
594 | typedef R (*function_pointer_type)(Args..., ...); | ||
595 | }; | ||
596 | |||
597 | // Member Functions | ||
598 | /* C-Style Variadics */ | ||
599 | template <typename T, typename R, typename... Args> | ||
600 | struct fx_traits<R (T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> { | ||
601 | typedef R (T::*function_pointer_type)(Args...); | ||
602 | }; | ||
603 | |||
604 | template <typename T, typename R, typename... Args> | ||
605 | struct fx_traits<R (T::*)(Args..., ...), false> : basic_traits<false, true, T, R, Args...> { | ||
606 | typedef R (T::*function_pointer_type)(Args..., ...); | ||
607 | }; | ||
608 | |||
609 | /* Const Volatile */ | ||
610 | template <typename T, typename R, typename... Args> | ||
611 | struct fx_traits<R (T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> { | ||
612 | typedef R (T::*function_pointer_type)(Args...) const; | ||
613 | }; | ||
614 | |||
615 | template <typename T, typename R, typename... Args> | ||
616 | struct fx_traits<R (T::*)(Args..., ...) const, false> : basic_traits<false, true, T, R, Args...> { | ||
617 | typedef R (T::*function_pointer_type)(Args..., ...) const; | ||
618 | }; | ||
619 | |||
620 | template <typename T, typename R, typename... Args> | ||
621 | struct fx_traits<R (T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> { | ||
622 | typedef R (T::*function_pointer_type)(Args...) const volatile; | ||
623 | }; | ||
624 | |||
625 | template <typename T, typename R, typename... Args> | ||
626 | struct fx_traits<R (T::*)(Args..., ...) const volatile, false> : basic_traits<false, true, T, R, Args...> { | ||
627 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile; | ||
628 | }; | ||
629 | |||
630 | /* Member Function Qualifiers */ | ||
631 | template <typename T, typename R, typename... Args> | ||
632 | struct fx_traits<R (T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> { | ||
633 | typedef R (T::*function_pointer_type)(Args...) &; | ||
634 | }; | ||
635 | |||
636 | template <typename T, typename R, typename... Args> | ||
637 | struct fx_traits<R (T::*)(Args..., ...)&, false> : basic_traits<false, true, T, R, Args...> { | ||
638 | typedef R (T::*function_pointer_type)(Args..., ...) &; | ||
639 | }; | ||
640 | |||
641 | template <typename T, typename R, typename... Args> | ||
642 | struct fx_traits<R (T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> { | ||
643 | typedef R (T::*function_pointer_type)(Args...) const&; | ||
644 | }; | ||
645 | |||
646 | template <typename T, typename R, typename... Args> | ||
647 | struct fx_traits<R (T::*)(Args..., ...) const&, false> : basic_traits<false, true, T, R, Args...> { | ||
648 | typedef R (T::*function_pointer_type)(Args..., ...) const&; | ||
649 | }; | ||
650 | |||
651 | template <typename T, typename R, typename... Args> | ||
652 | struct fx_traits<R (T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> { | ||
653 | typedef R (T::*function_pointer_type)(Args...) const volatile&; | ||
654 | }; | ||
655 | |||
656 | template <typename T, typename R, typename... Args> | ||
657 | struct fx_traits<R (T::*)(Args..., ...) const volatile&, false> : basic_traits<false, true, T, R, Args...> { | ||
658 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile&; | ||
659 | }; | ||
660 | |||
661 | template <typename T, typename R, typename... Args> | ||
662 | struct fx_traits<R (T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> { | ||
663 | typedef R (T::*function_pointer_type)(Args...) &&; | ||
664 | }; | ||
665 | |||
666 | template <typename T, typename R, typename... Args> | ||
667 | struct fx_traits<R (T::*)(Args..., ...)&&, false> : basic_traits<false, true, T, R, Args...> { | ||
668 | typedef R (T::*function_pointer_type)(Args..., ...) &&; | ||
669 | }; | ||
670 | |||
671 | template <typename T, typename R, typename... Args> | ||
672 | struct fx_traits<R (T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> { | ||
673 | typedef R (T::*function_pointer_type)(Args...) const&&; | ||
674 | }; | ||
675 | |||
676 | template <typename T, typename R, typename... Args> | ||
677 | struct fx_traits<R (T::*)(Args..., ...) const&&, false> : basic_traits<false, true, T, R, Args...> { | ||
678 | typedef R (T::*function_pointer_type)(Args..., ...) const&&; | ||
679 | }; | ||
680 | |||
681 | template <typename T, typename R, typename... Args> | ||
682 | struct fx_traits<R (T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> { | ||
683 | typedef R (T::*function_pointer_type)(Args...) const volatile&&; | ||
684 | }; | ||
685 | |||
686 | template <typename T, typename R, typename... Args> | ||
687 | struct fx_traits<R (T::*)(Args..., ...) const volatile&&, false> : basic_traits<false, true, T, R, Args...> { | ||
688 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile&&; | ||
689 | }; | ||
690 | |||
691 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
692 | |||
693 | template <typename R, typename... Args> | ||
694 | struct fx_traits<R(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { | ||
695 | typedef R (*function_pointer_type)(Args...) noexcept; | ||
696 | }; | ||
697 | |||
698 | template <typename R, typename... Args> | ||
699 | struct fx_traits<R (*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { | ||
700 | typedef R (*function_pointer_type)(Args...) noexcept; | ||
701 | }; | ||
702 | |||
703 | template <typename R, typename... Args> | ||
704 | struct fx_traits<R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { | ||
705 | typedef R (*function_pointer_type)(Args..., ...) noexcept; | ||
706 | }; | ||
707 | |||
708 | template <typename R, typename... Args> | ||
709 | struct fx_traits<R (*)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { | ||
710 | typedef R (*function_pointer_type)(Args..., ...) noexcept; | ||
711 | }; | ||
712 | |||
713 | template <typename T, typename R, typename... Args> | ||
714 | struct fx_traits<R (T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
715 | typedef R (T::*function_pointer_type)(Args...) noexcept; | ||
716 | }; | ||
717 | |||
718 | template <typename T, typename R, typename... Args> | ||
719 | struct fx_traits<R (T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
720 | typedef R (T::*function_pointer_type)(Args..., ...) noexcept; | ||
721 | }; | ||
722 | |||
723 | /* Const Volatile */ | ||
724 | template <typename T, typename R, typename... Args> | ||
725 | struct fx_traits<R (T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
726 | typedef R (T::*function_pointer_type)(Args...) const noexcept; | ||
727 | }; | ||
728 | |||
729 | template <typename T, typename R, typename... Args> | ||
730 | struct fx_traits<R (T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
731 | typedef R (T::*function_pointer_type)(Args..., ...) const noexcept; | ||
732 | }; | ||
733 | |||
734 | template <typename T, typename R, typename... Args> | ||
735 | struct fx_traits<R (T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
736 | typedef R (T::*function_pointer_type)(Args...) const volatile noexcept; | ||
737 | }; | ||
738 | |||
739 | template <typename T, typename R, typename... Args> | ||
740 | struct fx_traits<R (T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
741 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile noexcept; | ||
742 | }; | ||
743 | |||
744 | template <typename T, typename R, typename... Args> | ||
745 | struct fx_traits<R (T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
746 | typedef R (T::*function_pointer_type)(Args...) & noexcept; | ||
747 | }; | ||
748 | |||
749 | template <typename T, typename R, typename... Args> | ||
750 | struct fx_traits<R (T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
751 | typedef R (T::*function_pointer_type)(Args..., ...) & noexcept; | ||
752 | }; | ||
753 | |||
754 | template <typename T, typename R, typename... Args> | ||
755 | struct fx_traits<R (T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
756 | typedef R (T::*function_pointer_type)(Args...) const& noexcept; | ||
757 | }; | ||
758 | |||
759 | template <typename T, typename R, typename... Args> | ||
760 | struct fx_traits<R (T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
761 | typedef R (T::*function_pointer_type)(Args..., ...) const& noexcept; | ||
762 | }; | ||
763 | |||
764 | template <typename T, typename R, typename... Args> | ||
765 | struct fx_traits<R (T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
766 | typedef R (T::*function_pointer_type)(Args...) const volatile& noexcept; | ||
767 | }; | ||
768 | |||
769 | template <typename T, typename R, typename... Args> | ||
770 | struct fx_traits<R (T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
771 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile& noexcept; | ||
772 | }; | ||
773 | |||
774 | template <typename T, typename R, typename... Args> | ||
775 | struct fx_traits<R (T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
776 | typedef R (T::*function_pointer_type)(Args...) && noexcept; | ||
777 | }; | ||
778 | |||
779 | template <typename T, typename R, typename... Args> | ||
780 | struct fx_traits<R (T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
781 | typedef R (T::*function_pointer_type)(Args..., ...) && noexcept; | ||
782 | }; | ||
783 | |||
784 | template <typename T, typename R, typename... Args> | ||
785 | struct fx_traits<R (T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
786 | typedef R (T::*function_pointer_type)(Args...) const&& noexcept; | ||
787 | }; | ||
788 | |||
789 | template <typename T, typename R, typename... Args> | ||
790 | struct fx_traits<R (T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
791 | typedef R (T::*function_pointer_type)(Args..., ...) const&& noexcept; | ||
792 | }; | ||
793 | |||
794 | template <typename T, typename R, typename... Args> | ||
795 | struct fx_traits<R (T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
796 | typedef R (T::*function_pointer_type)(Args...) const volatile&& noexcept; | ||
797 | }; | ||
798 | |||
799 | template <typename T, typename R, typename... Args> | ||
800 | struct fx_traits<R (T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
801 | typedef R (T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; | ||
802 | }; | ||
803 | |||
804 | #endif // noexcept is part of a function's type | ||
805 | |||
806 | #if defined(_MSC_VER) && defined(_M_IX86) | ||
807 | template <typename R, typename... Args> | ||
808 | struct fx_traits<R __stdcall(Args...), false> : basic_traits<false, false, void, R, Args...> { | ||
809 | typedef R(__stdcall* function_pointer_type)(Args...); | ||
810 | }; | ||
811 | |||
812 | template <typename R, typename... Args> | ||
813 | struct fx_traits<R(__stdcall*)(Args...), false> : basic_traits<false, false, void, R, Args...> { | ||
814 | typedef R(__stdcall* function_pointer_type)(Args...); | ||
815 | }; | ||
816 | |||
817 | template <typename T, typename R, typename... Args> | ||
818 | struct fx_traits<R (__stdcall T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> { | ||
819 | typedef R (__stdcall T::*function_pointer_type)(Args...); | ||
820 | }; | ||
821 | |||
822 | /* Const Volatile */ | ||
823 | template <typename T, typename R, typename... Args> | ||
824 | struct fx_traits<R (__stdcall T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> { | ||
825 | typedef R (__stdcall T::*function_pointer_type)(Args...) const; | ||
826 | }; | ||
827 | |||
828 | template <typename T, typename R, typename... Args> | ||
829 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> { | ||
830 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile; | ||
831 | }; | ||
832 | |||
833 | /* Member Function Qualifiers */ | ||
834 | template <typename T, typename R, typename... Args> | ||
835 | struct fx_traits<R (__stdcall T::*)(Args...)&, false> : basic_traits<false, false, T, R, Args...> { | ||
836 | typedef R (__stdcall T::*function_pointer_type)(Args...) &; | ||
837 | }; | ||
838 | |||
839 | template <typename T, typename R, typename... Args> | ||
840 | struct fx_traits<R (__stdcall T::*)(Args...) const&, false> : basic_traits<false, false, T, R, Args...> { | ||
841 | typedef R (__stdcall T::*function_pointer_type)(Args...) const&; | ||
842 | }; | ||
843 | |||
844 | template <typename T, typename R, typename... Args> | ||
845 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile&, false> : basic_traits<false, false, T, R, Args...> { | ||
846 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&; | ||
847 | }; | ||
848 | |||
849 | template <typename T, typename R, typename... Args> | ||
850 | struct fx_traits<R (__stdcall T::*)(Args...)&&, false> : basic_traits<false, false, T, R, Args...> { | ||
851 | typedef R (__stdcall T::*function_pointer_type)(Args...) &&; | ||
852 | }; | ||
853 | |||
854 | template <typename T, typename R, typename... Args> | ||
855 | struct fx_traits<R (__stdcall T::*)(Args...) const&&, false> : basic_traits<false, false, T, R, Args...> { | ||
856 | typedef R (__stdcall T::*function_pointer_type)(Args...) const&&; | ||
857 | }; | ||
858 | |||
859 | template <typename T, typename R, typename... Args> | ||
860 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile&&, false> : basic_traits<false, false, T, R, Args...> { | ||
861 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&&; | ||
862 | }; | ||
863 | |||
864 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
865 | |||
866 | template <typename R, typename... Args> | ||
867 | struct fx_traits<R __stdcall(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { | ||
868 | typedef R(__stdcall* function_pointer_type)(Args...) noexcept; | ||
869 | }; | ||
870 | |||
871 | template <typename R, typename... Args> | ||
872 | struct fx_traits<R (__stdcall *)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> { | ||
873 | typedef R(__stdcall* function_pointer_type)(Args...) noexcept; | ||
874 | }; | ||
875 | |||
876 | /* __stdcall cannot be applied to functions with varargs*/ | ||
877 | /*template <typename R, typename... Args> | ||
878 | struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { | ||
879 | typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; | ||
880 | }; | ||
881 | |||
882 | template <typename R, typename... Args> | ||
883 | struct fx_traits<R (__stdcall *)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> { | ||
884 | typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; | ||
885 | };*/ | ||
886 | |||
887 | template <typename T, typename R, typename... Args> | ||
888 | struct fx_traits<R (__stdcall T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
889 | typedef R (__stdcall T::*function_pointer_type)(Args...) noexcept; | ||
890 | }; | ||
891 | |||
892 | /* __stdcall does not work with varargs */ | ||
893 | /*template <typename T, typename R, typename... Args> | ||
894 | struct fx_traits<R (__stdcall T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
895 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept; | ||
896 | };*/ | ||
897 | |||
898 | /* Const Volatile */ | ||
899 | template <typename T, typename R, typename... Args> | ||
900 | struct fx_traits<R (__stdcall T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
901 | typedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept; | ||
902 | }; | ||
903 | |||
904 | /* __stdcall does not work with varargs */ | ||
905 | /*template <typename T, typename R, typename... Args> | ||
906 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
907 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept; | ||
908 | };*/ | ||
909 | |||
910 | template <typename T, typename R, typename... Args> | ||
911 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
912 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept; | ||
913 | }; | ||
914 | |||
915 | /* __stdcall does not work with varargs */ | ||
916 | /*template <typename T, typename R, typename... Args> | ||
917 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
918 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept; | ||
919 | };*/ | ||
920 | |||
921 | template <typename T, typename R, typename... Args> | ||
922 | struct fx_traits<R (__stdcall T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
923 | typedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept; | ||
924 | }; | ||
925 | |||
926 | /* __stdcall does not work with varargs */ | ||
927 | /*template <typename T, typename R, typename... Args> | ||
928 | struct fx_traits<R (__stdcall T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
929 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept; | ||
930 | };*/ | ||
931 | |||
932 | template <typename T, typename R, typename... Args> | ||
933 | struct fx_traits<R (__stdcall T::*)(Args...) const& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
934 | typedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept; | ||
935 | }; | ||
936 | |||
937 | /* __stdcall does not work with varargs */ | ||
938 | /*template <typename T, typename R, typename... Args> | ||
939 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
940 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept; | ||
941 | };*/ | ||
942 | |||
943 | template <typename T, typename R, typename... Args> | ||
944 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
945 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept; | ||
946 | }; | ||
947 | |||
948 | /* __stdcall does not work with varargs */ | ||
949 | /*template <typename T, typename R, typename... Args> | ||
950 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
951 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept; | ||
952 | };*/ | ||
953 | |||
954 | template <typename T, typename R, typename... Args> | ||
955 | struct fx_traits<R (__stdcall T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
956 | typedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept; | ||
957 | }; | ||
958 | |||
959 | /* __stdcall does not work with varargs */ | ||
960 | /*template <typename T, typename R, typename... Args> | ||
961 | struct fx_traits<R (__stdcall T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
962 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept; | ||
963 | };*/ | ||
964 | |||
965 | template <typename T, typename R, typename... Args> | ||
966 | struct fx_traits<R (__stdcall T::*)(Args...) const&& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
967 | typedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept; | ||
968 | }; | ||
969 | |||
970 | /* __stdcall does not work with varargs */ | ||
971 | /*template <typename T, typename R, typename... Args> | ||
972 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const&& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
973 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept; | ||
974 | };*/ | ||
975 | |||
976 | template <typename T, typename R, typename... Args> | ||
977 | struct fx_traits<R (__stdcall T::*)(Args...) const volatile&& noexcept, false> : basic_traits<true, false, T, R, Args...> { | ||
978 | typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept; | ||
979 | }; | ||
980 | |||
981 | /* __stdcall does not work with varargs */ | ||
982 | /*template <typename T, typename R, typename... Args> | ||
983 | struct fx_traits<R (__stdcall T::*)(Args..., ...) const volatile&& noexcept, false> : basic_traits<true, true, T, R, Args...> { | ||
984 | typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; | ||
985 | };*/ | ||
986 | #endif // noexcept is part of a function's type | ||
987 | #endif // __stdcall x86 VC++ bug | ||
988 | |||
989 | template <typename Signature> | ||
990 | struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {}; | ||
991 | |||
992 | template <typename Signature, bool b = std::is_member_object_pointer<Signature>::value> | ||
993 | struct callable_traits : fx_traits<std::decay_t<Signature>> { | ||
994 | }; | ||
995 | |||
996 | template <typename R, typename T> | ||
997 | struct callable_traits<R(T::*), true> { | ||
998 | typedef std::conditional_t<std::is_array<R>::value, std::add_lvalue_reference_t<T>, R> return_type; | ||
999 | typedef return_type Arg; | ||
1000 | typedef T object_type; | ||
1001 | using signature_type = R(T::*); | ||
1002 | static const bool is_noexcept = false; | ||
1003 | static const bool is_member_function = false; | ||
1004 | static const std::size_t arity = 1; | ||
1005 | static const std::size_t free_arity = 2; | ||
1006 | typedef std::tuple<Arg> args_tuple; | ||
1007 | typedef types<Arg> args_list; | ||
1008 | typedef types<T, Arg> free_args_list; | ||
1009 | typedef meta::tuple_types<return_type> returns_list; | ||
1010 | typedef return_type(function_type)(T&, return_type); | ||
1011 | typedef return_type(*function_pointer_type)(T&, Arg); | ||
1012 | typedef return_type(*free_function_pointer_type)(T&, Arg); | ||
1013 | template <std::size_t i> | ||
1014 | using arg_at = void_tuple_element_t<i, args_tuple>; | ||
1015 | }; | ||
1016 | |||
1017 | } // namespace meta_detail | ||
1018 | |||
1019 | template <typename Signature> | ||
1020 | struct bind_traits : meta_detail::callable_traits<Signature> {}; | ||
1021 | |||
1022 | template <typename Signature> | ||
1023 | using function_args_t = typename bind_traits<Signature>::args_list; | ||
1024 | |||
1025 | template <typename Signature> | ||
1026 | using function_signature_t = typename bind_traits<Signature>::signature_type; | ||
1027 | |||
1028 | template <typename Signature> | ||
1029 | using function_return_t = typename bind_traits<Signature>::return_type; | ||
1030 | } | ||
1031 | } // namespace sol::meta | ||
1032 | |||
1033 | // end of sol/bind_traits.hpp | ||
1034 | |||
1035 | // beginning of sol/string_view.hpp | ||
1036 | |||
1037 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
1038 | #include <string_view> | ||
1039 | #endif // C++17 features | ||
1040 | #include <functional> | ||
1041 | #if defined(SOL_USE_BOOST) && SOL_USE_BOOST | ||
1042 | #include <boost/functional/hash.hpp> | ||
1043 | #endif | ||
1044 | |||
1045 | namespace sol { | ||
1046 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
1047 | template <typename C, typename T = std::char_traits<C>> | ||
1048 | using basic_string_view = std::basic_string_view<C, T>; | ||
1049 | typedef std::string_view string_view; | ||
1050 | typedef std::wstring_view wstring_view; | ||
1051 | typedef std::u16string_view u16string_view; | ||
1052 | typedef std::u32string_view u32string_view; | ||
1053 | typedef std::hash<std::string_view> string_view_hash; | ||
1054 | #else | ||
1055 | template <typename Char, typename Traits = std::char_traits<Char>> | ||
1056 | struct basic_string_view { | ||
1057 | std::size_t s; | ||
1058 | const Char* p; | ||
1059 | |||
1060 | basic_string_view(const std::string& r) | ||
1061 | : basic_string_view(r.data(), r.size()) { | ||
1062 | } | ||
1063 | basic_string_view(const Char* ptr) | ||
1064 | : basic_string_view(ptr, Traits::length(ptr)) { | ||
1065 | } | ||
1066 | basic_string_view(const Char* ptr, std::size_t sz) | ||
1067 | : s(sz), p(ptr) { | ||
1068 | } | ||
1069 | |||
1070 | static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { | ||
1071 | int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); | ||
1072 | if (result != 0) | ||
1073 | return result; | ||
1074 | if (lhs_sz < rhs_sz) | ||
1075 | return -1; | ||
1076 | if (lhs_sz > rhs_sz) | ||
1077 | return 1; | ||
1078 | return 0; | ||
1079 | } | ||
1080 | |||
1081 | const Char* begin() const { | ||
1082 | return p; | ||
1083 | } | ||
1084 | |||
1085 | const Char* end() const { | ||
1086 | return p + s; | ||
1087 | } | ||
1088 | |||
1089 | const Char* cbegin() const { | ||
1090 | return p; | ||
1091 | } | ||
1092 | |||
1093 | const Char* cend() const { | ||
1094 | return p + s; | ||
1095 | } | ||
1096 | |||
1097 | const Char* data() const { | ||
1098 | return p; | ||
1099 | } | ||
1100 | |||
1101 | std::size_t size() const { | ||
1102 | return s; | ||
1103 | } | ||
1104 | |||
1105 | std::size_t length() const { | ||
1106 | return size(); | ||
1107 | } | ||
1108 | |||
1109 | operator std::basic_string<Char, Traits>() const { | ||
1110 | return std::basic_string<Char, Traits>(data(), size()); | ||
1111 | } | ||
1112 | |||
1113 | bool operator==(const basic_string_view& r) const { | ||
1114 | return compare(p, s, r.data(), r.size()) == 0; | ||
1115 | } | ||
1116 | |||
1117 | bool operator==(const Char* r) const { | ||
1118 | return compare(r, Traits::length(r), p, s) == 0; | ||
1119 | } | ||
1120 | |||
1121 | bool operator==(const std::basic_string<Char, Traits>& r) const { | ||
1122 | return compare(r.data(), r.size(), p, s) == 0; | ||
1123 | } | ||
1124 | |||
1125 | bool operator!=(const basic_string_view& r) const { | ||
1126 | return !(*this == r); | ||
1127 | } | ||
1128 | |||
1129 | bool operator!=(const char* r) const { | ||
1130 | return !(*this == r); | ||
1131 | } | ||
1132 | |||
1133 | bool operator!=(const std::basic_string<Char, Traits>& r) const { | ||
1134 | return !(*this == r); | ||
1135 | } | ||
1136 | }; | ||
1137 | |||
1138 | template <typename Ch, typename Tr = std::char_traits<Ch>> | ||
1139 | struct basic_string_view_hash { | ||
1140 | typedef basic_string_view<Ch, Tr> argument_type; | ||
1141 | typedef std::size_t result_type; | ||
1142 | |||
1143 | template <typename Al> | ||
1144 | result_type operator()(const std::basic_string<Ch, Tr, Al>& r) const { | ||
1145 | return (*this)(argument_type(r.c_str(), r.size())); | ||
1146 | } | ||
1147 | |||
1148 | result_type operator()(const argument_type& r) const { | ||
1149 | #if defined(SOL_USE_BOOST) && SOL_USE_BOOST | ||
1150 | return boost::hash_range(r.begin(), r.end()); | ||
1151 | #else | ||
1152 | // Modified, from libstdc++ | ||
1153 | // An implementation attempt at Fowler No Voll, 1a. | ||
1154 | // Supposedly, used in MSVC, | ||
1155 | // GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...? | ||
1156 | // But, well. Can't win them all, right? | ||
1157 | // This should normally only apply when NOT using boost, | ||
1158 | // so this should almost never be tapped into... | ||
1159 | std::size_t hash = 0; | ||
1160 | const unsigned char* cptr = reinterpret_cast<const unsigned char*>(r.data()); | ||
1161 | for (std::size_t sz = r.size(); sz != 0; --sz) { | ||
1162 | hash ^= static_cast<size_t>(*cptr++); | ||
1163 | hash *= static_cast<size_t>(1099511628211ULL); | ||
1164 | } | ||
1165 | return hash; | ||
1166 | #endif | ||
1167 | } | ||
1168 | }; | ||
1169 | } // namespace sol | ||
1170 | |||
1171 | namespace std { | ||
1172 | template <typename Ch, typename Tr> | ||
1173 | struct hash< ::sol::basic_string_view<Ch, Tr> > : ::sol::basic_string_view_hash<Ch, Tr> {}; | ||
1174 | } // namespace std | ||
1175 | |||
1176 | namespace sol { | ||
1177 | using string_view = basic_string_view<char>; | ||
1178 | using wstring_view = basic_string_view<wchar_t>; | ||
1179 | using u16string_view = basic_string_view<char16_t>; | ||
1180 | using u32string_view = basic_string_view<char32_t>; | ||
1181 | using string_view_hash = std::hash<string_view>; | ||
1182 | #endif // C++17 Support | ||
1183 | } // namespace sol | ||
1184 | |||
1185 | // end of sol/string_view.hpp | ||
1186 | |||
1187 | #include <type_traits> | ||
1188 | #include <cstdint> | ||
1189 | #include <memory> | ||
1190 | #include <iterator> | ||
1191 | #include <iosfwd> | ||
1192 | |||
1193 | namespace sol { | ||
1194 | template <std::size_t I> | ||
1195 | using index_value = std::integral_constant<std::size_t, I>; | ||
1196 | |||
1197 | namespace meta { | ||
1198 | template <typename T> | ||
1199 | struct identity { typedef T type; }; | ||
1200 | |||
1201 | template <typename T> | ||
1202 | using identity_t = typename identity<T>::type; | ||
1203 | |||
1204 | template <typename... Args> | ||
1205 | struct is_tuple : std::false_type {}; | ||
1206 | |||
1207 | template <typename... Args> | ||
1208 | struct is_tuple<std::tuple<Args...>> : std::true_type {}; | ||
1209 | |||
1210 | template <typename T> | ||
1211 | struct is_builtin_type : std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value> {}; | ||
1212 | |||
1213 | template <typename T> | ||
1214 | struct unwrapped { | ||
1215 | typedef T type; | ||
1216 | }; | ||
1217 | |||
1218 | template <typename T> | ||
1219 | struct unwrapped<std::reference_wrapper<T>> { | ||
1220 | typedef T type; | ||
1221 | }; | ||
1222 | |||
1223 | template <typename T> | ||
1224 | using unwrapped_t = typename unwrapped<T>::type; | ||
1225 | |||
1226 | template <typename T> | ||
1227 | struct unwrap_unqualified : unwrapped<unqualified_t<T>> {}; | ||
1228 | |||
1229 | template <typename T> | ||
1230 | using unwrap_unqualified_t = typename unwrap_unqualified<T>::type; | ||
1231 | |||
1232 | template <typename T> | ||
1233 | struct remove_member_pointer; | ||
1234 | |||
1235 | template <typename R, typename T> | ||
1236 | struct remove_member_pointer<R T::*> { | ||
1237 | typedef R type; | ||
1238 | }; | ||
1239 | |||
1240 | template <typename R, typename T> | ||
1241 | struct remove_member_pointer<R T::*const> { | ||
1242 | typedef R type; | ||
1243 | }; | ||
1244 | |||
1245 | template <typename T> | ||
1246 | using remove_member_pointer_t = remove_member_pointer<T>; | ||
1247 | |||
1248 | namespace meta_detail { | ||
1249 | template <typename T, template <typename...> class Templ> | ||
1250 | struct is_specialization_of : std::false_type {}; | ||
1251 | template <typename... T, template <typename...> class Templ> | ||
1252 | struct is_specialization_of<Templ<T...>, Templ> : std::true_type {}; | ||
1253 | } | ||
1254 | |||
1255 | template <typename T, template <typename...> class Templ> | ||
1256 | using is_specialization_of = meta_detail::is_specialization_of<std::remove_cv_t<T>, Templ>; | ||
1257 | |||
1258 | template <class T, class...> | ||
1259 | struct all_same : std::true_type {}; | ||
1260 | |||
1261 | template <class T, class U, class... Args> | ||
1262 | struct all_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value && all_same<T, Args...>::value> {}; | ||
1263 | |||
1264 | template <class T, class...> | ||
1265 | struct any_same : std::false_type {}; | ||
1266 | |||
1267 | template <class T, class U, class... Args> | ||
1268 | struct any_same<T, U, Args...> : std::integral_constant<bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {}; | ||
1269 | |||
1270 | template <bool B> | ||
1271 | using boolean = std::integral_constant<bool, B>; | ||
1272 | |||
1273 | template <typename T> | ||
1274 | using invoke_t = typename T::type; | ||
1275 | |||
1276 | template <typename T> | ||
1277 | using invoke_b = boolean<T::value>; | ||
1278 | |||
1279 | template <typename T> | ||
1280 | using neg = boolean<!T::value>; | ||
1281 | |||
1282 | template <typename Condition, typename Then, typename Else> | ||
1283 | using condition = std::conditional_t<Condition::value, Then, Else>; | ||
1284 | |||
1285 | template <typename... Args> | ||
1286 | struct all : boolean<true> {}; | ||
1287 | |||
1288 | template <typename T, typename... Args> | ||
1289 | struct all<T, Args...> : condition<T, all<Args...>, boolean<false>> {}; | ||
1290 | |||
1291 | template <typename... Args> | ||
1292 | struct any : boolean<false> {}; | ||
1293 | |||
1294 | template <typename T, typename... Args> | ||
1295 | struct any<T, Args...> : condition<T, boolean<true>, any<Args...>> {}; | ||
1296 | |||
1297 | enum class enable_t { | ||
1298 | _ | ||
1299 | }; | ||
1300 | |||
1301 | constexpr const auto enabler = enable_t::_; | ||
1302 | |||
1303 | template <bool value, typename T = void> | ||
1304 | using disable_if_t = std::enable_if_t<!value, T>; | ||
1305 | |||
1306 | template <typename... Args> | ||
1307 | using enable = std::enable_if_t<all<Args...>::value, enable_t>; | ||
1308 | |||
1309 | template <typename... Args> | ||
1310 | using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>; | ||
1311 | |||
1312 | template <typename... Args> | ||
1313 | using enable_any = std::enable_if_t<any<Args...>::value, enable_t>; | ||
1314 | |||
1315 | template <typename... Args> | ||
1316 | using disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>; | ||
1317 | |||
1318 | template <typename V, typename... Vs> | ||
1319 | struct find_in_pack_v : boolean<false> {}; | ||
1320 | |||
1321 | template <typename V, typename Vs1, typename... Vs> | ||
1322 | struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> {}; | ||
1323 | |||
1324 | namespace meta_detail { | ||
1325 | template <std::size_t I, typename T, typename... Args> | ||
1326 | struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> {}; | ||
1327 | |||
1328 | template <std::size_t I, typename T, typename T1, typename... Args> | ||
1329 | struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> {}; | ||
1330 | } // namespace meta_detail | ||
1331 | |||
1332 | template <typename T, typename... Args> | ||
1333 | struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> {}; | ||
1334 | |||
1335 | template <typename T, typename List> | ||
1336 | struct index_in : meta_detail::index_in_pack<0, T, List> {}; | ||
1337 | |||
1338 | template <typename T, typename... Args> | ||
1339 | struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> {}; | ||
1340 | |||
1341 | template <std::size_t I, typename... Args> | ||
1342 | struct at_in_pack {}; | ||
1343 | |||
1344 | template <std::size_t I, typename... Args> | ||
1345 | using at_in_pack_t = typename at_in_pack<I, Args...>::type; | ||
1346 | |||
1347 | template <std::size_t I, typename Arg, typename... Args> | ||
1348 | struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {}; | ||
1349 | |||
1350 | template <typename Arg, typename... Args> | ||
1351 | struct at_in_pack<0, Arg, Args...> { typedef Arg type; }; | ||
1352 | |||
1353 | namespace meta_detail { | ||
1354 | template <std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts> | ||
1355 | struct count_for_pack : std::integral_constant<std::size_t, 0> {}; | ||
1356 | template <std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts> | ||
1357 | struct count_for_pack<Limit, I, Pred, T, Ts...> : std::conditional_t < sizeof...(Ts) | ||
1358 | == 0 | ||
1359 | || Limit<2, | ||
1360 | std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>, | ||
1361 | count_for_pack<Limit - 1, I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>> {}; | ||
1362 | template <std::size_t I, template <typename...> class Pred, typename... Ts> | ||
1363 | struct count_2_for_pack : std::integral_constant<std::size_t, 0> {}; | ||
1364 | template <std::size_t I, template <typename...> class Pred, typename T, typename U, typename... Ts> | ||
1365 | struct count_2_for_pack<I, Pred, T, U, Ts...> : std::conditional_t<sizeof...(Ts) == 0, | ||
1366 | std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>, | ||
1367 | count_2_for_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>> {}; | ||
1368 | } // namespace meta_detail | ||
1369 | |||
1370 | template <template <typename...> class Pred, typename... Ts> | ||
1371 | struct count_for_pack : meta_detail::count_for_pack<sizeof...(Ts), 0, Pred, Ts...> {}; | ||
1372 | |||
1373 | template <template <typename...> class Pred, typename List> | ||
1374 | struct count_for; | ||
1375 | |||
1376 | template <template <typename...> class Pred, typename... Args> | ||
1377 | struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {}; | ||
1378 | |||
1379 | template <std::size_t Limit, template <typename...> class Pred, typename... Ts> | ||
1380 | struct count_for_to_pack : meta_detail::count_for_pack<Limit, 0, Pred, Ts...> {}; | ||
1381 | |||
1382 | template <template <typename...> class Pred, typename... Ts> | ||
1383 | struct count_2_for_pack : meta_detail::count_2_for_pack<0, Pred, Ts...> {}; | ||
1384 | |||
1385 | template <typename... Args> | ||
1386 | struct return_type { | ||
1387 | typedef std::tuple<Args...> type; | ||
1388 | }; | ||
1389 | |||
1390 | template <typename T> | ||
1391 | struct return_type<T> { | ||
1392 | typedef T type; | ||
1393 | }; | ||
1394 | |||
1395 | template <> | ||
1396 | struct return_type<> { | ||
1397 | typedef void type; | ||
1398 | }; | ||
1399 | |||
1400 | template <typename... Args> | ||
1401 | using return_type_t = typename return_type<Args...>::type; | ||
1402 | |||
1403 | namespace meta_detail { | ||
1404 | template <typename> | ||
1405 | struct always_true : std::true_type {}; | ||
1406 | struct is_invokable_tester { | ||
1407 | template <typename Fun, typename... Args> | ||
1408 | static always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int); | ||
1409 | template <typename...> | ||
1410 | static std::false_type test(...); | ||
1411 | }; | ||
1412 | } // namespace meta_detail | ||
1413 | |||
1414 | template <typename T> | ||
1415 | struct is_invokable; | ||
1416 | template <typename Fun, typename... Args> | ||
1417 | struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) {}; | ||
1418 | |||
1419 | namespace meta_detail { | ||
1420 | |||
1421 | template <typename T, typename = void> | ||
1422 | struct is_callable : std::is_function<std::remove_pointer_t<T>> {}; | ||
1423 | |||
1424 | template <typename T> | ||
1425 | struct is_callable<T, std::enable_if_t<std::is_final<unqualified_t<T>>::value | ||
1426 | && std::is_class<unqualified_t<T>>::value | ||
1427 | && std::is_same<decltype(void(&T::operator())), void>::value>> { | ||
1428 | |||
1429 | }; | ||
1430 | |||
1431 | template <typename T> | ||
1432 | struct is_callable<T, std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value && std::is_destructible<unqualified_t<T>>::value>> { | ||
1433 | using yes = char; | ||
1434 | using no = struct { char s[2]; }; | ||
1435 | |||
1436 | struct F { | ||
1437 | void operator()(); | ||
1438 | }; | ||
1439 | struct Derived : T, F {}; | ||
1440 | template <typename U, U> | ||
1441 | struct Check; | ||
1442 | |||
1443 | template <typename V> | ||
1444 | static no test(Check<void (F::*)(), &V::operator()>*); | ||
1445 | |||
1446 | template <typename> | ||
1447 | static yes test(...); | ||
1448 | |||
1449 | static const bool value = sizeof(test<Derived>(0)) == sizeof(yes); | ||
1450 | }; | ||
1451 | |||
1452 | template <typename T> | ||
1453 | struct is_callable<T, std::enable_if_t<!std::is_final<unqualified_t<T>>::value && std::is_class<unqualified_t<T>>::value && !std::is_destructible<unqualified_t<T>>::value>> { | ||
1454 | using yes = char; | ||
1455 | using no = struct { char s[2]; }; | ||
1456 | |||
1457 | struct F { | ||
1458 | void operator()(); | ||
1459 | }; | ||
1460 | struct Derived : T, F { | ||
1461 | ~Derived() = delete; | ||
1462 | }; | ||
1463 | template <typename U, U> | ||
1464 | struct Check; | ||
1465 | |||
1466 | template <typename V> | ||
1467 | static no test(Check<void (F::*)(), &V::operator()>*); | ||
1468 | |||
1469 | template <typename> | ||
1470 | static yes test(...); | ||
1471 | |||
1472 | static const bool value = sizeof(test<Derived>(0)) == sizeof(yes); | ||
1473 | }; | ||
1474 | |||
1475 | struct has_begin_end_impl { | ||
1476 | template <typename T, typename U = unqualified_t<T>, | ||
1477 | typename B = decltype(std::declval<U&>().begin()), | ||
1478 | typename E = decltype(std::declval<U&>().end())> | ||
1479 | static std::true_type test(int); | ||
1480 | |||
1481 | template <typename...> | ||
1482 | static std::false_type test(...); | ||
1483 | }; | ||
1484 | |||
1485 | struct has_key_type_impl { | ||
1486 | template <typename T, typename U = unqualified_t<T>, | ||
1487 | typename V = typename U::key_type> | ||
1488 | static std::true_type test(int); | ||
1489 | |||
1490 | template <typename...> | ||
1491 | static std::false_type test(...); | ||
1492 | }; | ||
1493 | |||
1494 | struct has_mapped_type_impl { | ||
1495 | template <typename T, typename U = unqualified_t<T>, | ||
1496 | typename V = typename U::mapped_type> | ||
1497 | static std::true_type test(int); | ||
1498 | |||
1499 | template <typename...> | ||
1500 | static std::false_type test(...); | ||
1501 | }; | ||
1502 | |||
1503 | struct has_value_type_impl { | ||
1504 | template <typename T, typename U = unqualified_t<T>, | ||
1505 | typename V = typename U::value_type> | ||
1506 | static std::true_type test(int); | ||
1507 | |||
1508 | template <typename...> | ||
1509 | static std::false_type test(...); | ||
1510 | }; | ||
1511 | |||
1512 | struct has_iterator_impl { | ||
1513 | template <typename T, typename U = unqualified_t<T>, | ||
1514 | typename V = typename U::iterator> | ||
1515 | static std::true_type test(int); | ||
1516 | |||
1517 | template <typename...> | ||
1518 | static std::false_type test(...); | ||
1519 | }; | ||
1520 | |||
1521 | struct has_key_value_pair_impl { | ||
1522 | template <typename T, typename U = unqualified_t<T>, | ||
1523 | typename V = typename U::value_type, | ||
1524 | typename F = decltype(std::declval<V&>().first), | ||
1525 | typename S = decltype(std::declval<V&>().second)> | ||
1526 | static std::true_type test(int); | ||
1527 | |||
1528 | template <typename...> | ||
1529 | static std::false_type test(...); | ||
1530 | }; | ||
1531 | |||
1532 | template <typename T> | ||
1533 | struct has_push_back_test { | ||
1534 | private: | ||
1535 | typedef std::array<char, 1> one; | ||
1536 | typedef std::array<char, 2> two; | ||
1537 | |||
1538 | template <typename C> | ||
1539 | static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); | ||
1540 | template <typename C> | ||
1541 | static two test(...); | ||
1542 | |||
1543 | public: | ||
1544 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
1545 | }; | ||
1546 | |||
1547 | template <typename T> | ||
1548 | struct has_insert_test { | ||
1549 | private: | ||
1550 | typedef std::array<char, 1> one; | ||
1551 | typedef std::array<char, 2> two; | ||
1552 | |||
1553 | template <typename C> | ||
1554 | static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); | ||
1555 | template <typename C> | ||
1556 | static two test(...); | ||
1557 | |||
1558 | public: | ||
1559 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
1560 | }; | ||
1561 | |||
1562 | template <typename T> | ||
1563 | struct has_insert_after_test { | ||
1564 | private: | ||
1565 | typedef std::array<char, 1> one; | ||
1566 | typedef std::array<char, 2> two; | ||
1567 | |||
1568 | template <typename C> | ||
1569 | static one test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); | ||
1570 | template <typename C> | ||
1571 | static two test(...); | ||
1572 | |||
1573 | public: | ||
1574 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
1575 | }; | ||
1576 | |||
1577 | template <typename T> | ||
1578 | struct has_size_test { | ||
1579 | private: | ||
1580 | typedef std::array<char, 1> one; | ||
1581 | typedef std::array<char, 2> two; | ||
1582 | |||
1583 | template <typename C> | ||
1584 | static one test(decltype(std::declval<C>().size())*); | ||
1585 | template <typename C> | ||
1586 | static two test(...); | ||
1587 | |||
1588 | public: | ||
1589 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
1590 | }; | ||
1591 | |||
1592 | template <typename T> | ||
1593 | struct has_to_string_test { | ||
1594 | private: | ||
1595 | typedef std::array<char, 1> one; | ||
1596 | typedef std::array<char, 2> two; | ||
1597 | |||
1598 | template <typename C> | ||
1599 | static one test(decltype(std::declval<C>().to_string())*); | ||
1600 | template <typename C> | ||
1601 | static two test(...); | ||
1602 | |||
1603 | public: | ||
1604 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
1605 | }; | ||
1606 | #if defined(_MSC_VER) && _MSC_VER <= 1910 | ||
1607 | template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())> | ||
1608 | std::true_type supports_op_less_test(std::reference_wrapper<T>, std::reference_wrapper<U>); | ||
1609 | std::false_type supports_op_less_test(...); | ||
1610 | template <typename T, typename U, typename = decltype(std::declval<T&>() == std::declval<U&>())> | ||
1611 | std::true_type supports_op_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>); | ||
1612 | std::false_type supports_op_equal_test(...); | ||
1613 | template <typename T, typename U, typename = decltype(std::declval<T&>() <= std::declval<U&>())> | ||
1614 | std::true_type supports_op_less_equal_test(std::reference_wrapper<T>, std::reference_wrapper<U>); | ||
1615 | std::false_type supports_op_less_equal_test(...); | ||
1616 | template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())> | ||
1617 | std::true_type supports_ostream_op(std::reference_wrapper<T>, std::reference_wrapper<OS>); | ||
1618 | std::false_type supports_ostream_op(...); | ||
1619 | template <typename T, typename = decltype(to_string(std::declval<T&>()))> | ||
1620 | std::true_type supports_adl_to_string(std::reference_wrapper<T>); | ||
1621 | std::false_type supports_adl_to_string(...); | ||
1622 | #else | ||
1623 | template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())> | ||
1624 | std::true_type supports_op_less_test(const T&, const U&); | ||
1625 | std::false_type supports_op_less_test(...); | ||
1626 | template <typename T, typename U, typename = decltype(std::declval<T&>() == std::declval<U&>())> | ||
1627 | std::true_type supports_op_equal_test(const T&, const U&); | ||
1628 | std::false_type supports_op_equal_test(...); | ||
1629 | template <typename T, typename U, typename = decltype(std::declval<T&>() <= std::declval<U&>())> | ||
1630 | std::true_type supports_op_less_equal_test(const T&, const U&); | ||
1631 | std::false_type supports_op_less_equal_test(...); | ||
1632 | template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())> | ||
1633 | std::true_type supports_ostream_op(const T&, const OS&); | ||
1634 | std::false_type supports_ostream_op(...); | ||
1635 | template <typename T, typename = decltype(to_string(std::declval<T&>()))> | ||
1636 | std::true_type supports_adl_to_string(const T&); | ||
1637 | std::false_type supports_adl_to_string(...); | ||
1638 | #endif | ||
1639 | |||
1640 | template <typename T, bool b> | ||
1641 | struct is_matched_lookup_impl : std::false_type {}; | ||
1642 | template <typename T> | ||
1643 | struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> {}; | ||
1644 | } // namespace meta_detail | ||
1645 | |||
1646 | #if defined(_MSC_VER) && _MSC_VER <= 1910 | ||
1647 | template <typename T, typename U = T> | ||
1648 | using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>()))); | ||
1649 | template <typename T, typename U = T> | ||
1650 | using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>()))); | ||
1651 | template <typename T, typename U = T> | ||
1652 | using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>()))); | ||
1653 | template <typename T, typename U = std::ostream> | ||
1654 | using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval<T&>()), std::ref(std::declval<U&>()))); | ||
1655 | template <typename T> | ||
1656 | using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval<T&>()))); | ||
1657 | #else | ||
1658 | template <typename T, typename U = T> | ||
1659 | using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>())); | ||
1660 | template <typename T, typename U = T> | ||
1661 | using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>())); | ||
1662 | template <typename T, typename U = T> | ||
1663 | using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>())); | ||
1664 | template <typename T, typename U = std::ostream> | ||
1665 | using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>())); | ||
1666 | template <typename T> | ||
1667 | using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval<T&>())); | ||
1668 | #endif | ||
1669 | template <typename T> | ||
1670 | using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>; | ||
1671 | |||
1672 | template <typename T> | ||
1673 | struct is_callable : boolean<meta_detail::is_callable<T>::value> {}; | ||
1674 | |||
1675 | template <typename T> | ||
1676 | struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {}; | ||
1677 | |||
1678 | template <typename T> | ||
1679 | struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {}; | ||
1680 | |||
1681 | template <typename T> | ||
1682 | struct has_key_type : decltype(meta_detail::has_key_type_impl::test<T>(0)) {}; | ||
1683 | |||
1684 | template <typename T> | ||
1685 | struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) {}; | ||
1686 | |||
1687 | template <typename T> | ||
1688 | struct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) {}; | ||
1689 | |||
1690 | template <typename T> | ||
1691 | struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) {}; | ||
1692 | |||
1693 | template <typename T> | ||
1694 | using has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>; | ||
1695 | |||
1696 | template <typename T> | ||
1697 | using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>; | ||
1698 | |||
1699 | template <typename T> | ||
1700 | using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>; | ||
1701 | |||
1702 | template <typename T> | ||
1703 | using has_size = meta::boolean<meta_detail::has_size_test<T>::value || meta_detail::has_size_test<const T>::value>; | ||
1704 | |||
1705 | template <typename T> | ||
1706 | struct is_associative : meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>> {}; | ||
1707 | |||
1708 | template <typename T> | ||
1709 | struct is_lookup : meta::all<has_key_type<T>, has_value_type<T>> {}; | ||
1710 | |||
1711 | template <typename T> | ||
1712 | struct is_matched_lookup : meta_detail::is_matched_lookup_impl<T, is_lookup<T>::value> {}; | ||
1713 | |||
1714 | template <typename T> | ||
1715 | using is_string_like = any< | ||
1716 | is_specialization_of<meta::unqualified_t<T>, std::basic_string>, | ||
1717 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
1718 | is_specialization_of<meta::unqualified_t<T>, std::basic_string_view>, | ||
1719 | #else | ||
1720 | is_specialization_of<meta::unqualified_t<T>, basic_string_view>, | ||
1721 | #endif | ||
1722 | meta::all<std::is_array<unqualified_t<T>>, meta::any_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char, char16_t, char32_t, wchar_t>> | ||
1723 | >; | ||
1724 | |||
1725 | template <typename T> | ||
1726 | using is_string_constructible = any< | ||
1727 | meta::all<std::is_array<unqualified_t<T>>, std::is_same<meta::unqualified_t<std::remove_all_extents_t<meta::unqualified_t<T>>>, char>>, | ||
1728 | std::is_same<unqualified_t<T>, const char*>, | ||
1729 | std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>> | ||
1730 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
1731 | , std::is_same<unqualified_t<T>, std::string_view> | ||
1732 | #endif | ||
1733 | >; | ||
1734 | |||
1735 | template <typename T> | ||
1736 | struct is_pair : std::false_type {}; | ||
1737 | |||
1738 | template <typename T1, typename T2> | ||
1739 | struct is_pair<std::pair<T1, T2>> : std::true_type {}; | ||
1740 | |||
1741 | template <typename T> | ||
1742 | using is_c_str = any< | ||
1743 | std::is_same<std::decay_t<unqualified_t<T>>, const char*>, | ||
1744 | std::is_same<std::decay_t<unqualified_t<T>>, char*>, | ||
1745 | std::is_same<unqualified_t<T>, std::string>>; | ||
1746 | |||
1747 | template <typename T> | ||
1748 | struct is_move_only : all< | ||
1749 | neg<std::is_reference<T>>, | ||
1750 | neg<std::is_copy_constructible<unqualified_t<T>>>, | ||
1751 | std::is_move_constructible<unqualified_t<T>>> {}; | ||
1752 | |||
1753 | template <typename T> | ||
1754 | using is_not_move_only = neg<is_move_only<T>>; | ||
1755 | |||
1756 | namespace meta_detail { | ||
1757 | template <typename T, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>> = meta::enabler> | ||
1758 | decltype(auto) force_tuple(T&& x) { | ||
1759 | return std::tuple<std::decay_t<T>>(std::forward<T>(x)); | ||
1760 | } | ||
1761 | |||
1762 | template <typename T, meta::enable<meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>> = meta::enabler> | ||
1763 | decltype(auto) force_tuple(T&& x) { | ||
1764 | return std::forward<T>(x); | ||
1765 | } | ||
1766 | } // namespace meta_detail | ||
1767 | |||
1768 | template <typename... X> | ||
1769 | decltype(auto) tuplefy(X&&... x) { | ||
1770 | return std::tuple_cat(meta_detail::force_tuple(std::forward<X>(x))...); | ||
1771 | } | ||
1772 | |||
1773 | template <typename T, typename = void> | ||
1774 | struct iterator_tag { | ||
1775 | using type = std::input_iterator_tag; | ||
1776 | }; | ||
1777 | |||
1778 | template <typename T> | ||
1779 | struct iterator_tag<T, std::conditional_t<false, typename T::iterator_category, void>> { | ||
1780 | using type = typename T::iterator_category; | ||
1781 | }; | ||
1782 | |||
1783 | } // namespace meta | ||
1784 | |||
1785 | namespace detail { | ||
1786 | template <typename T> | ||
1787 | struct is_pointer_like : std::is_pointer<T> {}; | ||
1788 | template <typename T, typename D> | ||
1789 | struct is_pointer_like<std::unique_ptr<T, D>> : std::true_type {}; | ||
1790 | template <typename T> | ||
1791 | struct is_pointer_like<std::shared_ptr<T>> : std::true_type {}; | ||
1792 | |||
1793 | template <std::size_t I, typename Tuple> | ||
1794 | decltype(auto) forward_get(Tuple&& tuple) { | ||
1795 | return std::forward<meta::tuple_element_t<I, Tuple>>(std::get<I>(tuple)); | ||
1796 | } | ||
1797 | |||
1798 | template <std::size_t... I, typename Tuple> | ||
1799 | auto forward_tuple_impl(std::index_sequence<I...>, Tuple&& tuple) -> decltype(std::tuple<decltype(forward_get<I>(tuple))...>(forward_get<I>(tuple)...)) { | ||
1800 | return std::tuple<decltype(forward_get<I>(tuple))...>(std::move(std::get<I>(tuple))...); | ||
1801 | } | ||
1802 | |||
1803 | template <typename Tuple> | ||
1804 | auto forward_tuple(Tuple&& tuple) { | ||
1805 | auto x = forward_tuple_impl(std::make_index_sequence<std::tuple_size<meta::unqualified_t<Tuple>>::value>(), std::forward<Tuple>(tuple)); | ||
1806 | return x; | ||
1807 | } | ||
1808 | |||
1809 | template <typename T> | ||
1810 | auto unwrap(T&& item) -> decltype(std::forward<T>(item)) { | ||
1811 | return std::forward<T>(item); | ||
1812 | } | ||
1813 | |||
1814 | template <typename T> | ||
1815 | T& unwrap(std::reference_wrapper<T> arg) { | ||
1816 | return arg.get(); | ||
1817 | } | ||
1818 | |||
1819 | template <typename T, meta::enable<meta::neg<is_pointer_like<meta::unqualified_t<T>>>> = meta::enabler> | ||
1820 | auto deref(T&& item) -> decltype(std::forward<T>(item)) { | ||
1821 | return std::forward<T>(item); | ||
1822 | } | ||
1823 | |||
1824 | template <typename T, meta::enable<is_pointer_like<meta::unqualified_t<T>>> = meta::enabler> | ||
1825 | inline auto deref(T&& item) -> decltype(*std::forward<T>(item)) { | ||
1826 | return *std::forward<T>(item); | ||
1827 | } | ||
1828 | |||
1829 | template <typename T, meta::disable<is_pointer_like<meta::unqualified_t<T>>, meta::neg<std::is_pointer<meta::unqualified_t<T>>>> = meta::enabler> | ||
1830 | auto deref_non_pointer(T&& item) -> decltype(std::forward<T>(item)) { | ||
1831 | return std::forward<T>(item); | ||
1832 | } | ||
1833 | |||
1834 | template <typename T, meta::enable<is_pointer_like<meta::unqualified_t<T>>, meta::neg<std::is_pointer<meta::unqualified_t<T>>>> = meta::enabler> | ||
1835 | inline auto deref_non_pointer(T&& item) -> decltype(*std::forward<T>(item)) { | ||
1836 | return *std::forward<T>(item); | ||
1837 | } | ||
1838 | |||
1839 | template <typename T> | ||
1840 | inline T* ptr(T& val) { | ||
1841 | return std::addressof(val); | ||
1842 | } | ||
1843 | |||
1844 | template <typename T> | ||
1845 | inline T* ptr(std::reference_wrapper<T> val) { | ||
1846 | return std::addressof(val.get()); | ||
1847 | } | ||
1848 | |||
1849 | template <typename T> | ||
1850 | inline T* ptr(T* val) { | ||
1851 | return val; | ||
1852 | } | ||
1853 | } // namespace detail | ||
1854 | } // namespace sol | ||
1855 | |||
1856 | // end of sol/traits.hpp | ||
1857 | |||
1858 | // beginning of sol/function.hpp | ||
1859 | |||
1860 | // beginning of sol/stack.hpp | ||
1861 | |||
1862 | // beginning of sol/trampoline.hpp | ||
1863 | |||
1864 | // beginning of sol/types.hpp | ||
1865 | |||
1866 | // beginning of sol/optional.hpp | ||
1867 | |||
1868 | // beginning of sol/compatibility.hpp | ||
1869 | |||
1870 | // beginning of sol/compatibility/version.hpp | ||
1871 | |||
1872 | #if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA | ||
1873 | #include <lua.h> | ||
1874 | #include <lualib.h> | ||
1875 | #include <lauxlib.h> | ||
1876 | #if defined(SOL_USING_CXX_LUAJIT) && SOL_USING_CXX_LUAJIT | ||
1877 | #include <luajit.h> | ||
1878 | #endif // C++ LuaJIT ... whatever that means | ||
1879 | #if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !(SOL_EXCEPTIONS_SAFE_PROPAGATION)) && (!defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE) || !(SOL_EXCEPTIONS_ALWAYS_UNSAFE)) | ||
1880 | #define SOL_EXCEPTIONS_SAFE_PROPAGATION 1 | ||
1881 | #endif // Exceptions can be propagated safely using C++-compiled Lua | ||
1882 | #else | ||
1883 | #include <lua.hpp> | ||
1884 | #endif // C++ Mangling for Lua | ||
1885 | |||
1886 | #ifdef LUAJIT_VERSION | ||
1887 | #ifndef SOL_LUAJIT | ||
1888 | #define SOL_LUAJIT 1 | ||
1889 | #ifndef SOL_LUAJIT_VERSION | ||
1890 | #define SOL_LUAJIT_VERSION LUAJIT_VERSION_NUM | ||
1891 | #endif // SOL_LUAJIT_VERSION definition, if not present | ||
1892 | #endif // sol luajit | ||
1893 | #endif // luajit | ||
1894 | |||
1895 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 | ||
1896 | #define SOL_LUA_VERSION LUA_VERSION_NUM | ||
1897 | #elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | ||
1898 | #define SOL_LUA_VERSION LUA_VERSION_NUM | ||
1899 | #elif !defined(LUA_VERSION_NUM) || !(LUA_VERSION_NUM) | ||
1900 | #define SOL_LUA_VERSION 500 | ||
1901 | #else | ||
1902 | #define SOL_LUA_VERSION 502 | ||
1903 | #endif // Lua Version 502, 501 || luajit, 500 | ||
1904 | |||
1905 | // end of sol/compatibility/version.hpp | ||
1906 | |||
1907 | #if !defined(SOL_NO_COMPAT) || !(SOL_NO_COMPAT) | ||
1908 | |||
1909 | #if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA | ||
1910 | #ifndef COMPAT53_LUA_CPP | ||
1911 | #define COMPAT53_LUA_CPP 1 | ||
1912 | #endif // Build Lua Compat layer as C++ | ||
1913 | #endif | ||
1914 | #ifndef COMPAT53_INCLUDE_SOURCE | ||
1915 | #define COMPAT53_INCLUDE_SOURCE 1 | ||
1916 | #endif // Build Compat Layer Inline | ||
1917 | // beginning of sol/compatibility/compat-5.3.h | ||
1918 | |||
1919 | #ifndef KEPLER_PROJECT_COMPAT53_H_ | ||
1920 | #define KEPLER_PROJECT_COMPAT53_H_ | ||
1921 | |||
1922 | #include <stddef.h> | ||
1923 | #include <limits.h> | ||
1924 | #include <string.h> | ||
1925 | #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) | ||
1926 | extern "C" { | ||
1927 | #endif | ||
1928 | #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) | ||
1929 | } | ||
1930 | #endif | ||
1931 | |||
1932 | #ifndef COMPAT53_PREFIX | ||
1933 | /* we chose this name because many other lua bindings / libs have | ||
1934 | * their own compatibility layer, and that use the compat53 declaration | ||
1935 | * frequently, causing all kinds of linker / compiler issues | ||
1936 | */ | ||
1937 | # define COMPAT53_PREFIX kp_compat53 | ||
1938 | #endif // COMPAT53_PREFIX | ||
1939 | |||
1940 | #ifndef COMPAT53_API | ||
1941 | # if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE | ||
1942 | # if defined(__GNUC__) || defined(__clang__) | ||
1943 | # define COMPAT53_API __attribute__((__unused__)) static | ||
1944 | # else | ||
1945 | # define COMPAT53_API static | ||
1946 | # endif /* Clang/GCC */ | ||
1947 | # else /* COMPAT53_INCLUDE_SOURCE */ | ||
1948 | /* we are not including source, so everything is extern */ | ||
1949 | # define COMPAT53_API extern | ||
1950 | # endif /* COMPAT53_INCLUDE_SOURCE */ | ||
1951 | #endif /* COMPAT53_PREFIX */ | ||
1952 | |||
1953 | #define COMPAT53_CONCAT_HELPER(a, b) a##b | ||
1954 | #define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) | ||
1955 | |||
1956 | /* declarations for Lua 5.1 */ | ||
1957 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | ||
1958 | |||
1959 | /* XXX not implemented: | ||
1960 | * lua_arith (new operators) | ||
1961 | * lua_upvalueid | ||
1962 | * lua_upvaluejoin | ||
1963 | * lua_version | ||
1964 | * lua_yieldk | ||
1965 | */ | ||
1966 | |||
1967 | #ifndef LUA_OK | ||
1968 | # define LUA_OK 0 | ||
1969 | #endif | ||
1970 | #ifndef LUA_OPADD | ||
1971 | # define LUA_OPADD 0 | ||
1972 | #endif | ||
1973 | #ifndef LUA_OPSUB | ||
1974 | # define LUA_OPSUB 1 | ||
1975 | #endif | ||
1976 | #ifndef LUA_OPMUL | ||
1977 | # define LUA_OPMUL 2 | ||
1978 | #endif | ||
1979 | #ifndef LUA_OPDIV | ||
1980 | # define LUA_OPDIV 3 | ||
1981 | #endif | ||
1982 | #ifndef LUA_OPMOD | ||
1983 | # define LUA_OPMOD 4 | ||
1984 | #endif | ||
1985 | #ifndef LUA_OPPOW | ||
1986 | # define LUA_OPPOW 5 | ||
1987 | #endif | ||
1988 | #ifndef LUA_OPUNM | ||
1989 | # define LUA_OPUNM 6 | ||
1990 | #endif | ||
1991 | #ifndef LUA_OPEQ | ||
1992 | # define LUA_OPEQ 0 | ||
1993 | #endif | ||
1994 | #ifndef LUA_OPLT | ||
1995 | # define LUA_OPLT 1 | ||
1996 | #endif | ||
1997 | #ifndef LUA_OPLE | ||
1998 | # define LUA_OPLE 2 | ||
1999 | #endif | ||
2000 | |||
2001 | /* LuaJIT/Lua 5.1 does not have the updated | ||
2002 | * error codes for thread status/function returns (but some patched versions do) | ||
2003 | * define it only if it's not found | ||
2004 | */ | ||
2005 | #if !defined(LUA_ERRGCMM) | ||
2006 | /* Use + 2 because in some versions of Lua (Lua 5.1) | ||
2007 | * LUA_ERRFILE is defined as (LUA_ERRERR+1) | ||
2008 | * so we need to avoid it (LuaJIT might have something at this | ||
2009 | * integer value too) | ||
2010 | */ | ||
2011 | # define LUA_ERRGCMM (LUA_ERRERR + 2) | ||
2012 | #endif /* LUA_ERRGCMM define */ | ||
2013 | |||
2014 | typedef size_t lua_Unsigned; | ||
2015 | |||
2016 | typedef struct luaL_Buffer_53 { | ||
2017 | luaL_Buffer b; /* make incorrect code crash! */ | ||
2018 | char *ptr; | ||
2019 | size_t nelems; | ||
2020 | size_t capacity; | ||
2021 | lua_State *L2; | ||
2022 | } luaL_Buffer_53; | ||
2023 | #define luaL_Buffer luaL_Buffer_53 | ||
2024 | |||
2025 | /* In PUC-Rio 5.1, userdata is a simple FILE* | ||
2026 | * In LuaJIT, it's a struct where the first member is a FILE* | ||
2027 | * We can't support the `closef` member | ||
2028 | */ | ||
2029 | typedef struct luaL_Stream { | ||
2030 | FILE *f; | ||
2031 | } luaL_Stream; | ||
2032 | |||
2033 | #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) | ||
2034 | COMPAT53_API int lua_absindex(lua_State *L, int i); | ||
2035 | |||
2036 | #define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) | ||
2037 | COMPAT53_API void lua_arith(lua_State *L, int op); | ||
2038 | |||
2039 | #define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) | ||
2040 | COMPAT53_API int lua_compare(lua_State *L, int idx1, int idx2, int op); | ||
2041 | |||
2042 | #define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) | ||
2043 | COMPAT53_API void lua_copy(lua_State *L, int from, int to); | ||
2044 | |||
2045 | #define lua_getuservalue(L, i) \ | ||
2046 | (lua_getfenv((L), (i)), lua_type((L), -1)) | ||
2047 | #define lua_setuservalue(L, i) \ | ||
2048 | (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) | ||
2049 | |||
2050 | #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) | ||
2051 | COMPAT53_API void lua_len(lua_State *L, int i); | ||
2052 | |||
2053 | #define lua_pushstring(L, s) \ | ||
2054 | (lua_pushstring((L), (s)), lua_tostring((L), -1)) | ||
2055 | |||
2056 | #define lua_pushlstring(L, s, len) \ | ||
2057 | ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1)) | ||
2058 | |||
2059 | #ifndef luaL_newlibtable | ||
2060 | # define luaL_newlibtable(L, l) \ | ||
2061 | (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) | ||
2062 | #endif | ||
2063 | #ifndef luaL_newlib | ||
2064 | # define luaL_newlib(L, l) \ | ||
2065 | (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) | ||
2066 | #endif | ||
2067 | |||
2068 | #define lua_pushglobaltable(L) \ | ||
2069 | lua_pushvalue((L), LUA_GLOBALSINDEX) | ||
2070 | |||
2071 | #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) | ||
2072 | COMPAT53_API int lua_rawgetp(lua_State *L, int i, const void *p); | ||
2073 | |||
2074 | #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) | ||
2075 | COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); | ||
2076 | |||
2077 | #define lua_rawlen(L, i) lua_objlen((L), (i)) | ||
2078 | |||
2079 | #define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) | ||
2080 | |||
2081 | #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) | ||
2082 | COMPAT53_API lua_Number lua_tonumberx(lua_State *L, int i, int *isnum); | ||
2083 | |||
2084 | #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) | ||
2085 | COMPAT53_API void luaL_checkversion(lua_State *L); | ||
2086 | |||
2087 | #define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) | ||
2088 | COMPAT53_API int lua_load(lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); | ||
2089 | |||
2090 | #define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) | ||
2091 | COMPAT53_API int luaL_loadfilex(lua_State *L, const char *filename, const char *mode); | ||
2092 | |||
2093 | #define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) | ||
2094 | COMPAT53_API int luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); | ||
2095 | |||
2096 | #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) | ||
2097 | COMPAT53_API void luaL_checkstack(lua_State *L, int sp, const char *msg); | ||
2098 | |||
2099 | #define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) | ||
2100 | COMPAT53_API int luaL_getsubtable(lua_State* L, int i, const char *name); | ||
2101 | |||
2102 | #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) | ||
2103 | COMPAT53_API lua_Integer luaL_len(lua_State *L, int i); | ||
2104 | |||
2105 | #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) | ||
2106 | COMPAT53_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup); | ||
2107 | |||
2108 | #define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) | ||
2109 | COMPAT53_API void luaL_setmetatable(lua_State *L, const char *tname); | ||
2110 | |||
2111 | #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) | ||
2112 | COMPAT53_API void *luaL_testudata(lua_State *L, int i, const char *tname); | ||
2113 | |||
2114 | #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) | ||
2115 | COMPAT53_API void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level); | ||
2116 | |||
2117 | #define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) | ||
2118 | COMPAT53_API int luaL_fileresult(lua_State *L, int stat, const char *fname); | ||
2119 | |||
2120 | #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) | ||
2121 | COMPAT53_API int luaL_execresult(lua_State *L, int stat); | ||
2122 | |||
2123 | #define lua_callk(L, na, nr, ctx, cont) \ | ||
2124 | ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) | ||
2125 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ | ||
2126 | ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) | ||
2127 | |||
2128 | #define lua_resume(L, from, nargs) \ | ||
2129 | ((void)(from), lua_resume((L), (nargs))) | ||
2130 | |||
2131 | #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) | ||
2132 | COMPAT53_API void luaL_buffinit(lua_State *L, luaL_Buffer_53 *B); | ||
2133 | |||
2134 | #define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) | ||
2135 | COMPAT53_API char *luaL_prepbuffsize(luaL_Buffer_53 *B, size_t s); | ||
2136 | |||
2137 | #define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) | ||
2138 | COMPAT53_API void luaL_addlstring(luaL_Buffer_53 *B, const char *s, size_t l); | ||
2139 | |||
2140 | #define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) | ||
2141 | COMPAT53_API void luaL_addvalue(luaL_Buffer_53 *B); | ||
2142 | |||
2143 | #define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) | ||
2144 | COMPAT53_API void luaL_pushresult(luaL_Buffer_53 *B); | ||
2145 | |||
2146 | #undef luaL_buffinitsize | ||
2147 | #define luaL_buffinitsize(L, B, s) \ | ||
2148 | (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) | ||
2149 | |||
2150 | #undef luaL_prepbuffer | ||
2151 | #define luaL_prepbuffer(B) \ | ||
2152 | luaL_prepbuffsize((B), LUAL_BUFFERSIZE) | ||
2153 | |||
2154 | #undef luaL_addchar | ||
2155 | #define luaL_addchar(B, c) \ | ||
2156 | ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ | ||
2157 | ((B)->ptr[(B)->nelems++] = (c))) | ||
2158 | |||
2159 | #undef luaL_addsize | ||
2160 | #define luaL_addsize(B, s) \ | ||
2161 | ((B)->nelems += (s)) | ||
2162 | |||
2163 | #undef luaL_addstring | ||
2164 | #define luaL_addstring(B, s) \ | ||
2165 | luaL_addlstring((B), (s), strlen((s))) | ||
2166 | |||
2167 | #undef luaL_pushresultsize | ||
2168 | #define luaL_pushresultsize(B, s) \ | ||
2169 | (luaL_addsize((B), (s)), luaL_pushresult((B))) | ||
2170 | |||
2171 | #if defined(LUA_COMPAT_APIINTCASTS) | ||
2172 | #define lua_pushunsigned(L, n) \ | ||
2173 | lua_pushinteger((L), (lua_Integer)(n)) | ||
2174 | #define lua_tounsignedx(L, i, is) \ | ||
2175 | ((lua_Unsigned)lua_tointegerx((L), (i), (is))) | ||
2176 | #define lua_tounsigned(L, i) \ | ||
2177 | lua_tounsignedx((L), (i), NULL) | ||
2178 | #define luaL_checkunsigned(L, a) \ | ||
2179 | ((lua_Unsigned)luaL_checkinteger((L), (a))) | ||
2180 | #define luaL_optunsigned(L, a, d) \ | ||
2181 | ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) | ||
2182 | #endif | ||
2183 | |||
2184 | #endif /* Lua 5.1 only */ | ||
2185 | |||
2186 | /* declarations for Lua 5.1 and 5.2 */ | ||
2187 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 | ||
2188 | |||
2189 | typedef int lua_KContext; | ||
2190 | |||
2191 | typedef int(*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); | ||
2192 | |||
2193 | #define lua_dump(L, w, d, s) \ | ||
2194 | ((void)(s), lua_dump((L), (w), (d))) | ||
2195 | |||
2196 | #define lua_getfield(L, i, k) \ | ||
2197 | (lua_getfield((L), (i), (k)), lua_type((L), -1)) | ||
2198 | |||
2199 | #define lua_gettable(L, i) \ | ||
2200 | (lua_gettable((L), (i)), lua_type((L), -1)) | ||
2201 | |||
2202 | #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) | ||
2203 | COMPAT53_API int lua_geti(lua_State *L, int index, lua_Integer i); | ||
2204 | |||
2205 | #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) | ||
2206 | COMPAT53_API int lua_isinteger(lua_State *L, int index); | ||
2207 | |||
2208 | #define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) | ||
2209 | COMPAT53_API lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum); | ||
2210 | |||
2211 | #define lua_numbertointeger(n, p) \ | ||
2212 | ((*(p) = (lua_Integer)(n)), 1) | ||
2213 | |||
2214 | #define lua_rawget(L, i) \ | ||
2215 | (lua_rawget((L), (i)), lua_type((L), -1)) | ||
2216 | |||
2217 | #define lua_rawgeti(L, i, n) \ | ||
2218 | (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) | ||
2219 | |||
2220 | #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) | ||
2221 | COMPAT53_API void lua_rotate(lua_State *L, int idx, int n); | ||
2222 | |||
2223 | #define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) | ||
2224 | COMPAT53_API void lua_seti(lua_State *L, int index, lua_Integer i); | ||
2225 | |||
2226 | #define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) | ||
2227 | COMPAT53_API size_t lua_stringtonumber(lua_State *L, const char *s); | ||
2228 | |||
2229 | #define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) | ||
2230 | COMPAT53_API const char *luaL_tolstring(lua_State *L, int idx, size_t *len); | ||
2231 | |||
2232 | #define luaL_getmetafield(L, o, e) \ | ||
2233 | (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) | ||
2234 | |||
2235 | #define luaL_newmetatable(L, tn) \ | ||
2236 | (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) | ||
2237 | |||
2238 | #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) | ||
2239 | COMPAT53_API void luaL_requiref(lua_State *L, const char *modname, | ||
2240 | lua_CFunction openf, int glb); | ||
2241 | |||
2242 | #endif /* Lua 5.1 and Lua 5.2 */ | ||
2243 | |||
2244 | /* declarations for Lua 5.2 */ | ||
2245 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 | ||
2246 | |||
2247 | /* XXX not implemented: | ||
2248 | * lua_isyieldable | ||
2249 | * lua_getextraspace | ||
2250 | * lua_arith (new operators) | ||
2251 | * lua_pushfstring (new formats) | ||
2252 | */ | ||
2253 | |||
2254 | #define lua_getglobal(L, n) \ | ||
2255 | (lua_getglobal((L), (n)), lua_type((L), -1)) | ||
2256 | |||
2257 | #define lua_getuservalue(L, i) \ | ||
2258 | (lua_getuservalue((L), (i)), lua_type((L), -1)) | ||
2259 | |||
2260 | #define lua_pushlstring(L, s, len) \ | ||
2261 | (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))) | ||
2262 | |||
2263 | #define lua_rawgetp(L, i, p) \ | ||
2264 | (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) | ||
2265 | |||
2266 | #define LUA_KFUNCTION(_name) \ | ||
2267 | static int (_name)(lua_State *L, int status, lua_KContext ctx); \ | ||
2268 | static int (_name ## _52)(lua_State *L) { \ | ||
2269 | lua_KContext ctx; \ | ||
2270 | int status = lua_getctx(L, &ctx); \ | ||
2271 | return (_name)(L, status, ctx); \ | ||
2272 | } \ | ||
2273 | static int (_name)(lua_State *L, int status, lua_KContext ctx) | ||
2274 | |||
2275 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ | ||
2276 | lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) | ||
2277 | |||
2278 | #define lua_callk(L, na, nr, ctx, cont) \ | ||
2279 | lua_callk((L), (na), (nr), (ctx), cont ## _52) | ||
2280 | |||
2281 | #define lua_yieldk(L, nr, ctx, cont) \ | ||
2282 | lua_yieldk((L), (nr), (ctx), cont ## _52) | ||
2283 | |||
2284 | #ifdef lua_call | ||
2285 | # undef lua_call | ||
2286 | # define lua_call(L, na, nr) \ | ||
2287 | (lua_callk)((L), (na), (nr), 0, NULL) | ||
2288 | #endif | ||
2289 | |||
2290 | #ifdef lua_pcall | ||
2291 | # undef lua_pcall | ||
2292 | # define lua_pcall(L, na, nr, err) \ | ||
2293 | (lua_pcallk)((L), (na), (nr), (err), 0, NULL) | ||
2294 | #endif | ||
2295 | |||
2296 | #ifdef lua_yield | ||
2297 | # undef lua_yield | ||
2298 | # define lua_yield(L, nr) \ | ||
2299 | (lua_yieldk)((L), (nr), 0, NULL) | ||
2300 | #endif | ||
2301 | |||
2302 | #endif /* Lua 5.2 only */ | ||
2303 | |||
2304 | /* other Lua versions */ | ||
2305 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 503 | ||
2306 | |||
2307 | # error "unsupported Lua version (i.e. not Lua 5.1, 5.2, or 5.3)" | ||
2308 | |||
2309 | #endif /* other Lua versions except 5.1, 5.2, and 5.3 */ | ||
2310 | |||
2311 | /* helper macro for defining continuation functions (for every version | ||
2312 | * *except* Lua 5.2) */ | ||
2313 | #ifndef LUA_KFUNCTION | ||
2314 | #define LUA_KFUNCTION(_name) \ | ||
2315 | static int (_name)(lua_State *L, int status, lua_KContext ctx) | ||
2316 | #endif | ||
2317 | |||
2318 | #if defined(COMPAT53_INCLUDE_SOURCE) && COMPAT53_INCLUDE_SOURCE == 1 | ||
2319 | // beginning of sol/compatibility/compat-5.3.c | ||
2320 | |||
2321 | #include <stdlib.h> | ||
2322 | #include <ctype.h> | ||
2323 | #include <errno.h> | ||
2324 | #include <stdio.h> | ||
2325 | |||
2326 | /* don't compile it again if it already is included via compat53.h */ | ||
2327 | #ifndef KEPLER_PROJECT_COMPAT53_C_ | ||
2328 | #define KEPLER_PROJECT_COMPAT53_C_ | ||
2329 | |||
2330 | /* definitions for Lua 5.1 only */ | ||
2331 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | ||
2332 | |||
2333 | #ifndef COMPAT53_FOPEN_NO_LOCK | ||
2334 | # if defined(_MSC_VER) | ||
2335 | # define COMPAT53_FOPEN_NO_LOCK 1 | ||
2336 | # else /* otherwise */ | ||
2337 | # define COMPAT53_FOPEN_NO_LOCK 0 | ||
2338 | # endif /* VC++ only so far */ | ||
2339 | #endif /* No-lock fopen_s usage if possible */ | ||
2340 | |||
2341 | #if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK | ||
2342 | # include <share.h> | ||
2343 | #endif /* VC++ _fsopen for share-allowed file read */ | ||
2344 | |||
2345 | #ifndef COMPAT53_HAVE_STRERROR_R | ||
2346 | # if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || \ | ||
2347 | (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6)) | ||
2348 | # define COMPAT53_HAVE_STRERROR_R 1 | ||
2349 | # else /* none of the defines matched: define to 0 */ | ||
2350 | # define COMPAT53_HAVE_STRERROR_R 0 | ||
2351 | # endif /* have strerror_r of some form */ | ||
2352 | #endif /* strerror_r */ | ||
2353 | |||
2354 | #ifndef COMPAT53_HAVE_STRERROR_S | ||
2355 | # if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ | ||
2356 | (defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) | ||
2357 | # define COMPAT53_HAVE_STRERROR_S 1 | ||
2358 | # else /* not VC++ or C11 */ | ||
2359 | # define COMPAT53_HAVE_STRERROR_S 0 | ||
2360 | # endif /* strerror_s from VC++ or C11 */ | ||
2361 | #endif /* strerror_s */ | ||
2362 | |||
2363 | #ifndef COMPAT53_LUA_FILE_BUFFER_SIZE | ||
2364 | # define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 | ||
2365 | #endif /* Lua File Buffer Size */ | ||
2366 | |||
2367 | static char* compat53_strerror(int en, char* buff, size_t sz) { | ||
2368 | #if COMPAT53_HAVE_STRERROR_R | ||
2369 | /* use strerror_r here, because it's available on these specific platforms */ | ||
2370 | if (sz > 0) { | ||
2371 | buff[0] = '\0'; | ||
2372 | /* we don't care whether the GNU version or the XSI version is used: */ | ||
2373 | if (strerror_r(en, buff, sz)) { | ||
2374 | /* Yes, we really DO want to ignore the return value! | ||
2375 | * GCC makes that extra hard, not even a (void) cast will do. */ | ||
2376 | } | ||
2377 | if (buff[0] == '\0') { | ||
2378 | /* Buffer is unchanged, so we probably have called GNU strerror_r which | ||
2379 | * returned a static constant string. Chances are that strerror will | ||
2380 | * return the same static constant string and therefore be thread-safe. */ | ||
2381 | return strerror(en); | ||
2382 | } | ||
2383 | } | ||
2384 | return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ | ||
2385 | #elif COMPAT53_HAVE_STRERROR_S | ||
2386 | /* for MSVC and other C11 implementations, use strerror_s since it's | ||
2387 | * provided by default by the libraries */ | ||
2388 | strerror_s(buff, sz, en); | ||
2389 | return buff; | ||
2390 | #else | ||
2391 | /* fallback, but strerror is not guaranteed to be threadsafe due to modifying | ||
2392 | * errno itself and some impls not locking a static buffer for it ... but most | ||
2393 | * known systems have threadsafe errno: this might only change if the locale | ||
2394 | * is changed out from under someone while this function is being called */ | ||
2395 | (void)buff; | ||
2396 | (void)sz; | ||
2397 | return strerror(en); | ||
2398 | #endif | ||
2399 | } | ||
2400 | |||
2401 | COMPAT53_API int lua_absindex(lua_State *L, int i) { | ||
2402 | if (i < 0 && i > LUA_REGISTRYINDEX) | ||
2403 | i += lua_gettop(L) + 1; | ||
2404 | return i; | ||
2405 | } | ||
2406 | |||
2407 | static void compat53_call_lua(lua_State *L, char const code[], size_t len, | ||
2408 | int nargs, int nret) { | ||
2409 | lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); | ||
2410 | if (lua_type(L, -1) != LUA_TFUNCTION) { | ||
2411 | lua_pop(L, 1); | ||
2412 | if (luaL_loadbuffer(L, code, len, "=none")) | ||
2413 | lua_error(L); | ||
2414 | lua_pushvalue(L, -1); | ||
2415 | lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); | ||
2416 | } | ||
2417 | lua_insert(L, -nargs - 1); | ||
2418 | lua_call(L, nargs, nret); | ||
2419 | } | ||
2420 | |||
2421 | static const char compat53_arith_code[] = | ||
2422 | "local op,a,b=...\n" | ||
2423 | "if op==0 then return a+b\n" | ||
2424 | "elseif op==1 then return a-b\n" | ||
2425 | "elseif op==2 then return a*b\n" | ||
2426 | "elseif op==3 then return a/b\n" | ||
2427 | "elseif op==4 then return a%b\n" | ||
2428 | "elseif op==5 then return a^b\n" | ||
2429 | "elseif op==6 then return -a\n" | ||
2430 | "end\n"; | ||
2431 | |||
2432 | COMPAT53_API void lua_arith(lua_State *L, int op) { | ||
2433 | if (op < LUA_OPADD || op > LUA_OPUNM) | ||
2434 | luaL_error(L, "invalid 'op' argument for lua_arith"); | ||
2435 | luaL_checkstack(L, 5, "not enough stack slots"); | ||
2436 | if (op == LUA_OPUNM) | ||
2437 | lua_pushvalue(L, -1); | ||
2438 | lua_pushnumber(L, op); | ||
2439 | lua_insert(L, -3); | ||
2440 | compat53_call_lua(L, compat53_arith_code, | ||
2441 | sizeof(compat53_arith_code) - 1, 3, 1); | ||
2442 | } | ||
2443 | |||
2444 | static const char compat53_compare_code[] = | ||
2445 | "local a,b=...\n" | ||
2446 | "return a<=b\n"; | ||
2447 | |||
2448 | COMPAT53_API int lua_compare(lua_State *L, int idx1, int idx2, int op) { | ||
2449 | int result = 0; | ||
2450 | switch (op) { | ||
2451 | case LUA_OPEQ: | ||
2452 | return lua_equal(L, idx1, idx2); | ||
2453 | case LUA_OPLT: | ||
2454 | return lua_lessthan(L, idx1, idx2); | ||
2455 | case LUA_OPLE: | ||
2456 | luaL_checkstack(L, 5, "not enough stack slots"); | ||
2457 | idx1 = lua_absindex(L, idx1); | ||
2458 | idx2 = lua_absindex(L, idx2); | ||
2459 | lua_pushvalue(L, idx1); | ||
2460 | lua_pushvalue(L, idx2); | ||
2461 | compat53_call_lua(L, compat53_compare_code, | ||
2462 | sizeof(compat53_compare_code) - 1, 2, 1); | ||
2463 | result = lua_toboolean(L, -1); | ||
2464 | lua_pop(L, 1); | ||
2465 | return result; | ||
2466 | default: | ||
2467 | luaL_error(L, "invalid 'op' argument for lua_compare"); | ||
2468 | } | ||
2469 | return 0; | ||
2470 | } | ||
2471 | |||
2472 | COMPAT53_API void lua_copy(lua_State *L, int from, int to) { | ||
2473 | int abs_to = lua_absindex(L, to); | ||
2474 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
2475 | lua_pushvalue(L, from); | ||
2476 | lua_replace(L, abs_to); | ||
2477 | } | ||
2478 | |||
2479 | COMPAT53_API void lua_len(lua_State *L, int i) { | ||
2480 | switch (lua_type(L, i)) { | ||
2481 | case LUA_TSTRING: | ||
2482 | lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); | ||
2483 | break; | ||
2484 | case LUA_TTABLE: | ||
2485 | if (!luaL_callmeta(L, i, "__len")) | ||
2486 | lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); | ||
2487 | break; | ||
2488 | case LUA_TUSERDATA: | ||
2489 | if (luaL_callmeta(L, i, "__len")) | ||
2490 | break; | ||
2491 | /* FALLTHROUGH */ | ||
2492 | default: | ||
2493 | luaL_error(L, "attempt to get length of a %s value", | ||
2494 | lua_typename(L, lua_type(L, i))); | ||
2495 | } | ||
2496 | } | ||
2497 | |||
2498 | COMPAT53_API int lua_rawgetp(lua_State *L, int i, const void *p) { | ||
2499 | int abs_i = lua_absindex(L, i); | ||
2500 | lua_pushlightuserdata(L, (void*)p); | ||
2501 | lua_rawget(L, abs_i); | ||
2502 | return lua_type(L, -1); | ||
2503 | } | ||
2504 | |||
2505 | COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p) { | ||
2506 | int abs_i = lua_absindex(L, i); | ||
2507 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
2508 | lua_pushlightuserdata(L, (void*)p); | ||
2509 | lua_insert(L, -2); | ||
2510 | lua_rawset(L, abs_i); | ||
2511 | } | ||
2512 | |||
2513 | COMPAT53_API lua_Number lua_tonumberx(lua_State *L, int i, int *isnum) { | ||
2514 | lua_Number n = lua_tonumber(L, i); | ||
2515 | if (isnum != NULL) { | ||
2516 | *isnum = (n != 0 || lua_isnumber(L, i)); | ||
2517 | } | ||
2518 | return n; | ||
2519 | } | ||
2520 | |||
2521 | COMPAT53_API void luaL_checkversion(lua_State *L) { | ||
2522 | (void)L; | ||
2523 | } | ||
2524 | |||
2525 | COMPAT53_API void luaL_checkstack(lua_State *L, int sp, const char *msg) { | ||
2526 | if (!lua_checkstack(L, sp + LUA_MINSTACK)) { | ||
2527 | if (msg != NULL) | ||
2528 | luaL_error(L, "stack overflow (%s)", msg); | ||
2529 | else { | ||
2530 | lua_pushliteral(L, "stack overflow"); | ||
2531 | lua_error(L); | ||
2532 | } | ||
2533 | } | ||
2534 | } | ||
2535 | |||
2536 | COMPAT53_API int luaL_getsubtable(lua_State *L, int i, const char *name) { | ||
2537 | int abs_i = lua_absindex(L, i); | ||
2538 | luaL_checkstack(L, 3, "not enough stack slots"); | ||
2539 | lua_pushstring(L, name); | ||
2540 | lua_gettable(L, abs_i); | ||
2541 | if (lua_istable(L, -1)) | ||
2542 | return 1; | ||
2543 | lua_pop(L, 1); | ||
2544 | lua_newtable(L); | ||
2545 | lua_pushstring(L, name); | ||
2546 | lua_pushvalue(L, -2); | ||
2547 | lua_settable(L, abs_i); | ||
2548 | return 0; | ||
2549 | } | ||
2550 | |||
2551 | COMPAT53_API lua_Integer luaL_len(lua_State *L, int i) { | ||
2552 | lua_Integer res = 0; | ||
2553 | int isnum = 0; | ||
2554 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
2555 | lua_len(L, i); | ||
2556 | res = lua_tointegerx(L, -1, &isnum); | ||
2557 | lua_pop(L, 1); | ||
2558 | if (!isnum) | ||
2559 | luaL_error(L, "object length is not an integer"); | ||
2560 | return res; | ||
2561 | } | ||
2562 | |||
2563 | COMPAT53_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { | ||
2564 | luaL_checkstack(L, nup + 1, "too many upvalues"); | ||
2565 | for (; l->name != NULL; l++) { /* fill the table with given functions */ | ||
2566 | int i; | ||
2567 | lua_pushstring(L, l->name); | ||
2568 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ | ||
2569 | lua_pushvalue(L, -(nup + 1)); | ||
2570 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ | ||
2571 | lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ | ||
2572 | } | ||
2573 | lua_pop(L, nup); /* remove upvalues */ | ||
2574 | } | ||
2575 | |||
2576 | COMPAT53_API void luaL_setmetatable(lua_State *L, const char *tname) { | ||
2577 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
2578 | luaL_getmetatable(L, tname); | ||
2579 | lua_setmetatable(L, -2); | ||
2580 | } | ||
2581 | |||
2582 | COMPAT53_API void *luaL_testudata(lua_State *L, int i, const char *tname) { | ||
2583 | void *p = lua_touserdata(L, i); | ||
2584 | luaL_checkstack(L, 2, "not enough stack slots"); | ||
2585 | if (p == NULL || !lua_getmetatable(L, i)) | ||
2586 | return NULL; | ||
2587 | else { | ||
2588 | int res = 0; | ||
2589 | luaL_getmetatable(L, tname); | ||
2590 | res = lua_rawequal(L, -1, -2); | ||
2591 | lua_pop(L, 2); | ||
2592 | if (!res) | ||
2593 | p = NULL; | ||
2594 | } | ||
2595 | return p; | ||
2596 | } | ||
2597 | |||
2598 | static int compat53_countlevels(lua_State *L) { | ||
2599 | lua_Debug ar; | ||
2600 | int li = 1, le = 1; | ||
2601 | /* find an upper bound */ | ||
2602 | while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } | ||
2603 | /* do a binary search */ | ||
2604 | while (li < le) { | ||
2605 | int m = (li + le) / 2; | ||
2606 | if (lua_getstack(L, m, &ar)) li = m + 1; | ||
2607 | else le = m; | ||
2608 | } | ||
2609 | return le - 1; | ||
2610 | } | ||
2611 | |||
2612 | static int compat53_findfield(lua_State *L, int objidx, int level) { | ||
2613 | if (level == 0 || !lua_istable(L, -1)) | ||
2614 | return 0; /* not found */ | ||
2615 | lua_pushnil(L); /* start 'next' loop */ | ||
2616 | while (lua_next(L, -2)) { /* for each pair in table */ | ||
2617 | if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ | ||
2618 | if (lua_rawequal(L, objidx, -1)) { /* found object? */ | ||
2619 | lua_pop(L, 1); /* remove value (but keep name) */ | ||
2620 | return 1; | ||
2621 | } | ||
2622 | else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ | ||
2623 | lua_remove(L, -2); /* remove table (but keep name) */ | ||
2624 | lua_pushliteral(L, "."); | ||
2625 | lua_insert(L, -2); /* place '.' between the two names */ | ||
2626 | lua_concat(L, 3); | ||
2627 | return 1; | ||
2628 | } | ||
2629 | } | ||
2630 | lua_pop(L, 1); /* remove value */ | ||
2631 | } | ||
2632 | return 0; /* not found */ | ||
2633 | } | ||
2634 | |||
2635 | static int compat53_pushglobalfuncname(lua_State *L, lua_Debug *ar) { | ||
2636 | int top = lua_gettop(L); | ||
2637 | lua_getinfo(L, "f", ar); /* push function */ | ||
2638 | lua_pushvalue(L, LUA_GLOBALSINDEX); | ||
2639 | if (compat53_findfield(L, top + 1, 2)) { | ||
2640 | lua_copy(L, -1, top + 1); /* move name to proper place */ | ||
2641 | lua_pop(L, 2); /* remove pushed values */ | ||
2642 | return 1; | ||
2643 | } | ||
2644 | else { | ||
2645 | lua_settop(L, top); /* remove function and global table */ | ||
2646 | return 0; | ||
2647 | } | ||
2648 | } | ||
2649 | |||
2650 | static void compat53_pushfuncname(lua_State *L, lua_Debug *ar) { | ||
2651 | if (*ar->namewhat != '\0') /* is there a name? */ | ||
2652 | lua_pushfstring(L, "function " LUA_QS, ar->name); | ||
2653 | else if (*ar->what == 'm') /* main? */ | ||
2654 | lua_pushliteral(L, "main chunk"); | ||
2655 | else if (*ar->what == 'C') { | ||
2656 | if (compat53_pushglobalfuncname(L, ar)) { | ||
2657 | lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); | ||
2658 | lua_remove(L, -2); /* remove name */ | ||
2659 | } | ||
2660 | else | ||
2661 | lua_pushliteral(L, "?"); | ||
2662 | } | ||
2663 | else | ||
2664 | lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); | ||
2665 | } | ||
2666 | |||
2667 | #define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ | ||
2668 | #define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ | ||
2669 | |||
2670 | COMPAT53_API void luaL_traceback(lua_State *L, lua_State *L1, | ||
2671 | const char *msg, int level) { | ||
2672 | lua_Debug ar; | ||
2673 | int top = lua_gettop(L); | ||
2674 | int numlevels = compat53_countlevels(L1); | ||
2675 | int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; | ||
2676 | if (msg) lua_pushfstring(L, "%s\n", msg); | ||
2677 | lua_pushliteral(L, "stack traceback:"); | ||
2678 | while (lua_getstack(L1, level++, &ar)) { | ||
2679 | if (level == mark) { /* too many levels? */ | ||
2680 | lua_pushliteral(L, "\n\t..."); /* add a '...' */ | ||
2681 | level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ | ||
2682 | } | ||
2683 | else { | ||
2684 | lua_getinfo(L1, "Slnt", &ar); | ||
2685 | lua_pushfstring(L, "\n\t%s:", ar.short_src); | ||
2686 | if (ar.currentline > 0) | ||
2687 | lua_pushfstring(L, "%d:", ar.currentline); | ||
2688 | lua_pushliteral(L, " in "); | ||
2689 | compat53_pushfuncname(L, &ar); | ||
2690 | lua_concat(L, lua_gettop(L) - top); | ||
2691 | } | ||
2692 | } | ||
2693 | lua_concat(L, lua_gettop(L) - top); | ||
2694 | } | ||
2695 | |||
2696 | COMPAT53_API int luaL_fileresult(lua_State *L, int stat, const char *fname) { | ||
2697 | const char *serr = NULL; | ||
2698 | int en = errno; /* calls to Lua API may change this value */ | ||
2699 | char buf[512] = { 0 }; | ||
2700 | if (stat) { | ||
2701 | lua_pushboolean(L, 1); | ||
2702 | return 1; | ||
2703 | } | ||
2704 | else { | ||
2705 | lua_pushnil(L); | ||
2706 | serr = compat53_strerror(en, buf, sizeof(buf)); | ||
2707 | if (fname) | ||
2708 | lua_pushfstring(L, "%s: %s", fname, serr); | ||
2709 | else | ||
2710 | lua_pushstring(L, serr); | ||
2711 | lua_pushnumber(L, (lua_Number)en); | ||
2712 | return 3; | ||
2713 | } | ||
2714 | } | ||
2715 | |||
2716 | static int compat53_checkmode(lua_State *L, const char *mode, const char *modename, int err) { | ||
2717 | if (mode && strchr(mode, modename[0]) == NULL) { | ||
2718 | lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); | ||
2719 | return err; | ||
2720 | } | ||
2721 | return LUA_OK; | ||
2722 | } | ||
2723 | |||
2724 | typedef struct { | ||
2725 | lua_Reader reader; | ||
2726 | void *ud; | ||
2727 | int has_peeked_data; | ||
2728 | const char *peeked_data; | ||
2729 | size_t peeked_data_size; | ||
2730 | } compat53_reader_data; | ||
2731 | |||
2732 | static const char *compat53_reader(lua_State *L, void *ud, size_t *size) { | ||
2733 | compat53_reader_data *data = (compat53_reader_data *)ud; | ||
2734 | if (data->has_peeked_data) { | ||
2735 | data->has_peeked_data = 0; | ||
2736 | *size = data->peeked_data_size; | ||
2737 | return data->peeked_data; | ||
2738 | } | ||
2739 | else | ||
2740 | return data->reader(L, data->ud, size); | ||
2741 | } | ||
2742 | |||
2743 | COMPAT53_API int lua_load(lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) { | ||
2744 | int status = LUA_OK; | ||
2745 | compat53_reader_data compat53_data = { reader, data, 1, 0, 0 }; | ||
2746 | compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); | ||
2747 | if (compat53_data.peeked_data && compat53_data.peeked_data_size && | ||
2748 | compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ | ||
2749 | status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); | ||
2750 | else | ||
2751 | status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); | ||
2752 | if (status != LUA_OK) | ||
2753 | return status; | ||
2754 | /* we need to call the original 5.1 version of lua_load! */ | ||
2755 | #undef lua_load | ||
2756 | return lua_load(L, compat53_reader, &compat53_data, source); | ||
2757 | #define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) | ||
2758 | } | ||
2759 | |||
2760 | typedef struct { | ||
2761 | int n; /* number of pre-read characters */ | ||
2762 | FILE *f; /* file being read */ | ||
2763 | char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ | ||
2764 | } compat53_LoadF; | ||
2765 | |||
2766 | static const char *compat53_getF(lua_State *L, void *ud, size_t *size) { | ||
2767 | compat53_LoadF *lf = (compat53_LoadF *)ud; | ||
2768 | (void)L; /* not used */ | ||
2769 | if (lf->n > 0) { /* are there pre-read characters to be read? */ | ||
2770 | *size = lf->n; /* return them (chars already in buffer) */ | ||
2771 | lf->n = 0; /* no more pre-read characters */ | ||
2772 | } | ||
2773 | else { /* read a block from file */ | ||
2774 | /* 'fread' can return > 0 *and* set the EOF flag. If next call to | ||
2775 | 'compat53_getF' called 'fread', it might still wait for user input. | ||
2776 | The next check avoids this problem. */ | ||
2777 | if (feof(lf->f)) return NULL; | ||
2778 | *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ | ||
2779 | } | ||
2780 | return lf->buff; | ||
2781 | } | ||
2782 | |||
2783 | static int compat53_errfile(lua_State *L, const char *what, int fnameindex) { | ||
2784 | char buf[512] = { 0 }; | ||
2785 | const char *serr = compat53_strerror(errno, buf, sizeof(buf)); | ||
2786 | const char *filename = lua_tostring(L, fnameindex) + 1; | ||
2787 | lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); | ||
2788 | lua_remove(L, fnameindex); | ||
2789 | return LUA_ERRFILE; | ||
2790 | } | ||
2791 | |||
2792 | static int compat53_skipBOM(compat53_LoadF *lf) { | ||
2793 | const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ | ||
2794 | int c; | ||
2795 | lf->n = 0; | ||
2796 | do { | ||
2797 | c = getc(lf->f); | ||
2798 | if (c == EOF || c != *(const unsigned char *)p++) return c; | ||
2799 | lf->buff[lf->n++] = (char)c; /* to be read by the parser */ | ||
2800 | } while (*p != '\0'); | ||
2801 | lf->n = 0; /* prefix matched; discard it */ | ||
2802 | return getc(lf->f); /* return next character */ | ||
2803 | } | ||
2804 | |||
2805 | /* | ||
2806 | ** reads the first character of file 'f' and skips an optional BOM mark | ||
2807 | ** in its beginning plus its first line if it starts with '#'. Returns | ||
2808 | ** true if it skipped the first line. In any case, '*cp' has the | ||
2809 | ** first "valid" character of the file (after the optional BOM and | ||
2810 | ** a first-line comment). | ||
2811 | */ | ||
2812 | static int compat53_skipcomment(compat53_LoadF *lf, int *cp) { | ||
2813 | int c = *cp = compat53_skipBOM(lf); | ||
2814 | if (c == '#') { /* first line is a comment (Unix exec. file)? */ | ||
2815 | do { /* skip first line */ | ||
2816 | c = getc(lf->f); | ||
2817 | } while (c != EOF && c != '\n'); | ||
2818 | *cp = getc(lf->f); /* skip end-of-line, if present */ | ||
2819 | return 1; /* there was a comment */ | ||
2820 | } | ||
2821 | else return 0; /* no comment */ | ||
2822 | } | ||
2823 | |||
2824 | COMPAT53_API int luaL_loadfilex(lua_State *L, const char *filename, const char *mode) { | ||
2825 | compat53_LoadF lf; | ||
2826 | int status, readstatus; | ||
2827 | int c; | ||
2828 | int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ | ||
2829 | if (filename == NULL) { | ||
2830 | lua_pushliteral(L, "=stdin"); | ||
2831 | lf.f = stdin; | ||
2832 | } | ||
2833 | else { | ||
2834 | lua_pushfstring(L, "@%s", filename); | ||
2835 | #if defined(_MSC_VER) | ||
2836 | /* This code is here to stop a deprecation error that stops builds | ||
2837 | * if a certain macro is defined. While normally not caring would | ||
2838 | * be best, some header-only libraries and builds can't afford to | ||
2839 | * dictate this to the user. A quick check shows that fopen_s this | ||
2840 | * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, | ||
2841 | * possibly even before that so we don't need to do any version | ||
2842 | * number checks, since this has been there since forever. */ | ||
2843 | |||
2844 | /* TO USER: if you want the behavior of typical fopen_s/fopen, | ||
2845 | * which does lock the file on VC++, define the macro used below to 0 */ | ||
2846 | #if COMPAT53_FOPEN_NO_LOCK | ||
2847 | lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ | ||
2848 | if (lf.f == NULL) | ||
2849 | return compat53_errfile(L, "open", fnameindex); | ||
2850 | #else /* use default locking version */ | ||
2851 | if (fopen_s(&lf.f, filename, "r") != 0) | ||
2852 | return compat53_errfile(L, "open", fnameindex); | ||
2853 | #endif /* Locking vs. No-locking fopen variants */ | ||
2854 | #else | ||
2855 | lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ | ||
2856 | if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); | ||
2857 | #endif | ||
2858 | } | ||
2859 | if (compat53_skipcomment(&lf, &c)) /* read initial portion */ | ||
2860 | lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ | ||
2861 | if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ | ||
2862 | #if defined(_MSC_VER) | ||
2863 | if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) | ||
2864 | return compat53_errfile(L, "reopen", fnameindex); | ||
2865 | #else | ||
2866 | lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ | ||
2867 | if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex); | ||
2868 | #endif | ||
2869 | compat53_skipcomment(&lf, &c); /* re-read initial portion */ | ||
2870 | } | ||
2871 | if (c != EOF) | ||
2872 | lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ | ||
2873 | status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); | ||
2874 | readstatus = ferror(lf.f); | ||
2875 | if (filename) fclose(lf.f); /* close file (even in case of errors) */ | ||
2876 | if (readstatus) { | ||
2877 | lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ | ||
2878 | return compat53_errfile(L, "read", fnameindex); | ||
2879 | } | ||
2880 | lua_remove(L, fnameindex); | ||
2881 | return status; | ||
2882 | } | ||
2883 | |||
2884 | COMPAT53_API int luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) { | ||
2885 | int status = LUA_OK; | ||
2886 | if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { | ||
2887 | status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); | ||
2888 | } | ||
2889 | else { | ||
2890 | status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); | ||
2891 | } | ||
2892 | if (status != LUA_OK) | ||
2893 | return status; | ||
2894 | return luaL_loadbuffer(L, buff, sz, name); | ||
2895 | } | ||
2896 | |||
2897 | #if !defined(l_inspectstat) && \ | ||
2898 | (defined(unix) || defined(__unix) || defined(__unix__) || \ | ||
2899 | defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ | ||
2900 | (defined(__APPLE__) && defined(__MACH__))) | ||
2901 | /* some form of unix; check feature macros in unistd.h for details */ | ||
2902 | # include <unistd.h> | ||
2903 | /* check posix version; the relevant include files and macros probably | ||
2904 | * were available before 2001, but I'm not sure */ | ||
2905 | # if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L | ||
2906 | # include <sys/wait.h> | ||
2907 | # define l_inspectstat(stat,what) \ | ||
2908 | if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ | ||
2909 | else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } | ||
2910 | # endif | ||
2911 | #endif | ||
2912 | |||
2913 | /* provide default (no-op) version */ | ||
2914 | #if !defined(l_inspectstat) | ||
2915 | # define l_inspectstat(stat,what) ((void)0) | ||
2916 | #endif | ||
2917 | |||
2918 | COMPAT53_API int luaL_execresult(lua_State *L, int stat) { | ||
2919 | const char *what = "exit"; | ||
2920 | if (stat == -1) | ||
2921 | return luaL_fileresult(L, 0, NULL); | ||
2922 | else { | ||
2923 | l_inspectstat(stat, what); | ||
2924 | if (*what == 'e' && stat == 0) | ||
2925 | lua_pushboolean(L, 1); | ||
2926 | else | ||
2927 | lua_pushnil(L); | ||
2928 | lua_pushstring(L, what); | ||
2929 | lua_pushinteger(L, stat); | ||
2930 | return 3; | ||
2931 | } | ||
2932 | } | ||
2933 | |||
2934 | COMPAT53_API void luaL_buffinit(lua_State *L, luaL_Buffer_53 *B) { | ||
2935 | /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ | ||
2936 | B->b.p = NULL; | ||
2937 | B->b.L = NULL; | ||
2938 | B->b.lvl = 0; | ||
2939 | /* reuse the buffer from the 5.1-style luaL_Buffer though! */ | ||
2940 | B->ptr = B->b.buffer; | ||
2941 | B->capacity = LUAL_BUFFERSIZE; | ||
2942 | B->nelems = 0; | ||
2943 | B->L2 = L; | ||
2944 | } | ||
2945 | |||
2946 | COMPAT53_API char *luaL_prepbuffsize(luaL_Buffer_53 *B, size_t s) { | ||
2947 | if (B->capacity - B->nelems < s) { /* needs to grow */ | ||
2948 | char* newptr = NULL; | ||
2949 | size_t newcap = B->capacity * 2; | ||
2950 | if (newcap - B->nelems < s) | ||
2951 | newcap = B->nelems + s; | ||
2952 | if (newcap < B->capacity) /* overflow */ | ||
2953 | luaL_error(B->L2, "buffer too large"); | ||
2954 | newptr = (char*)lua_newuserdata(B->L2, newcap); | ||
2955 | memcpy(newptr, B->ptr, B->nelems); | ||
2956 | if (B->ptr != B->b.buffer) | ||
2957 | lua_replace(B->L2, -2); /* remove old buffer */ | ||
2958 | B->ptr = newptr; | ||
2959 | B->capacity = newcap; | ||
2960 | } | ||
2961 | return B->ptr + B->nelems; | ||
2962 | } | ||
2963 | |||
2964 | COMPAT53_API void luaL_addlstring(luaL_Buffer_53 *B, const char *s, size_t l) { | ||
2965 | memcpy(luaL_prepbuffsize(B, l), s, l); | ||
2966 | luaL_addsize(B, l); | ||
2967 | } | ||
2968 | |||
2969 | COMPAT53_API void luaL_addvalue(luaL_Buffer_53 *B) { | ||
2970 | size_t len = 0; | ||
2971 | const char *s = lua_tolstring(B->L2, -1, &len); | ||
2972 | if (!s) | ||
2973 | luaL_error(B->L2, "cannot convert value to string"); | ||
2974 | if (B->ptr != B->b.buffer) | ||
2975 | lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ | ||
2976 | luaL_addlstring(B, s, len); | ||
2977 | lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); | ||
2978 | } | ||
2979 | |||
2980 | void luaL_pushresult(luaL_Buffer_53 *B) { | ||
2981 | lua_pushlstring(B->L2, B->ptr, B->nelems); | ||
2982 | if (B->ptr != B->b.buffer) | ||
2983 | lua_replace(B->L2, -2); /* remove userdata buffer */ | ||
2984 | } | ||
2985 | |||
2986 | #endif /* Lua 5.1 */ | ||
2987 | |||
2988 | /* definitions for Lua 5.1 and Lua 5.2 */ | ||
2989 | #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 | ||
2990 | |||
2991 | COMPAT53_API int lua_geti(lua_State *L, int index, lua_Integer i) { | ||
2992 | index = lua_absindex(L, index); | ||
2993 | lua_pushinteger(L, i); | ||
2994 | lua_gettable(L, index); | ||
2995 | return lua_type(L, -1); | ||
2996 | } | ||
2997 | |||
2998 | COMPAT53_API int lua_isinteger(lua_State *L, int index) { | ||
2999 | if (lua_type(L, index) == LUA_TNUMBER) { | ||
3000 | lua_Number n = lua_tonumber(L, index); | ||
3001 | lua_Integer i = lua_tointeger(L, index); | ||
3002 | if (i == n) | ||
3003 | return 1; | ||
3004 | } | ||
3005 | return 0; | ||
3006 | } | ||
3007 | |||
3008 | COMPAT53_API lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum) { | ||
3009 | int ok = 0; | ||
3010 | lua_Number n = lua_tonumberx(L, i, &ok); | ||
3011 | if (ok) { | ||
3012 | if (n == (lua_Integer)n) { | ||
3013 | if (isnum) | ||
3014 | *isnum = 1; | ||
3015 | return (lua_Integer)n; | ||
3016 | } | ||
3017 | } | ||
3018 | if (isnum) | ||
3019 | *isnum = 0; | ||
3020 | return 0; | ||
3021 | } | ||
3022 | |||
3023 | static void compat53_reverse(lua_State *L, int a, int b) { | ||
3024 | for (; a < b; ++a, --b) { | ||
3025 | lua_pushvalue(L, a); | ||
3026 | lua_pushvalue(L, b); | ||
3027 | lua_replace(L, a); | ||
3028 | lua_replace(L, b); | ||
3029 | } | ||
3030 | } | ||
3031 | |||
3032 | COMPAT53_API void lua_rotate(lua_State *L, int idx, int n) { | ||
3033 | int n_elems = 0; | ||
3034 | idx = lua_absindex(L, idx); | ||
3035 | n_elems = lua_gettop(L) - idx + 1; | ||
3036 | if (n < 0) | ||
3037 | n += n_elems; | ||
3038 | if (n > 0 && n < n_elems) { | ||
3039 | luaL_checkstack(L, 2, "not enough stack slots available"); | ||
3040 | n = n_elems - n; | ||
3041 | compat53_reverse(L, idx, idx + n - 1); | ||
3042 | compat53_reverse(L, idx + n, idx + n_elems - 1); | ||
3043 | compat53_reverse(L, idx, idx + n_elems - 1); | ||
3044 | } | ||
3045 | } | ||
3046 | |||
3047 | COMPAT53_API void lua_seti(lua_State *L, int index, lua_Integer i) { | ||
3048 | luaL_checkstack(L, 1, "not enough stack slots available"); | ||
3049 | index = lua_absindex(L, index); | ||
3050 | lua_pushinteger(L, i); | ||
3051 | lua_insert(L, -2); | ||
3052 | lua_settable(L, index); | ||
3053 | } | ||
3054 | |||
3055 | #if !defined(lua_str2number) | ||
3056 | # define lua_str2number(s, p) strtod((s), (p)) | ||
3057 | #endif | ||
3058 | |||
3059 | COMPAT53_API size_t lua_stringtonumber(lua_State *L, const char *s) { | ||
3060 | char* endptr; | ||
3061 | lua_Number n = lua_str2number(s, &endptr); | ||
3062 | if (endptr != s) { | ||
3063 | while (*endptr != '\0' && isspace((unsigned char)*endptr)) | ||
3064 | ++endptr; | ||
3065 | if (*endptr == '\0') { | ||
3066 | lua_pushnumber(L, n); | ||
3067 | return endptr - s + 1; | ||
3068 | } | ||
3069 | } | ||
3070 | return 0; | ||
3071 | } | ||
3072 | |||
3073 | COMPAT53_API const char *luaL_tolstring(lua_State *L, int idx, size_t *len) { | ||
3074 | if (!luaL_callmeta(L, idx, "__tostring")) { | ||
3075 | int t = lua_type(L, idx), tt = 0; | ||
3076 | char const* name = NULL; | ||
3077 | switch (t) { | ||
3078 | case LUA_TNIL: | ||
3079 | lua_pushliteral(L, "nil"); | ||
3080 | break; | ||
3081 | case LUA_TSTRING: | ||
3082 | case LUA_TNUMBER: | ||
3083 | lua_pushvalue(L, idx); | ||
3084 | break; | ||
3085 | case LUA_TBOOLEAN: | ||
3086 | if (lua_toboolean(L, idx)) | ||
3087 | lua_pushliteral(L, "true"); | ||
3088 | else | ||
3089 | lua_pushliteral(L, "false"); | ||
3090 | break; | ||
3091 | default: | ||
3092 | tt = luaL_getmetafield(L, idx, "__name"); | ||
3093 | name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); | ||
3094 | lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); | ||
3095 | if (tt != LUA_TNIL) | ||
3096 | lua_replace(L, -2); | ||
3097 | break; | ||
3098 | } | ||
3099 | } | ||
3100 | else { | ||
3101 | if (!lua_isstring(L, -1)) | ||
3102 | luaL_error(L, "'__tostring' must return a string"); | ||
3103 | } | ||
3104 | return lua_tolstring(L, -1, len); | ||
3105 | } | ||
3106 | |||
3107 | COMPAT53_API void luaL_requiref(lua_State *L, const char *modname, | ||
3108 | lua_CFunction openf, int glb) { | ||
3109 | luaL_checkstack(L, 3, "not enough stack slots available"); | ||
3110 | luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); | ||
3111 | if (lua_getfield(L, -1, modname) == LUA_TNIL) { | ||
3112 | lua_pop(L, 1); | ||
3113 | lua_pushcfunction(L, openf); | ||
3114 | lua_pushstring(L, modname); | ||
3115 | lua_call(L, 1, 1); | ||
3116 | lua_pushvalue(L, -1); | ||
3117 | lua_setfield(L, -3, modname); | ||
3118 | } | ||
3119 | if (glb) { | ||
3120 | lua_pushvalue(L, -1); | ||
3121 | lua_setglobal(L, modname); | ||
3122 | } | ||
3123 | lua_replace(L, -2); | ||
3124 | } | ||
3125 | |||
3126 | #endif /* Lua 5.1 and 5.2 */ | ||
3127 | |||
3128 | #endif /* KEPLER_PROJECT_COMPAT53_C_ */ | ||
3129 | |||
3130 | /********************************************************************* | ||
3131 | * This file contains parts of Lua 5.2's and Lua 5.3's source code: | ||
3132 | * | ||
3133 | * Copyright (C) 1994-2014 Lua.org, PUC-Rio. | ||
3134 | * | ||
3135 | * Permission is hereby granted, free of charge, to any person obtaining | ||
3136 | * a copy of this software and associated documentation files (the | ||
3137 | * "Software"), to deal in the Software without restriction, including | ||
3138 | * without limitation the rights to use, copy, modify, merge, publish, | ||
3139 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
3140 | * permit persons to whom the Software is furnished to do so, subject to | ||
3141 | * the following conditions: | ||
3142 | * | ||
3143 | * The above copyright notice and this permission notice shall be | ||
3144 | * included in all copies or substantial portions of the Software. | ||
3145 | * | ||
3146 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
3147 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
3148 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
3149 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
3150 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
3151 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
3152 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
3153 | *********************************************************************/ | ||
3154 | |||
3155 | // end of sol/compatibility/compat-5.3.c | ||
3156 | |||
3157 | #endif | ||
3158 | |||
3159 | #endif /* KEPLER_PROJECT_COMPAT53_H_ */ | ||
3160 | |||
3161 | // end of sol/compatibility/compat-5.3.h | ||
3162 | |||
3163 | |||
3164 | #endif // SOL_NO_COMPAT | ||
3165 | |||
3166 | // end of sol/compatibility.hpp | ||
3167 | |||
3168 | // beginning of sol/in_place.hpp | ||
3169 | |||
3170 | #include <utility> | ||
3171 | |||
3172 | namespace sol { | ||
3173 | |||
3174 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
3175 | using in_place_t = std::in_place_t; | ||
3176 | constexpr std::in_place_t in_place{}; | ||
3177 | constexpr std::in_place_t in_place_of{}; | ||
3178 | |||
3179 | template <typename T> | ||
3180 | using in_place_type_t = std::in_place_type_t<T>; | ||
3181 | template <typename T> | ||
3182 | constexpr std::in_place_type_t<T> in_place_type{}; | ||
3183 | |||
3184 | template <size_t I> | ||
3185 | using in_place_index_t = std::in_place_index_t<I>; | ||
3186 | template <size_t I> | ||
3187 | constexpr in_place_index_t<I> in_place_index{}; | ||
3188 | #else | ||
3189 | namespace detail { | ||
3190 | struct in_place_of_tag {}; | ||
3191 | template <std::size_t I> | ||
3192 | struct in_place_of_i {}; | ||
3193 | template <typename T> | ||
3194 | struct in_place_of_t {}; | ||
3195 | } // namespace detail | ||
3196 | |||
3197 | struct in_place_tag { | ||
3198 | constexpr in_place_tag() = default; | ||
3199 | }; | ||
3200 | |||
3201 | constexpr inline in_place_tag in_place(detail::in_place_of_tag) { | ||
3202 | return in_place_tag(); | ||
3203 | } | ||
3204 | template <typename T> | ||
3205 | constexpr inline in_place_tag in_place(detail::in_place_of_t<T>) { | ||
3206 | return in_place_tag(); | ||
3207 | } | ||
3208 | template <std::size_t I> | ||
3209 | constexpr inline in_place_tag in_place(detail::in_place_of_i<I>) { | ||
3210 | return in_place_tag(); | ||
3211 | } | ||
3212 | |||
3213 | constexpr inline in_place_tag in_place_of(detail::in_place_of_tag) { | ||
3214 | return in_place_tag(); | ||
3215 | } | ||
3216 | template <typename T> | ||
3217 | constexpr inline in_place_tag in_place_type(detail::in_place_of_t<T>) { | ||
3218 | return in_place_tag(); | ||
3219 | } | ||
3220 | template <std::size_t I> | ||
3221 | constexpr inline in_place_tag in_place_index(detail::in_place_of_i<I>) { | ||
3222 | return in_place_tag(); | ||
3223 | } | ||
3224 | |||
3225 | using in_place_t = in_place_tag (&)(detail::in_place_of_tag); | ||
3226 | template <typename T> | ||
3227 | using in_place_type_t = in_place_tag (&)(detail::in_place_of_t<T>); | ||
3228 | template <std::size_t I> | ||
3229 | using in_place_index_t = in_place_tag (&)(detail::in_place_of_i<I>); | ||
3230 | #endif | ||
3231 | |||
3232 | } // namespace sol | ||
3233 | |||
3234 | // end of sol/in_place.hpp | ||
3235 | |||
3236 | #if defined(SOL_USE_BOOST) && SOL_USE_BOOST | ||
3237 | #include <boost/optional.hpp> | ||
3238 | #else | ||
3239 | // beginning of sol/optional_implementation.hpp | ||
3240 | |||
3241 | #include <initializer_list> | ||
3242 | #include <cassert> | ||
3243 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
3244 | #include <cstdlib> | ||
3245 | #endif // Exceptions | ||
3246 | |||
3247 | #define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false | ||
3248 | |||
3249 | #if defined __GNUC__ // NOTE: GNUC is also defined for Clang | ||
3250 | #if (__GNUC__ >= 5) | ||
3251 | #define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ | ||
3252 | #define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ | ||
3253 | #elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) | ||
3254 | #define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ | ||
3255 | #elif (__GNUC__ > 4) | ||
3256 | #define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ | ||
3257 | #endif | ||
3258 | # | ||
3259 | #if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) | ||
3260 | #define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ | ||
3261 | #elif (__GNUC__ > 4) | ||
3262 | #define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ | ||
3263 | #endif | ||
3264 | # | ||
3265 | #if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) | ||
3266 | #define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ | ||
3267 | #elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) | ||
3268 | #define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ | ||
3269 | #elif (__GNUC__ > 4) | ||
3270 | #define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ | ||
3271 | #endif | ||
3272 | #endif | ||
3273 | # | ||
3274 | #if defined __clang_major__ | ||
3275 | #if (__clang_major__ == 3 && __clang_minor__ >= 5) | ||
3276 | #define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ | ||
3277 | #elif (__clang_major__ > 3) | ||
3278 | #define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ | ||
3279 | #endif | ||
3280 | #if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ | ||
3281 | #define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ | ||
3282 | #elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) | ||
3283 | #define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ | ||
3284 | #endif | ||
3285 | #endif | ||
3286 | # | ||
3287 | #if defined _MSC_VER | ||
3288 | #if (_MSC_VER >= 1900) | ||
3289 | #define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
3290 | #endif | ||
3291 | #endif | ||
3292 | |||
3293 | #if defined __clang__ | ||
3294 | #if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) | ||
3295 | #define OPTIONAL_HAS_THIS_RVALUE_REFS 1 | ||
3296 | #else | ||
3297 | #define OPTIONAL_HAS_THIS_RVALUE_REFS 0 | ||
3298 | #endif | ||
3299 | #elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ | ||
3300 | #define OPTIONAL_HAS_THIS_RVALUE_REFS 1 | ||
3301 | #elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
3302 | #define OPTIONAL_HAS_THIS_RVALUE_REFS 1 | ||
3303 | #else | ||
3304 | #define OPTIONAL_HAS_THIS_RVALUE_REFS 0 | ||
3305 | #endif | ||
3306 | |||
3307 | #if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ | ||
3308 | #define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 | ||
3309 | #define OPTIONAL_CONSTEXPR_INIT_LIST constexpr | ||
3310 | #else | ||
3311 | #define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 | ||
3312 | #define OPTIONAL_CONSTEXPR_INIT_LIST | ||
3313 | #endif | ||
3314 | |||
3315 | #if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || (defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)) | ||
3316 | #define OPTIONAL_HAS_MOVE_ACCESSORS 1 | ||
3317 | #else | ||
3318 | #define OPTIONAL_HAS_MOVE_ACCESSORS 0 | ||
3319 | #endif | ||
3320 | |||
3321 | #// In C++11 constexpr implies const, so we need to make non-const members also non-constexpr | ||
3322 | #if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || ((defined __cplusplus) && (__cplusplus == 201103L)) | ||
3323 | #define OPTIONAL_MUTABLE_CONSTEXPR | ||
3324 | #else | ||
3325 | #define OPTIONAL_MUTABLE_CONSTEXPR constexpr | ||
3326 | #endif | ||
3327 | |||
3328 | #if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
3329 | #pragma warning(push) | ||
3330 | #pragma warning(disable : 4814) | ||
3331 | #endif | ||
3332 | |||
3333 | namespace sol { | ||
3334 | |||
3335 | // BEGIN workaround for missing is_trivially_destructible | ||
3336 | #if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ | ||
3337 | // leave it: it is already there | ||
3338 | #elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ | ||
3339 | // leave it: it is already there | ||
3340 | #elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
3341 | // leave it: it is already there | ||
3342 | #elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS | ||
3343 | // leave it: the user doesn't want it | ||
3344 | #else | ||
3345 | template <typename T> | ||
3346 | using is_trivially_destructible = ::std::has_trivial_destructor<T>; | ||
3347 | #endif | ||
3348 | // END workaround for missing is_trivially_destructible | ||
3349 | |||
3350 | #if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) | ||
3351 | // leave it; our metafunctions are already defined. | ||
3352 | #elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ | ||
3353 | // leave it; our metafunctions are already defined. | ||
3354 | #elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
3355 | // leave it: it is already there | ||
3356 | #elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS | ||
3357 | // leave it: the user doesn't want it | ||
3358 | #else | ||
3359 | |||
3360 | // workaround for missing traits in GCC and CLANG | ||
3361 | template <class T> | ||
3362 | struct is_nothrow_move_constructible { | ||
3363 | static constexprbool value = ::std::is_nothrow_constructible<T, T&&>::value; | ||
3364 | }; | ||
3365 | |||
3366 | template <class T, class U> | ||
3367 | struct is_assignable { | ||
3368 | template <class X, class Y> | ||
3369 | static constexprbool has_assign(...) { | ||
3370 | return false; | ||
3371 | } | ||
3372 | |||
3373 | template <class X, class Y, size_t S = sizeof((::std::declval<X>() = ::std::declval<Y>(), true))> | ||
3374 | // the comma operator is necessary for the cases where operator= returns void | ||
3375 | static constexprbool has_assign(bool) { | ||
3376 | return true; | ||
3377 | } | ||
3378 | |||
3379 | static constexprbool value = has_assign<T, U>(true); | ||
3380 | }; | ||
3381 | |||
3382 | template <class T> | ||
3383 | struct is_nothrow_move_assignable { | ||
3384 | template <class X, bool has_any_move_assign> | ||
3385 | struct has_nothrow_move_assign { | ||
3386 | static constexprbool value = false; | ||
3387 | }; | ||
3388 | |||
3389 | template <class X> | ||
3390 | struct has_nothrow_move_assign<X, true> { | ||
3391 | static constexprbool value = noexcept(::std::declval<X&>() = ::std::declval<X&&>()); | ||
3392 | }; | ||
3393 | |||
3394 | static constexprbool value = has_nothrow_move_assign<T, is_assignable<T&, T&&>::value>::value; | ||
3395 | }; | ||
3396 | // end workaround | ||
3397 | |||
3398 | #endif | ||
3399 | |||
3400 | // 20.5.4, optional for object types | ||
3401 | template <class T> | ||
3402 | class optional; | ||
3403 | |||
3404 | // 20.5.5, optional for lvalue reference types | ||
3405 | template <class T> | ||
3406 | class optional<T&>; | ||
3407 | |||
3408 | // workaround: std utility functions aren't constexpr yet | ||
3409 | template <class T> | ||
3410 | inline constexpr T&& constexpr_forward(typename ::std::remove_reference<T>::type& t) noexcept { | ||
3411 | return static_cast<T&&>(t); | ||
3412 | } | ||
3413 | |||
3414 | template <class T> | ||
3415 | inline constexpr T&& constexpr_forward(typename ::std::remove_reference<T>::type&& t) noexcept { | ||
3416 | static_assert(!::std::is_lvalue_reference<T>::value, "!!"); | ||
3417 | return static_cast<T&&>(t); | ||
3418 | } | ||
3419 | |||
3420 | template <class T> | ||
3421 | inline constexpr typename ::std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept { | ||
3422 | return static_cast<typename ::std::remove_reference<T>::type&&>(t); | ||
3423 | } | ||
3424 | |||
3425 | #if defined NDEBUG | ||
3426 | #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) | ||
3427 | #else | ||
3428 | #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([] { assert(!#CHECK); }(), (EXPR))) | ||
3429 | #endif | ||
3430 | |||
3431 | namespace detail_ { | ||
3432 | |||
3433 | // static_addressof: a constexpr version of addressof | ||
3434 | template <typename T> | ||
3435 | struct has_overloaded_addressof { | ||
3436 | template <class X> | ||
3437 | static constexpr bool has_overload(...) { | ||
3438 | return false; | ||
3439 | } | ||
3440 | |||
3441 | template <class X, size_t S = sizeof(::std::declval<X&>().operator&())> | ||
3442 | static constexpr bool has_overload(bool) { | ||
3443 | return true; | ||
3444 | } | ||
3445 | |||
3446 | static constexpr bool value = has_overload<T>(true); | ||
3447 | }; | ||
3448 | |||
3449 | template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)> | ||
3450 | constexpr T* static_addressof(T& ref) { | ||
3451 | return &ref; | ||
3452 | } | ||
3453 | |||
3454 | template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)> | ||
3455 | T* static_addressof(T& ref) { | ||
3456 | return ::std::addressof(ref); | ||
3457 | } | ||
3458 | |||
3459 | // the call to convert<A>(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A | ||
3460 | template <class U> | ||
3461 | constexpr U convert(U v) { | ||
3462 | return v; | ||
3463 | } | ||
3464 | |||
3465 | } // namespace detail_ | ||
3466 | |||
3467 | constexpr struct trivial_init_t { | ||
3468 | } trivial_init{}; | ||
3469 | |||
3470 | // 20.5.7, Disengaged state indicator | ||
3471 | struct nullopt_t { | ||
3472 | struct init {}; | ||
3473 | constexpr explicit nullopt_t(init) { | ||
3474 | } | ||
3475 | }; | ||
3476 | constexpr nullopt_t nullopt{nullopt_t::init()}; | ||
3477 | |||
3478 | // 20.5.8, class bad_optional_access | ||
3479 | class bad_optional_access : public ::std::logic_error { | ||
3480 | public: | ||
3481 | explicit bad_optional_access(const ::std::string& what_arg) | ||
3482 | : ::std::logic_error{what_arg} { | ||
3483 | } | ||
3484 | explicit bad_optional_access(const char* what_arg) | ||
3485 | : ::std::logic_error{what_arg} { | ||
3486 | } | ||
3487 | }; | ||
3488 | |||
3489 | template <class T> | ||
3490 | struct alignas(T) optional_base { | ||
3491 | char storage_[sizeof(T)]; | ||
3492 | bool init_; | ||
3493 | |||
3494 | constexpr optional_base() noexcept | ||
3495 | : storage_(), init_(false){}; | ||
3496 | |||
3497 | explicit optional_base(const T& v) | ||
3498 | : storage_(), init_(true) { | ||
3499 | new (&storage()) T(v); | ||
3500 | } | ||
3501 | |||
3502 | explicit optional_base(T&& v) | ||
3503 | : storage_(), init_(true) { | ||
3504 | new (&storage()) T(constexpr_move(v)); | ||
3505 | } | ||
3506 | |||
3507 | template <class... Args> | ||
3508 | explicit optional_base(in_place_t, Args&&... args) | ||
3509 | : init_(true), storage_() { | ||
3510 | new (&storage()) T(constexpr_forward<Args>(args)...); | ||
3511 | } | ||
3512 | |||
3513 | template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)> | ||
3514 | explicit optional_base(in_place_t, ::std::initializer_list<U> il, Args&&... args) | ||
3515 | : init_(true), storage_() { | ||
3516 | new (&storage()) T(il, constexpr_forward<Args>(args)...); | ||
3517 | } | ||
3518 | #if defined __GNUC__ | ||
3519 | #pragma GCC diagnostic push | ||
3520 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" | ||
3521 | #endif | ||
3522 | T& storage() { | ||
3523 | return *reinterpret_cast<T*>(&storage_[0]); | ||
3524 | } | ||
3525 | |||
3526 | constexpr const T& storage() const { | ||
3527 | return *reinterpret_cast<T const*>(&storage_[0]); | ||
3528 | } | ||
3529 | #if defined __GNUC__ | ||
3530 | #pragma GCC diagnostic pop | ||
3531 | #endif | ||
3532 | |||
3533 | ~optional_base() { | ||
3534 | if (init_) { | ||
3535 | storage().T::~T(); | ||
3536 | } | ||
3537 | } | ||
3538 | }; | ||
3539 | |||
3540 | #if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ | ||
3541 | // Sorry, GCC 4.x; you're just a piece of shit | ||
3542 | template <typename T> | ||
3543 | using constexpr_optional_base = optional_base<T>; | ||
3544 | #else | ||
3545 | template <class T> | ||
3546 | struct alignas(T) constexpr_optional_base { | ||
3547 | char storage_[sizeof(T)]; | ||
3548 | bool init_; | ||
3549 | constexpr constexpr_optional_base() noexcept | ||
3550 | : storage_(), init_(false) { | ||
3551 | } | ||
3552 | |||
3553 | explicit constexpr constexpr_optional_base(const T& v) | ||
3554 | : storage_(), init_(true) { | ||
3555 | new (&storage()) T(v); | ||
3556 | } | ||
3557 | |||
3558 | explicit constexpr constexpr_optional_base(T&& v) | ||
3559 | : storage_(), init_(true) { | ||
3560 | new (&storage()) T(constexpr_move(v)); | ||
3561 | } | ||
3562 | |||
3563 | template <class... Args> | ||
3564 | explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) | ||
3565 | : init_(true), storage_() { | ||
3566 | new (&storage()) T(constexpr_forward<Args>(args)...); | ||
3567 | } | ||
3568 | |||
3569 | template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)> | ||
3570 | OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list<U> il, Args&&... args) | ||
3571 | : init_(true), storage_() { | ||
3572 | new (&storage()) T(il, constexpr_forward<Args>(args)...); | ||
3573 | } | ||
3574 | |||
3575 | #if defined __GNUC__ | ||
3576 | #pragma GCC diagnostic push | ||
3577 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" | ||
3578 | #endif | ||
3579 | T& storage() { | ||
3580 | return (*reinterpret_cast<T*>(&storage_[0])); | ||
3581 | } | ||
3582 | |||
3583 | constexpr const T& storage() const { | ||
3584 | return (*reinterpret_cast<T const*>(&storage_[0])); | ||
3585 | } | ||
3586 | #if defined __GNUC__ | ||
3587 | #pragma GCC diagnostic pop | ||
3588 | #endif | ||
3589 | |||
3590 | ~constexpr_optional_base() = default; | ||
3591 | }; | ||
3592 | #endif | ||
3593 | |||
3594 | template <class T> | ||
3595 | using OptionalBase = typename ::std::conditional< | ||
3596 | ::std::is_trivially_destructible<T>::value, | ||
3597 | constexpr_optional_base<typename ::std::remove_const<T>::type>, | ||
3598 | optional_base<typename ::std::remove_const<T>::type>>::type; | ||
3599 | |||
3600 | template <class T> | ||
3601 | class optional : private OptionalBase<T> { | ||
3602 | static_assert(!::std::is_same<typename ::std::decay<T>::type, nullopt_t>::value, "bad T"); | ||
3603 | static_assert(!::std::is_same<typename ::std::decay<T>::type, in_place_t>::value, "bad T"); | ||
3604 | |||
3605 | constexpr bool initialized() const noexcept { | ||
3606 | return OptionalBase<T>::init_; | ||
3607 | } | ||
3608 | typename ::std::remove_const<T>::type* dataptr() { | ||
3609 | return ::std::addressof(OptionalBase<T>::storage()); | ||
3610 | } | ||
3611 | constexpr const T* dataptr() const { | ||
3612 | return detail_::static_addressof(OptionalBase<T>::storage()); | ||
3613 | } | ||
3614 | |||
3615 | #if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 | ||
3616 | constexpr const T& contained_val() const& { | ||
3617 | return OptionalBase<T>::storage(); | ||
3618 | } | ||
3619 | #if OPTIONAL_HAS_MOVE_ACCESSORS == 1 | ||
3620 | OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { | ||
3621 | return ::std::move(OptionalBase<T>::storage()); | ||
3622 | } | ||
3623 | OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { | ||
3624 | return OptionalBase<T>::storage(); | ||
3625 | } | ||
3626 | #else | ||
3627 | T& contained_val() & { | ||
3628 | return OptionalBase<T>::storage(); | ||
3629 | } | ||
3630 | T&& contained_val() && { | ||
3631 | return ::std::move(OptionalBase<T>::storage()); | ||
3632 | } | ||
3633 | #endif | ||
3634 | #else | ||
3635 | constexpr const T& contained_val() const { | ||
3636 | return OptionalBase<T>::storage(); | ||
3637 | } | ||
3638 | T& contained_val() { | ||
3639 | return OptionalBase<T>::storage(); | ||
3640 | } | ||
3641 | #endif | ||
3642 | |||
3643 | void clear() noexcept { | ||
3644 | if (initialized()) | ||
3645 | dataptr()->T::~T(); | ||
3646 | OptionalBase<T>::init_ = false; | ||
3647 | } | ||
3648 | |||
3649 | template <class... Args> | ||
3650 | void initialize(Args&&... args) noexcept(noexcept(T(::std::forward<Args>(args)...))) { | ||
3651 | assert(!OptionalBase<T>::init_); | ||
3652 | ::new (static_cast<void*>(dataptr())) T(::std::forward<Args>(args)...); | ||
3653 | OptionalBase<T>::init_ = true; | ||
3654 | } | ||
3655 | |||
3656 | template <class U, class... Args> | ||
3657 | void initialize(::std::initializer_list<U> il, Args&&... args) noexcept(noexcept(T(il, ::std::forward<Args>(args)...))) { | ||
3658 | assert(!OptionalBase<T>::init_); | ||
3659 | ::new (static_cast<void*>(dataptr())) T(il, ::std::forward<Args>(args)...); | ||
3660 | OptionalBase<T>::init_ = true; | ||
3661 | } | ||
3662 | |||
3663 | public: | ||
3664 | typedef T value_type; | ||
3665 | |||
3666 | // 20.5.5.1, constructors | ||
3667 | constexpr optional() noexcept | ||
3668 | : OptionalBase<T>(){}; | ||
3669 | constexpr optional(nullopt_t) noexcept | ||
3670 | : OptionalBase<T>(){}; | ||
3671 | |||
3672 | optional(const optional& rhs) | ||
3673 | : OptionalBase<T>() { | ||
3674 | if (rhs.initialized()) { | ||
3675 | ::new (static_cast<void*>(dataptr())) T(*rhs); | ||
3676 | OptionalBase<T>::init_ = true; | ||
3677 | } | ||
3678 | } | ||
3679 | |||
3680 | optional(const optional<T&>& rhs) | ||
3681 | : optional() { | ||
3682 | if (rhs) { | ||
3683 | ::new (static_cast<void*>(dataptr())) T(*rhs); | ||
3684 | OptionalBase<T>::init_ = true; | ||
3685 | } | ||
3686 | } | ||
3687 | |||
3688 | optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible<T>::value) | ||
3689 | : OptionalBase<T>() { | ||
3690 | if (rhs.initialized()) { | ||
3691 | ::new (static_cast<void*>(dataptr())) T(::std::move(*rhs)); | ||
3692 | OptionalBase<T>::init_ = true; | ||
3693 | } | ||
3694 | } | ||
3695 | |||
3696 | constexpr optional(const T& v) | ||
3697 | : OptionalBase<T>(v) { | ||
3698 | } | ||
3699 | |||
3700 | constexpr optional(T&& v) | ||
3701 | : OptionalBase<T>(constexpr_move(v)) { | ||
3702 | } | ||
3703 | |||
3704 | template <class... Args> | ||
3705 | explicit constexpr optional(in_place_t, Args&&... args) | ||
3706 | : OptionalBase<T>(in_place, constexpr_forward<Args>(args)...) { | ||
3707 | } | ||
3708 | |||
3709 | template <class U, class... Args, TR2_OPTIONAL_REQUIRES(::std::is_constructible<T, ::std::initializer_list<U>>)> | ||
3710 | OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list<U> il, Args&&... args) | ||
3711 | : OptionalBase<T>(in_place, il, constexpr_forward<Args>(args)...) { | ||
3712 | } | ||
3713 | |||
3714 | // 20.5.4.2, Destructor | ||
3715 | ~optional() = default; | ||
3716 | |||
3717 | // 20.5.4.3, assignment | ||
3718 | optional& operator=(nullopt_t) noexcept { | ||
3719 | clear(); | ||
3720 | return *this; | ||
3721 | } | ||
3722 | |||
3723 | optional& operator=(const optional& rhs) { | ||
3724 | if (initialized() == true && rhs.initialized() == false) | ||
3725 | clear(); | ||
3726 | else if (initialized() == false && rhs.initialized() == true) | ||
3727 | initialize(*rhs); | ||
3728 | else if (initialized() == true && rhs.initialized() == true) | ||
3729 | contained_val() = *rhs; | ||
3730 | return *this; | ||
3731 | } | ||
3732 | |||
3733 | optional& operator=(optional&& rhs) noexcept(::std::is_nothrow_move_assignable<T>::value&& ::std::is_nothrow_move_constructible<T>::value) { | ||
3734 | if (initialized() == true && rhs.initialized() == false) | ||
3735 | clear(); | ||
3736 | else if (initialized() == false && rhs.initialized() == true) | ||
3737 | initialize(::std::move(*rhs)); | ||
3738 | else if (initialized() == true && rhs.initialized() == true) | ||
3739 | contained_val() = ::std::move(*rhs); | ||
3740 | return *this; | ||
3741 | } | ||
3742 | |||
3743 | template <class U> | ||
3744 | auto operator=(U&& v) | ||
3745 | -> typename ::std::enable_if< | ||
3746 | ::std::is_same<typename ::std::decay<U>::type, T>::value, | ||
3747 | optional&>::type { | ||
3748 | if (initialized()) { | ||
3749 | contained_val() = ::std::forward<U>(v); | ||
3750 | } | ||
3751 | else { | ||
3752 | initialize(::std::forward<U>(v)); | ||
3753 | } | ||
3754 | return *this; | ||
3755 | } | ||
3756 | |||
3757 | template <class... Args> | ||
3758 | void emplace(Args&&... args) { | ||
3759 | clear(); | ||
3760 | initialize(::std::forward<Args>(args)...); | ||
3761 | } | ||
3762 | |||
3763 | template <class U, class... Args> | ||
3764 | void emplace(::std::initializer_list<U> il, Args&&... args) { | ||
3765 | clear(); | ||
3766 | initialize<U, Args...>(il, ::std::forward<Args>(args)...); | ||
3767 | } | ||
3768 | |||
3769 | // 20.5.4.4, Swap | ||
3770 | void swap(optional<T>& rhs) noexcept(::std::is_nothrow_move_constructible<T>::value&& noexcept(swap(::std::declval<T&>(), ::std::declval<T&>()))) { | ||
3771 | if (initialized() == true && rhs.initialized() == false) { | ||
3772 | rhs.initialize(::std::move(**this)); | ||
3773 | clear(); | ||
3774 | } | ||
3775 | else if (initialized() == false && rhs.initialized() == true) { | ||
3776 | initialize(::std::move(*rhs)); | ||
3777 | rhs.clear(); | ||
3778 | } | ||
3779 | else if (initialized() == true && rhs.initialized() == true) { | ||
3780 | using ::std::swap; | ||
3781 | swap(**this, *rhs); | ||
3782 | } | ||
3783 | } | ||
3784 | |||
3785 | // 20.5.4.5, Observers | ||
3786 | |||
3787 | explicit constexpr operator bool() const noexcept { | ||
3788 | return initialized(); | ||
3789 | } | ||
3790 | |||
3791 | constexpr T const* operator->() const { | ||
3792 | return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); | ||
3793 | } | ||
3794 | |||
3795 | #if OPTIONAL_HAS_MOVE_ACCESSORS == 1 | ||
3796 | |||
3797 | OPTIONAL_MUTABLE_CONSTEXPR T* operator->() { | ||
3798 | assert(initialized()); | ||
3799 | return dataptr(); | ||
3800 | } | ||
3801 | |||
3802 | constexpr T const& operator*() const& { | ||
3803 | return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); | ||
3804 | } | ||
3805 | |||
3806 | OPTIONAL_MUTABLE_CONSTEXPR T& operator*() & { | ||
3807 | assert(initialized()); | ||
3808 | return contained_val(); | ||
3809 | } | ||
3810 | |||
3811 | OPTIONAL_MUTABLE_CONSTEXPR T&& operator*() && { | ||
3812 | assert(initialized()); | ||
3813 | return constexpr_move(contained_val()); | ||
3814 | } | ||
3815 | |||
3816 | constexpr T const& value() const& { | ||
3817 | return initialized() ? contained_val() | ||
3818 | #ifdef SOL_NO_EXCEPTIONS | ||
3819 | // we can't abort here | ||
3820 | // because there's no constexpr abort | ||
3821 | : *static_cast<T*>(nullptr); | ||
3822 | #else | ||
3823 | : (throw bad_optional_access("bad optional access"), contained_val()); | ||
3824 | #endif | ||
3825 | } | ||
3826 | |||
3827 | OPTIONAL_MUTABLE_CONSTEXPR T& value() & { | ||
3828 | return initialized() ? contained_val() | ||
3829 | #ifdef SOL_NO_EXCEPTIONS | ||
3830 | : *static_cast<T*>(nullptr); | ||
3831 | #else | ||
3832 | : (throw bad_optional_access("bad optional access"), contained_val()); | ||
3833 | #endif | ||
3834 | } | ||
3835 | |||
3836 | OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { | ||
3837 | return initialized() ? contained_val() | ||
3838 | #ifdef SOL_NO_EXCEPTIONS | ||
3839 | // we can't abort here | ||
3840 | // because there's no constexpr abort | ||
3841 | : std::move(*static_cast<T*>(nullptr)); | ||
3842 | #else | ||
3843 | : (throw bad_optional_access("bad optional access"), contained_val()); | ||
3844 | #endif | ||
3845 | } | ||
3846 | |||
3847 | #else | ||
3848 | |||
3849 | T* operator->() { | ||
3850 | assert(initialized()); | ||
3851 | return dataptr(); | ||
3852 | } | ||
3853 | |||
3854 | constexpr T const& operator*() const { | ||
3855 | return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); | ||
3856 | } | ||
3857 | |||
3858 | T& operator*() { | ||
3859 | assert(initialized()); | ||
3860 | return contained_val(); | ||
3861 | } | ||
3862 | |||
3863 | constexpr T const& value() const { | ||
3864 | return initialized() ? contained_val() | ||
3865 | #ifdef SOL_NO_EXCEPTIONS | ||
3866 | // we can't abort here | ||
3867 | // because there's no constexpr abort | ||
3868 | : *static_cast<T*>(nullptr); | ||
3869 | #else | ||
3870 | : (throw bad_optional_access("bad optional access"), contained_val()); | ||
3871 | #endif | ||
3872 | } | ||
3873 | |||
3874 | T& value() { | ||
3875 | return initialized() ? contained_val() | ||
3876 | #ifdef SOL_NO_EXCEPTIONS | ||
3877 | // we can abort here | ||
3878 | // but the others are constexpr, so we can't... | ||
3879 | : (std::abort(), *static_cast<T*>(nullptr)); | ||
3880 | #else | ||
3881 | : (throw bad_optional_access("bad optional access"), contained_val()); | ||
3882 | #endif | ||
3883 | } | ||
3884 | |||
3885 | #endif | ||
3886 | |||
3887 | #if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 | ||
3888 | |||
3889 | template <class V> | ||
3890 | constexpr T value_or(V&& v) const& { | ||
3891 | return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); | ||
3892 | } | ||
3893 | |||
3894 | #if OPTIONAL_HAS_MOVE_ACCESSORS == 1 | ||
3895 | |||
3896 | template <class V> | ||
3897 | OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && { | ||
3898 | return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); | ||
3899 | } | ||
3900 | |||
3901 | #else | ||
3902 | |||
3903 | template <class V> | ||
3904 | T value_or(V&& v) && { | ||
3905 | return *this ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) : detail_::convert<T>(constexpr_forward<V>(v)); | ||
3906 | } | ||
3907 | |||
3908 | #endif | ||
3909 | |||
3910 | #else | ||
3911 | |||
3912 | template <class V> | ||
3913 | constexpr T value_or(V&& v) const { | ||
3914 | return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); | ||
3915 | } | ||
3916 | |||
3917 | #endif | ||
3918 | }; | ||
3919 | |||
3920 | template <class T> | ||
3921 | class optional<T&> { | ||
3922 | static_assert(!::std::is_same<T, nullopt_t>::value, "bad T"); | ||
3923 | static_assert(!::std::is_same<T, in_place_t>::value, "bad T"); | ||
3924 | T* ref; | ||
3925 | |||
3926 | public: | ||
3927 | // 20.5.5.1, construction/destruction | ||
3928 | constexpr optional() noexcept | ||
3929 | : ref(nullptr) { | ||
3930 | } | ||
3931 | |||
3932 | constexpr optional(nullopt_t) noexcept | ||
3933 | : ref(nullptr) { | ||
3934 | } | ||
3935 | |||
3936 | constexpr optional(T& v) noexcept | ||
3937 | : ref(detail_::static_addressof(v)) { | ||
3938 | } | ||
3939 | |||
3940 | optional(T&&) = delete; | ||
3941 | |||
3942 | constexpr optional(const optional& rhs) noexcept | ||
3943 | : ref(rhs.ref) { | ||
3944 | } | ||
3945 | |||
3946 | explicit constexpr optional(in_place_t, T& v) noexcept | ||
3947 | : ref(detail_::static_addressof(v)) { | ||
3948 | } | ||
3949 | |||
3950 | explicit optional(in_place_t, T&&) = delete; | ||
3951 | |||
3952 | ~optional() = default; | ||
3953 | |||
3954 | // 20.5.5.2, mutation | ||
3955 | optional& operator=(nullopt_t) noexcept { | ||
3956 | ref = nullptr; | ||
3957 | return *this; | ||
3958 | } | ||
3959 | |||
3960 | // optional& operator=(const optional& rhs) noexcept { | ||
3961 | // ref = rhs.ref; | ||
3962 | // return *this; | ||
3963 | // } | ||
3964 | |||
3965 | // optional& operator=(optional&& rhs) noexcept { | ||
3966 | // ref = rhs.ref; | ||
3967 | // return *this; | ||
3968 | // } | ||
3969 | |||
3970 | template <typename U> | ||
3971 | auto operator=(U&& rhs) noexcept | ||
3972 | -> typename ::std::enable_if< | ||
3973 | ::std::is_same<typename ::std::decay<U>::type, optional<T&>>::value, | ||
3974 | optional&>::type { | ||
3975 | ref = rhs.ref; | ||
3976 | return *this; | ||
3977 | } | ||
3978 | |||
3979 | template <typename U> | ||
3980 | auto operator=(U&& rhs) noexcept | ||
3981 | -> typename ::std::enable_if< | ||
3982 | !::std::is_same<typename ::std::decay<U>::type, optional<T&>>::value, | ||
3983 | optional&>::type = delete; | ||
3984 | |||
3985 | void emplace(T& v) noexcept { | ||
3986 | ref = detail_::static_addressof(v); | ||
3987 | } | ||
3988 | |||
3989 | void emplace(T&&) = delete; | ||
3990 | |||
3991 | void swap(optional<T&>& rhs) noexcept { | ||
3992 | ::std::swap(ref, rhs.ref); | ||
3993 | } | ||
3994 | |||
3995 | // 20.5.5.3, observers | ||
3996 | constexpr T* operator->() const { | ||
3997 | return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); | ||
3998 | } | ||
3999 | |||
4000 | constexpr T& operator*() const { | ||
4001 | return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); | ||
4002 | } | ||
4003 | |||
4004 | constexpr T& value() const { | ||
4005 | #ifdef SOL_NO_EXCEPTIONS | ||
4006 | return *ref; | ||
4007 | #else | ||
4008 | return ref ? *ref | ||
4009 | : (throw bad_optional_access("bad optional access"), *ref); | ||
4010 | #endif // Exceptions | ||
4011 | } | ||
4012 | |||
4013 | explicit constexpr operator bool() const noexcept { | ||
4014 | return ref != nullptr; | ||
4015 | } | ||
4016 | |||
4017 | template <typename V> | ||
4018 | constexpr T& value_or(V&& v) const { | ||
4019 | return *this ? **this : detail_::convert<T&>(constexpr_forward<V>(v)); | ||
4020 | } | ||
4021 | }; | ||
4022 | |||
4023 | template <class T> | ||
4024 | class optional<T&&> { | ||
4025 | static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); | ||
4026 | }; | ||
4027 | |||
4028 | // 20.5.8, Relational operators | ||
4029 | template <class T> | ||
4030 | constexpr bool operator==(const optional<T>& x, const optional<T>& y) { | ||
4031 | return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; | ||
4032 | } | ||
4033 | |||
4034 | template <class T> | ||
4035 | constexpr bool operator!=(const optional<T>& x, const optional<T>& y) { | ||
4036 | return !(x == y); | ||
4037 | } | ||
4038 | |||
4039 | template <class T> | ||
4040 | constexpr bool operator<(const optional<T>& x, const optional<T>& y) { | ||
4041 | return (!y) ? false : (!x) ? true : *x < *y; | ||
4042 | } | ||
4043 | |||
4044 | template <class T> | ||
4045 | constexpr bool operator>(const optional<T>& x, const optional<T>& y) { | ||
4046 | return (y < x); | ||
4047 | } | ||
4048 | |||
4049 | template <class T> | ||
4050 | constexpr bool operator<=(const optional<T>& x, const optional<T>& y) { | ||
4051 | return !(y < x); | ||
4052 | } | ||
4053 | |||
4054 | template <class T> | ||
4055 | constexpr bool operator>=(const optional<T>& x, const optional<T>& y) { | ||
4056 | return !(x < y); | ||
4057 | } | ||
4058 | |||
4059 | // 20.5.9, Comparison with nullopt | ||
4060 | template <class T> | ||
4061 | constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { | ||
4062 | return (!x); | ||
4063 | } | ||
4064 | |||
4065 | template <class T> | ||
4066 | constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { | ||
4067 | return (!x); | ||
4068 | } | ||
4069 | |||
4070 | template <class T> | ||
4071 | constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept { | ||
4072 | return bool(x); | ||
4073 | } | ||
4074 | |||
4075 | template <class T> | ||
4076 | constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept { | ||
4077 | return bool(x); | ||
4078 | } | ||
4079 | |||
4080 | template <class T> | ||
4081 | constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { | ||
4082 | return false; | ||
4083 | } | ||
4084 | |||
4085 | template <class T> | ||
4086 | constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept { | ||
4087 | return bool(x); | ||
4088 | } | ||
4089 | |||
4090 | template <class T> | ||
4091 | constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept { | ||
4092 | return (!x); | ||
4093 | } | ||
4094 | |||
4095 | template <class T> | ||
4096 | constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { | ||
4097 | return true; | ||
4098 | } | ||
4099 | |||
4100 | template <class T> | ||
4101 | constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept { | ||
4102 | return bool(x); | ||
4103 | } | ||
4104 | |||
4105 | template <class T> | ||
4106 | constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { | ||
4107 | return false; | ||
4108 | } | ||
4109 | |||
4110 | template <class T> | ||
4111 | constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { | ||
4112 | return true; | ||
4113 | } | ||
4114 | |||
4115 | template <class T> | ||
4116 | constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept { | ||
4117 | return (!x); | ||
4118 | } | ||
4119 | |||
4120 | // 20.5.10, Comparison with T | ||
4121 | template <class T> | ||
4122 | constexpr bool operator==(const optional<T>& x, const T& v) { | ||
4123 | return bool(x) ? *x == v : false; | ||
4124 | } | ||
4125 | |||
4126 | template <class T> | ||
4127 | constexpr bool operator==(const T& v, const optional<T>& x) { | ||
4128 | return bool(x) ? v == *x : false; | ||
4129 | } | ||
4130 | |||
4131 | template <class T> | ||
4132 | constexpr bool operator!=(const optional<T>& x, const T& v) { | ||
4133 | return bool(x) ? *x != v : true; | ||
4134 | } | ||
4135 | |||
4136 | template <class T> | ||
4137 | constexpr bool operator!=(const T& v, const optional<T>& x) { | ||
4138 | return bool(x) ? v != *x : true; | ||
4139 | } | ||
4140 | |||
4141 | template <class T> | ||
4142 | constexpr bool operator<(const optional<T>& x, const T& v) { | ||
4143 | return bool(x) ? *x < v : true; | ||
4144 | } | ||
4145 | |||
4146 | template <class T> | ||
4147 | constexpr bool operator>(const T& v, const optional<T>& x) { | ||
4148 | return bool(x) ? v > *x : true; | ||
4149 | } | ||
4150 | |||
4151 | template <class T> | ||
4152 | constexpr bool operator>(const optional<T>& x, const T& v) { | ||
4153 | return bool(x) ? *x > v : false; | ||
4154 | } | ||
4155 | |||
4156 | template <class T> | ||
4157 | constexpr bool operator<(const T& v, const optional<T>& x) { | ||
4158 | return bool(x) ? v < *x : false; | ||
4159 | } | ||
4160 | |||
4161 | template <class T> | ||
4162 | constexpr bool operator>=(const optional<T>& x, const T& v) { | ||
4163 | return bool(x) ? *x >= v : false; | ||
4164 | } | ||
4165 | |||
4166 | template <class T> | ||
4167 | constexpr bool operator<=(const T& v, const optional<T>& x) { | ||
4168 | return bool(x) ? v <= *x : false; | ||
4169 | } | ||
4170 | |||
4171 | template <class T> | ||
4172 | constexpr bool operator<=(const optional<T>& x, const T& v) { | ||
4173 | return bool(x) ? *x <= v : true; | ||
4174 | } | ||
4175 | |||
4176 | template <class T> | ||
4177 | constexpr bool operator>=(const T& v, const optional<T>& x) { | ||
4178 | return bool(x) ? v >= *x : true; | ||
4179 | } | ||
4180 | |||
4181 | // Comparison of optional<T&> with T | ||
4182 | template <class T> | ||
4183 | constexpr bool operator==(const optional<T&>& x, const T& v) { | ||
4184 | return bool(x) ? *x == v : false; | ||
4185 | } | ||
4186 | |||
4187 | template <class T> | ||
4188 | constexpr bool operator==(const T& v, const optional<T&>& x) { | ||
4189 | return bool(x) ? v == *x : false; | ||
4190 | } | ||
4191 | |||
4192 | template <class T> | ||
4193 | constexpr bool operator!=(const optional<T&>& x, const T& v) { | ||
4194 | return bool(x) ? *x != v : true; | ||
4195 | } | ||
4196 | |||
4197 | template <class T> | ||
4198 | constexpr bool operator!=(const T& v, const optional<T&>& x) { | ||
4199 | return bool(x) ? v != *x : true; | ||
4200 | } | ||
4201 | |||
4202 | template <class T> | ||
4203 | constexpr bool operator<(const optional<T&>& x, const T& v) { | ||
4204 | return bool(x) ? *x < v : true; | ||
4205 | } | ||
4206 | |||
4207 | template <class T> | ||
4208 | constexpr bool operator>(const T& v, const optional<T&>& x) { | ||
4209 | return bool(x) ? v > *x : true; | ||
4210 | } | ||
4211 | |||
4212 | template <class T> | ||
4213 | constexpr bool operator>(const optional<T&>& x, const T& v) { | ||
4214 | return bool(x) ? *x > v : false; | ||
4215 | } | ||
4216 | |||
4217 | template <class T> | ||
4218 | constexpr bool operator<(const T& v, const optional<T&>& x) { | ||
4219 | return bool(x) ? v < *x : false; | ||
4220 | } | ||
4221 | |||
4222 | template <class T> | ||
4223 | constexpr bool operator>=(const optional<T&>& x, const T& v) { | ||
4224 | return bool(x) ? *x >= v : false; | ||
4225 | } | ||
4226 | |||
4227 | template <class T> | ||
4228 | constexpr bool operator<=(const T& v, const optional<T&>& x) { | ||
4229 | return bool(x) ? v <= *x : false; | ||
4230 | } | ||
4231 | |||
4232 | template <class T> | ||
4233 | constexpr bool operator<=(const optional<T&>& x, const T& v) { | ||
4234 | return bool(x) ? *x <= v : true; | ||
4235 | } | ||
4236 | |||
4237 | template <class T> | ||
4238 | constexpr bool operator>=(const T& v, const optional<T&>& x) { | ||
4239 | return bool(x) ? v >= *x : true; | ||
4240 | } | ||
4241 | |||
4242 | // Comparison of optional<T const&> with T | ||
4243 | template <class T> | ||
4244 | constexpr bool operator==(const optional<const T&>& x, const T& v) { | ||
4245 | return bool(x) ? *x == v : false; | ||
4246 | } | ||
4247 | |||
4248 | template <class T> | ||
4249 | constexpr bool operator==(const T& v, const optional<const T&>& x) { | ||
4250 | return bool(x) ? v == *x : false; | ||
4251 | } | ||
4252 | |||
4253 | template <class T> | ||
4254 | constexpr bool operator!=(const optional<const T&>& x, const T& v) { | ||
4255 | return bool(x) ? *x != v : true; | ||
4256 | } | ||
4257 | |||
4258 | template <class T> | ||
4259 | constexpr bool operator!=(const T& v, const optional<const T&>& x) { | ||
4260 | return bool(x) ? v != *x : true; | ||
4261 | } | ||
4262 | |||
4263 | template <class T> | ||
4264 | constexpr bool operator<(const optional<const T&>& x, const T& v) { | ||
4265 | return bool(x) ? *x < v : true; | ||
4266 | } | ||
4267 | |||
4268 | template <class T> | ||
4269 | constexpr bool operator>(const T& v, const optional<const T&>& x) { | ||
4270 | return bool(x) ? v > *x : true; | ||
4271 | } | ||
4272 | |||
4273 | template <class T> | ||
4274 | constexpr bool operator>(const optional<const T&>& x, const T& v) { | ||
4275 | return bool(x) ? *x > v : false; | ||
4276 | } | ||
4277 | |||
4278 | template <class T> | ||
4279 | constexpr bool operator<(const T& v, const optional<const T&>& x) { | ||
4280 | return bool(x) ? v < *x : false; | ||
4281 | } | ||
4282 | |||
4283 | template <class T> | ||
4284 | constexpr bool operator>=(const optional<const T&>& x, const T& v) { | ||
4285 | return bool(x) ? *x >= v : false; | ||
4286 | } | ||
4287 | |||
4288 | template <class T> | ||
4289 | constexpr bool operator<=(const T& v, const optional<const T&>& x) { | ||
4290 | return bool(x) ? v <= *x : false; | ||
4291 | } | ||
4292 | |||
4293 | template <class T> | ||
4294 | constexpr bool operator<=(const optional<const T&>& x, const T& v) { | ||
4295 | return bool(x) ? *x <= v : true; | ||
4296 | } | ||
4297 | |||
4298 | template <class T> | ||
4299 | constexpr bool operator>=(const T& v, const optional<const T&>& x) { | ||
4300 | return bool(x) ? v >= *x : true; | ||
4301 | } | ||
4302 | |||
4303 | // 20.5.12, Specialized algorithms | ||
4304 | template <class T> | ||
4305 | void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) { | ||
4306 | x.swap(y); | ||
4307 | } | ||
4308 | |||
4309 | template <class T> | ||
4310 | constexpr optional<typename ::std::decay<T>::type> make_optional(T&& v) { | ||
4311 | return optional<typename ::std::decay<T>::type>(constexpr_forward<T>(v)); | ||
4312 | } | ||
4313 | |||
4314 | template <class X> | ||
4315 | constexpr optional<X&> make_optional(::std::reference_wrapper<X> v) { | ||
4316 | return optional<X&>(v.get()); | ||
4317 | } | ||
4318 | |||
4319 | } // namespace sol | ||
4320 | |||
4321 | namespace std { | ||
4322 | template <typename T> | ||
4323 | struct hash<sol::optional<T>> { | ||
4324 | typedef typename hash<T>::result_type result_type; | ||
4325 | typedef sol::optional<T> argument_type; | ||
4326 | |||
4327 | constexpr result_type operator()(argument_type const& arg) const { | ||
4328 | return arg ? ::std::hash<T>{}(*arg) : result_type{}; | ||
4329 | } | ||
4330 | }; | ||
4331 | |||
4332 | template <typename T> | ||
4333 | struct hash<sol::optional<T&>> { | ||
4334 | typedef typename hash<T>::result_type result_type; | ||
4335 | typedef sol::optional<T&> argument_type; | ||
4336 | |||
4337 | constexpr result_type operator()(argument_type const& arg) const { | ||
4338 | return arg ? ::std::hash<T>{}(*arg) : result_type{}; | ||
4339 | } | ||
4340 | }; | ||
4341 | } // namespace std | ||
4342 | |||
4343 | #if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ | ||
4344 | #pragma warning(pop) | ||
4345 | #endif | ||
4346 | |||
4347 | #undef TR2_OPTIONAL_REQUIRES | ||
4348 | #undef TR2_OPTIONAL_ASSERTED_EXPRESSION | ||
4349 | |||
4350 | // end of sol/optional_implementation.hpp | ||
4351 | |||
4352 | #endif // Boost vs. Better optional | ||
4353 | |||
4354 | namespace sol { | ||
4355 | |||
4356 | #if defined(SOL_USE_BOOST) && SOL_USE_BOOST | ||
4357 | template <typename T> | ||
4358 | using optional = boost::optional<T>; | ||
4359 | using nullopt_t = boost::none_t; | ||
4360 | const nullopt_t nullopt = boost::none; | ||
4361 | #endif // Boost vs. Better optional | ||
4362 | |||
4363 | namespace meta { | ||
4364 | template <typename T> | ||
4365 | struct is_optional : std::false_type {}; | ||
4366 | template <typename T> | ||
4367 | struct is_optional<optional<T>> : std::true_type {}; | ||
4368 | } // namespace meta | ||
4369 | } // namespace sol | ||
4370 | |||
4371 | // end of sol/optional.hpp | ||
4372 | |||
4373 | // beginning of sol/forward_detail.hpp | ||
4374 | |||
4375 | namespace sol { | ||
4376 | namespace detail { | ||
4377 | const bool default_safe_function_calls = | ||
4378 | #if defined(SOL_SAFE_FUNCTION_CALLS) && SOL_SAFE_FUNCTION_CALLS | ||
4379 | true; | ||
4380 | #else | ||
4381 | false; | ||
4382 | #endif | ||
4383 | } // namespace detail | ||
4384 | |||
4385 | namespace meta { | ||
4386 | namespace meta_detail { | ||
4387 | } | ||
4388 | } // namespace meta::meta_detail | ||
4389 | |||
4390 | namespace stack { | ||
4391 | namespace stack_detail { | ||
4392 | template <typename T> | ||
4393 | struct undefined_metatable; | ||
4394 | } | ||
4395 | } // namespace stack::stack_detail | ||
4396 | |||
4397 | namespace usertype_detail { | ||
4398 | template <typename T, typename Regs, typename Fx> | ||
4399 | void insert_default_registrations(Regs& l, int& index, Fx&& fx); | ||
4400 | |||
4401 | template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler> | ||
4402 | void make_destructor(Regs& l, int& index); | ||
4403 | template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> = meta::enabler> | ||
4404 | void make_destructor(Regs& l, int& index); | ||
4405 | } // namespace usertype_detail | ||
4406 | } // namespace sol | ||
4407 | |||
4408 | // end of sol/forward_detail.hpp | ||
4409 | |||
4410 | // beginning of sol/raii.hpp | ||
4411 | |||
4412 | namespace sol { | ||
4413 | namespace detail { | ||
4414 | struct default_construct { | ||
4415 | template <typename T, typename... Args> | ||
4416 | static void construct(T&& obj, Args&&... args) { | ||
4417 | typedef meta::unqualified_t<T> Tu; | ||
4418 | std::allocator<Tu> alloc{}; | ||
4419 | std::allocator_traits<std::allocator<Tu>>::construct(alloc, obj, std::forward<Args>(args)...); | ||
4420 | } | ||
4421 | |||
4422 | template <typename T, typename... Args> | ||
4423 | void operator()(T&& obj, Args&&... args) const { | ||
4424 | construct(std::forward<T>(obj), std::forward<Args>(args)...); | ||
4425 | } | ||
4426 | }; | ||
4427 | |||
4428 | struct default_destruct { | ||
4429 | template <typename T> | ||
4430 | static void destroy(T&& obj) { | ||
4431 | std::allocator<meta::unqualified_t<T>> alloc{}; | ||
4432 | alloc.destroy(obj); | ||
4433 | } | ||
4434 | |||
4435 | template <typename T> | ||
4436 | void operator()(T&& obj) const { | ||
4437 | destroy(std::forward<T>(obj)); | ||
4438 | } | ||
4439 | }; | ||
4440 | |||
4441 | struct deleter { | ||
4442 | template <typename T> | ||
4443 | void operator()(T* p) const { | ||
4444 | delete p; | ||
4445 | } | ||
4446 | }; | ||
4447 | |||
4448 | struct state_deleter { | ||
4449 | void operator()(lua_State* L) const { | ||
4450 | lua_close(L); | ||
4451 | } | ||
4452 | }; | ||
4453 | |||
4454 | template <typename T, typename Dx, typename... Args> | ||
4455 | inline std::unique_ptr<T, Dx> make_unique_deleter(Args&&... args) { | ||
4456 | return std::unique_ptr<T, Dx>(new T(std::forward<Args>(args)...)); | ||
4457 | } | ||
4458 | |||
4459 | template <typename Tag, typename T> | ||
4460 | struct tagged { | ||
4461 | T value; | ||
4462 | template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, tagged>> = meta::enabler> | ||
4463 | tagged(Arg&& arg, Args&&... args) | ||
4464 | : value(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
4465 | } | ||
4466 | }; | ||
4467 | } // namespace detail | ||
4468 | |||
4469 | template <typename... Args> | ||
4470 | struct constructor_list {}; | ||
4471 | |||
4472 | template <typename... Args> | ||
4473 | using constructors = constructor_list<Args...>; | ||
4474 | |||
4475 | const auto default_constructor = constructors<types<>>{}; | ||
4476 | |||
4477 | struct no_construction {}; | ||
4478 | const auto no_constructor = no_construction{}; | ||
4479 | |||
4480 | struct call_construction {}; | ||
4481 | const auto call_constructor = call_construction{}; | ||
4482 | |||
4483 | template <typename... Functions> | ||
4484 | struct constructor_wrapper { | ||
4485 | std::tuple<Functions...> functions; | ||
4486 | template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler> | ||
4487 | constructor_wrapper(Arg&& arg, Args&&... args) | ||
4488 | : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
4489 | } | ||
4490 | }; | ||
4491 | |||
4492 | template <typename... Functions> | ||
4493 | inline auto initializers(Functions&&... functions) { | ||
4494 | return constructor_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...); | ||
4495 | } | ||
4496 | |||
4497 | template <typename... Functions> | ||
4498 | struct factory_wrapper { | ||
4499 | std::tuple<Functions...> functions; | ||
4500 | template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, factory_wrapper>> = meta::enabler> | ||
4501 | factory_wrapper(Arg&& arg, Args&&... args) | ||
4502 | : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
4503 | } | ||
4504 | }; | ||
4505 | |||
4506 | template <typename... Functions> | ||
4507 | inline auto factories(Functions&&... functions) { | ||
4508 | return factory_wrapper<std::decay_t<Functions>...>(std::forward<Functions>(functions)...); | ||
4509 | } | ||
4510 | |||
4511 | template <typename Function> | ||
4512 | struct destructor_wrapper { | ||
4513 | Function fx; | ||
4514 | destructor_wrapper(Function f) | ||
4515 | : fx(std::move(f)) { | ||
4516 | } | ||
4517 | }; | ||
4518 | |||
4519 | template <> | ||
4520 | struct destructor_wrapper<void> {}; | ||
4521 | |||
4522 | const destructor_wrapper<void> default_destructor{}; | ||
4523 | |||
4524 | template <typename Fx> | ||
4525 | inline auto destructor(Fx&& fx) { | ||
4526 | return destructor_wrapper<std::decay_t<Fx>>(std::forward<Fx>(fx)); | ||
4527 | } | ||
4528 | |||
4529 | } // namespace sol | ||
4530 | |||
4531 | // end of sol/raii.hpp | ||
4532 | |||
4533 | // beginning of sol/filters.hpp | ||
4534 | |||
4535 | #include <array> | ||
4536 | |||
4537 | namespace sol { | ||
4538 | namespace detail { | ||
4539 | struct filter_base_tag {}; | ||
4540 | } // namespace detail | ||
4541 | |||
4542 | template <int Target, int... In> | ||
4543 | struct static_stack_dependencies : detail::filter_base_tag {}; | ||
4544 | typedef static_stack_dependencies<-1, 1> self_dependency; | ||
4545 | template <int... In> | ||
4546 | struct returns_self_with : detail::filter_base_tag {}; | ||
4547 | typedef returns_self_with<> returns_self; | ||
4548 | |||
4549 | struct stack_dependencies : detail::filter_base_tag { | ||
4550 | int target; | ||
4551 | std::array<int, 64> stack_indices; | ||
4552 | std::size_t len; | ||
4553 | |||
4554 | template <typename... Args> | ||
4555 | stack_dependencies(int stack_target, Args&&... args) | ||
4556 | : target(stack_target), stack_indices(), len(sizeof...(Args)) { | ||
4557 | std::size_t i = 0; | ||
4558 | (void)detail::swallow{int(), (stack_indices[i++] = static_cast<int>(std::forward<Args>(args)), int())...}; | ||
4559 | } | ||
4560 | |||
4561 | int& operator[](std::size_t i) { | ||
4562 | return stack_indices[i]; | ||
4563 | } | ||
4564 | |||
4565 | const int& operator[](std::size_t i) const { | ||
4566 | return stack_indices[i]; | ||
4567 | } | ||
4568 | |||
4569 | std::size_t size() const { | ||
4570 | return len; | ||
4571 | } | ||
4572 | }; | ||
4573 | |||
4574 | template <typename F, typename... Filters> | ||
4575 | struct filter_wrapper { | ||
4576 | typedef std::index_sequence_for<Filters...> indices; | ||
4577 | |||
4578 | F value; | ||
4579 | std::tuple<Filters...> filters; | ||
4580 | |||
4581 | template <typename Fx, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Fx>, filter_wrapper>>> = meta::enabler> | ||
4582 | filter_wrapper(Fx&& fx, Args&&... args) | ||
4583 | : value(std::forward<Fx>(fx)), filters(std::forward<Args>(args)...) { | ||
4584 | } | ||
4585 | |||
4586 | filter_wrapper(const filter_wrapper&) = default; | ||
4587 | filter_wrapper& operator=(const filter_wrapper&) = default; | ||
4588 | filter_wrapper(filter_wrapper&&) = default; | ||
4589 | filter_wrapper& operator=(filter_wrapper&&) = default; | ||
4590 | }; | ||
4591 | |||
4592 | template <typename F, typename... Args> | ||
4593 | auto filters(F&& f, Args&&... args) { | ||
4594 | return filter_wrapper<std::decay_t<F>, std::decay_t<Args>...>(std::forward<F>(f), std::forward<Args>(args)...); | ||
4595 | } | ||
4596 | } // namespace sol | ||
4597 | |||
4598 | // end of sol/filters.hpp | ||
4599 | |||
4600 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
4601 | #ifdef SOL_STD_VARIANT | ||
4602 | #include <variant> | ||
4603 | #endif | ||
4604 | #endif // C++17 | ||
4605 | #ifdef SOL_USE_BOOST | ||
4606 | #include <boost/unordered_map.hpp> | ||
4607 | #else | ||
4608 | #include <unordered_map> | ||
4609 | #endif // Using Boost | ||
4610 | |||
4611 | namespace sol { | ||
4612 | namespace usertype_detail { | ||
4613 | #if defined(SOL_USE_BOOST) | ||
4614 | #if defined(SOL_CXX17_FEATURES) | ||
4615 | template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>> | ||
4616 | using map_t = boost::unordered_map<K, V, H, E>; | ||
4617 | #else | ||
4618 | template <typename K, typename V, typename H = boost::hash<K>, typename E = std::equal_to<>> | ||
4619 | using map_t = boost::unordered_map<K, V, H, E>; | ||
4620 | #endif // C++17 or not, WITH boost | ||
4621 | #else | ||
4622 | template <typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<>> | ||
4623 | using map_t = std::unordered_map<K, V, H, E>; | ||
4624 | #endif // Boost map target | ||
4625 | } | ||
4626 | |||
4627 | namespace detail { | ||
4628 | #ifdef SOL_NOEXCEPT_FUNCTION_TYPE | ||
4629 | typedef int(*lua_CFunction_noexcept)(lua_State* L) noexcept; | ||
4630 | #else | ||
4631 | typedef int(*lua_CFunction_noexcept)(lua_State* L); | ||
4632 | #endif // noexcept function type for lua_CFunction | ||
4633 | |||
4634 | template <typename T> | ||
4635 | struct unique_usertype {}; | ||
4636 | |||
4637 | template <typename T> | ||
4638 | struct implicit_wrapper { | ||
4639 | T& item; | ||
4640 | implicit_wrapper(T* item) | ||
4641 | : item(*item) { | ||
4642 | } | ||
4643 | implicit_wrapper(T& item) | ||
4644 | : item(item) { | ||
4645 | } | ||
4646 | operator T&() { | ||
4647 | return item; | ||
4648 | } | ||
4649 | operator T*() { | ||
4650 | return std::addressof(item); | ||
4651 | } | ||
4652 | }; | ||
4653 | |||
4654 | struct unchecked_t {}; | ||
4655 | const unchecked_t unchecked = unchecked_t{}; | ||
4656 | |||
4657 | struct yield_tag_t {}; | ||
4658 | const yield_tag_t yield_tag = yield_tag_t{}; | ||
4659 | } // namespace detail | ||
4660 | |||
4661 | struct lua_nil_t {}; | ||
4662 | const lua_nil_t lua_nil{}; | ||
4663 | inline bool operator==(lua_nil_t, lua_nil_t) { | ||
4664 | return true; | ||
4665 | } | ||
4666 | inline bool operator!=(lua_nil_t, lua_nil_t) { | ||
4667 | return false; | ||
4668 | } | ||
4669 | typedef lua_nil_t nil_t; | ||
4670 | #if !defined(SOL_NO_NIL) | ||
4671 | const nil_t nil{}; | ||
4672 | #endif | ||
4673 | |||
4674 | struct metatable_t {}; | ||
4675 | const metatable_t metatable_key = {}; | ||
4676 | |||
4677 | struct env_t {}; | ||
4678 | const env_t env_key = {}; | ||
4679 | |||
4680 | struct no_metatable_t {}; | ||
4681 | const no_metatable_t no_metatable = {}; | ||
4682 | |||
4683 | template <typename T> | ||
4684 | struct yielding_t { | ||
4685 | T func; | ||
4686 | |||
4687 | yielding_t() = default; | ||
4688 | yielding_t(const yielding_t&) = default; | ||
4689 | yielding_t(yielding_t&&) = default; | ||
4690 | yielding_t& operator=(const yielding_t&) = default; | ||
4691 | yielding_t& operator=(yielding_t&&) = default; | ||
4692 | template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, yielding_t>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> | ||
4693 | yielding_t(Arg&& arg) | ||
4694 | : func(std::forward<Arg>(arg)) { | ||
4695 | } | ||
4696 | template <typename Arg0, typename Arg1, typename... Args> | ||
4697 | yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) | ||
4698 | : func(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { | ||
4699 | } | ||
4700 | }; | ||
4701 | |||
4702 | template <typename F> | ||
4703 | inline yielding_t<std::decay_t<F>> yielding(F&& f) { | ||
4704 | return yielding_t<std::decay_t<F>>(std::forward<F>(f)); | ||
4705 | } | ||
4706 | |||
4707 | typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref; | ||
4708 | |||
4709 | template <typename T> | ||
4710 | struct unique_usertype_traits { | ||
4711 | typedef T type; | ||
4712 | typedef T actual_type; | ||
4713 | static const bool value = false; | ||
4714 | |||
4715 | template <typename U> | ||
4716 | static bool is_null(U&&) { | ||
4717 | return false; | ||
4718 | } | ||
4719 | |||
4720 | template <typename U> | ||
4721 | static auto get(U&& value) { | ||
4722 | return std::addressof(detail::deref(value)); | ||
4723 | } | ||
4724 | }; | ||
4725 | |||
4726 | template <typename T> | ||
4727 | struct unique_usertype_traits<std::shared_ptr<T>> { | ||
4728 | typedef T type; | ||
4729 | typedef std::shared_ptr<T> actual_type; | ||
4730 | static const bool value = true; | ||
4731 | |||
4732 | static bool is_null(const actual_type& p) { | ||
4733 | return p == nullptr; | ||
4734 | } | ||
4735 | |||
4736 | static type* get(const actual_type& p) { | ||
4737 | return p.get(); | ||
4738 | } | ||
4739 | }; | ||
4740 | |||
4741 | template <typename T, typename D> | ||
4742 | struct unique_usertype_traits<std::unique_ptr<T, D>> { | ||
4743 | typedef T type; | ||
4744 | typedef std::unique_ptr<T, D> actual_type; | ||
4745 | static const bool value = true; | ||
4746 | |||
4747 | static bool is_null(const actual_type& p) { | ||
4748 | return p == nullptr; | ||
4749 | } | ||
4750 | |||
4751 | static type* get(const actual_type& p) { | ||
4752 | return p.get(); | ||
4753 | } | ||
4754 | }; | ||
4755 | |||
4756 | template <typename T> | ||
4757 | struct non_null {}; | ||
4758 | |||
4759 | template <typename... Args> | ||
4760 | struct function_sig {}; | ||
4761 | |||
4762 | struct upvalue_index { | ||
4763 | int index; | ||
4764 | upvalue_index(int idx) | ||
4765 | : index(lua_upvalueindex(idx)) { | ||
4766 | } | ||
4767 | |||
4768 | operator int() const { | ||
4769 | return index; | ||
4770 | } | ||
4771 | }; | ||
4772 | |||
4773 | struct raw_index { | ||
4774 | int index; | ||
4775 | raw_index(int i) | ||
4776 | : index(i) { | ||
4777 | } | ||
4778 | |||
4779 | operator int() const { | ||
4780 | return index; | ||
4781 | } | ||
4782 | }; | ||
4783 | |||
4784 | struct absolute_index { | ||
4785 | int index; | ||
4786 | absolute_index(lua_State* L, int idx) | ||
4787 | : index(lua_absindex(L, idx)) { | ||
4788 | } | ||
4789 | |||
4790 | operator int() const { | ||
4791 | return index; | ||
4792 | } | ||
4793 | }; | ||
4794 | |||
4795 | struct ref_index { | ||
4796 | int index; | ||
4797 | ref_index(int idx) | ||
4798 | : index(idx) { | ||
4799 | } | ||
4800 | |||
4801 | operator int() const { | ||
4802 | return index; | ||
4803 | } | ||
4804 | }; | ||
4805 | |||
4806 | struct stack_count { | ||
4807 | int count; | ||
4808 | |||
4809 | stack_count(int cnt) | ||
4810 | : count(cnt) { | ||
4811 | } | ||
4812 | }; | ||
4813 | |||
4814 | struct lightuserdata_value { | ||
4815 | void* value; | ||
4816 | lightuserdata_value(void* data) | ||
4817 | : value(data) { | ||
4818 | } | ||
4819 | operator void*() const { | ||
4820 | return value; | ||
4821 | } | ||
4822 | }; | ||
4823 | |||
4824 | struct userdata_value { | ||
4825 | void* value; | ||
4826 | userdata_value(void* data) | ||
4827 | : value(data) { | ||
4828 | } | ||
4829 | operator void*() const { | ||
4830 | return value; | ||
4831 | } | ||
4832 | }; | ||
4833 | |||
4834 | template <typename L> | ||
4835 | struct light { | ||
4836 | L* value; | ||
4837 | |||
4838 | light(L& x) | ||
4839 | : value(std::addressof(x)) { | ||
4840 | } | ||
4841 | light(L* x) | ||
4842 | : value(x) { | ||
4843 | } | ||
4844 | light(void* x) | ||
4845 | : value(static_cast<L*>(x)) { | ||
4846 | } | ||
4847 | operator L*() const { | ||
4848 | return value; | ||
4849 | } | ||
4850 | operator L&() const { | ||
4851 | return *value; | ||
4852 | } | ||
4853 | }; | ||
4854 | |||
4855 | template <typename T> | ||
4856 | auto make_light(T& l) { | ||
4857 | typedef meta::unwrapped_t<std::remove_pointer_t<std::remove_pointer_t<T>>> L; | ||
4858 | return light<L>(l); | ||
4859 | } | ||
4860 | |||
4861 | template <typename U> | ||
4862 | struct user { | ||
4863 | U value; | ||
4864 | |||
4865 | user(U x) | ||
4866 | : value(std::forward<U>(x)) { | ||
4867 | } | ||
4868 | operator std::add_pointer_t<std::remove_reference_t<U>>() { | ||
4869 | return std::addressof(value); | ||
4870 | } | ||
4871 | operator std::add_lvalue_reference_t<U>() { | ||
4872 | return value; | ||
4873 | } | ||
4874 | operator std::add_const_t<std::add_lvalue_reference_t<U>>&() const { | ||
4875 | return value; | ||
4876 | } | ||
4877 | }; | ||
4878 | |||
4879 | template <typename T> | ||
4880 | auto make_user(T&& u) { | ||
4881 | typedef meta::unwrapped_t<meta::unqualified_t<T>> U; | ||
4882 | return user<U>(std::forward<T>(u)); | ||
4883 | } | ||
4884 | |||
4885 | template <typename T> | ||
4886 | struct metatable_registry_key { | ||
4887 | T key; | ||
4888 | |||
4889 | metatable_registry_key(T key) | ||
4890 | : key(std::forward<T>(key)) { | ||
4891 | } | ||
4892 | }; | ||
4893 | |||
4894 | template <typename T> | ||
4895 | auto meta_registry_key(T&& key) { | ||
4896 | typedef meta::unqualified_t<T> K; | ||
4897 | return metatable_registry_key<K>(std::forward<T>(key)); | ||
4898 | } | ||
4899 | |||
4900 | template <typename... Upvalues> | ||
4901 | struct closure { | ||
4902 | lua_CFunction c_function; | ||
4903 | std::tuple<Upvalues...> upvalues; | ||
4904 | closure(lua_CFunction f, Upvalues... targetupvalues) | ||
4905 | : c_function(f), upvalues(std::forward<Upvalues>(targetupvalues)...) { | ||
4906 | } | ||
4907 | }; | ||
4908 | |||
4909 | template <> | ||
4910 | struct closure<> { | ||
4911 | lua_CFunction c_function; | ||
4912 | int upvalues; | ||
4913 | closure(lua_CFunction f, int upvalue_count = 0) | ||
4914 | : c_function(f), upvalues(upvalue_count) { | ||
4915 | } | ||
4916 | }; | ||
4917 | |||
4918 | typedef closure<> c_closure; | ||
4919 | |||
4920 | template <typename... Args> | ||
4921 | closure<Args...> make_closure(lua_CFunction f, Args&&... args) { | ||
4922 | return closure<Args...>(f, std::forward<Args>(args)...); | ||
4923 | } | ||
4924 | |||
4925 | template <typename Sig, typename... Ps> | ||
4926 | struct function_arguments { | ||
4927 | std::tuple<Ps...> arguments; | ||
4928 | template <typename Arg, typename... Args, meta::disable<std::is_same<meta::unqualified_t<Arg>, function_arguments>> = meta::enabler> | ||
4929 | function_arguments(Arg&& arg, Args&&... args) | ||
4930 | : arguments(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
4931 | } | ||
4932 | }; | ||
4933 | |||
4934 | template <typename Sig = function_sig<>, typename... Args> | ||
4935 | auto as_function(Args&&... args) { | ||
4936 | return function_arguments<Sig, std::decay_t<Args>...>(std::forward<Args>(args)...); | ||
4937 | } | ||
4938 | |||
4939 | template <typename Sig = function_sig<>, typename... Args> | ||
4940 | auto as_function_reference(Args&&... args) { | ||
4941 | return function_arguments<Sig, Args...>(std::forward<Args>(args)...); | ||
4942 | } | ||
4943 | |||
4944 | template <typename T> | ||
4945 | struct as_table_t { | ||
4946 | T source; | ||
4947 | |||
4948 | as_table_t() = default; | ||
4949 | as_table_t(const as_table_t&) = default; | ||
4950 | as_table_t(as_table_t&&) = default; | ||
4951 | as_table_t& operator=(const as_table_t&) = default; | ||
4952 | as_table_t& operator=(as_table_t&&) = default; | ||
4953 | template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> | ||
4954 | as_table_t(Arg&& arg) | ||
4955 | : source(std::forward<Arg>(arg)) { | ||
4956 | } | ||
4957 | template <typename Arg0, typename Arg1, typename... Args> | ||
4958 | as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) | ||
4959 | : source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { | ||
4960 | } | ||
4961 | |||
4962 | operator std::add_lvalue_reference_t<T>() { | ||
4963 | return source; | ||
4964 | } | ||
4965 | }; | ||
4966 | |||
4967 | template <typename T> | ||
4968 | struct nested { | ||
4969 | T source; | ||
4970 | |||
4971 | nested() = default; | ||
4972 | nested(const nested&) = default; | ||
4973 | nested(nested&&) = default; | ||
4974 | nested& operator=(const nested&) = default; | ||
4975 | nested& operator=(nested&&) = default; | ||
4976 | template <typename Arg, meta::enable<meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>> = meta::enabler> | ||
4977 | nested(Arg&& arg) | ||
4978 | : source(std::forward<Arg>(arg)) { | ||
4979 | } | ||
4980 | template <typename Arg0, typename Arg1, typename... Args> | ||
4981 | nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) | ||
4982 | : source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) { | ||
4983 | } | ||
4984 | |||
4985 | operator std::add_lvalue_reference_t<T>() { | ||
4986 | return source; | ||
4987 | } | ||
4988 | }; | ||
4989 | |||
4990 | template <typename T> | ||
4991 | as_table_t<T> as_table_ref(T&& container) { | ||
4992 | return as_table_t<T>(std::forward<T>(container)); | ||
4993 | } | ||
4994 | |||
4995 | template <typename T> | ||
4996 | as_table_t<meta::unqualified_t<T>> as_table(T&& container) { | ||
4997 | return as_table_t<meta::unqualified_t<T>>(std::forward<T>(container)); | ||
4998 | } | ||
4999 | |||
5000 | template <typename T> | ||
5001 | nested<T> as_nested_ref(T&& container) { | ||
5002 | return nested<T>(std::forward<T>(container)); | ||
5003 | } | ||
5004 | |||
5005 | template <typename T> | ||
5006 | nested<meta::unqualified_t<T>> as_nested(T&& container) { | ||
5007 | return nested<meta::unqualified_t<T>>(std::forward<T>(container)); | ||
5008 | } | ||
5009 | |||
5010 | struct this_state { | ||
5011 | lua_State* L; | ||
5012 | |||
5013 | this_state(lua_State* Ls) | ||
5014 | : L(Ls) { | ||
5015 | } | ||
5016 | |||
5017 | operator lua_State*() const noexcept { | ||
5018 | return lua_state(); | ||
5019 | } | ||
5020 | |||
5021 | lua_State* operator->() const noexcept { | ||
5022 | return lua_state(); | ||
5023 | } | ||
5024 | |||
5025 | lua_State* lua_state() const noexcept { | ||
5026 | return L; | ||
5027 | } | ||
5028 | }; | ||
5029 | |||
5030 | struct this_main_state { | ||
5031 | lua_State* L; | ||
5032 | |||
5033 | this_main_state(lua_State* Ls) | ||
5034 | : L(Ls) { | ||
5035 | } | ||
5036 | |||
5037 | operator lua_State*() const noexcept { | ||
5038 | return lua_state(); | ||
5039 | } | ||
5040 | |||
5041 | lua_State* operator->() const noexcept { | ||
5042 | return lua_state(); | ||
5043 | } | ||
5044 | |||
5045 | lua_State* lua_state() const noexcept { | ||
5046 | return L; | ||
5047 | } | ||
5048 | }; | ||
5049 | |||
5050 | struct new_table { | ||
5051 | int sequence_hint = 0; | ||
5052 | int map_hint = 0; | ||
5053 | |||
5054 | new_table() = default; | ||
5055 | new_table(const new_table&) = default; | ||
5056 | new_table(new_table&&) = default; | ||
5057 | new_table& operator=(const new_table&) = default; | ||
5058 | new_table& operator=(new_table&&) = default; | ||
5059 | |||
5060 | new_table(int sequence_hint, int map_hint = 0) | ||
5061 | : sequence_hint(sequence_hint), map_hint(map_hint) { | ||
5062 | } | ||
5063 | }; | ||
5064 | |||
5065 | enum class lib : char { | ||
5066 | // print, assert, and other base functions | ||
5067 | base, | ||
5068 | // require and other package functions | ||
5069 | package, | ||
5070 | // coroutine functions and utilities | ||
5071 | coroutine, | ||
5072 | // string library | ||
5073 | string, | ||
5074 | // functionality from the OS | ||
5075 | os, | ||
5076 | // all things math | ||
5077 | math, | ||
5078 | // the table manipulator and observer functions | ||
5079 | table, | ||
5080 | // the debug library | ||
5081 | debug, | ||
5082 | // the bit library: different based on which you're using | ||
5083 | bit32, | ||
5084 | // input/output library | ||
5085 | io, | ||
5086 | // LuaJIT only | ||
5087 | ffi, | ||
5088 | // LuaJIT only | ||
5089 | jit, | ||
5090 | // library for handling utf8: new to Lua | ||
5091 | utf8, | ||
5092 | // do not use | ||
5093 | count | ||
5094 | }; | ||
5095 | |||
5096 | enum class call_syntax { | ||
5097 | dot = 0, | ||
5098 | colon = 1 | ||
5099 | }; | ||
5100 | |||
5101 | enum class load_mode { | ||
5102 | any = 0, | ||
5103 | text = 1, | ||
5104 | binary = 2, | ||
5105 | }; | ||
5106 | |||
5107 | enum class call_status : int { | ||
5108 | ok = LUA_OK, | ||
5109 | yielded = LUA_YIELD, | ||
5110 | runtime = LUA_ERRRUN, | ||
5111 | memory = LUA_ERRMEM, | ||
5112 | handler = LUA_ERRERR, | ||
5113 | gc = LUA_ERRGCMM, | ||
5114 | syntax = LUA_ERRSYNTAX, | ||
5115 | file = LUA_ERRFILE, | ||
5116 | }; | ||
5117 | |||
5118 | enum class thread_status : int { | ||
5119 | ok = LUA_OK, | ||
5120 | yielded = LUA_YIELD, | ||
5121 | runtime = LUA_ERRRUN, | ||
5122 | memory = LUA_ERRMEM, | ||
5123 | gc = LUA_ERRGCMM, | ||
5124 | handler = LUA_ERRERR, | ||
5125 | dead = -1, | ||
5126 | }; | ||
5127 | |||
5128 | enum class load_status : int { | ||
5129 | ok = LUA_OK, | ||
5130 | syntax = LUA_ERRSYNTAX, | ||
5131 | memory = LUA_ERRMEM, | ||
5132 | gc = LUA_ERRGCMM, | ||
5133 | file = LUA_ERRFILE, | ||
5134 | }; | ||
5135 | |||
5136 | enum class type : int { | ||
5137 | none = LUA_TNONE, | ||
5138 | lua_nil = LUA_TNIL, | ||
5139 | #if !defined(SOL_NO_NIL) | ||
5140 | nil = lua_nil, | ||
5141 | #endif // Objective C/C++ Keyword that's found in OSX SDK and OBJC -- check for all forms to protect | ||
5142 | string = LUA_TSTRING, | ||
5143 | number = LUA_TNUMBER, | ||
5144 | thread = LUA_TTHREAD, | ||
5145 | boolean = LUA_TBOOLEAN, | ||
5146 | function = LUA_TFUNCTION, | ||
5147 | userdata = LUA_TUSERDATA, | ||
5148 | lightuserdata = LUA_TLIGHTUSERDATA, | ||
5149 | table = LUA_TTABLE, | ||
5150 | poly = -0xFFFF | ||
5151 | }; | ||
5152 | |||
5153 | inline const std::string& to_string(call_status c) { | ||
5154 | static const std::array<std::string, 10> names{ { | ||
5155 | "ok", | ||
5156 | "yielded", | ||
5157 | "runtime", | ||
5158 | "memory", | ||
5159 | "handler", | ||
5160 | "gc", | ||
5161 | "syntax", | ||
5162 | "file", | ||
5163 | "CRITICAL_EXCEPTION_FAILURE", | ||
5164 | "CRITICAL_INDETERMINATE_STATE_FAILURE" | ||
5165 | } }; | ||
5166 | switch (c) { | ||
5167 | case call_status::ok: | ||
5168 | return names[0]; | ||
5169 | case call_status::yielded: | ||
5170 | return names[1]; | ||
5171 | case call_status::runtime: | ||
5172 | return names[2]; | ||
5173 | case call_status::memory: | ||
5174 | return names[3]; | ||
5175 | case call_status::handler: | ||
5176 | return names[4]; | ||
5177 | case call_status::gc: | ||
5178 | return names[5]; | ||
5179 | case call_status::syntax: | ||
5180 | return names[6]; | ||
5181 | case call_status::file: | ||
5182 | return names[7]; | ||
5183 | } | ||
5184 | if (static_cast<std::ptrdiff_t>(c) == -1) { | ||
5185 | // One of the many cases where a critical exception error has occurred | ||
5186 | return names[8]; | ||
5187 | } | ||
5188 | return names[9]; | ||
5189 | } | ||
5190 | |||
5191 | inline bool is_indeterminate_call_failure(call_status c) { | ||
5192 | switch (c) { | ||
5193 | case call_status::ok: | ||
5194 | case call_status::yielded: | ||
5195 | case call_status::runtime: | ||
5196 | case call_status::memory: | ||
5197 | case call_status::handler: | ||
5198 | case call_status::gc: | ||
5199 | case call_status::syntax: | ||
5200 | case call_status::file: | ||
5201 | return false; | ||
5202 | } | ||
5203 | return true; | ||
5204 | } | ||
5205 | |||
5206 | inline const std::string& to_string(load_status c) { | ||
5207 | static const std::array<std::string, 7> names{ { | ||
5208 | "ok", | ||
5209 | "memory", | ||
5210 | "gc", | ||
5211 | "syntax", | ||
5212 | "file", | ||
5213 | "CRITICAL_EXCEPTION_FAILURE", | ||
5214 | "CRITICAL_INDETERMINATE_STATE_FAILURE" | ||
5215 | } }; | ||
5216 | switch (c) { | ||
5217 | case load_status::ok: | ||
5218 | return names[0]; | ||
5219 | case load_status::memory: | ||
5220 | return names[1]; | ||
5221 | case load_status::gc: | ||
5222 | return names[2]; | ||
5223 | case load_status::syntax: | ||
5224 | return names[3]; | ||
5225 | case load_status::file: | ||
5226 | return names[4]; | ||
5227 | } | ||
5228 | if (static_cast<int>(c) == -1) { | ||
5229 | // One of the many cases where a critical exception error has occurred | ||
5230 | return names[5]; | ||
5231 | } | ||
5232 | return names[6]; | ||
5233 | } | ||
5234 | |||
5235 | inline const std::string& to_string(load_mode c) { | ||
5236 | static const std::array<std::string, 3> names{ { | ||
5237 | "bt", | ||
5238 | "t", | ||
5239 | "b", | ||
5240 | } }; | ||
5241 | return names[static_cast<std::size_t>(c)]; | ||
5242 | } | ||
5243 | |||
5244 | enum class meta_function { | ||
5245 | construct, | ||
5246 | index, | ||
5247 | new_index, | ||
5248 | mode, | ||
5249 | call, | ||
5250 | call_function = call, | ||
5251 | metatable, | ||
5252 | to_string, | ||
5253 | length, | ||
5254 | unary_minus, | ||
5255 | addition, | ||
5256 | subtraction, | ||
5257 | multiplication, | ||
5258 | division, | ||
5259 | modulus, | ||
5260 | power_of, | ||
5261 | involution = power_of, | ||
5262 | concatenation, | ||
5263 | equal_to, | ||
5264 | less_than, | ||
5265 | less_than_or_equal_to, | ||
5266 | garbage_collect, | ||
5267 | floor_division, | ||
5268 | bitwise_left_shift, | ||
5269 | bitwise_right_shift, | ||
5270 | bitwise_not, | ||
5271 | bitwise_and, | ||
5272 | bitwise_or, | ||
5273 | bitwise_xor, | ||
5274 | pairs, | ||
5275 | ipairs, | ||
5276 | next, | ||
5277 | type, | ||
5278 | type_info, | ||
5279 | }; | ||
5280 | |||
5281 | typedef meta_function meta_method; | ||
5282 | |||
5283 | inline const std::array<std::string, 32>& meta_function_names() { | ||
5284 | static const std::array<std::string, 32> names = { { "new", | ||
5285 | "__index", | ||
5286 | "__newindex", | ||
5287 | "__mode", | ||
5288 | "__call", | ||
5289 | "__mt", | ||
5290 | "__tostring", | ||
5291 | "__len", | ||
5292 | "__unm", | ||
5293 | "__add", | ||
5294 | "__sub", | ||
5295 | "__mul", | ||
5296 | "__div", | ||
5297 | "__mod", | ||
5298 | "__pow", | ||
5299 | "__concat", | ||
5300 | "__eq", | ||
5301 | "__lt", | ||
5302 | "__le", | ||
5303 | "__gc", | ||
5304 | |||
5305 | "__idiv", | ||
5306 | "__shl", | ||
5307 | "__shr", | ||
5308 | "__bnot", | ||
5309 | "__band", | ||
5310 | "__bor", | ||
5311 | "__bxor", | ||
5312 | |||
5313 | "__pairs", | ||
5314 | "__ipairs", | ||
5315 | "next", | ||
5316 | "__type", | ||
5317 | "__typeinfo" | ||
5318 | } }; | ||
5319 | return names; | ||
5320 | } | ||
5321 | |||
5322 | inline const std::string& to_string(meta_function mf) { | ||
5323 | return meta_function_names()[static_cast<int>(mf)]; | ||
5324 | } | ||
5325 | |||
5326 | inline type type_of(lua_State* L, int index) { | ||
5327 | return static_cast<type>(lua_type(L, index)); | ||
5328 | } | ||
5329 | |||
5330 | inline std::string type_name(lua_State* L, type t) { | ||
5331 | return lua_typename(L, static_cast<int>(t)); | ||
5332 | } | ||
5333 | |||
5334 | namespace detail { | ||
5335 | template <typename T> | ||
5336 | struct is_initializer_list : std::false_type {}; | ||
5337 | |||
5338 | template <typename T> | ||
5339 | struct is_initializer_list<std::initializer_list<T>> : std::true_type {}; | ||
5340 | |||
5341 | template <typename T, typename C = void> | ||
5342 | struct is_container : std::false_type {}; | ||
5343 | |||
5344 | template <typename T> | ||
5345 | struct is_container<std::initializer_list<T>> : std::false_type {}; | ||
5346 | |||
5347 | template <typename T> | ||
5348 | struct is_container<T, std::enable_if_t<meta::is_string_like<meta::unqualified_t<T>>::value>> : std::false_type {}; | ||
5349 | |||
5350 | template <typename T> | ||
5351 | struct is_container<T, std::enable_if_t<meta::all< | ||
5352 | std::is_array<meta::unqualified_t<T>> | ||
5353 | , meta::neg<meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>> | ||
5354 | >::value | ||
5355 | >> : std::true_type {}; | ||
5356 | |||
5357 | template <typename T> | ||
5358 | struct is_container<T, std::enable_if_t<meta::all< | ||
5359 | meta::has_begin_end<meta::unqualified_t<T>> | ||
5360 | , meta::neg<is_initializer_list<meta::unqualified_t<T>>> | ||
5361 | , meta::neg<meta::is_string_like<meta::unqualified_t<T>>> | ||
5362 | >::value | ||
5363 | >> : std::true_type {}; | ||
5364 | } // namespace detail | ||
5365 | |||
5366 | template <typename T> | ||
5367 | struct is_container : detail::is_container<T> {}; | ||
5368 | |||
5369 | template <typename T> | ||
5370 | struct is_to_stringable : meta::any<meta::supports_to_string_member<meta::unqualified_t<T>>, meta::supports_adl_to_string<meta::unqualified_t<T>>, meta::supports_ostream_op<meta::unqualified_t<T>>> {}; | ||
5371 | |||
5372 | namespace detail { | ||
5373 | template <typename T, typename = void> | ||
5374 | struct lua_type_of : std::integral_constant<type, type::userdata> {}; | ||
5375 | |||
5376 | template <typename C, typename T, typename A> | ||
5377 | struct lua_type_of<std::basic_string<C, T, A>> : std::integral_constant<type, type::string> {}; | ||
5378 | |||
5379 | template <typename C, typename T> | ||
5380 | struct lua_type_of<basic_string_view<C, T>> : std::integral_constant<type, type::string> {}; | ||
5381 | |||
5382 | template <std::size_t N> | ||
5383 | struct lua_type_of<char[N]> : std::integral_constant<type, type::string> {}; | ||
5384 | |||
5385 | template <std::size_t N> | ||
5386 | struct lua_type_of<wchar_t[N]> : std::integral_constant<type, type::string> {}; | ||
5387 | |||
5388 | template <std::size_t N> | ||
5389 | struct lua_type_of<char16_t[N]> : std::integral_constant<type, type::string> {}; | ||
5390 | |||
5391 | template <std::size_t N> | ||
5392 | struct lua_type_of<char32_t[N]> : std::integral_constant<type, type::string> {}; | ||
5393 | |||
5394 | template <> | ||
5395 | struct lua_type_of<char> : std::integral_constant<type, type::string> {}; | ||
5396 | |||
5397 | template <> | ||
5398 | struct lua_type_of<wchar_t> : std::integral_constant<type, type::string> {}; | ||
5399 | |||
5400 | template <> | ||
5401 | struct lua_type_of<char16_t> : std::integral_constant<type, type::string> {}; | ||
5402 | |||
5403 | template <> | ||
5404 | struct lua_type_of<char32_t> : std::integral_constant<type, type::string> {}; | ||
5405 | |||
5406 | template <> | ||
5407 | struct lua_type_of<const char*> : std::integral_constant<type, type::string> {}; | ||
5408 | |||
5409 | template <> | ||
5410 | struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string> {}; | ||
5411 | |||
5412 | template <> | ||
5413 | struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {}; | ||
5414 | |||
5415 | template <> | ||
5416 | struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {}; | ||
5417 | |||
5418 | template <> | ||
5419 | struct lua_type_of<lua_nil_t> : std::integral_constant<type, type::lua_nil> {}; | ||
5420 | |||
5421 | template <> | ||
5422 | struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> {}; | ||
5423 | |||
5424 | template <> | ||
5425 | struct lua_type_of<std::nullptr_t> : std::integral_constant<type, type::lua_nil> {}; | ||
5426 | |||
5427 | template <> | ||
5428 | struct lua_type_of<error> : std::integral_constant<type, type::string> {}; | ||
5429 | |||
5430 | template <bool b, typename Base> | ||
5431 | struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> {}; | ||
5432 | |||
5433 | template <> | ||
5434 | struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> {}; | ||
5435 | |||
5436 | template <typename B> | ||
5437 | struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> {}; | ||
5438 | |||
5439 | template <> | ||
5440 | struct lua_type_of<env_t> : std::integral_constant<type, type::poly> {}; | ||
5441 | |||
5442 | template <> | ||
5443 | struct lua_type_of<new_table> : std::integral_constant<type, type::table> {}; | ||
5444 | |||
5445 | template <typename T> | ||
5446 | struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {}; | ||
5447 | |||
5448 | template <typename T> | ||
5449 | struct lua_type_of<std::initializer_list<T>> : std::integral_constant<type, type::table> {}; | ||
5450 | |||
5451 | template <bool b> | ||
5452 | struct lua_type_of<basic_reference<b>> : std::integral_constant<type, type::poly> {}; | ||
5453 | |||
5454 | template <> | ||
5455 | struct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> {}; | ||
5456 | |||
5457 | template <typename Base> | ||
5458 | struct lua_type_of<basic_object<Base>> : std::integral_constant<type, type::poly> {}; | ||
5459 | |||
5460 | template <typename... Args> | ||
5461 | struct lua_type_of<std::tuple<Args...>> : std::integral_constant<type, type::poly> {}; | ||
5462 | |||
5463 | template <typename A, typename B> | ||
5464 | struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {}; | ||
5465 | |||
5466 | template <> | ||
5467 | struct lua_type_of<void*> : std::integral_constant<type, type::lightuserdata> {}; | ||
5468 | |||
5469 | template <> | ||
5470 | struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> {}; | ||
5471 | |||
5472 | template <> | ||
5473 | struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {}; | ||
5474 | |||
5475 | template <typename T> | ||
5476 | struct lua_type_of<light<T>> : std::integral_constant<type, type::lightuserdata> {}; | ||
5477 | |||
5478 | template <typename T> | ||
5479 | struct lua_type_of<user<T>> : std::integral_constant<type, type::userdata> {}; | ||
5480 | |||
5481 | template <typename Base> | ||
5482 | struct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> {}; | ||
5483 | |||
5484 | template <typename Base> | ||
5485 | struct lua_type_of<basic_userdata<Base>> : std::integral_constant<type, type::userdata> {}; | ||
5486 | |||
5487 | template <> | ||
5488 | struct lua_type_of<lua_CFunction> : std::integral_constant<type, type::function> {}; | ||
5489 | |||
5490 | template <> | ||
5491 | struct lua_type_of<std::remove_pointer_t<lua_CFunction>> : std::integral_constant<type, type::function> {}; | ||
5492 | |||
5493 | template <typename Base, bool aligned> | ||
5494 | struct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> {}; | ||
5495 | |||
5496 | template <typename Base, bool aligned, typename Handler> | ||
5497 | struct lua_type_of<basic_protected_function<Base, aligned, Handler>> : std::integral_constant<type, type::function> {}; | ||
5498 | |||
5499 | template <typename Base> | ||
5500 | struct lua_type_of<basic_coroutine<Base>> : std::integral_constant<type, type::function> {}; | ||
5501 | |||
5502 | template <typename Base> | ||
5503 | struct lua_type_of<basic_thread<Base>> : std::integral_constant<type, type::thread> {}; | ||
5504 | |||
5505 | template <typename Signature> | ||
5506 | struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function> {}; | ||
5507 | |||
5508 | template <typename T> | ||
5509 | struct lua_type_of<optional<T>> : std::integral_constant<type, type::poly> {}; | ||
5510 | |||
5511 | template <> | ||
5512 | struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> {}; | ||
5513 | |||
5514 | template <> | ||
5515 | struct lua_type_of<variadic_results> : std::integral_constant<type, type::poly> {}; | ||
5516 | |||
5517 | template <> | ||
5518 | struct lua_type_of<stack_count> : std::integral_constant<type, type::poly> {}; | ||
5519 | |||
5520 | template <> | ||
5521 | struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {}; | ||
5522 | |||
5523 | template <> | ||
5524 | struct lua_type_of<this_main_state> : std::integral_constant<type, type::poly> {}; | ||
5525 | |||
5526 | template <> | ||
5527 | struct lua_type_of<this_environment> : std::integral_constant<type, type::poly> {}; | ||
5528 | |||
5529 | template <> | ||
5530 | struct lua_type_of<type> : std::integral_constant<type, type::poly> {}; | ||
5531 | |||
5532 | template <typename T> | ||
5533 | struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {}; | ||
5534 | |||
5535 | template <typename T> | ||
5536 | struct lua_type_of<T, std::enable_if_t<std::is_arithmetic<T>::value>> : std::integral_constant<type, type::number> {}; | ||
5537 | |||
5538 | template <typename T> | ||
5539 | struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {}; | ||
5540 | |||
5541 | template <> | ||
5542 | struct lua_type_of<meta_function> : std::integral_constant<type, type::string> {}; | ||
5543 | |||
5544 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
5545 | #ifdef SOL_STD_VARIANT | ||
5546 | template <typename... Tn> | ||
5547 | struct lua_type_of<std::variant<Tn...>> : std::integral_constant<type, type::poly> {}; | ||
5548 | #endif // SOL_STD_VARIANT | ||
5549 | #endif // SOL_CXX17_FEATURES | ||
5550 | |||
5551 | template <typename T> | ||
5552 | struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {}; | ||
5553 | |||
5554 | template <typename T> | ||
5555 | struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {}; | ||
5556 | |||
5557 | template <typename C, C v, template <typename...> class V, typename... Args> | ||
5558 | struct accumulate : std::integral_constant<C, v> {}; | ||
5559 | |||
5560 | template <typename C, C v, template <typename...> class V, typename T, typename... Args> | ||
5561 | struct accumulate<C, v, V, T, Args...> : accumulate<C, v + V<T>::value, V, Args...> {}; | ||
5562 | } // namespace detail | ||
5563 | |||
5564 | template <typename T> | ||
5565 | struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {}; | ||
5566 | |||
5567 | template <typename T> | ||
5568 | struct lua_type_of : detail::lua_type_of<T> { | ||
5569 | typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; | ||
5570 | }; | ||
5571 | |||
5572 | template <typename T> | ||
5573 | struct lua_size : std::integral_constant<int, 1> { | ||
5574 | typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; | ||
5575 | }; | ||
5576 | |||
5577 | template <typename A, typename B> | ||
5578 | struct lua_size<std::pair<A, B>> : std::integral_constant<int, lua_size<A>::value + lua_size<B>::value> {}; | ||
5579 | |||
5580 | template <typename... Args> | ||
5581 | struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> {}; | ||
5582 | |||
5583 | namespace detail { | ||
5584 | template <typename...> | ||
5585 | struct void_ { typedef void type; }; | ||
5586 | template <typename T, typename = void> | ||
5587 | struct has_internal_marker_impl : std::false_type {}; | ||
5588 | template <typename T> | ||
5589 | struct has_internal_marker_impl<T, typename void_<typename T::SOL_INTERNAL_UNSPECIALIZED_MARKER_>::type> : std::true_type {}; | ||
5590 | |||
5591 | template <typename T> | ||
5592 | struct has_internal_marker : has_internal_marker_impl<T> {}; | ||
5593 | } // namespace detail | ||
5594 | |||
5595 | template <typename T> | ||
5596 | struct is_lua_primitive : std::integral_constant<bool, | ||
5597 | type::userdata != lua_type_of<meta::unqualified_t<T>>::value | ||
5598 | || ((type::userdata == lua_type_of<meta::unqualified_t<T>>::value) | ||
5599 | && detail::has_internal_marker<lua_type_of<meta::unqualified_t<T>>>::value | ||
5600 | && !detail::has_internal_marker<lua_size<meta::unqualified_t<T>>>::value) | ||
5601 | || std::is_base_of<reference, meta::unqualified_t<T>>::value | ||
5602 | || std::is_base_of<main_reference, meta::unqualified_t<T>>::value | ||
5603 | || std::is_base_of<stack_reference, meta::unqualified_t<T>>::value | ||
5604 | || meta::is_specialization_of<meta::unqualified_t<T>, std::tuple>::value | ||
5605 | || meta::is_specialization_of<meta::unqualified_t<T>, std::pair>::value> {}; | ||
5606 | |||
5607 | template <typename T> | ||
5608 | struct is_lua_reference : std::integral_constant<bool, | ||
5609 | std::is_base_of<reference, meta::unqualified_t<T>>::value | ||
5610 | || std::is_base_of<main_reference, meta::unqualified_t<T>>::value | ||
5611 | || std::is_base_of<stack_reference, meta::unqualified_t<T>>::value> {}; | ||
5612 | |||
5613 | template <typename T> | ||
5614 | struct is_lua_reference_or_proxy : std::integral_constant<bool, | ||
5615 | is_lua_reference<meta::unqualified_t<T>>::value | ||
5616 | || meta::is_specialization_of<meta::unqualified_t<T>, proxy>::value> {}; | ||
5617 | |||
5618 | template <typename T> | ||
5619 | struct is_main_threaded : std::is_base_of<main_reference, T> {}; | ||
5620 | |||
5621 | template <typename T> | ||
5622 | struct is_stack_based : std::is_base_of<stack_reference, T> {}; | ||
5623 | template <> | ||
5624 | struct is_stack_based<variadic_args> : std::true_type {}; | ||
5625 | template <> | ||
5626 | struct is_stack_based<unsafe_function_result> : std::true_type {}; | ||
5627 | template <> | ||
5628 | struct is_stack_based<protected_function_result> : std::true_type {}; | ||
5629 | template <> | ||
5630 | struct is_stack_based<stack_proxy> : std::true_type {}; | ||
5631 | template <> | ||
5632 | struct is_stack_based<stack_proxy_base> : std::true_type {}; | ||
5633 | |||
5634 | template <typename T> | ||
5635 | struct is_lua_primitive<T*> : std::true_type {}; | ||
5636 | template <> | ||
5637 | struct is_lua_primitive<unsafe_function_result> : std::true_type {}; | ||
5638 | template <> | ||
5639 | struct is_lua_primitive<protected_function_result> : std::true_type {}; | ||
5640 | template <typename T> | ||
5641 | struct is_lua_primitive<std::reference_wrapper<T>> : std::true_type {}; | ||
5642 | template <typename T> | ||
5643 | struct is_lua_primitive<user<T>> : std::true_type {}; | ||
5644 | template <typename T> | ||
5645 | struct is_lua_primitive<light<T>> : is_lua_primitive<T*> {}; | ||
5646 | template <typename T> | ||
5647 | struct is_lua_primitive<optional<T>> : std::true_type {}; | ||
5648 | template <typename T> | ||
5649 | struct is_lua_primitive<as_table_t<T>> : std::true_type {}; | ||
5650 | template <typename T> | ||
5651 | struct is_lua_primitive<nested<T>> : std::true_type {}; | ||
5652 | template <> | ||
5653 | struct is_lua_primitive<userdata_value> : std::true_type {}; | ||
5654 | template <> | ||
5655 | struct is_lua_primitive<lightuserdata_value> : std::true_type {}; | ||
5656 | template <typename T> | ||
5657 | struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> {}; | ||
5658 | |||
5659 | template <typename T> | ||
5660 | struct is_proxy_primitive : is_lua_primitive<T> {}; | ||
5661 | |||
5662 | template <typename T> | ||
5663 | struct is_transparent_argument : std::false_type {}; | ||
5664 | template <> | ||
5665 | struct is_transparent_argument<this_state> : std::true_type {}; | ||
5666 | template <> | ||
5667 | struct is_transparent_argument<this_main_state> : std::true_type {}; | ||
5668 | template <> | ||
5669 | struct is_transparent_argument<this_environment> : std::true_type {}; | ||
5670 | template <> | ||
5671 | struct is_transparent_argument<variadic_args> : std::true_type {}; | ||
5672 | template <typename T> | ||
5673 | struct is_variadic_arguments : std::is_same<meta::unqualified_t<T>, variadic_args> {}; | ||
5674 | |||
5675 | template <typename T> | ||
5676 | struct is_lua_index : std::is_integral<T> {}; | ||
5677 | template <> | ||
5678 | struct is_lua_index<raw_index> : std::true_type {}; | ||
5679 | template <> | ||
5680 | struct is_lua_index<absolute_index> : std::true_type {}; | ||
5681 | template <> | ||
5682 | struct is_lua_index<ref_index> : std::true_type {}; | ||
5683 | template <> | ||
5684 | struct is_lua_index<upvalue_index> : std::true_type {}; | ||
5685 | |||
5686 | template <typename Signature> | ||
5687 | struct lua_bind_traits : meta::bind_traits<Signature> { | ||
5688 | private: | ||
5689 | typedef meta::bind_traits<Signature> base_t; | ||
5690 | |||
5691 | public: | ||
5692 | typedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t; | ||
5693 | static const std::size_t true_arity = base_t::arity; | ||
5694 | static const std::size_t arity = base_t::arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; | ||
5695 | static const std::size_t true_free_arity = base_t::free_arity; | ||
5696 | static const std::size_t free_arity = base_t::free_arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value; | ||
5697 | }; | ||
5698 | |||
5699 | template <typename T> | ||
5700 | struct is_table : std::false_type {}; | ||
5701 | template <bool x, typename T> | ||
5702 | struct is_table<basic_table_core<x, T>> : std::true_type {}; | ||
5703 | |||
5704 | template <typename T> | ||
5705 | struct is_function : std::false_type {}; | ||
5706 | template <typename T, bool aligned> | ||
5707 | struct is_function<basic_function<T, aligned>> : std::true_type {}; | ||
5708 | template <typename T, bool aligned, typename Handler> | ||
5709 | struct is_function<basic_protected_function<T, aligned, Handler>> : std::true_type {}; | ||
5710 | |||
5711 | template <typename T> | ||
5712 | struct is_lightuserdata : std::false_type {}; | ||
5713 | template <typename T> | ||
5714 | struct is_lightuserdata<basic_lightuserdata<T>> : std::true_type {}; | ||
5715 | |||
5716 | template <typename T> | ||
5717 | struct is_userdata : std::false_type {}; | ||
5718 | template <typename T> | ||
5719 | struct is_userdata<basic_userdata<T>> : std::true_type {}; | ||
5720 | |||
5721 | template <typename T> | ||
5722 | struct is_environment : std::integral_constant<bool, is_userdata<T>::value || is_table<T>::value> {}; | ||
5723 | |||
5724 | template <typename T> | ||
5725 | struct is_automagical : std::true_type {}; | ||
5726 | |||
5727 | template <typename T> | ||
5728 | inline type type_of() { | ||
5729 | return lua_type_of<meta::unqualified_t<T>>::value; | ||
5730 | } | ||
5731 | |||
5732 | namespace detail { | ||
5733 | template <typename T> | ||
5734 | struct is_non_factory_constructor : std::false_type {}; | ||
5735 | |||
5736 | template <typename... Args> | ||
5737 | struct is_non_factory_constructor<constructors<Args...>> : std::true_type {}; | ||
5738 | |||
5739 | template <typename... Args> | ||
5740 | struct is_non_factory_constructor<constructor_wrapper<Args...>> : std::true_type {}; | ||
5741 | |||
5742 | template <> | ||
5743 | struct is_non_factory_constructor<no_construction> : std::true_type {}; | ||
5744 | |||
5745 | template <typename T> | ||
5746 | struct is_constructor : is_non_factory_constructor<T> {}; | ||
5747 | |||
5748 | template <typename... Args> | ||
5749 | struct is_constructor<factory_wrapper<Args...>> : std::true_type {}; | ||
5750 | |||
5751 | template <typename T> | ||
5752 | struct is_constructor<protect_t<T>> : is_constructor<meta::unqualified_t<T>> {}; | ||
5753 | |||
5754 | template <typename F, typename... Filters> | ||
5755 | struct is_constructor<filter_wrapper<F, Filters...>> : is_constructor<meta::unqualified_t<F>> {}; | ||
5756 | |||
5757 | template <typename... Args> | ||
5758 | using has_constructor = meta::any<is_constructor<meta::unqualified_t<Args>>...>; | ||
5759 | |||
5760 | template <typename T> | ||
5761 | struct is_destructor : std::false_type {}; | ||
5762 | |||
5763 | template <typename Fx> | ||
5764 | struct is_destructor<destructor_wrapper<Fx>> : std::true_type {}; | ||
5765 | |||
5766 | template <typename... Args> | ||
5767 | using has_destructor = meta::any<is_destructor<meta::unqualified_t<Args>>...>; | ||
5768 | |||
5769 | struct add_destructor_tag {}; | ||
5770 | struct check_destructor_tag {}; | ||
5771 | struct verified_tag { | ||
5772 | } const verified{}; | ||
5773 | } // namespace detail | ||
5774 | } // namespace sol | ||
5775 | |||
5776 | // end of sol/types.hpp | ||
5777 | |||
5778 | #include <exception> | ||
5779 | #include <cstring> | ||
5780 | |||
5781 | #ifdef SOL_PRINT_ERRORS | ||
5782 | #include <iostream> | ||
5783 | #endif | ||
5784 | |||
5785 | namespace sol { | ||
5786 | // must push a single object to be the error object | ||
5787 | // NOTE: the VAST MAJORITY of all Lua libraries -- C or otherwise -- expect a string for the type of error | ||
5788 | // break this convention at your own risk | ||
5789 | using exception_handler_function = int(*)(lua_State*, optional<const std::exception&>, string_view); | ||
5790 | |||
5791 | namespace detail { | ||
5792 | inline const char(&default_exception_handler_name())[11]{ | ||
5793 | static const char name[11] = "sol.\xE2\x98\xA2\xE2\x98\xA2"; | ||
5794 | return name; | ||
5795 | } | ||
5796 | |||
5797 | // must push at least 1 object on the stack | ||
5798 | inline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) { | ||
5799 | #ifdef SOL_PRINT_ERRORS | ||
5800 | std::cerr << "[sol2] An exception occurred: "; | ||
5801 | std::cerr.write(what.data(), what.size()); | ||
5802 | std::cerr << std::endl; | ||
5803 | #endif | ||
5804 | lua_pushlstring(L, what.data(), what.size()); | ||
5805 | return 1; | ||
5806 | } | ||
5807 | |||
5808 | inline int call_exception_handler(lua_State* L, optional<const std::exception&> maybe_ex, string_view what) { | ||
5809 | lua_getglobal(L, default_exception_handler_name()); | ||
5810 | type t = static_cast<type>(lua_type(L, -1)); | ||
5811 | if (t != type::lightuserdata) { | ||
5812 | lua_pop(L, 1); | ||
5813 | return default_exception_handler(L, std::move(maybe_ex), std::move(what)); | ||
5814 | } | ||
5815 | void* vfunc = lua_touserdata(L, -1); | ||
5816 | lua_pop(L, 1); | ||
5817 | if (vfunc == nullptr) { | ||
5818 | return default_exception_handler(L, std::move(maybe_ex), std::move(what)); | ||
5819 | } | ||
5820 | exception_handler_function exfunc = reinterpret_cast<exception_handler_function>(vfunc); | ||
5821 | return exfunc(L, std::move(maybe_ex), std::move(what)); | ||
5822 | } | ||
5823 | |||
5824 | #ifdef SOL_NO_EXCEPTIONS | ||
5825 | template <lua_CFunction f> | ||
5826 | int static_trampoline(lua_State* L) noexcept { | ||
5827 | return f(L); | ||
5828 | } | ||
5829 | |||
5830 | #ifdef SOL_NOEXCEPT_FUNCTION_TYPE | ||
5831 | template <lua_CFunction_noexcept f> | ||
5832 | int static_trampoline_noexcept(lua_State* L) noexcept { | ||
5833 | return f(L); | ||
5834 | } | ||
5835 | #else | ||
5836 | template <lua_CFunction f> | ||
5837 | int static_trampoline_noexcept(lua_State* L) noexcept { | ||
5838 | return f(L); | ||
5839 | } | ||
5840 | #endif | ||
5841 | |||
5842 | template <typename Fx, typename... Args> | ||
5843 | int trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept { | ||
5844 | return f(L, std::forward<Args>(args)...); | ||
5845 | } | ||
5846 | |||
5847 | inline int c_trampoline(lua_State* L, lua_CFunction f) noexcept { | ||
5848 | return trampoline(L, f); | ||
5849 | } | ||
5850 | #else | ||
5851 | template <lua_CFunction f> | ||
5852 | int static_trampoline(lua_State* L) { | ||
5853 | #if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT) | ||
5854 | return f(L); | ||
5855 | |||
5856 | #else | ||
5857 | try { | ||
5858 | return f(L); | ||
5859 | } | ||
5860 | catch (const char* cs) { | ||
5861 | call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs)); | ||
5862 | } | ||
5863 | catch (const std::string& s) { | ||
5864 | call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size())); | ||
5865 | } | ||
5866 | catch (const std::exception& e) { | ||
5867 | call_exception_handler(L, optional<const std::exception&>(e), e.what()); | ||
5868 | } | ||
5869 | #if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) | ||
5870 | // LuaJIT cannot have the catchall when the safe propagation is on | ||
5871 | // but LuaJIT will swallow all C++ errors | ||
5872 | // if we don't at least catch std::exception ones | ||
5873 | catch (...) { | ||
5874 | call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception"); | ||
5875 | } | ||
5876 | #endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it | ||
5877 | return lua_error(L); | ||
5878 | #endif // Safe exceptions | ||
5879 | } | ||
5880 | |||
5881 | #ifdef SOL_NOEXCEPT_FUNCTION_TYPE | ||
5882 | #if 0 | ||
5883 | // impossible: g++/clang++ choke as they think this function is ambiguous: | ||
5884 | // to fix, wait for template <auto X> and then switch on no-exceptness of the function | ||
5885 | template <lua_CFunction_noexcept f> | ||
5886 | int static_trampoline(lua_State* L) noexcept { | ||
5887 | return f(L); | ||
5888 | } | ||
5889 | #else | ||
5890 | template <lua_CFunction_noexcept f> | ||
5891 | int static_trampoline_noexcept(lua_State* L) noexcept { | ||
5892 | return f(L); | ||
5893 | } | ||
5894 | #endif // impossible | ||
5895 | |||
5896 | #else | ||
5897 | template <lua_CFunction f> | ||
5898 | int static_trampoline_noexcept(lua_State* L) noexcept { | ||
5899 | return f(L); | ||
5900 | } | ||
5901 | #endif // noexcept lua_CFunction type | ||
5902 | |||
5903 | template <typename Fx, typename... Args> | ||
5904 | int trampoline(lua_State* L, Fx&& f, Args&&... args) { | ||
5905 | if (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) { | ||
5906 | return f(L, std::forward<Args>(args)...); | ||
5907 | } | ||
5908 | #if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT) | ||
5909 | return f(L, std::forward<Args>(args)...); | ||
5910 | #else | ||
5911 | try { | ||
5912 | return f(L, std::forward<Args>(args)...); | ||
5913 | } | ||
5914 | catch (const char* cs) { | ||
5915 | call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs)); | ||
5916 | } | ||
5917 | catch (const std::string& s) { | ||
5918 | call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size())); | ||
5919 | } | ||
5920 | catch (const std::exception& e) { | ||
5921 | call_exception_handler(L, optional<const std::exception&>(e), e.what()); | ||
5922 | } | ||
5923 | #if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) | ||
5924 | // LuaJIT cannot have the catchall when the safe propagation is on | ||
5925 | // but LuaJIT will swallow all C++ errors | ||
5926 | // if we don't at least catch std::exception ones | ||
5927 | catch (...) { | ||
5928 | call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception"); | ||
5929 | } | ||
5930 | #endif | ||
5931 | return lua_error(L); | ||
5932 | #endif | ||
5933 | } | ||
5934 | |||
5935 | inline int c_trampoline(lua_State* L, lua_CFunction f) { | ||
5936 | return trampoline(L, f); | ||
5937 | } | ||
5938 | #endif // Exceptions vs. No Exceptions | ||
5939 | |||
5940 | template <typename F, F fx> | ||
5941 | inline int typed_static_trampoline_raw(std::true_type, lua_State* L) { | ||
5942 | return static_trampoline_noexcept<fx>(L); | ||
5943 | } | ||
5944 | |||
5945 | template <typename F, F fx> | ||
5946 | inline int typed_static_trampoline_raw(std::false_type, lua_State* L) { | ||
5947 | return static_trampoline<fx>(L); | ||
5948 | } | ||
5949 | |||
5950 | template <typename F, F fx> | ||
5951 | inline int typed_static_trampoline(lua_State* L) { | ||
5952 | return typed_static_trampoline_raw<F, fx>(std::integral_constant<bool, meta::bind_traits<F>::is_noexcept>(), L); | ||
5953 | } | ||
5954 | } // namespace detail | ||
5955 | |||
5956 | inline void set_default_exception_handler(lua_State* L, exception_handler_function exf = &detail::default_exception_handler) { | ||
5957 | static_assert(sizeof(void*) >= sizeof(exception_handler_function), "void* storage is too small to transport the exception handler: please file a bug on the issue tracker"); | ||
5958 | void* storage; | ||
5959 | std::memcpy(&storage, &exf, sizeof(exception_handler_function)); | ||
5960 | lua_pushlightuserdata(L, storage); | ||
5961 | lua_setglobal(L, detail::default_exception_handler_name()); | ||
5962 | } | ||
5963 | } // sol | ||
5964 | |||
5965 | // end of sol/trampoline.hpp | ||
5966 | |||
5967 | // beginning of sol/stack_core.hpp | ||
5968 | |||
5969 | // beginning of sol/error_handler.hpp | ||
5970 | |||
5971 | // beginning of sol/demangle.hpp | ||
5972 | |||
5973 | #include <cctype> | ||
5974 | #if defined(__GNUC__) && defined(__MINGW32__) && (__GNUC__ < 6) | ||
5975 | extern "C" { | ||
5976 | } | ||
5977 | #endif // MinGW is on some stuff | ||
5978 | #include <locale> | ||
5979 | |||
5980 | namespace sol { | ||
5981 | namespace detail { | ||
5982 | #if defined(__GNUC__) || defined(__clang__) | ||
5983 | template <typename T, class seperator_mark = int> | ||
5984 | inline std::string ctti_get_type_name() { | ||
5985 | // cardinal sins from MINGW | ||
5986 | using namespace std; | ||
5987 | static const std::array<std::string, 2> removals = {{"{anonymous}", "(anonymous namespace)"}}; | ||
5988 | std::string name = __PRETTY_FUNCTION__; | ||
5989 | std::size_t start = name.find_first_of('['); | ||
5990 | start = name.find_first_of('=', start); | ||
5991 | std::size_t end = name.find_last_of(']'); | ||
5992 | if (end == std::string::npos) | ||
5993 | end = name.size(); | ||
5994 | if (start == std::string::npos) | ||
5995 | start = 0; | ||
5996 | if (start < name.size() - 1) | ||
5997 | start += 1; | ||
5998 | name = name.substr(start, end - start); | ||
5999 | start = name.rfind("seperator_mark"); | ||
6000 | if (start != std::string::npos) { | ||
6001 | name.erase(start - 2, name.length()); | ||
6002 | } | ||
6003 | while (!name.empty() && isblank(name.front())) | ||
6004 | name.erase(name.begin()); | ||
6005 | while (!name.empty() && isblank(name.back())) | ||
6006 | name.pop_back(); | ||
6007 | |||
6008 | for (std::size_t r = 0; r < removals.size(); ++r) { | ||
6009 | auto found = name.find(removals[r]); | ||
6010 | while (found != std::string::npos) { | ||
6011 | name.erase(found, removals[r].size()); | ||
6012 | found = name.find(removals[r]); | ||
6013 | } | ||
6014 | } | ||
6015 | |||
6016 | return name; | ||
6017 | } | ||
6018 | #elif defined(_MSC_VER) | ||
6019 | template <typename T> | ||
6020 | inline std::string ctti_get_type_name() { | ||
6021 | static const std::array<std::string, 7> removals = {{"public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'"}}; | ||
6022 | std::string name = __FUNCSIG__; | ||
6023 | std::size_t start = name.find("get_type_name"); | ||
6024 | if (start == std::string::npos) | ||
6025 | start = 0; | ||
6026 | else | ||
6027 | start += 13; | ||
6028 | if (start < name.size() - 1) | ||
6029 | start += 1; | ||
6030 | std::size_t end = name.find_last_of('>'); | ||
6031 | if (end == std::string::npos) | ||
6032 | end = name.size(); | ||
6033 | name = name.substr(start, end - start); | ||
6034 | if (name.find("struct", 0) == 0) | ||
6035 | name.replace(0, 6, "", 0); | ||
6036 | if (name.find("class", 0) == 0) | ||
6037 | name.replace(0, 5, "", 0); | ||
6038 | while (!name.empty() && isblank(name.front())) | ||
6039 | name.erase(name.begin()); | ||
6040 | while (!name.empty() && isblank(name.back())) | ||
6041 | name.pop_back(); | ||
6042 | |||
6043 | for (std::size_t r = 0; r < removals.size(); ++r) { | ||
6044 | auto found = name.find(removals[r]); | ||
6045 | while (found != std::string::npos) { | ||
6046 | name.erase(found, removals[r].size()); | ||
6047 | found = name.find(removals[r]); | ||
6048 | } | ||
6049 | } | ||
6050 | |||
6051 | return name; | ||
6052 | } | ||
6053 | #else | ||
6054 | #error Compiler not supported for demangling | ||
6055 | #endif // compilers | ||
6056 | |||
6057 | template <typename T> | ||
6058 | inline std::string demangle_once() { | ||
6059 | std::string realname = ctti_get_type_name<T>(); | ||
6060 | return realname; | ||
6061 | } | ||
6062 | |||
6063 | template <typename T> | ||
6064 | inline std::string short_demangle_once() { | ||
6065 | std::string realname = ctti_get_type_name<T>(); | ||
6066 | // This isn't the most complete but it'll do for now...? | ||
6067 | static const std::array<std::string, 10> ops = {{"operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*"}}; | ||
6068 | int level = 0; | ||
6069 | std::ptrdiff_t idx = 0; | ||
6070 | for (idx = static_cast<std::ptrdiff_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { | ||
6071 | if (level == 0 && realname[idx] == ':') { | ||
6072 | break; | ||
6073 | } | ||
6074 | bool isleft = realname[idx] == '<'; | ||
6075 | bool isright = realname[idx] == '>'; | ||
6076 | if (!isleft && !isright) | ||
6077 | continue; | ||
6078 | bool earlybreak = false; | ||
6079 | for (const auto& op : ops) { | ||
6080 | std::size_t nisop = realname.rfind(op, idx); | ||
6081 | if (nisop == std::string::npos) | ||
6082 | continue; | ||
6083 | std::size_t nisopidx = idx - op.size() + 1; | ||
6084 | if (nisop == nisopidx) { | ||
6085 | idx = static_cast<std::ptrdiff_t>(nisopidx); | ||
6086 | earlybreak = true; | ||
6087 | } | ||
6088 | break; | ||
6089 | } | ||
6090 | if (earlybreak) { | ||
6091 | continue; | ||
6092 | } | ||
6093 | level += isleft ? -1 : 1; | ||
6094 | } | ||
6095 | if (idx > 0) { | ||
6096 | realname.erase(0, realname.length() < static_cast<std::size_t>(idx) ? realname.length() : idx + 1); | ||
6097 | } | ||
6098 | return realname; | ||
6099 | } | ||
6100 | |||
6101 | template <typename T> | ||
6102 | inline const std::string& demangle() { | ||
6103 | static const std::string d = demangle_once<T>(); | ||
6104 | return d; | ||
6105 | } | ||
6106 | |||
6107 | template <typename T> | ||
6108 | inline const std::string& short_demangle() { | ||
6109 | static const std::string d = short_demangle_once<T>(); | ||
6110 | return d; | ||
6111 | } | ||
6112 | } | ||
6113 | } // namespace sol::detail | ||
6114 | |||
6115 | // end of sol/demangle.hpp | ||
6116 | |||
6117 | namespace sol { | ||
6118 | |||
6119 | inline std::string associated_type_name(lua_State* L, int index, type t) { | ||
6120 | switch (t) { | ||
6121 | case type::poly: | ||
6122 | return "anything"; | ||
6123 | case type::userdata: | ||
6124 | { | ||
6125 | if (lua_getmetatable(L, index) == 0) { | ||
6126 | break; | ||
6127 | } | ||
6128 | lua_pushlstring(L, "__name", 6); | ||
6129 | lua_rawget(L, -2); | ||
6130 | size_t sz; | ||
6131 | const char* name = lua_tolstring(L, -1, &sz); | ||
6132 | std::string tn(name, static_cast<std::string::size_type>(sz)); | ||
6133 | lua_pop(L, 2); | ||
6134 | return name; | ||
6135 | } | ||
6136 | default: | ||
6137 | break; | ||
6138 | } | ||
6139 | return lua_typename(L, static_cast<int>(t)); | ||
6140 | } | ||
6141 | |||
6142 | inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) { | ||
6143 | const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s"; | ||
6144 | std::string actualname = associated_type_name(L, index, actual); | ||
6145 | return luaL_error(L, err, index, | ||
6146 | expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)), | ||
6147 | actualname.c_str(), | ||
6148 | message.c_str()); | ||
6149 | } | ||
6150 | |||
6151 | inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) { | ||
6152 | const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s: %s"; | ||
6153 | std::string actualname = associated_type_name(L, index, actual); | ||
6154 | return luaL_error(L, err, index, | ||
6155 | expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)), | ||
6156 | actualname.c_str(), | ||
6157 | message); | ||
6158 | } | ||
6159 | |||
6160 | struct type_panic_t { | ||
6161 | int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) { | ||
6162 | return type_panic_c_str(L, index, expected, actual, nullptr); | ||
6163 | } | ||
6164 | int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) { | ||
6165 | return type_panic_c_str(L, index, expected, actual, message); | ||
6166 | } | ||
6167 | int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) { | ||
6168 | return type_panic_string(L, index, expected, actual, message); | ||
6169 | } | ||
6170 | }; | ||
6171 | |||
6172 | const type_panic_t type_panic = {}; | ||
6173 | |||
6174 | struct constructor_handler { | ||
6175 | int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) { | ||
6176 | std::string str = "(type check failed in constructor)"; | ||
6177 | return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str); | ||
6178 | } | ||
6179 | }; | ||
6180 | |||
6181 | template <typename F = void> | ||
6182 | struct argument_handler { | ||
6183 | int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) { | ||
6184 | std::string str = "(bad argument to variable or function call)"; | ||
6185 | return type_panic_string(L, index, expected, actual, message.empty() ? str : message + " " + str ); | ||
6186 | } | ||
6187 | }; | ||
6188 | |||
6189 | template <typename R, typename... Args> | ||
6190 | struct argument_handler<types<R, Args...>> { | ||
6191 | int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) { | ||
6192 | std::string addendum = "(bad argument into '"; | ||
6193 | addendum += detail::demangle<R>(); | ||
6194 | addendum += "("; | ||
6195 | int marker = 0; | ||
6196 | auto action = [&addendum, &marker](const std::string& n) { | ||
6197 | if (marker > 0) { | ||
6198 | addendum += ", "; | ||
6199 | } | ||
6200 | addendum += n; | ||
6201 | ++marker; | ||
6202 | }; | ||
6203 | (void)detail::swallow{int(), (action(detail::demangle<Args>()), int())...}; | ||
6204 | addendum += ")')"; | ||
6205 | return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum); | ||
6206 | } | ||
6207 | }; | ||
6208 | |||
6209 | // Specify this function as the handler for lua::check if you know there's nothing wrong | ||
6210 | inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept { | ||
6211 | return 0; | ||
6212 | } | ||
6213 | |||
6214 | inline void type_error(lua_State* L, int expected, int actual) noexcept(false) { | ||
6215 | luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); | ||
6216 | } | ||
6217 | |||
6218 | inline void type_error(lua_State* L, type expected, type actual) noexcept(false) { | ||
6219 | type_error(L, static_cast<int>(expected), static_cast<int>(actual)); | ||
6220 | } | ||
6221 | |||
6222 | inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) { | ||
6223 | if (expected != type::poly && expected != actual) { | ||
6224 | type_panic_c_str(L, index, expected, actual, nullptr); | ||
6225 | } | ||
6226 | } | ||
6227 | |||
6228 | inline void type_assert(lua_State* L, int index, type expected) { | ||
6229 | type actual = type_of(L, index); | ||
6230 | type_assert(L, index, expected, actual); | ||
6231 | } | ||
6232 | |||
6233 | } // namespace sol | ||
6234 | |||
6235 | // end of sol/error_handler.hpp | ||
6236 | |||
6237 | // beginning of sol/reference.hpp | ||
6238 | |||
6239 | // beginning of sol/stack_reference.hpp | ||
6240 | |||
6241 | namespace sol { | ||
6242 | namespace detail { | ||
6243 | inline bool xmovable(lua_State* leftL, lua_State* rightL) { | ||
6244 | if (rightL == nullptr || leftL == nullptr || leftL == rightL) { | ||
6245 | return false; | ||
6246 | } | ||
6247 | const void* leftregistry = lua_topointer(leftL, LUA_REGISTRYINDEX); | ||
6248 | const void* rightregistry = lua_topointer(rightL, LUA_REGISTRYINDEX); | ||
6249 | return leftregistry == rightregistry; | ||
6250 | } | ||
6251 | } // namespace detail | ||
6252 | |||
6253 | class stack_reference { | ||
6254 | private: | ||
6255 | lua_State* luastate = nullptr; | ||
6256 | int index = 0; | ||
6257 | |||
6258 | protected: | ||
6259 | int registry_index() const noexcept { | ||
6260 | return LUA_NOREF; | ||
6261 | } | ||
6262 | |||
6263 | public: | ||
6264 | stack_reference() noexcept = default; | ||
6265 | stack_reference(lua_nil_t) noexcept | ||
6266 | : stack_reference(){}; | ||
6267 | stack_reference(lua_State* L, lua_nil_t) noexcept | ||
6268 | : luastate(L), index(0) { | ||
6269 | } | ||
6270 | stack_reference(lua_State* L, int i) noexcept | ||
6271 | : stack_reference(L, absolute_index(L, i)) { | ||
6272 | } | ||
6273 | stack_reference(lua_State* L, absolute_index i) noexcept | ||
6274 | : luastate(L), index(i) { | ||
6275 | } | ||
6276 | stack_reference(lua_State* L, raw_index i) noexcept | ||
6277 | : luastate(L), index(i) { | ||
6278 | } | ||
6279 | stack_reference(lua_State* L, ref_index i) noexcept = delete; | ||
6280 | stack_reference(lua_State* L, const reference& r) noexcept = delete; | ||
6281 | stack_reference(lua_State* L, const stack_reference& r) noexcept | ||
6282 | : luastate(L) { | ||
6283 | if (!r.valid()) { | ||
6284 | index = 0; | ||
6285 | return; | ||
6286 | } | ||
6287 | int i = r.stack_index(); | ||
6288 | if (detail::xmovable(lua_state(), r.lua_state())) { | ||
6289 | lua_pushvalue(r.lua_state(), r.index); | ||
6290 | lua_xmove(r.lua_state(), luastate, 1); | ||
6291 | i = absolute_index(luastate, -1); | ||
6292 | } | ||
6293 | index = i; | ||
6294 | } | ||
6295 | stack_reference(stack_reference&& o) noexcept = default; | ||
6296 | stack_reference& operator=(stack_reference&&) noexcept = default; | ||
6297 | stack_reference(const stack_reference&) noexcept = default; | ||
6298 | stack_reference& operator=(const stack_reference&) noexcept = default; | ||
6299 | |||
6300 | int push() const noexcept { | ||
6301 | return push(lua_state()); | ||
6302 | } | ||
6303 | |||
6304 | int push(lua_State* Ls) const noexcept { | ||
6305 | if (lua_state() == nullptr) { | ||
6306 | lua_pushnil(Ls); | ||
6307 | return 1; | ||
6308 | } | ||
6309 | lua_pushvalue(lua_state(), index); | ||
6310 | if (Ls != lua_state()) { | ||
6311 | lua_xmove(lua_state(), Ls, 1); | ||
6312 | } | ||
6313 | return 1; | ||
6314 | } | ||
6315 | |||
6316 | void pop() const noexcept { | ||
6317 | pop(lua_state()); | ||
6318 | } | ||
6319 | |||
6320 | void pop(lua_State* Ls, int n = 1) const noexcept { | ||
6321 | lua_pop(Ls, n); | ||
6322 | } | ||
6323 | |||
6324 | int stack_index() const noexcept { | ||
6325 | return index; | ||
6326 | } | ||
6327 | |||
6328 | type get_type() const noexcept { | ||
6329 | int result = lua_type(lua_state(), index); | ||
6330 | return static_cast<type>(result); | ||
6331 | } | ||
6332 | |||
6333 | lua_State* lua_state() const noexcept { | ||
6334 | return luastate; | ||
6335 | } | ||
6336 | |||
6337 | bool valid() const noexcept { | ||
6338 | type t = get_type(); | ||
6339 | return t != type::lua_nil && t != type::none; | ||
6340 | } | ||
6341 | }; | ||
6342 | |||
6343 | inline bool operator==(const stack_reference& l, const stack_reference& r) { | ||
6344 | return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 0; | ||
6345 | } | ||
6346 | |||
6347 | inline bool operator!=(const stack_reference& l, const stack_reference& r) { | ||
6348 | return !operator==(l, r); | ||
6349 | } | ||
6350 | |||
6351 | inline bool operator==(const stack_reference& lhs, const lua_nil_t&) { | ||
6352 | return !lhs.valid(); | ||
6353 | } | ||
6354 | |||
6355 | inline bool operator==(const lua_nil_t&, const stack_reference& rhs) { | ||
6356 | return !rhs.valid(); | ||
6357 | } | ||
6358 | |||
6359 | inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) { | ||
6360 | return lhs.valid(); | ||
6361 | } | ||
6362 | |||
6363 | inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) { | ||
6364 | return rhs.valid(); | ||
6365 | } | ||
6366 | } // namespace sol | ||
6367 | |||
6368 | // end of sol/stack_reference.hpp | ||
6369 | |||
6370 | namespace sol { | ||
6371 | namespace detail { | ||
6372 | inline const char (&default_main_thread_name())[9] { | ||
6373 | static const char name[9] = "sol.\xF0\x9F\x93\x8C"; | ||
6374 | return name; | ||
6375 | } | ||
6376 | } // namespace detail | ||
6377 | |||
6378 | namespace stack { | ||
6379 | inline void remove(lua_State* L, int rawindex, int count) { | ||
6380 | if (count < 1) | ||
6381 | return; | ||
6382 | int top = lua_gettop(L); | ||
6383 | if (top < 1) { | ||
6384 | return; | ||
6385 | } | ||
6386 | if (rawindex == -count || top == rawindex) { | ||
6387 | // Slice them right off the top | ||
6388 | lua_pop(L, static_cast<int>(count)); | ||
6389 | return; | ||
6390 | } | ||
6391 | |||
6392 | // Remove each item one at a time using stack operations | ||
6393 | // Probably slower, maybe, haven't benchmarked, | ||
6394 | // but necessary | ||
6395 | int index = lua_absindex(L, rawindex); | ||
6396 | if (index < 0) { | ||
6397 | index = lua_gettop(L) + (index + 1); | ||
6398 | } | ||
6399 | int last = index + count; | ||
6400 | for (int i = index; i < last; ++i) { | ||
6401 | lua_remove(L, index); | ||
6402 | } | ||
6403 | } | ||
6404 | |||
6405 | struct push_popper_at { | ||
6406 | lua_State* L; | ||
6407 | int index; | ||
6408 | int count; | ||
6409 | push_popper_at(lua_State* luastate, int index = -1, int count = 1) | ||
6410 | : L(luastate), index(index), count(count) { | ||
6411 | } | ||
6412 | ~push_popper_at() { | ||
6413 | remove(L, index, count); | ||
6414 | } | ||
6415 | }; | ||
6416 | |||
6417 | template <bool top_level> | ||
6418 | struct push_popper_n { | ||
6419 | lua_State* L; | ||
6420 | int t; | ||
6421 | push_popper_n(lua_State* luastate, int x) | ||
6422 | : L(luastate), t(x) { | ||
6423 | } | ||
6424 | push_popper_n(const push_popper_n&) = delete; | ||
6425 | push_popper_n(push_popper_n&&) = default; | ||
6426 | push_popper_n& operator=(const push_popper_n&) = delete; | ||
6427 | push_popper_n& operator=(push_popper_n&&) = default; | ||
6428 | ~push_popper_n() { | ||
6429 | lua_pop(L, t); | ||
6430 | } | ||
6431 | }; | ||
6432 | template <> | ||
6433 | struct push_popper_n<true> { | ||
6434 | push_popper_n(lua_State*, int) { | ||
6435 | } | ||
6436 | }; | ||
6437 | template <bool, typename T, typename = void> | ||
6438 | struct push_popper { | ||
6439 | T t; | ||
6440 | push_popper(T x) | ||
6441 | : t(x) { | ||
6442 | t.push(); | ||
6443 | } | ||
6444 | ~push_popper() { | ||
6445 | t.pop(); | ||
6446 | } | ||
6447 | }; | ||
6448 | template <typename T, typename C> | ||
6449 | struct push_popper<true, T, C> { | ||
6450 | push_popper(T) { | ||
6451 | } | ||
6452 | ~push_popper() { | ||
6453 | } | ||
6454 | }; | ||
6455 | template <typename T> | ||
6456 | struct push_popper<false, T, std::enable_if_t<std::is_base_of<stack_reference, meta::unqualified_t<T>>::value>> { | ||
6457 | push_popper(T) { | ||
6458 | } | ||
6459 | ~push_popper() { | ||
6460 | } | ||
6461 | }; | ||
6462 | |||
6463 | template <bool top_level = false, typename T> | ||
6464 | push_popper<top_level, T> push_pop(T&& x) { | ||
6465 | return push_popper<top_level, T>(std::forward<T>(x)); | ||
6466 | } | ||
6467 | template <typename T> | ||
6468 | push_popper_at push_pop_at(T&& x) { | ||
6469 | int c = x.push(); | ||
6470 | lua_State* L = x.lua_state(); | ||
6471 | return push_popper_at(L, lua_absindex(L, -c), c); | ||
6472 | } | ||
6473 | template <bool top_level = false> | ||
6474 | push_popper_n<top_level> pop_n(lua_State* L, int x) { | ||
6475 | return push_popper_n<top_level>(L, x); | ||
6476 | } | ||
6477 | } // namespace stack | ||
6478 | |||
6479 | inline lua_State* main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { | ||
6480 | #if SOL_LUA_VERSION < 502 | ||
6481 | if (L == nullptr) | ||
6482 | return backup_if_unsupported; | ||
6483 | lua_getglobal(L, detail::default_main_thread_name()); | ||
6484 | auto pp = stack::pop_n(L, 1); | ||
6485 | if (type_of(L, -1) == type::thread) { | ||
6486 | return lua_tothread(L, -1); | ||
6487 | } | ||
6488 | return backup_if_unsupported; | ||
6489 | #else | ||
6490 | if (L == nullptr) | ||
6491 | return backup_if_unsupported; | ||
6492 | lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); | ||
6493 | lua_State* Lmain = lua_tothread(L, -1); | ||
6494 | lua_pop(L, 1); | ||
6495 | return Lmain; | ||
6496 | #endif // Lua 5.2+ has the main thread getter | ||
6497 | } | ||
6498 | |||
6499 | namespace detail { | ||
6500 | struct global_tag { | ||
6501 | } const global_{}; | ||
6502 | struct no_safety_tag { | ||
6503 | } const no_safety{}; | ||
6504 | |||
6505 | template <bool b> | ||
6506 | inline lua_State* pick_main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { | ||
6507 | (void)L; | ||
6508 | (void)backup_if_unsupported; | ||
6509 | if (b) { | ||
6510 | return main_thread(L, backup_if_unsupported); | ||
6511 | } | ||
6512 | return L; | ||
6513 | } | ||
6514 | } // namespace detail | ||
6515 | |||
6516 | template <bool main_only = false> | ||
6517 | class basic_reference { | ||
6518 | private: | ||
6519 | template <bool o_main_only> | ||
6520 | friend class basic_reference; | ||
6521 | lua_State* luastate = nullptr; // non-owning | ||
6522 | int ref = LUA_NOREF; | ||
6523 | |||
6524 | int copy() const noexcept { | ||
6525 | if (ref == LUA_NOREF) | ||
6526 | return LUA_NOREF; | ||
6527 | push(); | ||
6528 | return luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6529 | } | ||
6530 | |||
6531 | template <bool r_main_only> | ||
6532 | void copy_assign(const basic_reference<r_main_only>& r) { | ||
6533 | if (valid()) { | ||
6534 | deref(); | ||
6535 | } | ||
6536 | if (r.ref == LUA_REFNIL) { | ||
6537 | luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); | ||
6538 | ref = LUA_REFNIL; | ||
6539 | return; | ||
6540 | } | ||
6541 | if (r.ref == LUA_NOREF) { | ||
6542 | luastate = r.luastate; | ||
6543 | ref = LUA_NOREF; | ||
6544 | return; | ||
6545 | } | ||
6546 | if (detail::xmovable(lua_state(), r.lua_state())) { | ||
6547 | r.push(lua_state()); | ||
6548 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6549 | return; | ||
6550 | } | ||
6551 | luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); | ||
6552 | ref = r.copy(); | ||
6553 | } | ||
6554 | |||
6555 | template <bool r_main_only> | ||
6556 | void move_assign(basic_reference<r_main_only>&& r) { | ||
6557 | if (valid()) { | ||
6558 | deref(); | ||
6559 | } | ||
6560 | if (r.ref == LUA_REFNIL) { | ||
6561 | luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); | ||
6562 | ref = LUA_REFNIL; | ||
6563 | return; | ||
6564 | } | ||
6565 | if (r.ref == LUA_NOREF) { | ||
6566 | luastate = r.luastate; | ||
6567 | ref = LUA_NOREF; | ||
6568 | return; | ||
6569 | } | ||
6570 | if (detail::xmovable(lua_state(), r.lua_state())) { | ||
6571 | r.push(lua_state()); | ||
6572 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6573 | return; | ||
6574 | } | ||
6575 | |||
6576 | luastate = detail::pick_main_thread < main_only && !r_main_only > (r.lua_state(), r.lua_state()); | ||
6577 | ref = r.ref; | ||
6578 | r.ref = LUA_NOREF; | ||
6579 | r.luastate = nullptr; | ||
6580 | } | ||
6581 | |||
6582 | protected: | ||
6583 | basic_reference(lua_State* L, detail::global_tag) noexcept | ||
6584 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6585 | lua_pushglobaltable(lua_state()); | ||
6586 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6587 | } | ||
6588 | |||
6589 | int stack_index() const noexcept { | ||
6590 | return -1; | ||
6591 | } | ||
6592 | |||
6593 | void deref() const noexcept { | ||
6594 | luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref); | ||
6595 | } | ||
6596 | |||
6597 | public: | ||
6598 | basic_reference() noexcept = default; | ||
6599 | basic_reference(lua_nil_t) noexcept | ||
6600 | : basic_reference() { | ||
6601 | } | ||
6602 | basic_reference(const stack_reference& r) noexcept | ||
6603 | : basic_reference(r.lua_state(), r.stack_index()) { | ||
6604 | } | ||
6605 | basic_reference(stack_reference&& r) noexcept | ||
6606 | : basic_reference(r.lua_state(), r.stack_index()) { | ||
6607 | } | ||
6608 | template <bool r_main_only> | ||
6609 | basic_reference(lua_State* L, const basic_reference<r_main_only>& r) noexcept | ||
6610 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6611 | if (r.ref == LUA_REFNIL) { | ||
6612 | ref = LUA_REFNIL; | ||
6613 | return; | ||
6614 | } | ||
6615 | if (r.ref == LUA_NOREF || lua_state() == nullptr) { | ||
6616 | ref = LUA_NOREF; | ||
6617 | return; | ||
6618 | } | ||
6619 | if (detail::xmovable(lua_state(), r.lua_state())) { | ||
6620 | r.push(lua_state()); | ||
6621 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6622 | return; | ||
6623 | } | ||
6624 | ref = r.copy(); | ||
6625 | } | ||
6626 | |||
6627 | template <bool r_main_only> | ||
6628 | basic_reference(lua_State* L, basic_reference<r_main_only>&& r) noexcept | ||
6629 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6630 | if (r.ref == LUA_REFNIL) { | ||
6631 | ref = LUA_REFNIL; | ||
6632 | return; | ||
6633 | } | ||
6634 | if (r.ref == LUA_NOREF || lua_state() == nullptr) { | ||
6635 | ref = LUA_NOREF; | ||
6636 | return; | ||
6637 | } | ||
6638 | if (detail::xmovable(lua_state(), r.lua_state())) { | ||
6639 | r.push(lua_state()); | ||
6640 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6641 | return; | ||
6642 | } | ||
6643 | ref = r.ref; | ||
6644 | r.ref = LUA_NOREF; | ||
6645 | r.luastate = nullptr; | ||
6646 | } | ||
6647 | |||
6648 | basic_reference(lua_State* L, const stack_reference& r) noexcept | ||
6649 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6650 | if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { | ||
6651 | ref = LUA_NOREF; | ||
6652 | return; | ||
6653 | } | ||
6654 | if (r.get_type() == type::lua_nil) { | ||
6655 | ref = LUA_REFNIL; | ||
6656 | return; | ||
6657 | } | ||
6658 | if (lua_state() != r.lua_state() && !detail::xmovable(lua_state(), r.lua_state())) { | ||
6659 | return; | ||
6660 | } | ||
6661 | r.push(lua_state()); | ||
6662 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6663 | } | ||
6664 | basic_reference(lua_State* L, int index = -1) noexcept | ||
6665 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6666 | // use L to stick with that state's execution stack | ||
6667 | lua_pushvalue(L, index); | ||
6668 | ref = luaL_ref(L, LUA_REGISTRYINDEX); | ||
6669 | } | ||
6670 | basic_reference(lua_State* L, ref_index index) noexcept | ||
6671 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6672 | lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); | ||
6673 | ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); | ||
6674 | } | ||
6675 | basic_reference(lua_State* L, lua_nil_t) noexcept | ||
6676 | : luastate(detail::pick_main_thread<main_only>(L, L)) { | ||
6677 | } | ||
6678 | |||
6679 | ~basic_reference() noexcept { | ||
6680 | if (lua_state() == nullptr || ref == LUA_NOREF) | ||
6681 | return; | ||
6682 | deref(); | ||
6683 | } | ||
6684 | |||
6685 | basic_reference(const basic_reference& o) noexcept | ||
6686 | : luastate(o.lua_state()), ref(o.copy()) { | ||
6687 | } | ||
6688 | |||
6689 | basic_reference(basic_reference&& o) noexcept | ||
6690 | : luastate(o.lua_state()), ref(o.ref) { | ||
6691 | o.luastate = nullptr; | ||
6692 | o.ref = LUA_NOREF; | ||
6693 | } | ||
6694 | |||
6695 | basic_reference(const basic_reference<!main_only>& o) noexcept | ||
6696 | : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.copy()) { | ||
6697 | } | ||
6698 | |||
6699 | basic_reference(basic_reference<!main_only>&& o) noexcept | ||
6700 | : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.ref) { | ||
6701 | o.luastate = nullptr; | ||
6702 | o.ref = LUA_NOREF; | ||
6703 | } | ||
6704 | |||
6705 | basic_reference& operator=(basic_reference&& r) noexcept { | ||
6706 | move_assign(std::move(r)); | ||
6707 | return *this; | ||
6708 | } | ||
6709 | |||
6710 | basic_reference& operator=(const basic_reference& r) noexcept { | ||
6711 | copy_assign(r); | ||
6712 | return *this; | ||
6713 | } | ||
6714 | |||
6715 | basic_reference& operator=(basic_reference<!main_only>&& r) noexcept { | ||
6716 | move_assign(std::move(r)); | ||
6717 | return *this; | ||
6718 | } | ||
6719 | |||
6720 | basic_reference& operator=(const basic_reference<!main_only>& r) noexcept { | ||
6721 | copy_assign(r); | ||
6722 | return *this; | ||
6723 | } | ||
6724 | |||
6725 | basic_reference& operator=(const lua_nil_t&) noexcept { | ||
6726 | if (valid()) { | ||
6727 | deref(); | ||
6728 | } | ||
6729 | luastate = nullptr; | ||
6730 | ref = LUA_NOREF; | ||
6731 | return *this; | ||
6732 | } | ||
6733 | |||
6734 | template <typename Super> | ||
6735 | basic_reference& operator=(proxy_base<Super>&& r); | ||
6736 | |||
6737 | template <typename Super> | ||
6738 | basic_reference& operator=(const proxy_base<Super>& r); | ||
6739 | |||
6740 | int push() const noexcept { | ||
6741 | return push(lua_state()); | ||
6742 | } | ||
6743 | |||
6744 | int push(lua_State* Ls) const noexcept { | ||
6745 | if (lua_state() == nullptr) { | ||
6746 | lua_pushnil(Ls); | ||
6747 | return 1; | ||
6748 | } | ||
6749 | lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); | ||
6750 | if (Ls != lua_state()) { | ||
6751 | lua_xmove(lua_state(), Ls, 1); | ||
6752 | } | ||
6753 | return 1; | ||
6754 | } | ||
6755 | |||
6756 | void pop() const noexcept { | ||
6757 | pop(lua_state()); | ||
6758 | } | ||
6759 | |||
6760 | void pop(lua_State* Ls, int n = 1) const noexcept { | ||
6761 | lua_pop(Ls, n); | ||
6762 | } | ||
6763 | |||
6764 | int registry_index() const noexcept { | ||
6765 | return ref; | ||
6766 | } | ||
6767 | |||
6768 | bool valid() const noexcept { | ||
6769 | return !(ref == LUA_NOREF || ref == LUA_REFNIL); | ||
6770 | } | ||
6771 | |||
6772 | explicit operator bool() const noexcept { | ||
6773 | return valid(); | ||
6774 | } | ||
6775 | |||
6776 | type get_type() const noexcept { | ||
6777 | auto pp = stack::push_pop(*this); | ||
6778 | int result = lua_type(lua_state(), -1); | ||
6779 | return static_cast<type>(result); | ||
6780 | } | ||
6781 | |||
6782 | lua_State* lua_state() const noexcept { | ||
6783 | return luastate; | ||
6784 | } | ||
6785 | }; | ||
6786 | |||
6787 | template <bool lb, bool rb> | ||
6788 | inline bool operator==(const basic_reference<lb>& l, const basic_reference<rb>& r) { | ||
6789 | auto ppl = stack::push_pop(l); | ||
6790 | auto ppr = stack::push_pop(r); | ||
6791 | return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; | ||
6792 | } | ||
6793 | |||
6794 | template <bool lb, bool rb> | ||
6795 | inline bool operator!=(const basic_reference<lb>& l, const basic_reference<rb>& r) { | ||
6796 | return !operator==(l, r); | ||
6797 | } | ||
6798 | |||
6799 | template <bool lb> | ||
6800 | inline bool operator==(const basic_reference<lb>& lhs, const lua_nil_t&) { | ||
6801 | return !lhs.valid(); | ||
6802 | } | ||
6803 | |||
6804 | template <bool rb> | ||
6805 | inline bool operator==(const lua_nil_t&, const basic_reference<rb>& rhs) { | ||
6806 | return !rhs.valid(); | ||
6807 | } | ||
6808 | |||
6809 | template <bool lb> | ||
6810 | inline bool operator!=(const basic_reference<lb>& lhs, const lua_nil_t&) { | ||
6811 | return lhs.valid(); | ||
6812 | } | ||
6813 | |||
6814 | template <bool rb> | ||
6815 | inline bool operator!=(const lua_nil_t&, const basic_reference<rb>& rhs) { | ||
6816 | return rhs.valid(); | ||
6817 | } | ||
6818 | } // namespace sol | ||
6819 | |||
6820 | // end of sol/reference.hpp | ||
6821 | |||
6822 | // beginning of sol/tie.hpp | ||
6823 | |||
6824 | namespace sol { | ||
6825 | |||
6826 | namespace detail { | ||
6827 | template <typename T> | ||
6828 | struct is_speshul : std::false_type {}; | ||
6829 | } // namespace detail | ||
6830 | |||
6831 | template <typename T> | ||
6832 | struct tie_size : std::tuple_size<T> {}; | ||
6833 | |||
6834 | template <typename T> | ||
6835 | struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> {}; | ||
6836 | |||
6837 | template <typename... Tn> | ||
6838 | struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> { | ||
6839 | private: | ||
6840 | typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t; | ||
6841 | |||
6842 | template <typename T> | ||
6843 | void set(std::false_type, T&& target) { | ||
6844 | std::get<0>(*this) = std::forward<T>(target); | ||
6845 | } | ||
6846 | |||
6847 | template <typename T> | ||
6848 | void set(std::true_type, T&& target) { | ||
6849 | typedef tie_size<meta::unqualified_t<T>> value_size; | ||
6850 | typedef tie_size<std::tuple<Tn...>> tie_size; | ||
6851 | typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; | ||
6852 | typedef std::make_index_sequence<indices_size::value> indices; | ||
6853 | set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target)); | ||
6854 | } | ||
6855 | |||
6856 | template <std::size_t... I, typename T> | ||
6857 | void set_extra(std::true_type, std::index_sequence<I...>, T&& target) { | ||
6858 | using std::get; | ||
6859 | (void)detail::swallow{0, | ||
6860 | (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0}; | ||
6861 | } | ||
6862 | |||
6863 | template <std::size_t... I, typename T> | ||
6864 | void set_extra(std::false_type, std::index_sequence<I...>, T&& target) { | ||
6865 | using std::get; | ||
6866 | (void)detail::swallow{0, | ||
6867 | (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0}; | ||
6868 | } | ||
6869 | |||
6870 | public: | ||
6871 | using base_t::base_t; | ||
6872 | |||
6873 | template <typename T> | ||
6874 | tie_t& operator=(T&& value) { | ||
6875 | typedef is_tieable<meta::unqualified_t<T>> tieable; | ||
6876 | set(tieable(), std::forward<T>(value)); | ||
6877 | return *this; | ||
6878 | } | ||
6879 | }; | ||
6880 | |||
6881 | template <typename... Tn> | ||
6882 | struct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> {}; | ||
6883 | |||
6884 | namespace adl_barrier_detail { | ||
6885 | template <typename... Tn> | ||
6886 | inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) { | ||
6887 | return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...); | ||
6888 | } | ||
6889 | } // namespace adl_barrier_detail | ||
6890 | |||
6891 | using namespace adl_barrier_detail; | ||
6892 | |||
6893 | } // namespace sol | ||
6894 | |||
6895 | // end of sol/tie.hpp | ||
6896 | |||
6897 | // beginning of sol/stack_guard.hpp | ||
6898 | |||
6899 | namespace sol { | ||
6900 | namespace detail { | ||
6901 | inline void stack_fail(int, int) { | ||
6902 | #if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) | ||
6903 | throw error(detail::direct_error, "imbalanced stack after operation finish"); | ||
6904 | #else | ||
6905 | // Lol, what do you want, an error printout? :3c | ||
6906 | // There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so | ||
6907 | // hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard. | ||
6908 | #endif // No Exceptions | ||
6909 | } | ||
6910 | } // namespace detail | ||
6911 | |||
6912 | struct stack_guard { | ||
6913 | lua_State* L; | ||
6914 | int top; | ||
6915 | std::function<void(int, int)> on_mismatch; | ||
6916 | |||
6917 | stack_guard(lua_State* L) | ||
6918 | : stack_guard(L, lua_gettop(L)) { | ||
6919 | } | ||
6920 | stack_guard(lua_State* L, int top, std::function<void(int, int)> fx = detail::stack_fail) | ||
6921 | : L(L), top(top), on_mismatch(std::move(fx)) { | ||
6922 | } | ||
6923 | bool check_stack(int modification = 0) const { | ||
6924 | int bottom = lua_gettop(L) + modification; | ||
6925 | if (top == bottom) { | ||
6926 | return true; | ||
6927 | } | ||
6928 | on_mismatch(top, bottom); | ||
6929 | return false; | ||
6930 | } | ||
6931 | ~stack_guard() { | ||
6932 | check_stack(); | ||
6933 | } | ||
6934 | }; | ||
6935 | } // namespace sol | ||
6936 | |||
6937 | // end of sol/stack_guard.hpp | ||
6938 | |||
6939 | #include <vector> | ||
6940 | #include <forward_list> | ||
6941 | #include <algorithm> | ||
6942 | |||
6943 | namespace sol { | ||
6944 | namespace detail { | ||
6945 | struct as_reference_tag {}; | ||
6946 | template <typename T> | ||
6947 | struct as_pointer_tag {}; | ||
6948 | template <typename T> | ||
6949 | struct as_value_tag {}; | ||
6950 | template <typename T> | ||
6951 | struct as_table_tag {}; | ||
6952 | |||
6953 | using unique_destructor = void (*)(void*); | ||
6954 | |||
6955 | inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) { | ||
6956 | // this handels arbitrary alignments... | ||
6957 | // make this into a power-of-2-only? | ||
6958 | // actually can't: this is a C++14-compatible framework, | ||
6959 | // power of 2 alignment is C++17 | ||
6960 | std::uintptr_t initial = reinterpret_cast<std::uintptr_t>(ptr); | ||
6961 | std::uintptr_t offby = static_cast<std::uintptr_t>(initial % alignment); | ||
6962 | std::uintptr_t padding = (alignment - offby) % alignment; | ||
6963 | required_space += size + padding; | ||
6964 | if (space < required_space) { | ||
6965 | return nullptr; | ||
6966 | } | ||
6967 | ptr = static_cast<void*>(static_cast<char*>(ptr) + padding); | ||
6968 | space -= padding; | ||
6969 | return ptr; | ||
6970 | } | ||
6971 | |||
6972 | inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space) { | ||
6973 | std::size_t required_space = 0; | ||
6974 | return align(alignment, size, ptr, space, required_space); | ||
6975 | } | ||
6976 | |||
6977 | template <typename... Args> | ||
6978 | inline std::size_t aligned_space_for(void* alignment = nullptr) { | ||
6979 | char* start = static_cast<char*>(alignment); | ||
6980 | auto specific_align = [&alignment](std::size_t a, std::size_t s) { | ||
6981 | std::size_t space = (std::numeric_limits<std::size_t>::max)(); | ||
6982 | alignment = align(a, s, alignment, space); | ||
6983 | alignment = static_cast<void*>(static_cast<char*>(alignment) + s); | ||
6984 | }; | ||
6985 | (void)detail::swallow{ int{}, (specific_align(std::alignment_of<Args>::value, sizeof(Args)), int{})... }; | ||
6986 | return static_cast<char*>(alignment) - start; | ||
6987 | } | ||
6988 | |||
6989 | inline void* align_usertype_pointer(void* ptr) { | ||
6990 | typedef std::integral_constant<bool, | ||
6991 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
6992 | false | ||
6993 | #else | ||
6994 | (std::alignment_of<void*>::value > 1) | ||
6995 | #endif | ||
6996 | > | ||
6997 | use_align; | ||
6998 | if (!use_align::value) { | ||
6999 | return ptr; | ||
7000 | } | ||
7001 | std::size_t space = (std::numeric_limits<std::size_t>::max)(); | ||
7002 | return align(std::alignment_of<void*>::value, sizeof(void*), ptr, space); | ||
7003 | } | ||
7004 | |||
7005 | inline void* align_usertype_unique_destructor(void* ptr) { | ||
7006 | typedef std::integral_constant<bool, | ||
7007 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7008 | false | ||
7009 | #else | ||
7010 | (std::alignment_of<unique_destructor>::value > 1) | ||
7011 | #endif | ||
7012 | > | ||
7013 | use_align; | ||
7014 | if (!use_align::value) { | ||
7015 | return static_cast<void*>(static_cast<void**>(ptr) + 1); | ||
7016 | } | ||
7017 | ptr = align_usertype_pointer(ptr); | ||
7018 | ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*)); | ||
7019 | std::size_t space = (std::numeric_limits<std::size_t>::max)(); | ||
7020 | return align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space); | ||
7021 | } | ||
7022 | |||
7023 | template <typename T, bool pre_aligned = false> | ||
7024 | inline void* align_usertype_unique(void* ptr) { | ||
7025 | typedef std::integral_constant<bool, | ||
7026 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7027 | false | ||
7028 | #else | ||
7029 | (std::alignment_of<T>::value > 1) | ||
7030 | #endif | ||
7031 | > | ||
7032 | use_align; | ||
7033 | if (!pre_aligned) { | ||
7034 | ptr = align_usertype_unique_destructor(ptr); | ||
7035 | ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor)); | ||
7036 | } | ||
7037 | if (!use_align::value) { | ||
7038 | return ptr; | ||
7039 | } | ||
7040 | std::size_t space = (std::numeric_limits<std::size_t>::max)(); | ||
7041 | return align(std::alignment_of<T>::value, sizeof(T), ptr, space); | ||
7042 | } | ||
7043 | |||
7044 | template <typename T> | ||
7045 | inline void* align_user(void* ptr) { | ||
7046 | typedef std::integral_constant<bool, | ||
7047 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7048 | false | ||
7049 | #else | ||
7050 | (std::alignment_of<T>::value > 1) | ||
7051 | #endif | ||
7052 | > | ||
7053 | use_align; | ||
7054 | if (!use_align::value) { | ||
7055 | return ptr; | ||
7056 | } | ||
7057 | std::size_t space = (std::numeric_limits<std::size_t>::max)(); | ||
7058 | return align(std::alignment_of<T>::value, sizeof(T), ptr, space); | ||
7059 | } | ||
7060 | |||
7061 | template <typename T> | ||
7062 | inline T** usertype_allocate_pointer(lua_State* L) { | ||
7063 | typedef std::integral_constant<bool, | ||
7064 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7065 | false | ||
7066 | #else | ||
7067 | (std::alignment_of<T*>::value > 1) | ||
7068 | #endif | ||
7069 | > | ||
7070 | use_align; | ||
7071 | if (!use_align::value) { | ||
7072 | T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*))); | ||
7073 | return pointerpointer; | ||
7074 | } | ||
7075 | static const std::size_t initial_size = aligned_space_for<T*>(nullptr); | ||
7076 | static const std::size_t misaligned_size = aligned_space_for<T*>(reinterpret_cast<void*>(0x1)); | ||
7077 | |||
7078 | std::size_t allocated_size = initial_size; | ||
7079 | void* unadjusted = lua_newuserdata(L, initial_size); | ||
7080 | void* adjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size); | ||
7081 | if (adjusted == nullptr) { | ||
7082 | lua_pop(L, 1); | ||
7083 | // what kind of absolute garbage trash allocator are we dealing with? | ||
7084 | // whatever, add some padding in the case of MAXIMAL alignment waste... | ||
7085 | allocated_size = misaligned_size; | ||
7086 | unadjusted = lua_newuserdata(L, allocated_size); | ||
7087 | adjusted = align(std::alignment_of<T*>::value, sizeof(T*), unadjusted, allocated_size); | ||
7088 | if (adjusted == nullptr) { | ||
7089 | // trash allocator can burn in hell | ||
7090 | lua_pop(L, 1); | ||
7091 | //luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a worse job than malloc/realloc and should go read some books, yeah?"); | ||
7092 | luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T*>().data()); | ||
7093 | } | ||
7094 | } | ||
7095 | return static_cast<T**>(adjusted); | ||
7096 | } | ||
7097 | |||
7098 | template <typename T> | ||
7099 | inline T* usertype_allocate(lua_State* L) { | ||
7100 | typedef std::integral_constant<bool, | ||
7101 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7102 | false | ||
7103 | #else | ||
7104 | (std::alignment_of<T*>::value > 1 || std::alignment_of<T>::value > 1) | ||
7105 | #endif | ||
7106 | > | ||
7107 | use_align; | ||
7108 | if (!use_align::value) { | ||
7109 | T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T))); | ||
7110 | T*& pointerreference = *pointerpointer; | ||
7111 | T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1); | ||
7112 | pointerreference = allocationtarget; | ||
7113 | return allocationtarget; | ||
7114 | } | ||
7115 | |||
7116 | /* the assumption is that `lua_newuserdata` -- unless someone | ||
7117 | passes a specific lua_Alloc that gives us bogus, un-aligned pointers | ||
7118 | -- uses malloc, which tends to hand out more or less aligned pointers to memory | ||
7119 | (most of the time, anyhow) | ||
7120 | |||
7121 | but it's not guaranteed, so we have to do a post-adjustment check and increase padding | ||
7122 | |||
7123 | we do this preliminarily with compile-time stuff, to see | ||
7124 | if we strike lucky with the allocator and alignment values | ||
7125 | |||
7126 | otherwise, we have to re-allocate the userdata and | ||
7127 | over-allocate some space for additional padding because | ||
7128 | compilers are optimized for aligned reads/writes | ||
7129 | (and clang will barf UBsan errors on us for not being aligned) | ||
7130 | */ | ||
7131 | static const std::size_t initial_size = aligned_space_for<T*, T>(nullptr); | ||
7132 | static const std::size_t misaligned_size = aligned_space_for<T*, T>(reinterpret_cast<void*>(0x1)); | ||
7133 | |||
7134 | void* pointer_adjusted; | ||
7135 | void* data_adjusted; | ||
7136 | auto attempt_alloc = [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) -> bool { | ||
7137 | void* adjusted = lua_newuserdata(L, allocated_size); | ||
7138 | pointer_adjusted = align(std::alignment_of<T*>::value, sizeof(T*), adjusted, allocated_size); | ||
7139 | if (pointer_adjusted == nullptr) { | ||
7140 | lua_pop(L, 1); | ||
7141 | return false; | ||
7142 | } | ||
7143 | // subtract size of what we're going to allocate there | ||
7144 | allocated_size -= sizeof(T*); | ||
7145 | adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*)); | ||
7146 | data_adjusted = align(std::alignment_of<T>::value, sizeof(T), adjusted, allocated_size); | ||
7147 | if (data_adjusted == nullptr) { | ||
7148 | lua_pop(L, 1); | ||
7149 | return false; | ||
7150 | } | ||
7151 | return true; | ||
7152 | }; | ||
7153 | bool result = attempt_alloc(L, initial_size, pointer_adjusted, data_adjusted); | ||
7154 | if (!result) { | ||
7155 | // we're likely to get something that fails to perform the proper allocation a second time, | ||
7156 | // so we use the suggested_new_size bump to help us out here | ||
7157 | pointer_adjusted = nullptr; | ||
7158 | data_adjusted = nullptr; | ||
7159 | result = attempt_alloc(L, misaligned_size, pointer_adjusted, data_adjusted); | ||
7160 | if (!result) { | ||
7161 | if (pointer_adjusted == nullptr) { | ||
7162 | luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); | ||
7163 | } | ||
7164 | else { | ||
7165 | luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<T>().c_str()); | ||
7166 | } | ||
7167 | return nullptr; | ||
7168 | } | ||
7169 | } | ||
7170 | |||
7171 | T** pointerpointer = reinterpret_cast<T**>(pointer_adjusted); | ||
7172 | T*& pointerreference = *pointerpointer; | ||
7173 | T* allocationtarget = reinterpret_cast<T*>(data_adjusted); | ||
7174 | pointerreference = allocationtarget; | ||
7175 | return allocationtarget; | ||
7176 | } | ||
7177 | |||
7178 | template <typename T, typename Real> | ||
7179 | inline Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx) { | ||
7180 | typedef std::integral_constant<bool, | ||
7181 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7182 | false | ||
7183 | #else | ||
7184 | (std::alignment_of<T*>::value > 1 || std::alignment_of<unique_destructor>::value > 1 || std::alignment_of<Real>::value > 1) | ||
7185 | #endif | ||
7186 | > | ||
7187 | use_align; | ||
7188 | if (!use_align::value) { | ||
7189 | pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(Real))); | ||
7190 | dx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1)); | ||
7191 | Real* mem = static_cast<Real*>(static_cast<void*>(dx + 1)); | ||
7192 | return mem; | ||
7193 | } | ||
7194 | |||
7195 | static const std::size_t initial_size = aligned_space_for<T*, unique_destructor, Real>(nullptr); | ||
7196 | static const std::size_t misaligned_size = aligned_space_for<T*, unique_destructor, Real>(reinterpret_cast<void*>(0x1)); | ||
7197 | |||
7198 | void* pointer_adjusted; | ||
7199 | void* dx_adjusted; | ||
7200 | void* data_adjusted; | ||
7201 | auto attempt_alloc = [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& data_adjusted) -> bool { | ||
7202 | void* adjusted = lua_newuserdata(L, allocated_size); | ||
7203 | pointer_adjusted = align(std::alignment_of<T*>::value, sizeof(T*), adjusted, allocated_size); | ||
7204 | if (pointer_adjusted == nullptr) { | ||
7205 | lua_pop(L, 1); | ||
7206 | return false; | ||
7207 | } | ||
7208 | allocated_size -= sizeof(T*); | ||
7209 | adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*)); | ||
7210 | dx_adjusted = align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), adjusted, allocated_size); | ||
7211 | if (dx_adjusted == nullptr) { | ||
7212 | lua_pop(L, 1); | ||
7213 | return false; | ||
7214 | } | ||
7215 | allocated_size -= sizeof(unique_destructor); | ||
7216 | adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor)); | ||
7217 | data_adjusted = align(std::alignment_of<Real>::value, sizeof(Real), adjusted, allocated_size); | ||
7218 | if (data_adjusted == nullptr) { | ||
7219 | lua_pop(L, 1); | ||
7220 | return false; | ||
7221 | } | ||
7222 | return true; | ||
7223 | }; | ||
7224 | bool result = attempt_alloc(L, initial_size, pointer_adjusted, dx_adjusted, data_adjusted); | ||
7225 | if (!result) { | ||
7226 | // we're likely to get something that fails to perform the proper allocation a second time, | ||
7227 | // so we use the suggested_new_size bump to help us out here | ||
7228 | pointer_adjusted = nullptr; | ||
7229 | dx_adjusted = nullptr; | ||
7230 | data_adjusted = nullptr; | ||
7231 | result = attempt_alloc(L, misaligned_size, pointer_adjusted, dx_adjusted, data_adjusted); | ||
7232 | if (!result) { | ||
7233 | if (pointer_adjusted == nullptr) { | ||
7234 | luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); | ||
7235 | } | ||
7236 | else if (dx_adjusted == nullptr) { | ||
7237 | luaL_error(L, "aligned allocation of userdata block (deleter section) for '%s' failed", detail::demangle<Real>().c_str()); | ||
7238 | } | ||
7239 | else { | ||
7240 | luaL_error(L, "aligned allocation of userdata block (data section) for '%s' failed", detail::demangle<Real>().c_str()); | ||
7241 | } | ||
7242 | return nullptr; | ||
7243 | } | ||
7244 | } | ||
7245 | |||
7246 | pref = static_cast<T**>(pointer_adjusted); | ||
7247 | dx = static_cast<detail::unique_destructor*>(dx_adjusted); | ||
7248 | Real* mem = static_cast<Real*>(data_adjusted); | ||
7249 | return mem; | ||
7250 | } | ||
7251 | |||
7252 | template <typename T> | ||
7253 | inline T* user_allocate(lua_State* L) { | ||
7254 | typedef std::integral_constant<bool, | ||
7255 | #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT | ||
7256 | false | ||
7257 | #else | ||
7258 | (std::alignment_of<T>::value > 1) | ||
7259 | #endif | ||
7260 | > | ||
7261 | use_align; | ||
7262 | if (!use_align::value) { | ||
7263 | T* pointer = static_cast<T*>(lua_newuserdata(L, sizeof(T))); | ||
7264 | return pointer; | ||
7265 | } | ||
7266 | |||
7267 | static const std::size_t initial_size = aligned_space_for<T>(nullptr); | ||
7268 | static const std::size_t misaligned_size = aligned_space_for<T>(reinterpret_cast<void*>(0x1)); | ||
7269 | |||
7270 | std::size_t allocated_size = initial_size; | ||
7271 | void* unadjusted = lua_newuserdata(L, allocated_size); | ||
7272 | void* adjusted = align(std::alignment_of<T>::value, sizeof(T), unadjusted, allocated_size); | ||
7273 | if (adjusted == nullptr) { | ||
7274 | lua_pop(L, 1); | ||
7275 | // try again, add extra space for alignment padding | ||
7276 | allocated_size = misaligned_size; | ||
7277 | unadjusted = lua_newuserdata(L, allocated_size); | ||
7278 | adjusted = align(std::alignment_of<T>::value, sizeof(T), unadjusted, allocated_size); | ||
7279 | if (adjusted == nullptr) { | ||
7280 | lua_pop(L, 1); | ||
7281 | luaL_error(L, "cannot properly align memory for '%s'", detail::demangle<T>().data()); | ||
7282 | } | ||
7283 | } | ||
7284 | return static_cast<T*>(adjusted); | ||
7285 | } | ||
7286 | |||
7287 | template <typename T> | ||
7288 | inline int usertype_alloc_destruct(lua_State* L) { | ||
7289 | void* memory = lua_touserdata(L, 1); | ||
7290 | memory = align_usertype_pointer(memory); | ||
7291 | T** pdata = static_cast<T**>(memory); | ||
7292 | T* data = *pdata; | ||
7293 | std::allocator<T> alloc{}; | ||
7294 | std::allocator_traits<std::allocator<T>>::destroy(alloc, data); | ||
7295 | return 0; | ||
7296 | } | ||
7297 | |||
7298 | template <typename T> | ||
7299 | inline int unique_destruct(lua_State* L) { | ||
7300 | void* memory = lua_touserdata(L, 1); | ||
7301 | memory = align_usertype_unique_destructor(memory); | ||
7302 | unique_destructor& dx = *static_cast<unique_destructor*>(memory); | ||
7303 | memory = static_cast<void*>(static_cast<char*>(memory) + sizeof(unique_destructor)); | ||
7304 | (dx)(memory); | ||
7305 | return 0; | ||
7306 | } | ||
7307 | |||
7308 | template <typename T> | ||
7309 | inline int user_alloc_destruct(lua_State* L) { | ||
7310 | void* memory = lua_touserdata(L, 1); | ||
7311 | memory = align_user<T>(memory); | ||
7312 | T* data = static_cast<T*>(memory); | ||
7313 | std::allocator<T> alloc; | ||
7314 | std::allocator_traits<std::allocator<T>>::destroy(alloc, data); | ||
7315 | return 0; | ||
7316 | } | ||
7317 | |||
7318 | template <typename T, typename Real> | ||
7319 | inline void usertype_unique_alloc_destroy(void* memory) { | ||
7320 | memory = align_usertype_unique<Real, true>(memory); | ||
7321 | Real* target = static_cast<Real*>(memory); | ||
7322 | std::allocator<Real> alloc; | ||
7323 | std::allocator_traits<std::allocator<Real>>::destroy(alloc, target); | ||
7324 | } | ||
7325 | |||
7326 | template <typename T> | ||
7327 | inline int cannot_destruct(lua_State* L) { | ||
7328 | return luaL_error(L, "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= delete' and thusly this type is being destroyed without properly destructing, invoking undefined behavior: please bind a usertype and specify a custom destructor to define the behavior properly", detail::demangle<T>().data()); | ||
7329 | } | ||
7330 | |||
7331 | template <typename T> | ||
7332 | void reserve(T&, std::size_t) { | ||
7333 | } | ||
7334 | |||
7335 | template <typename T, typename Al> | ||
7336 | void reserve(std::vector<T, Al>& arr, std::size_t hint) { | ||
7337 | arr.reserve(hint); | ||
7338 | } | ||
7339 | |||
7340 | template <typename T, typename Tr, typename Al> | ||
7341 | void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) { | ||
7342 | arr.reserve(hint); | ||
7343 | } | ||
7344 | } // namespace detail | ||
7345 | |||
7346 | namespace stack { | ||
7347 | |||
7348 | template <typename T> | ||
7349 | struct extensible {}; | ||
7350 | |||
7351 | template <typename T, bool global = false, bool raw = false, typename = void> | ||
7352 | struct field_getter; | ||
7353 | template <typename T, bool global = false, bool raw = false, typename = void> | ||
7354 | struct probe_field_getter; | ||
7355 | template <typename T, bool global = false, bool raw = false, typename = void> | ||
7356 | struct field_setter; | ||
7357 | template <typename T, typename = void> | ||
7358 | struct getter; | ||
7359 | template <typename T, typename = void> | ||
7360 | struct userdata_getter; | ||
7361 | template <typename T, typename = void> | ||
7362 | struct popper; | ||
7363 | template <typename T, typename = void> | ||
7364 | struct pusher; | ||
7365 | template <typename T, type = lua_type_of<T>::value, typename = void> | ||
7366 | struct checker; | ||
7367 | template <typename T, typename = void> | ||
7368 | struct userdata_checker; | ||
7369 | template <typename T, typename = void> | ||
7370 | struct check_getter; | ||
7371 | |||
7372 | struct probe { | ||
7373 | bool success; | ||
7374 | int levels; | ||
7375 | |||
7376 | probe(bool s, int l) | ||
7377 | : success(s), levels(l) { | ||
7378 | } | ||
7379 | |||
7380 | operator bool() const { | ||
7381 | return success; | ||
7382 | }; | ||
7383 | }; | ||
7384 | |||
7385 | struct record { | ||
7386 | int last; | ||
7387 | int used; | ||
7388 | |||
7389 | record() | ||
7390 | : last(), used() { | ||
7391 | } | ||
7392 | void use(int count) { | ||
7393 | last = count; | ||
7394 | used += count; | ||
7395 | } | ||
7396 | }; | ||
7397 | |||
7398 | namespace stack_detail { | ||
7399 | template <typename T> | ||
7400 | struct strip { | ||
7401 | typedef T type; | ||
7402 | }; | ||
7403 | template <typename T> | ||
7404 | struct strip<std::reference_wrapper<T>> { | ||
7405 | typedef T& type; | ||
7406 | }; | ||
7407 | template <typename T> | ||
7408 | struct strip<user<T>> { | ||
7409 | typedef T& type; | ||
7410 | }; | ||
7411 | template <typename T> | ||
7412 | struct strip<non_null<T>> { | ||
7413 | typedef T type; | ||
7414 | }; | ||
7415 | template <typename T> | ||
7416 | using strip_t = typename strip<T>::type; | ||
7417 | |||
7418 | template <typename T> | ||
7419 | struct strip_extensible { typedef T type; }; | ||
7420 | |||
7421 | template <typename T> | ||
7422 | struct strip_extensible<extensible<T>> { typedef T type; }; | ||
7423 | |||
7424 | template <typename T> | ||
7425 | using strip_extensible_t = typename strip_extensible<T>::type; | ||
7426 | |||
7427 | template <typename C> | ||
7428 | static int get_size_hint(const C& c) { | ||
7429 | return static_cast<int>(c.size()); | ||
7430 | } | ||
7431 | |||
7432 | template <typename V, typename Al> | ||
7433 | static int get_size_hint(const std::forward_list<V, Al>&) { | ||
7434 | // forward_list makes me sad | ||
7435 | return static_cast<int>(32); | ||
7436 | } | ||
7437 | |||
7438 | template <typename T> | ||
7439 | inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { | ||
7440 | getter<meta::unqualified_t<T>> g{}; | ||
7441 | (void)g; | ||
7442 | return g.get(L, index, tracking); | ||
7443 | } | ||
7444 | |||
7445 | template <typename T, typename Arg, typename... Args> | ||
7446 | inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { | ||
7447 | typedef meta::all< | ||
7448 | std::is_lvalue_reference<T>, | ||
7449 | meta::neg<std::is_const<T>>, | ||
7450 | meta::neg<is_lua_primitive<meta::unqualified_t<T>>>, | ||
7451 | meta::neg<is_unique_usertype<meta::unqualified_t<T>>>> | ||
7452 | use_reference_tag; | ||
7453 | return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); | ||
7454 | } | ||
7455 | |||
7456 | template <typename T, typename Handler> | ||
7457 | bool check_usertype(std::false_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { | ||
7458 | typedef meta::unqualified_t<T> Tu; | ||
7459 | typedef detail::as_value_tag<Tu> detail_t; | ||
7460 | return checker<detail_t, type::userdata>{}.check(types<meta::unqualified_t<T>>(), L, index, indextype, std::forward<Handler>(handler), tracking); | ||
7461 | } | ||
7462 | |||
7463 | template <typename T, typename Handler> | ||
7464 | bool check_usertype(std::true_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { | ||
7465 | typedef meta::unqualified_t<std::remove_pointer_t<meta::unqualified_t<T>>> Tu; | ||
7466 | typedef detail::as_pointer_tag<Tu> detail_t; | ||
7467 | return checker<detail_t, type::userdata>{}.check(L, index, indextype, std::forward<Handler>(handler), tracking); | ||
7468 | } | ||
7469 | } // namespace stack_detail | ||
7470 | |||
7471 | inline bool maybe_indexable(lua_State* L, int index = -1) { | ||
7472 | type t = type_of(L, index); | ||
7473 | return t == type::userdata || t == type::table; | ||
7474 | } | ||
7475 | |||
7476 | inline int top(lua_State* L) { | ||
7477 | return lua_gettop(L); | ||
7478 | } | ||
7479 | |||
7480 | inline bool is_main_thread(lua_State* L) { | ||
7481 | int ismainthread = lua_pushthread(L); | ||
7482 | lua_pop(L, 1); | ||
7483 | return ismainthread == 1; | ||
7484 | } | ||
7485 | |||
7486 | inline void coroutine_create_guard(lua_State* L) { | ||
7487 | if (is_main_thread(L)) { | ||
7488 | return; | ||
7489 | } | ||
7490 | int stacksize = lua_gettop(L); | ||
7491 | if (stacksize < 1) { | ||
7492 | return; | ||
7493 | } | ||
7494 | if (type_of(L, 1) != type::function) { | ||
7495 | return; | ||
7496 | } | ||
7497 | // well now we're screwed... | ||
7498 | // we can clean the stack and pray it doesn't destroy anything? | ||
7499 | lua_pop(L, stacksize); | ||
7500 | } | ||
7501 | |||
7502 | template <typename T, typename... Args> | ||
7503 | inline int push(lua_State* L, T&& t, Args&&... args) { | ||
7504 | return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...); | ||
7505 | } | ||
7506 | |||
7507 | // overload allows to use a pusher of a specific type, but pass in any kind of args | ||
7508 | template <typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>> | ||
7509 | inline int push(lua_State* L, Arg&& arg, Args&&... args) { | ||
7510 | return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...); | ||
7511 | } | ||
7512 | |||
7513 | template <typename T, typename... Args> | ||
7514 | inline int push_reference(lua_State* L, T&& t, Args&&... args) { | ||
7515 | return stack_detail::push_reference<T>(L, std::forward<T>(t), std::forward<Args>(args)...); | ||
7516 | } | ||
7517 | |||
7518 | template <typename T, typename Arg, typename... Args> | ||
7519 | inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { | ||
7520 | return stack_detail::push_reference<T>(L, std::forward<Arg>(arg), std::forward<Args>(args)...); | ||
7521 | } | ||
7522 | |||
7523 | inline int multi_push(lua_State*) { | ||
7524 | // do nothing | ||
7525 | return 0; | ||
7526 | } | ||
7527 | |||
7528 | template <typename T, typename... Args> | ||
7529 | inline int multi_push(lua_State* L, T&& t, Args&&... args) { | ||
7530 | int pushcount = push(L, std::forward<T>(t)); | ||
7531 | void(detail::swallow{ (pushcount += stack::push(L, std::forward<Args>(args)), 0)... }); | ||
7532 | return pushcount; | ||
7533 | } | ||
7534 | |||
7535 | inline int multi_push_reference(lua_State*) { | ||
7536 | // do nothing | ||
7537 | return 0; | ||
7538 | } | ||
7539 | |||
7540 | template <typename T, typename... Args> | ||
7541 | inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { | ||
7542 | int pushcount = push_reference(L, std::forward<T>(t)); | ||
7543 | void(detail::swallow{ (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... }); | ||
7544 | return pushcount; | ||
7545 | } | ||
7546 | |||
7547 | template <typename T, typename Handler> | ||
7548 | bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7549 | typedef meta::unqualified_t<T> Tu; | ||
7550 | checker<Tu> c; | ||
7551 | // VC++ has a bad warning here: shut it up | ||
7552 | (void)c; | ||
7553 | return c.check(L, index, std::forward<Handler>(handler), tracking); | ||
7554 | } | ||
7555 | |||
7556 | template <typename T, typename Handler> | ||
7557 | bool check(lua_State* L, int index, Handler&& handler) { | ||
7558 | record tracking{}; | ||
7559 | return check<T>(L, index, std::forward<Handler>(handler), tracking); | ||
7560 | } | ||
7561 | |||
7562 | template <typename T> | ||
7563 | bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { | ||
7564 | auto handler = no_panic; | ||
7565 | return check<T>(L, index, handler); | ||
7566 | } | ||
7567 | |||
7568 | template <typename T, typename Handler> | ||
7569 | bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7570 | type indextype = type_of(L, index); | ||
7571 | return stack_detail::check_usertype<T>(std::is_pointer<T>(), L, index, indextype, std::forward<Handler>(handler), tracking); | ||
7572 | } | ||
7573 | |||
7574 | template <typename T, typename Handler> | ||
7575 | bool check_usertype(lua_State* L, int index, Handler&& handler) { | ||
7576 | record tracking{}; | ||
7577 | return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); | ||
7578 | } | ||
7579 | |||
7580 | template <typename T> | ||
7581 | bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { | ||
7582 | auto handler = no_panic; | ||
7583 | return check_usertype<T>(L, index, handler); | ||
7584 | } | ||
7585 | |||
7586 | template <typename T, typename Handler> | ||
7587 | inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7588 | typedef meta::unqualified_t<T> Tu; | ||
7589 | check_getter<Tu> cg{}; | ||
7590 | (void)cg; | ||
7591 | return cg.get(L, index, std::forward<Handler>(handler), tracking); | ||
7592 | } | ||
7593 | |||
7594 | template <typename T, typename Handler> | ||
7595 | inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { | ||
7596 | record tracking{}; | ||
7597 | return check_get<T>(L, index, handler, tracking); | ||
7598 | } | ||
7599 | |||
7600 | template <typename T> | ||
7601 | inline decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { | ||
7602 | auto handler = no_panic; | ||
7603 | return check_get<T>(L, index, handler); | ||
7604 | } | ||
7605 | |||
7606 | namespace stack_detail { | ||
7607 | |||
7608 | #if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER | ||
7609 | template <typename T> | ||
7610 | inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) { | ||
7611 | auto op = check_get<T>(L, index, type_panic_c_str, tracking); | ||
7612 | return *std::move(op); | ||
7613 | } | ||
7614 | |||
7615 | template <typename T> | ||
7616 | inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) { | ||
7617 | return stack_detail::unchecked_get<optional<T>>(L, index, tracking); | ||
7618 | } | ||
7619 | #else | ||
7620 | template <typename T> | ||
7621 | inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) { | ||
7622 | return stack_detail::unchecked_get<T>(L, index, tracking); | ||
7623 | } | ||
7624 | #endif | ||
7625 | |||
7626 | template <bool b> | ||
7627 | struct check_types { | ||
7628 | template <typename T, typename... Args, typename Handler> | ||
7629 | static bool check(types<T, Args...>, lua_State* L, int firstargument, Handler&& handler, record& tracking) { | ||
7630 | if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking)) | ||
7631 | return false; | ||
7632 | return check(types<Args...>(), L, firstargument, std::forward<Handler>(handler), tracking); | ||
7633 | } | ||
7634 | |||
7635 | template <typename Handler> | ||
7636 | static bool check(types<>, lua_State*, int, Handler&&, record&) { | ||
7637 | return true; | ||
7638 | } | ||
7639 | }; | ||
7640 | |||
7641 | template <> | ||
7642 | struct check_types<false> { | ||
7643 | template <typename... Args, typename Handler> | ||
7644 | static bool check(types<Args...>, lua_State*, int, Handler&&, record&) { | ||
7645 | return true; | ||
7646 | } | ||
7647 | }; | ||
7648 | |||
7649 | } // namespace stack_detail | ||
7650 | |||
7651 | template <bool b, typename... Args, typename Handler> | ||
7652 | bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7653 | return stack_detail::check_types<b>{}.check(types<meta::unqualified_t<Args>...>(), L, index, std::forward<Handler>(handler), tracking); | ||
7654 | } | ||
7655 | |||
7656 | template <bool b, typename... Args, typename Handler> | ||
7657 | bool multi_check(lua_State* L, int index, Handler&& handler) { | ||
7658 | record tracking{}; | ||
7659 | return multi_check<b, Args...>(L, index, std::forward<Handler>(handler), tracking); | ||
7660 | } | ||
7661 | |||
7662 | template <bool b, typename... Args> | ||
7663 | bool multi_check(lua_State* L, int index) { | ||
7664 | auto handler = no_panic; | ||
7665 | return multi_check<b, Args...>(L, index, handler); | ||
7666 | } | ||
7667 | |||
7668 | template <typename... Args, typename Handler> | ||
7669 | bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7670 | return multi_check<true, Args...>(L, index, std::forward<Handler>(handler), tracking); | ||
7671 | } | ||
7672 | |||
7673 | template <typename... Args, typename Handler> | ||
7674 | bool multi_check(lua_State* L, int index, Handler&& handler) { | ||
7675 | return multi_check<true, Args...>(L, index, std::forward<Handler>(handler)); | ||
7676 | } | ||
7677 | |||
7678 | template <typename... Args> | ||
7679 | bool multi_check(lua_State* L, int index) { | ||
7680 | return multi_check<true, Args...>(L, index); | ||
7681 | } | ||
7682 | |||
7683 | template <typename T> | ||
7684 | inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { | ||
7685 | #if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER | ||
7686 | return stack_detail::tagged_get(types<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(), L, index, tracking); | ||
7687 | #else | ||
7688 | return stack_detail::unchecked_get<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(L, index, tracking); | ||
7689 | #endif | ||
7690 | } | ||
7691 | |||
7692 | template <typename T> | ||
7693 | inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { | ||
7694 | record tracking{}; | ||
7695 | return get_usertype<T>(L, index, tracking); | ||
7696 | } | ||
7697 | |||
7698 | template <typename T> | ||
7699 | inline decltype(auto) get(lua_State* L, int index, record& tracking) { | ||
7700 | return stack_detail::tagged_get(types<T>(), L, index, tracking); | ||
7701 | } | ||
7702 | |||
7703 | template <typename T> | ||
7704 | inline decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) { | ||
7705 | record tracking{}; | ||
7706 | return get<T>(L, index, tracking); | ||
7707 | } | ||
7708 | |||
7709 | template <typename T> | ||
7710 | inline decltype(auto) pop(lua_State* L) { | ||
7711 | return popper<meta::unqualified_t<T>>{}.pop(L); | ||
7712 | } | ||
7713 | |||
7714 | template <bool global = false, bool raw = false, typename Key> | ||
7715 | void get_field(lua_State* L, Key&& key) { | ||
7716 | field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key)); | ||
7717 | } | ||
7718 | |||
7719 | template <bool global = false, bool raw = false, typename Key> | ||
7720 | void get_field(lua_State* L, Key&& key, int tableindex) { | ||
7721 | field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex); | ||
7722 | } | ||
7723 | |||
7724 | template <bool global = false, typename Key> | ||
7725 | void raw_get_field(lua_State* L, Key&& key) { | ||
7726 | get_field<global, true>(L, std::forward<Key>(key)); | ||
7727 | } | ||
7728 | |||
7729 | template <bool global = false, typename Key> | ||
7730 | void raw_get_field(lua_State* L, Key&& key, int tableindex) { | ||
7731 | get_field<global, true>(L, std::forward<Key>(key), tableindex); | ||
7732 | } | ||
7733 | |||
7734 | template <bool global = false, bool raw = false, typename Key> | ||
7735 | probe probe_get_field(lua_State* L, Key&& key) { | ||
7736 | return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key)); | ||
7737 | } | ||
7738 | |||
7739 | template <bool global = false, bool raw = false, typename Key> | ||
7740 | probe probe_get_field(lua_State* L, Key&& key, int tableindex) { | ||
7741 | return probe_field_getter<meta::unqualified_t<Key>, global, raw>{}.get(L, std::forward<Key>(key), tableindex); | ||
7742 | } | ||
7743 | |||
7744 | template <bool global = false, typename Key> | ||
7745 | probe probe_raw_get_field(lua_State* L, Key&& key) { | ||
7746 | return probe_get_field<global, true>(L, std::forward<Key>(key)); | ||
7747 | } | ||
7748 | |||
7749 | template <bool global = false, typename Key> | ||
7750 | probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) { | ||
7751 | return probe_get_field<global, true>(L, std::forward<Key>(key), tableindex); | ||
7752 | } | ||
7753 | |||
7754 | template <bool global = false, bool raw = false, typename Key, typename Value> | ||
7755 | void set_field(lua_State* L, Key&& key, Value&& value) { | ||
7756 | field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value)); | ||
7757 | } | ||
7758 | |||
7759 | template <bool global = false, bool raw = false, typename Key, typename Value> | ||
7760 | void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { | ||
7761 | field_setter<meta::unqualified_t<Key>, global, raw>{}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex); | ||
7762 | } | ||
7763 | |||
7764 | template <bool global = false, typename Key, typename Value> | ||
7765 | void raw_set_field(lua_State* L, Key&& key, Value&& value) { | ||
7766 | set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value)); | ||
7767 | } | ||
7768 | |||
7769 | template <bool global = false, typename Key, typename Value> | ||
7770 | void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { | ||
7771 | set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex); | ||
7772 | } | ||
7773 | |||
7774 | template <typename T, typename F> | ||
7775 | inline void modify_unique_usertype_as(const stack_reference& obj, F&& f) { | ||
7776 | typedef unique_usertype_traits<T> u_traits; | ||
7777 | void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); | ||
7778 | void* ptr_memory = detail::align_usertype_pointer(raw); | ||
7779 | void* uu_memory = detail::align_usertype_unique<T>(raw); | ||
7780 | T& uu = *static_cast<T*>(uu_memory); | ||
7781 | f(uu); | ||
7782 | *static_cast<void**>(ptr_memory) = static_cast<void*>(u_traits::get(uu)); | ||
7783 | } | ||
7784 | |||
7785 | template <typename F> | ||
7786 | inline void modify_unique_usertype(const stack_reference& obj, F&& f) { | ||
7787 | typedef meta::bind_traits<meta::unqualified_t<F>> bt; | ||
7788 | typedef typename bt::template arg_at<0> T; | ||
7789 | modify_unique_usertype_as<meta::unqualified_t<T>>(obj, std::forward<F>(f)); | ||
7790 | } | ||
7791 | } // namespace stack | ||
7792 | } // namespace sol | ||
7793 | |||
7794 | // end of sol/stack_core.hpp | ||
7795 | |||
7796 | // beginning of sol/stack_check.hpp | ||
7797 | |||
7798 | // beginning of sol/usertype_traits.hpp | ||
7799 | |||
7800 | namespace sol { | ||
7801 | |||
7802 | template <typename T> | ||
7803 | struct usertype_traits { | ||
7804 | static const std::string& name() { | ||
7805 | static const std::string& n = detail::short_demangle<T>(); | ||
7806 | return n; | ||
7807 | } | ||
7808 | static const std::string& qualified_name() { | ||
7809 | static const std::string& q_n = detail::demangle<T>(); | ||
7810 | return q_n; | ||
7811 | } | ||
7812 | static const std::string& metatable() { | ||
7813 | static const std::string m = std::string("sol.").append(detail::demangle<T>()); | ||
7814 | return m; | ||
7815 | } | ||
7816 | static const std::string& user_metatable() { | ||
7817 | static const std::string u_m = std::string("sol.").append(detail::demangle<T>()).append(".user"); | ||
7818 | return u_m; | ||
7819 | } | ||
7820 | static const std::string& user_gc_metatable() { | ||
7821 | static const std::string u_g_m = std::string("sol.").append(detail::demangle<T>()).append(".user\xE2\x99\xBB"); | ||
7822 | return u_g_m; | ||
7823 | } | ||
7824 | static const std::string& gc_table() { | ||
7825 | static const std::string g_t = std::string("sol.").append(detail::demangle<T>()).append(".\xE2\x99\xBB"); | ||
7826 | return g_t; | ||
7827 | } | ||
7828 | }; | ||
7829 | |||
7830 | } // namespace sol | ||
7831 | |||
7832 | // end of sol/usertype_traits.hpp | ||
7833 | |||
7834 | // beginning of sol/inheritance.hpp | ||
7835 | |||
7836 | namespace sol { | ||
7837 | template <typename... Args> | ||
7838 | struct base_list {}; | ||
7839 | template <typename... Args> | ||
7840 | using bases = base_list<Args...>; | ||
7841 | |||
7842 | typedef bases<> base_classes_tag; | ||
7843 | const auto base_classes = base_classes_tag(); | ||
7844 | |||
7845 | namespace detail { | ||
7846 | |||
7847 | template <typename T> | ||
7848 | struct has_derived { | ||
7849 | static bool value; | ||
7850 | }; | ||
7851 | |||
7852 | template <typename T> | ||
7853 | bool has_derived<T>::value = false; | ||
7854 | |||
7855 | inline decltype(auto) base_class_check_key() { | ||
7856 | static const auto& key = "class_check"; | ||
7857 | return key; | ||
7858 | } | ||
7859 | |||
7860 | inline decltype(auto) base_class_cast_key() { | ||
7861 | static const auto& key = "class_cast"; | ||
7862 | return key; | ||
7863 | } | ||
7864 | |||
7865 | inline decltype(auto) base_class_index_propogation_key() { | ||
7866 | static const auto& key = u8"\xF0\x9F\x8C\xB2.index"; | ||
7867 | return key; | ||
7868 | } | ||
7869 | |||
7870 | inline decltype(auto) base_class_new_index_propogation_key() { | ||
7871 | static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index"; | ||
7872 | return key; | ||
7873 | } | ||
7874 | |||
7875 | template <typename T, typename... Bases> | ||
7876 | struct inheritance { | ||
7877 | static bool type_check_bases(types<>, const std::string&) { | ||
7878 | return false; | ||
7879 | } | ||
7880 | |||
7881 | template <typename Base, typename... Args> | ||
7882 | static bool type_check_bases(types<Base, Args...>, const std::string& ti) { | ||
7883 | return ti == usertype_traits<Base>::qualified_name() || type_check_bases(types<Args...>(), ti); | ||
7884 | } | ||
7885 | |||
7886 | static bool type_check(const std::string& ti) { | ||
7887 | return ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti); | ||
7888 | } | ||
7889 | |||
7890 | static void* type_cast_bases(types<>, T*, const std::string&) { | ||
7891 | return nullptr; | ||
7892 | } | ||
7893 | |||
7894 | template <typename Base, typename... Args> | ||
7895 | static void* type_cast_bases(types<Base, Args...>, T* data, const std::string& ti) { | ||
7896 | // Make sure to convert to T first, and then dynamic cast to the proper type | ||
7897 | return ti != usertype_traits<Base>::qualified_name() ? type_cast_bases(types<Args...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data)); | ||
7898 | } | ||
7899 | |||
7900 | static void* type_cast(void* voiddata, const std::string& ti) { | ||
7901 | T* data = static_cast<T*>(voiddata); | ||
7902 | return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data); | ||
7903 | } | ||
7904 | }; | ||
7905 | |||
7906 | using inheritance_check_function = decltype(&inheritance<void>::type_check); | ||
7907 | using inheritance_cast_function = decltype(&inheritance<void>::type_cast); | ||
7908 | |||
7909 | } // namespace detail | ||
7910 | } // namespace sol | ||
7911 | |||
7912 | // end of sol/inheritance.hpp | ||
7913 | |||
7914 | #include <cmath> | ||
7915 | #ifdef SOL_CXX17_FEATURES | ||
7916 | #ifdef SOL_STD_VARIANT | ||
7917 | #endif // SOL_STD_VARIANT | ||
7918 | #endif // SOL_CXX17_FEATURES | ||
7919 | |||
7920 | namespace sol { | ||
7921 | namespace stack { | ||
7922 | namespace stack_detail { | ||
7923 | template <typename T, bool poptable = true> | ||
7924 | inline bool check_metatable(lua_State* L, int index = -2) { | ||
7925 | const auto& metakey = usertype_traits<T>::metatable(); | ||
7926 | luaL_getmetatable(L, &metakey[0]); | ||
7927 | const type expectedmetatabletype = static_cast<type>(lua_type(L, -1)); | ||
7928 | if (expectedmetatabletype != type::lua_nil) { | ||
7929 | if (lua_rawequal(L, -1, index) == 1) { | ||
7930 | lua_pop(L, 1 + static_cast<int>(poptable)); | ||
7931 | return true; | ||
7932 | } | ||
7933 | } | ||
7934 | lua_pop(L, 1); | ||
7935 | return false; | ||
7936 | } | ||
7937 | |||
7938 | template <type expected, int (*check_func)(lua_State*, int)> | ||
7939 | struct basic_check { | ||
7940 | template <typename Handler> | ||
7941 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7942 | tracking.use(1); | ||
7943 | bool success = check_func(L, index) == 1; | ||
7944 | if (!success) { | ||
7945 | // expected type, actual type | ||
7946 | handler(L, index, expected, type_of(L, index), ""); | ||
7947 | } | ||
7948 | return success; | ||
7949 | } | ||
7950 | }; | ||
7951 | } // namespace stack_detail | ||
7952 | |||
7953 | template <typename T, typename> | ||
7954 | struct userdata_checker { | ||
7955 | template <typename Handler> | ||
7956 | static bool check(lua_State*, int, type, Handler&&, record&) { | ||
7957 | return false; | ||
7958 | } | ||
7959 | }; | ||
7960 | |||
7961 | template <typename T, type expected, typename> | ||
7962 | struct checker { | ||
7963 | template <typename Handler> | ||
7964 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7965 | tracking.use(1); | ||
7966 | const type indextype = type_of(L, index); | ||
7967 | bool success = expected == indextype; | ||
7968 | if (!success) { | ||
7969 | // expected type, actual type, message | ||
7970 | handler(L, index, expected, indextype, ""); | ||
7971 | } | ||
7972 | return success; | ||
7973 | } | ||
7974 | }; | ||
7975 | |||
7976 | template <typename T> | ||
7977 | struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> { | ||
7978 | template <typename Handler> | ||
7979 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
7980 | tracking.use(1); | ||
7981 | #if SOL_LUA_VERSION >= 503 | ||
7982 | #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS | ||
7983 | int isnum = 0; | ||
7984 | lua_tointegerx(L, index, &isnum); | ||
7985 | const bool success = isnum != 0; | ||
7986 | if (!success) { | ||
7987 | // expected type, actual type | ||
7988 | handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); | ||
7989 | } | ||
7990 | #elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) | ||
7991 | // this check is precise, does not convert | ||
7992 | if (lua_isinteger(L, index) == 1) { | ||
7993 | return true; | ||
7994 | } | ||
7995 | const bool success = false; | ||
7996 | if (!success) { | ||
7997 | // expected type, actual type | ||
7998 | handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type"); | ||
7999 | } | ||
8000 | #else | ||
8001 | type t = type_of(L, index); | ||
8002 | const bool success = t == type::number; | ||
8003 | #endif // If numbers are enabled, use the imprecise check | ||
8004 | if (!success) { | ||
8005 | // expected type, actual type | ||
8006 | handler(L, index, type::number, type_of(L, index), "not a numeric type"); | ||
8007 | } | ||
8008 | return success; | ||
8009 | #else | ||
8010 | #if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS | ||
8011 | // must pre-check, because it will convert | ||
8012 | type t = type_of(L, index); | ||
8013 | if (t != type::number) { | ||
8014 | // expected type, actual type | ||
8015 | handler(L, index, type::number, t, "not a numeric type"); | ||
8016 | return false; | ||
8017 | } | ||
8018 | #endif // Do not allow strings to be numbers | ||
8019 | int isnum = 0; | ||
8020 | const lua_Number v = lua_tonumberx(L, index, &isnum); | ||
8021 | const bool success = isnum != 0 | ||
8022 | #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) | ||
8023 | && static_cast<lua_Number>(llround(v)) == v | ||
8024 | #endif // Safe numerics and number precision checking | ||
8025 | ; | ||
8026 | if (!success) { | ||
8027 | // expected type, actual type | ||
8028 | #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS | ||
8029 | handler(L, index, type::number, t, "not a numeric type"); | ||
8030 | #else | ||
8031 | handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); | ||
8032 | #endif | ||
8033 | } | ||
8034 | return success; | ||
8035 | #endif // Lua Version 5.3 versus others | ||
8036 | } | ||
8037 | }; | ||
8038 | |||
8039 | template <typename T> | ||
8040 | struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> { | ||
8041 | template <typename Handler> | ||
8042 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8043 | tracking.use(1); | ||
8044 | #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS | ||
8045 | bool success = lua_isnumber(L, index) == 1; | ||
8046 | if (!success) { | ||
8047 | // expected type, actual type | ||
8048 | handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); | ||
8049 | } | ||
8050 | return success; | ||
8051 | #else | ||
8052 | type t = type_of(L, index); | ||
8053 | bool success = t == type::number; | ||
8054 | if (!success) { | ||
8055 | // expected type, actual type | ||
8056 | handler(L, index, type::number, t, "not a numeric type"); | ||
8057 | } | ||
8058 | return success; | ||
8059 | #endif // Strings are Numbers | ||
8060 | } | ||
8061 | }; | ||
8062 | |||
8063 | template <type expected, typename C> | ||
8064 | struct checker<lua_nil_t, expected, C> { | ||
8065 | template <typename Handler> | ||
8066 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8067 | bool success = lua_isnil(L, index); | ||
8068 | if (success) { | ||
8069 | tracking.use(1); | ||
8070 | return success; | ||
8071 | } | ||
8072 | tracking.use(0); | ||
8073 | success = lua_isnone(L, index); | ||
8074 | if (!success) { | ||
8075 | // expected type, actual type | ||
8076 | handler(L, index, expected, type_of(L, index), ""); | ||
8077 | } | ||
8078 | return success; | ||
8079 | } | ||
8080 | }; | ||
8081 | |||
8082 | template <type expected, typename C> | ||
8083 | struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {}; | ||
8084 | |||
8085 | template <typename C> | ||
8086 | struct checker<this_state, type::poly, C> { | ||
8087 | template <typename Handler> | ||
8088 | static bool check(lua_State*, int, Handler&&, record& tracking) { | ||
8089 | tracking.use(0); | ||
8090 | return true; | ||
8091 | } | ||
8092 | }; | ||
8093 | |||
8094 | template <typename C> | ||
8095 | struct checker<this_main_state, type::poly, C> { | ||
8096 | template <typename Handler> | ||
8097 | static bool check(lua_State*, int, Handler&&, record& tracking) { | ||
8098 | tracking.use(0); | ||
8099 | return true; | ||
8100 | } | ||
8101 | }; | ||
8102 | |||
8103 | template <typename C> | ||
8104 | struct checker<this_environment, type::poly, C> { | ||
8105 | template <typename Handler> | ||
8106 | static bool check(lua_State*, int, Handler&&, record& tracking) { | ||
8107 | tracking.use(0); | ||
8108 | return true; | ||
8109 | } | ||
8110 | }; | ||
8111 | |||
8112 | template <typename C> | ||
8113 | struct checker<variadic_args, type::poly, C> { | ||
8114 | template <typename Handler> | ||
8115 | static bool check(lua_State*, int, Handler&&, record& tracking) { | ||
8116 | tracking.use(0); | ||
8117 | return true; | ||
8118 | } | ||
8119 | }; | ||
8120 | |||
8121 | template <typename C> | ||
8122 | struct checker<type, type::poly, C> { | ||
8123 | template <typename Handler> | ||
8124 | static bool check(lua_State*, int, Handler&&, record& tracking) { | ||
8125 | tracking.use(0); | ||
8126 | return true; | ||
8127 | } | ||
8128 | }; | ||
8129 | |||
8130 | template <typename T, typename C> | ||
8131 | struct checker<T, type::poly, C> { | ||
8132 | template <typename Handler> | ||
8133 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8134 | tracking.use(1); | ||
8135 | bool success = is_lua_reference<T>::value || !lua_isnone(L, index); | ||
8136 | if (!success) { | ||
8137 | // expected type, actual type | ||
8138 | handler(L, index, type::poly, type_of(L, index), ""); | ||
8139 | } | ||
8140 | return success; | ||
8141 | } | ||
8142 | }; | ||
8143 | |||
8144 | template <typename T, typename C> | ||
8145 | struct checker<T, type::lightuserdata, C> { | ||
8146 | template <typename Handler> | ||
8147 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8148 | tracking.use(1); | ||
8149 | type t = type_of(L, index); | ||
8150 | bool success = t == type::userdata || t == type::lightuserdata; | ||
8151 | if (!success) { | ||
8152 | // expected type, actual type | ||
8153 | handler(L, index, type::lightuserdata, t, ""); | ||
8154 | } | ||
8155 | return success; | ||
8156 | } | ||
8157 | }; | ||
8158 | |||
8159 | template <typename C> | ||
8160 | struct checker<userdata_value, type::userdata, C> { | ||
8161 | template <typename Handler> | ||
8162 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8163 | tracking.use(1); | ||
8164 | type t = type_of(L, index); | ||
8165 | bool success = t == type::userdata; | ||
8166 | if (!success) { | ||
8167 | // expected type, actual type | ||
8168 | handler(L, index, type::userdata, t, ""); | ||
8169 | } | ||
8170 | return success; | ||
8171 | } | ||
8172 | }; | ||
8173 | |||
8174 | template <typename B, typename C> | ||
8175 | struct checker<basic_userdata<B>, type::userdata, C> { | ||
8176 | template <typename Handler> | ||
8177 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8178 | return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking); | ||
8179 | } | ||
8180 | }; | ||
8181 | |||
8182 | template <typename T, typename C> | ||
8183 | struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {}; | ||
8184 | |||
8185 | template <typename T, typename C> | ||
8186 | struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {}; | ||
8187 | |||
8188 | template <typename C> | ||
8189 | struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {}; | ||
8190 | template <typename C> | ||
8191 | struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {}; | ||
8192 | template <typename C> | ||
8193 | struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {}; | ||
8194 | |||
8195 | template <typename T, typename C> | ||
8196 | struct checker<T, type::function, C> { | ||
8197 | template <typename Handler> | ||
8198 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8199 | tracking.use(1); | ||
8200 | type t = type_of(L, index); | ||
8201 | if (t == type::lua_nil || t == type::none || t == type::function) { | ||
8202 | // allow for lua_nil to be returned | ||
8203 | return true; | ||
8204 | } | ||
8205 | if (t != type::userdata && t != type::table) { | ||
8206 | handler(L, index, type::function, t, "must be a function or table or a userdata"); | ||
8207 | return false; | ||
8208 | } | ||
8209 | // Do advanced check for call-style userdata? | ||
8210 | static const auto& callkey = to_string(meta_function::call); | ||
8211 | if (lua_getmetatable(L, index) == 0) { | ||
8212 | // No metatable, no __call key possible | ||
8213 | handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); | ||
8214 | return false; | ||
8215 | } | ||
8216 | if (lua_isnoneornil(L, -1)) { | ||
8217 | lua_pop(L, 1); | ||
8218 | handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); | ||
8219 | return false; | ||
8220 | } | ||
8221 | lua_getfield(L, -1, &callkey[0]); | ||
8222 | if (lua_isnoneornil(L, -1)) { | ||
8223 | lua_pop(L, 2); | ||
8224 | handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); | ||
8225 | return false; | ||
8226 | } | ||
8227 | // has call, is definitely a function | ||
8228 | lua_pop(L, 2); | ||
8229 | return true; | ||
8230 | } | ||
8231 | }; | ||
8232 | |||
8233 | template <typename T, typename C> | ||
8234 | struct checker<T, type::table, C> { | ||
8235 | template <typename Handler> | ||
8236 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8237 | tracking.use(1); | ||
8238 | type t = type_of(L, index); | ||
8239 | if (t == type::table) { | ||
8240 | return true; | ||
8241 | } | ||
8242 | if (t != type::userdata) { | ||
8243 | handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one"); | ||
8244 | return false; | ||
8245 | } | ||
8246 | return true; | ||
8247 | } | ||
8248 | }; | ||
8249 | |||
8250 | template <type expected, typename C> | ||
8251 | struct checker<metatable_t, expected, C> { | ||
8252 | template <typename Handler> | ||
8253 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8254 | tracking.use(1); | ||
8255 | if (lua_getmetatable(L, index) == 0) { | ||
8256 | return true; | ||
8257 | } | ||
8258 | type t = type_of(L, -1); | ||
8259 | if (t == type::table || t == type::none || t == type::lua_nil) { | ||
8260 | lua_pop(L, 1); | ||
8261 | return true; | ||
8262 | } | ||
8263 | if (t != type::userdata) { | ||
8264 | lua_pop(L, 1); | ||
8265 | handler(L, index, expected, t, "value does not have a valid metatable"); | ||
8266 | return false; | ||
8267 | } | ||
8268 | return true; | ||
8269 | } | ||
8270 | }; | ||
8271 | |||
8272 | template <typename C> | ||
8273 | struct checker<env_t, type::poly, C> { | ||
8274 | template <typename Handler> | ||
8275 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8276 | tracking.use(1); | ||
8277 | type t = type_of(L, index); | ||
8278 | if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { | ||
8279 | return true; | ||
8280 | } | ||
8281 | handler(L, index, type::table, t, "value cannot not have a valid environment"); | ||
8282 | return true; | ||
8283 | } | ||
8284 | }; | ||
8285 | |||
8286 | template <typename E, typename C> | ||
8287 | struct checker<basic_environment<E>, type::poly, C> { | ||
8288 | template <typename Handler> | ||
8289 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8290 | tracking.use(1); | ||
8291 | if (lua_getmetatable(L, index) == 0) { | ||
8292 | return true; | ||
8293 | } | ||
8294 | type t = type_of(L, -1); | ||
8295 | if (t == type::table || t == type::none || t == type::lua_nil) { | ||
8296 | lua_pop(L, 1); | ||
8297 | return true; | ||
8298 | } | ||
8299 | if (t != type::userdata) { | ||
8300 | lua_pop(L, 1); | ||
8301 | handler(L, index, type::table, t, "value does not have a valid metatable"); | ||
8302 | return false; | ||
8303 | } | ||
8304 | return true; | ||
8305 | } | ||
8306 | }; | ||
8307 | |||
8308 | template <typename T, typename C> | ||
8309 | struct checker<detail::as_value_tag<T>, type::userdata, C> { | ||
8310 | template <typename Handler> | ||
8311 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8312 | const type indextype = type_of(L, index); | ||
8313 | return check(types<T>(), L, index, indextype, handler, tracking); | ||
8314 | } | ||
8315 | |||
8316 | template <typename U, typename Handler> | ||
8317 | static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { | ||
8318 | #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP | ||
8319 | userdata_checker<extensible<T>> uc; | ||
8320 | (void)uc; | ||
8321 | if (uc.check(L, index, indextype, handler, tracking)) { | ||
8322 | return true; | ||
8323 | } | ||
8324 | #endif // interop extensibility | ||
8325 | tracking.use(1); | ||
8326 | if (indextype != type::userdata) { | ||
8327 | handler(L, index, type::userdata, indextype, "value is not a valid userdata"); | ||
8328 | return false; | ||
8329 | } | ||
8330 | if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value) | ||
8331 | return true; | ||
8332 | if (lua_getmetatable(L, index) == 0) { | ||
8333 | return true; | ||
8334 | } | ||
8335 | int metatableindex = lua_gettop(L); | ||
8336 | if (stack_detail::check_metatable<U>(L, metatableindex)) | ||
8337 | return true; | ||
8338 | if (stack_detail::check_metatable<U*>(L, metatableindex)) | ||
8339 | return true; | ||
8340 | if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex)) | ||
8341 | return true; | ||
8342 | if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex)) | ||
8343 | return true; | ||
8344 | bool success = false; | ||
8345 | if (detail::has_derived<T>::value) { | ||
8346 | auto pn = stack::pop_n(L, 1); | ||
8347 | lua_pushstring(L, &detail::base_class_check_key()[0]); | ||
8348 | lua_rawget(L, metatableindex); | ||
8349 | if (type_of(L, -1) != type::lua_nil) { | ||
8350 | void* basecastdata = lua_touserdata(L, -1); | ||
8351 | detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata); | ||
8352 | success = ic(usertype_traits<T>::qualified_name()); | ||
8353 | } | ||
8354 | } | ||
8355 | if (!success) { | ||
8356 | lua_pop(L, 1); | ||
8357 | handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); | ||
8358 | return false; | ||
8359 | } | ||
8360 | lua_pop(L, 1); | ||
8361 | return true; | ||
8362 | } | ||
8363 | }; | ||
8364 | |||
8365 | template <typename T, typename C> | ||
8366 | struct checker<detail::as_pointer_tag<T>, type::userdata, C> { | ||
8367 | template <typename Handler> | ||
8368 | static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { | ||
8369 | if (indextype == type::lua_nil) { | ||
8370 | tracking.use(1); | ||
8371 | return true; | ||
8372 | } | ||
8373 | return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking); | ||
8374 | } | ||
8375 | |||
8376 | template <typename Handler> | ||
8377 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8378 | const type indextype = type_of(L, index); | ||
8379 | return check(L, index, handler, indextype, tracking); | ||
8380 | } | ||
8381 | }; | ||
8382 | |||
8383 | template <typename T, typename C> | ||
8384 | struct checker<T, type::userdata, C> { | ||
8385 | template <typename Handler> | ||
8386 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8387 | return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); | ||
8388 | } | ||
8389 | }; | ||
8390 | |||
8391 | template <typename T, typename C> | ||
8392 | struct checker<T*, type::userdata, C> { | ||
8393 | template <typename Handler> | ||
8394 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8395 | return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking); | ||
8396 | } | ||
8397 | }; | ||
8398 | |||
8399 | template <typename X> | ||
8400 | struct checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> { | ||
8401 | typedef typename unique_usertype_traits<X>::type T; | ||
8402 | template <typename Handler> | ||
8403 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8404 | const type indextype = type_of(L, index); | ||
8405 | tracking.use(1); | ||
8406 | if (indextype != type::userdata) { | ||
8407 | handler(L, index, type::userdata, indextype, "value is not a userdata"); | ||
8408 | return false; | ||
8409 | } | ||
8410 | if (lua_getmetatable(L, index) == 0) { | ||
8411 | return true; | ||
8412 | } | ||
8413 | int metatableindex = lua_gettop(L); | ||
8414 | if (stack_detail::check_metatable<detail::unique_usertype<T>>(L, metatableindex)) { | ||
8415 | void* memory = lua_touserdata(L, index); | ||
8416 | memory = detail::align_usertype_unique_destructor(memory); | ||
8417 | detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); | ||
8418 | bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx; | ||
8419 | if (!success) { | ||
8420 | handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); | ||
8421 | } | ||
8422 | return success; | ||
8423 | } | ||
8424 | lua_pop(L, 1); | ||
8425 | handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); | ||
8426 | return false; | ||
8427 | } | ||
8428 | }; | ||
8429 | |||
8430 | template <typename T, typename C> | ||
8431 | struct checker<std::reference_wrapper<T>, type::userdata, C> { | ||
8432 | template <typename Handler> | ||
8433 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8434 | return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking); | ||
8435 | } | ||
8436 | }; | ||
8437 | |||
8438 | template <typename... Args, typename C> | ||
8439 | struct checker<std::tuple<Args...>, type::poly, C> { | ||
8440 | template <typename Handler> | ||
8441 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8442 | return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking); | ||
8443 | } | ||
8444 | }; | ||
8445 | |||
8446 | template <typename A, typename B, typename C> | ||
8447 | struct checker<std::pair<A, B>, type::poly, C> { | ||
8448 | template <typename Handler> | ||
8449 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8450 | return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking); | ||
8451 | } | ||
8452 | }; | ||
8453 | |||
8454 | template <typename T, typename C> | ||
8455 | struct checker<optional<T>, type::poly, C> { | ||
8456 | template <typename Handler> | ||
8457 | static bool check(lua_State* L, int index, Handler&&, record& tracking) { | ||
8458 | type t = type_of(L, index); | ||
8459 | if (t == type::none) { | ||
8460 | tracking.use(0); | ||
8461 | return true; | ||
8462 | } | ||
8463 | if (t == type::lua_nil) { | ||
8464 | tracking.use(1); | ||
8465 | return true; | ||
8466 | } | ||
8467 | return stack::check<T>(L, index, no_panic, tracking); | ||
8468 | } | ||
8469 | }; | ||
8470 | |||
8471 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
8472 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
8473 | template <typename... Tn, typename C> | ||
8474 | struct checker<std::variant<Tn...>, type::poly, C> { | ||
8475 | typedef std::variant<Tn...> V; | ||
8476 | typedef std::variant_size<V> V_size; | ||
8477 | typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; | ||
8478 | |||
8479 | template <typename Handler> | ||
8480 | static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8481 | if (V_is_empty::value && lua_isnone(L, index)) { | ||
8482 | return true; | ||
8483 | } | ||
8484 | tracking.use(1); | ||
8485 | handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant"); | ||
8486 | return false; | ||
8487 | } | ||
8488 | |||
8489 | template <std::size_t I, typename Handler> | ||
8490 | static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8491 | typedef std::variant_alternative_t<I - 1, V> T; | ||
8492 | if (stack::check<T>(L, index, no_panic, tracking)) { | ||
8493 | return true; | ||
8494 | } | ||
8495 | return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); | ||
8496 | } | ||
8497 | |||
8498 | template <typename Handler> | ||
8499 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
8500 | return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking); | ||
8501 | } | ||
8502 | }; | ||
8503 | #endif // SOL_STD_VARIANT | ||
8504 | #endif // SOL_CXX17_FEATURES | ||
8505 | } | ||
8506 | } // namespace sol::stack | ||
8507 | |||
8508 | // end of sol/stack_check.hpp | ||
8509 | |||
8510 | // beginning of sol/stack_get.hpp | ||
8511 | |||
8512 | // beginning of sol/overload.hpp | ||
8513 | |||
8514 | namespace sol { | ||
8515 | template <typename... Functions> | ||
8516 | struct overload_set { | ||
8517 | std::tuple<Functions...> functions; | ||
8518 | template <typename Arg, typename... Args, meta::disable<std::is_same<overload_set, meta::unqualified_t<Arg>>> = meta::enabler> | ||
8519 | overload_set(Arg&& arg, Args&&... args) | ||
8520 | : functions(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
8521 | } | ||
8522 | overload_set(const overload_set&) = default; | ||
8523 | overload_set(overload_set&&) = default; | ||
8524 | overload_set& operator=(const overload_set&) = default; | ||
8525 | overload_set& operator=(overload_set&&) = default; | ||
8526 | }; | ||
8527 | |||
8528 | template <typename... Args> | ||
8529 | decltype(auto) overload(Args&&... args) { | ||
8530 | return overload_set<std::decay_t<Args>...>(std::forward<Args>(args)...); | ||
8531 | } | ||
8532 | } // namespace sol | ||
8533 | |||
8534 | // end of sol/overload.hpp | ||
8535 | |||
8536 | // beginning of sol/unicode.hpp | ||
8537 | |||
8538 | namespace sol { | ||
8539 | // Everything here was lifted pretty much straight out of | ||
8540 | // ogonek, because fuck figuring it out= | ||
8541 | namespace unicode { | ||
8542 | enum class error_code { | ||
8543 | ok = 0, | ||
8544 | invalid_code_point, | ||
8545 | invalid_code_unit, | ||
8546 | invalid_leading_surrogate, | ||
8547 | invalid_trailing_surrogate, | ||
8548 | sequence_too_short, | ||
8549 | overlong_sequence, | ||
8550 | }; | ||
8551 | |||
8552 | inline const string_view& to_string(error_code ec) { | ||
8553 | static const string_view arr[4] = { | ||
8554 | "ok", | ||
8555 | "invalid code points", | ||
8556 | "invalid code unit", | ||
8557 | "overlong sequence" | ||
8558 | }; | ||
8559 | return arr[static_cast<std::size_t>(ec)]; | ||
8560 | } | ||
8561 | |||
8562 | template <typename It> | ||
8563 | struct decoded_result { | ||
8564 | error_code error; | ||
8565 | char32_t codepoint; | ||
8566 | It next; | ||
8567 | }; | ||
8568 | |||
8569 | template <typename C> | ||
8570 | struct encoded_result { | ||
8571 | error_code error; | ||
8572 | std::size_t code_units_size; | ||
8573 | std::array<C, 4> code_units; | ||
8574 | }; | ||
8575 | |||
8576 | struct unicode_detail { | ||
8577 | // codepoint related | ||
8578 | static constexpr char32_t last_code_point = 0x10FFFF; | ||
8579 | |||
8580 | static constexpr char32_t first_lead_surrogate = 0xD800; | ||
8581 | static constexpr char32_t last_lead_surrogate = 0xDBFF; | ||
8582 | |||
8583 | static constexpr char32_t first_trail_surrogate = 0xDC00; | ||
8584 | static constexpr char32_t last_trail_surrogate = 0xDFFF; | ||
8585 | |||
8586 | static constexpr char32_t first_surrogate = first_lead_surrogate; | ||
8587 | static constexpr char32_t last_surrogate = last_trail_surrogate; | ||
8588 | |||
8589 | static constexpr bool is_lead_surrogate(char32_t u) { | ||
8590 | return u >= first_lead_surrogate && u <= last_lead_surrogate; | ||
8591 | } | ||
8592 | static constexpr bool is_trail_surrogate(char32_t u) { | ||
8593 | return u >= first_trail_surrogate && u <= last_trail_surrogate; | ||
8594 | } | ||
8595 | static constexpr bool is_surrogate(char32_t u) { | ||
8596 | return u >= first_surrogate && u <= last_surrogate; | ||
8597 | } | ||
8598 | |||
8599 | // utf8 related | ||
8600 | static constexpr auto last_1byte_value = 0x7Fu; | ||
8601 | static constexpr auto last_2byte_value = 0x7FFu; | ||
8602 | static constexpr auto last_3byte_value = 0xFFFFu; | ||
8603 | |||
8604 | static constexpr auto start_2byte_mask = 0x80u; | ||
8605 | static constexpr auto start_3byte_mask = 0xE0u; | ||
8606 | static constexpr auto start_4byte_mask = 0xF0u; | ||
8607 | |||
8608 | static constexpr auto continuation_mask = 0xC0u; | ||
8609 | static constexpr auto continuation_signature = 0x80u; | ||
8610 | |||
8611 | static constexpr int sequence_length(unsigned char b) { | ||
8612 | return (b & start_2byte_mask) == 0 ? 1 | ||
8613 | : (b & start_3byte_mask) != start_3byte_mask ? 2 | ||
8614 | : (b & start_4byte_mask) != start_4byte_mask ? 3 | ||
8615 | : 4; | ||
8616 | } | ||
8617 | |||
8618 | static constexpr char32_t decode(unsigned char b0, unsigned char b1) { | ||
8619 | return ((b0 & 0x1F) << 6) | (b1 & 0x3F); | ||
8620 | } | ||
8621 | static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) { | ||
8622 | return ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F); | ||
8623 | } | ||
8624 | static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3) { | ||
8625 | return ((b0 & 0x07) << 18) | ((b1 & 0x3F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F); | ||
8626 | } | ||
8627 | |||
8628 | // utf16 related | ||
8629 | static constexpr char32_t last_bmp_value = 0xFFFF; | ||
8630 | static constexpr char32_t normalizing_value = 0x10000; | ||
8631 | static constexpr int lead_surrogate_bitmask = 0xFFC00; | ||
8632 | static constexpr int trail_surrogate_bitmask = 0x3FF; | ||
8633 | static constexpr int lead_shifted_bits = 10; | ||
8634 | static constexpr char32_t replacement = 0xFFFD; | ||
8635 | |||
8636 | static char32_t combine_surrogates(char16_t lead, char16_t trail) { | ||
8637 | auto hi = lead - first_lead_surrogate; | ||
8638 | auto lo = trail - first_trail_surrogate; | ||
8639 | return normalizing_value + ((hi << lead_shifted_bits) | lo); | ||
8640 | } | ||
8641 | }; | ||
8642 | |||
8643 | inline encoded_result<char> code_point_to_utf8(char32_t codepoint) { | ||
8644 | encoded_result<char> er; | ||
8645 | er.error = error_code::ok; | ||
8646 | if (codepoint <= unicode_detail::last_1byte_value) { | ||
8647 | er.code_units_size = 1; | ||
8648 | er.code_units = std::array<char, 4>{ { static_cast<char>(codepoint) } }; | ||
8649 | } | ||
8650 | else if (codepoint <= unicode_detail::last_2byte_value) { | ||
8651 | er.code_units_size = 2; | ||
8652 | er.code_units = std::array<char, 4>{{ | ||
8653 | static_cast<char>(0xC0 | ((codepoint & 0x7C0) >> 6)), | ||
8654 | static_cast<char>(0x80 | (codepoint & 0x3F)), | ||
8655 | }}; | ||
8656 | } | ||
8657 | else if (codepoint <= unicode_detail::last_3byte_value) { | ||
8658 | er.code_units_size = 3; | ||
8659 | er.code_units = std::array<char, 4>{{ | ||
8660 | static_cast<char>(0xE0 | ((codepoint & 0xF000) >> 12)), | ||
8661 | static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), | ||
8662 | static_cast<char>(0x80 | (codepoint & 0x3F)), | ||
8663 | }}; | ||
8664 | } | ||
8665 | else { | ||
8666 | er.code_units_size = 4; | ||
8667 | er.code_units = std::array<char, 4>{ { | ||
8668 | static_cast<char>(0xF0 | ((codepoint & 0x1C0000) >> 18)), | ||
8669 | static_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)), | ||
8670 | static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)), | ||
8671 | static_cast<char>(0x80 | (codepoint & 0x3F)), | ||
8672 | } }; | ||
8673 | } | ||
8674 | return er; | ||
8675 | } | ||
8676 | |||
8677 | inline encoded_result<char16_t> code_point_to_utf16(char32_t codepoint) { | ||
8678 | encoded_result<char16_t> er; | ||
8679 | |||
8680 | if (codepoint <= unicode_detail::last_bmp_value) { | ||
8681 | er.code_units_size = 1; | ||
8682 | er.code_units = std::array<char16_t, 4>{ { static_cast<char16_t>(codepoint) } }; | ||
8683 | er.error = error_code::ok; | ||
8684 | } | ||
8685 | else { | ||
8686 | auto normal = codepoint - unicode_detail::normalizing_value; | ||
8687 | auto lead = unicode_detail::first_lead_surrogate + ((normal & unicode_detail::lead_surrogate_bitmask) >> unicode_detail::lead_shifted_bits); | ||
8688 | auto trail = unicode_detail::first_trail_surrogate + (normal & unicode_detail::trail_surrogate_bitmask); | ||
8689 | er.code_units = std::array<char16_t, 4>{ { | ||
8690 | static_cast<char16_t>(lead), | ||
8691 | static_cast<char16_t>(trail) | ||
8692 | } }; | ||
8693 | er.code_units_size = 2; | ||
8694 | er.error = error_code::ok; | ||
8695 | } | ||
8696 | return er; | ||
8697 | } | ||
8698 | |||
8699 | inline encoded_result<char32_t> code_point_to_utf32(char32_t codepoint) { | ||
8700 | encoded_result<char32_t> er; | ||
8701 | er.code_units_size = 1; | ||
8702 | er.code_units[0] = codepoint; | ||
8703 | er.error = error_code::ok; | ||
8704 | return er; | ||
8705 | } | ||
8706 | |||
8707 | template <typename It> | ||
8708 | inline decoded_result<It> utf8_to_code_point(It it, It last) { | ||
8709 | decoded_result<It> dr; | ||
8710 | if (it == last) { | ||
8711 | dr.next = it; | ||
8712 | dr.error = error_code::sequence_too_short; | ||
8713 | return dr; | ||
8714 | } | ||
8715 | |||
8716 | unsigned char b0 = *it; | ||
8717 | std::size_t length = unicode_detail::sequence_length(b0); | ||
8718 | |||
8719 | if (length == 1) { | ||
8720 | dr.codepoint = static_cast<char32_t>(b0); | ||
8721 | dr.error = error_code::ok; | ||
8722 | ++it; | ||
8723 | dr.next = it; | ||
8724 | return dr; | ||
8725 | } | ||
8726 | |||
8727 | auto is_invalid = [](unsigned char b) { return b == 0xC0 || b == 0xC1 || b > 0xF4; }; | ||
8728 | auto is_continuation = [](unsigned char b) { | ||
8729 | return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature; | ||
8730 | }; | ||
8731 | |||
8732 | if (is_invalid(b0) || is_continuation(b0)) { | ||
8733 | dr.error = error_code::invalid_code_unit; | ||
8734 | dr.next = it; | ||
8735 | return dr; | ||
8736 | } | ||
8737 | |||
8738 | ++it; | ||
8739 | std::array<unsigned char, 4> b; | ||
8740 | b[0] = b0; | ||
8741 | for (std::size_t i = 1; i < length; ++i) { | ||
8742 | b[i] = *it; | ||
8743 | if (!is_continuation(b[i])) { | ||
8744 | dr.error = error_code::invalid_code_unit; | ||
8745 | dr.next = it; | ||
8746 | return dr; | ||
8747 | } | ||
8748 | ++it; | ||
8749 | } | ||
8750 | |||
8751 | char32_t decoded; | ||
8752 | switch (length) { | ||
8753 | case 2: | ||
8754 | decoded = unicode_detail::decode(b[0], b[1]); | ||
8755 | break; | ||
8756 | case 3: | ||
8757 | decoded = unicode_detail::decode(b[0], b[1], b[2]); | ||
8758 | break; | ||
8759 | default: | ||
8760 | decoded = unicode_detail::decode(b[0], b[1], b[2], b[3]); | ||
8761 | break; | ||
8762 | } | ||
8763 | |||
8764 | auto is_overlong = [](char32_t u, std::size_t bytes) { | ||
8765 | return u <= unicode_detail::last_1byte_value | ||
8766 | || (u <= unicode_detail::last_2byte_value && bytes > 2) | ||
8767 | || (u <= unicode_detail::last_3byte_value && bytes > 3); | ||
8768 | }; | ||
8769 | if (is_overlong(decoded, length)) { | ||
8770 | dr.error = error_code::overlong_sequence; | ||
8771 | return dr; | ||
8772 | } | ||
8773 | if (unicode_detail::is_surrogate(decoded) || decoded > unicode_detail::last_code_point) { | ||
8774 | dr.error = error_code::invalid_code_point; | ||
8775 | return dr; | ||
8776 | } | ||
8777 | |||
8778 | // then everything is fine | ||
8779 | dr.codepoint = decoded; | ||
8780 | dr.error = error_code::ok; | ||
8781 | dr.next = it; | ||
8782 | return dr; | ||
8783 | } | ||
8784 | |||
8785 | template <typename It> | ||
8786 | inline decoded_result<It> utf16_to_code_point(It it, It last) { | ||
8787 | decoded_result<It> dr; | ||
8788 | if (it == last) { | ||
8789 | dr.next = it; | ||
8790 | dr.error = error_code::sequence_too_short; | ||
8791 | return dr; | ||
8792 | } | ||
8793 | |||
8794 | char16_t lead = static_cast<char16_t>(*it); | ||
8795 | |||
8796 | if (!unicode_detail::is_surrogate(lead)) { | ||
8797 | ++it; | ||
8798 | dr.codepoint = static_cast<char32_t>(lead); | ||
8799 | dr.next = it; | ||
8800 | dr.error = error_code::ok; | ||
8801 | return dr; | ||
8802 | } | ||
8803 | if (!unicode_detail::is_lead_surrogate(lead)) { | ||
8804 | dr.error = error_code::invalid_leading_surrogate; | ||
8805 | dr.next = it; | ||
8806 | return dr; | ||
8807 | } | ||
8808 | |||
8809 | ++it; | ||
8810 | auto trail = *it; | ||
8811 | if (!unicode_detail::is_trail_surrogate(trail)) { | ||
8812 | dr.error = error_code::invalid_trailing_surrogate; | ||
8813 | dr.next = it; | ||
8814 | return dr; | ||
8815 | } | ||
8816 | |||
8817 | dr.codepoint = unicode_detail::combine_surrogates(lead, trail); | ||
8818 | dr.next = ++it; | ||
8819 | dr.error = error_code::ok; | ||
8820 | return dr; | ||
8821 | } | ||
8822 | |||
8823 | template <typename It> | ||
8824 | inline decoded_result<It> utf32_to_code_point(It it, It last) { | ||
8825 | decoded_result<It> dr; | ||
8826 | if (it == last) { | ||
8827 | dr.next = it; | ||
8828 | dr.error = error_code::sequence_too_short; | ||
8829 | return dr; | ||
8830 | } | ||
8831 | dr.codepoint = static_cast<char32_t>(*it); | ||
8832 | dr.next = ++it; | ||
8833 | dr.error = error_code::ok; | ||
8834 | return dr; | ||
8835 | } | ||
8836 | } | ||
8837 | } | ||
8838 | // end of sol/unicode.hpp | ||
8839 | |||
8840 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
8841 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
8842 | #endif // Apple clang screwed up | ||
8843 | #endif // C++17 | ||
8844 | |||
8845 | namespace sol { | ||
8846 | namespace stack { | ||
8847 | |||
8848 | template <typename U> | ||
8849 | struct userdata_getter<U> { | ||
8850 | typedef stack_detail::strip_extensible_t<U> T; | ||
8851 | |||
8852 | static std::pair<bool, T*> get(lua_State*, int, void*, record&) { | ||
8853 | return { false, nullptr }; | ||
8854 | } | ||
8855 | }; | ||
8856 | |||
8857 | template <typename T, typename> | ||
8858 | struct getter { | ||
8859 | static T& get(lua_State* L, int index, record& tracking) { | ||
8860 | return getter<detail::as_value_tag<T>>{}.get(L, index, tracking); | ||
8861 | } | ||
8862 | }; | ||
8863 | |||
8864 | template <typename T> | ||
8865 | struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> { | ||
8866 | static T get(lua_State* L, int index, record& tracking) { | ||
8867 | tracking.use(1); | ||
8868 | return static_cast<T>(lua_tonumber(L, index)); | ||
8869 | } | ||
8870 | }; | ||
8871 | |||
8872 | template <typename T> | ||
8873 | struct getter<T, std::enable_if_t<std::is_integral<T>::value>> { | ||
8874 | static T get(lua_State* L, int index, record& tracking) { | ||
8875 | tracking.use(1); | ||
8876 | #if SOL_LUA_VERSION >= 503 | ||
8877 | if (lua_isinteger(L, index) != 0) { | ||
8878 | return static_cast<T>(lua_tointeger(L, index)); | ||
8879 | } | ||
8880 | #endif | ||
8881 | return static_cast<T>(llround(lua_tonumber(L, index))); | ||
8882 | } | ||
8883 | }; | ||
8884 | |||
8885 | template <typename T> | ||
8886 | struct getter<T, std::enable_if_t<std::is_enum<T>::value>> { | ||
8887 | static T get(lua_State* L, int index, record& tracking) { | ||
8888 | tracking.use(1); | ||
8889 | return static_cast<T>(lua_tointegerx(L, index, nullptr)); | ||
8890 | } | ||
8891 | }; | ||
8892 | |||
8893 | template <typename T> | ||
8894 | struct getter<as_table_t<T>> { | ||
8895 | typedef meta::unqualified_t<T> Tu; | ||
8896 | |||
8897 | template <typename V> | ||
8898 | static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) { | ||
8899 | arr.push_back(stack::get<V>(L, -lua_size<V>::value)); | ||
8900 | } | ||
8901 | |||
8902 | template <typename V> | ||
8903 | static void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& arr, std::size_t idx) { | ||
8904 | insert_at_end(meta::has_insert<Tu>(), t, L, arr, idx); | ||
8905 | } | ||
8906 | |||
8907 | template <typename V> | ||
8908 | static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) { | ||
8909 | using std::end; | ||
8910 | arr.insert(end(arr), stack::get<V>(L, -lua_size<V>::value)); | ||
8911 | } | ||
8912 | |||
8913 | template <typename V> | ||
8914 | static void insert_at_end(std::false_type, types<V>, lua_State* L, T& arr, std::size_t idx) { | ||
8915 | arr[idx] = stack::get<V>(L, -lua_size<V>::value); | ||
8916 | } | ||
8917 | |||
8918 | static T get(lua_State* L, int relindex, record& tracking) { | ||
8919 | return get(meta::has_key_value_pair<meta::unqualified_t<T>>(), L, relindex, tracking); | ||
8920 | } | ||
8921 | |||
8922 | static T get(std::false_type, lua_State* L, int relindex, record& tracking) { | ||
8923 | typedef typename T::value_type V; | ||
8924 | return get(types<V>(), L, relindex, tracking); | ||
8925 | } | ||
8926 | |||
8927 | template <typename V> | ||
8928 | static T get(types<V> t, lua_State* L, int relindex, record& tracking) { | ||
8929 | tracking.use(1); | ||
8930 | |||
8931 | int index = lua_absindex(L, relindex); | ||
8932 | T arr; | ||
8933 | std::size_t idx = 0; | ||
8934 | #if SOL_LUA_VERSION >= 503 | ||
8935 | // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 | ||
8936 | for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { | ||
8937 | if (idx >= arr.max_size()) { | ||
8938 | return arr; | ||
8939 | } | ||
8940 | bool isnil = false; | ||
8941 | for (int vi = 0; vi < lua_size<V>::value; ++vi) { | ||
8942 | type vt = static_cast<type>(lua_geti(L, index, i + vi)); | ||
8943 | isnil = vt == type::lua_nil; | ||
8944 | if (isnil) { | ||
8945 | if (i == 0) { | ||
8946 | break; | ||
8947 | } | ||
8948 | lua_pop(L, (vi + 1)); | ||
8949 | return arr; | ||
8950 | } | ||
8951 | } | ||
8952 | if (isnil) | ||
8953 | continue; | ||
8954 | push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx); | ||
8955 | ++idx; | ||
8956 | } | ||
8957 | #else | ||
8958 | // Zzzz slower but necessary thanks to the lower version API and missing functions qq | ||
8959 | for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { | ||
8960 | if (idx >= arr.max_size()) { | ||
8961 | return arr; | ||
8962 | } | ||
8963 | bool isnil = false; | ||
8964 | for (int vi = 0; vi < lua_size<V>::value; ++vi) { | ||
8965 | lua_pushinteger(L, i); | ||
8966 | lua_gettable(L, index); | ||
8967 | type vt = type_of(L, -1); | ||
8968 | isnil = vt == type::lua_nil; | ||
8969 | if (isnil) { | ||
8970 | if (i == 0) { | ||
8971 | break; | ||
8972 | } | ||
8973 | lua_pop(L, (vi + 1)); | ||
8974 | return arr; | ||
8975 | } | ||
8976 | } | ||
8977 | if (isnil) | ||
8978 | continue; | ||
8979 | push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx); | ||
8980 | ++idx; | ||
8981 | } | ||
8982 | #endif | ||
8983 | return arr; | ||
8984 | } | ||
8985 | |||
8986 | static T get(std::true_type, lua_State* L, int index, record& tracking) { | ||
8987 | typedef typename T::value_type P; | ||
8988 | typedef typename P::first_type K; | ||
8989 | typedef typename P::second_type V; | ||
8990 | return get(types<K, V>(), L, index, tracking); | ||
8991 | } | ||
8992 | |||
8993 | template <typename K, typename V> | ||
8994 | static T get(types<K, V>, lua_State* L, int relindex, record& tracking) { | ||
8995 | tracking.use(1); | ||
8996 | |||
8997 | T associative; | ||
8998 | int index = lua_absindex(L, relindex); | ||
8999 | lua_pushnil(L); | ||
9000 | while (lua_next(L, index) != 0) { | ||
9001 | decltype(auto) key = stack::check_get<K>(L, -2); | ||
9002 | if (!key) { | ||
9003 | lua_pop(L, 1); | ||
9004 | continue; | ||
9005 | } | ||
9006 | associative.emplace(std::forward<decltype(*key)>(*key), stack::get<V>(L, -1)); | ||
9007 | lua_pop(L, 1); | ||
9008 | } | ||
9009 | return associative; | ||
9010 | } | ||
9011 | }; | ||
9012 | |||
9013 | template <typename T, typename Al> | ||
9014 | struct getter<as_table_t<std::forward_list<T, Al>>> { | ||
9015 | typedef std::forward_list<T, Al> C; | ||
9016 | |||
9017 | static C get(lua_State* L, int relindex, record& tracking) { | ||
9018 | return get(meta::has_key_value_pair<C>(), L, relindex, tracking); | ||
9019 | } | ||
9020 | |||
9021 | static C get(std::true_type, lua_State* L, int index, record& tracking) { | ||
9022 | typedef typename T::value_type P; | ||
9023 | typedef typename P::first_type K; | ||
9024 | typedef typename P::second_type V; | ||
9025 | return get(types<K, V>(), L, index, tracking); | ||
9026 | } | ||
9027 | |||
9028 | static C get(std::false_type, lua_State* L, int relindex, record& tracking) { | ||
9029 | typedef typename C::value_type V; | ||
9030 | return get(types<V>(), L, relindex, tracking); | ||
9031 | } | ||
9032 | |||
9033 | template <typename V> | ||
9034 | static C get(types<V>, lua_State* L, int relindex, record& tracking) { | ||
9035 | tracking.use(1); | ||
9036 | |||
9037 | int index = lua_absindex(L, relindex); | ||
9038 | C arr; | ||
9039 | auto at = arr.cbefore_begin(); | ||
9040 | std::size_t idx = 0; | ||
9041 | #if SOL_LUA_VERSION >= 503 | ||
9042 | // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 | ||
9043 | for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { | ||
9044 | if (idx >= arr.max_size()) { | ||
9045 | return arr; | ||
9046 | } | ||
9047 | bool isnil = false; | ||
9048 | for (int vi = 0; vi < lua_size<V>::value; ++vi) { | ||
9049 | type t = static_cast<type>(lua_geti(L, index, i + vi)); | ||
9050 | isnil = t == type::lua_nil; | ||
9051 | if (isnil) { | ||
9052 | if (i == 0) { | ||
9053 | break; | ||
9054 | } | ||
9055 | lua_pop(L, (vi + 1)); | ||
9056 | return arr; | ||
9057 | } | ||
9058 | } | ||
9059 | if (isnil) | ||
9060 | continue; | ||
9061 | at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value)); | ||
9062 | ++idx; | ||
9063 | } | ||
9064 | #else | ||
9065 | // Zzzz slower but necessary thanks to the lower version API and missing functions qq | ||
9066 | for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { | ||
9067 | if (idx >= arr.max_size()) { | ||
9068 | return arr; | ||
9069 | } | ||
9070 | bool isnil = false; | ||
9071 | for (int vi = 0; vi < lua_size<V>::value; ++vi) { | ||
9072 | lua_pushinteger(L, i); | ||
9073 | lua_gettable(L, index); | ||
9074 | type t = type_of(L, -1); | ||
9075 | isnil = t == type::lua_nil; | ||
9076 | if (isnil) { | ||
9077 | if (i == 0) { | ||
9078 | break; | ||
9079 | } | ||
9080 | lua_pop(L, (vi + 1)); | ||
9081 | return arr; | ||
9082 | } | ||
9083 | } | ||
9084 | if (isnil) | ||
9085 | continue; | ||
9086 | at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value)); | ||
9087 | ++idx; | ||
9088 | } | ||
9089 | #endif | ||
9090 | return arr; | ||
9091 | } | ||
9092 | |||
9093 | template <typename K, typename V> | ||
9094 | static C get(types<K, V>, lua_State* L, int relindex, record& tracking) { | ||
9095 | tracking.use(1); | ||
9096 | |||
9097 | C associative; | ||
9098 | auto at = associative.cbefore_begin(); | ||
9099 | int index = lua_absindex(L, relindex); | ||
9100 | lua_pushnil(L); | ||
9101 | while (lua_next(L, index) != 0) { | ||
9102 | decltype(auto) key = stack::check_get<K>(L, -2); | ||
9103 | if (!key) { | ||
9104 | lua_pop(L, 1); | ||
9105 | continue; | ||
9106 | } | ||
9107 | at = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1)); | ||
9108 | lua_pop(L, 1); | ||
9109 | } | ||
9110 | return associative; | ||
9111 | } | ||
9112 | }; | ||
9113 | |||
9114 | template <typename T> | ||
9115 | struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> { | ||
9116 | static T get(lua_State* L, int index, record& tracking) { | ||
9117 | getter<T> g; | ||
9118 | // VC++ has a bad warning here: shut it up | ||
9119 | (void)g; | ||
9120 | return g.get(L, index, tracking); | ||
9121 | } | ||
9122 | }; | ||
9123 | |||
9124 | template <typename T> | ||
9125 | struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> { | ||
9126 | static T get(lua_State* L, int index, record& tracking) { | ||
9127 | typedef typename T::value_type V; | ||
9128 | getter<as_table_t<T>> g; | ||
9129 | // VC++ has a bad warning here: shut it up | ||
9130 | (void)g; | ||
9131 | return g.get(types<nested<V>>(), L, index, tracking); | ||
9132 | } | ||
9133 | }; | ||
9134 | |||
9135 | template <typename T> | ||
9136 | struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> { | ||
9137 | static T get(lua_State* L, int index, record& tracking) { | ||
9138 | typedef typename T::value_type P; | ||
9139 | typedef typename P::first_type K; | ||
9140 | typedef typename P::second_type V; | ||
9141 | getter<as_table_t<T>> g; | ||
9142 | // VC++ has a bad warning here: shut it up | ||
9143 | (void)g; | ||
9144 | return g.get(types<K, nested<V>>(), L, index, tracking); | ||
9145 | } | ||
9146 | }; | ||
9147 | |||
9148 | template <typename T> | ||
9149 | struct getter<T, std::enable_if_t<is_lua_reference<T>::value>> { | ||
9150 | static T get(lua_State* L, int index, record& tracking) { | ||
9151 | tracking.use(1); | ||
9152 | return T(L, index); | ||
9153 | } | ||
9154 | }; | ||
9155 | |||
9156 | template <> | ||
9157 | struct getter<userdata_value> { | ||
9158 | static userdata_value get(lua_State* L, int index, record& tracking) { | ||
9159 | tracking.use(1); | ||
9160 | return userdata_value(lua_touserdata(L, index)); | ||
9161 | } | ||
9162 | }; | ||
9163 | |||
9164 | template <> | ||
9165 | struct getter<lightuserdata_value> { | ||
9166 | static lightuserdata_value get(lua_State* L, int index, record& tracking) { | ||
9167 | tracking.use(1); | ||
9168 | return lightuserdata_value(lua_touserdata(L, index)); | ||
9169 | } | ||
9170 | }; | ||
9171 | |||
9172 | template <typename T> | ||
9173 | struct getter<light<T>> { | ||
9174 | static light<T> get(lua_State* L, int index, record& tracking) { | ||
9175 | tracking.use(1); | ||
9176 | void* memory = lua_touserdata(L, index); | ||
9177 | return light<T>(static_cast<T*>(memory)); | ||
9178 | } | ||
9179 | }; | ||
9180 | |||
9181 | template <typename T> | ||
9182 | struct getter<user<T>> { | ||
9183 | static std::add_lvalue_reference_t<T> get(lua_State* L, int index, record& tracking) { | ||
9184 | tracking.use(1); | ||
9185 | void* memory = lua_touserdata(L, index); | ||
9186 | memory = detail::align_user<T>(memory); | ||
9187 | return *static_cast<std::remove_reference_t<T>*>(memory); | ||
9188 | } | ||
9189 | }; | ||
9190 | |||
9191 | template <typename T> | ||
9192 | struct getter<user<T*>> { | ||
9193 | static T* get(lua_State* L, int index, record& tracking) { | ||
9194 | tracking.use(1); | ||
9195 | void* memory = lua_touserdata(L, index); | ||
9196 | memory = detail::align_user<T*>(memory); | ||
9197 | return static_cast<T*>(memory); | ||
9198 | } | ||
9199 | }; | ||
9200 | |||
9201 | template <> | ||
9202 | struct getter<type> { | ||
9203 | static type get(lua_State* L, int index, record& tracking) { | ||
9204 | tracking.use(1); | ||
9205 | return static_cast<type>(lua_type(L, index)); | ||
9206 | } | ||
9207 | }; | ||
9208 | |||
9209 | template <> | ||
9210 | struct getter<bool> { | ||
9211 | static bool get(lua_State* L, int index, record& tracking) { | ||
9212 | tracking.use(1); | ||
9213 | return lua_toboolean(L, index) != 0; | ||
9214 | } | ||
9215 | }; | ||
9216 | |||
9217 | template <> | ||
9218 | struct getter<std::string> { | ||
9219 | static std::string get(lua_State* L, int index, record& tracking) { | ||
9220 | tracking.use(1); | ||
9221 | std::size_t len; | ||
9222 | auto str = lua_tolstring(L, index, &len); | ||
9223 | return std::string(str, len); | ||
9224 | } | ||
9225 | }; | ||
9226 | |||
9227 | template <> | ||
9228 | struct getter<const char*> { | ||
9229 | static const char* get(lua_State* L, int index, record& tracking) { | ||
9230 | tracking.use(1); | ||
9231 | size_t sz; | ||
9232 | return lua_tolstring(L, index, &sz); | ||
9233 | } | ||
9234 | }; | ||
9235 | |||
9236 | template <> | ||
9237 | struct getter<char> { | ||
9238 | static char get(lua_State* L, int index, record& tracking) { | ||
9239 | tracking.use(1); | ||
9240 | size_t len; | ||
9241 | auto str = lua_tolstring(L, index, &len); | ||
9242 | return len > 0 ? str[0] : '\0'; | ||
9243 | } | ||
9244 | }; | ||
9245 | |||
9246 | template <typename Traits> | ||
9247 | struct getter<basic_string_view<char, Traits>> { | ||
9248 | static string_view get(lua_State* L, int index, record& tracking) { | ||
9249 | tracking.use(1); | ||
9250 | size_t sz; | ||
9251 | const char* str = lua_tolstring(L, index, &sz); | ||
9252 | return basic_string_view<char, Traits>(str, sz); | ||
9253 | } | ||
9254 | }; | ||
9255 | |||
9256 | template <typename Traits, typename Al> | ||
9257 | struct getter<std::basic_string<wchar_t, Traits, Al>> { | ||
9258 | typedef std::basic_string<wchar_t, Traits, Al> S; | ||
9259 | static S get(lua_State* L, int index, record& tracking) { | ||
9260 | typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch; | ||
9261 | typedef typename std::allocator_traits<Al>::template rebind_alloc<Ch> ChAl; | ||
9262 | typedef std::char_traits<Ch> ChTraits; | ||
9263 | getter<std::basic_string<Ch, ChTraits, ChAl>> g; | ||
9264 | (void)g; | ||
9265 | return g.template get_into<S>(L, index, tracking); | ||
9266 | } | ||
9267 | }; | ||
9268 | |||
9269 | template <typename Traits, typename Al> | ||
9270 | struct getter<std::basic_string<char16_t, Traits, Al>> { | ||
9271 | template <typename F> | ||
9272 | static void convert(const char* strb, const char* stre, F&& f) { | ||
9273 | char32_t cp = 0; | ||
9274 | for (const char* strtarget = strb; strtarget < stre;) { | ||
9275 | auto dr = unicode::utf8_to_code_point(strtarget, stre); | ||
9276 | if (dr.error != unicode::error_code::ok) { | ||
9277 | cp = unicode::unicode_detail::replacement; | ||
9278 | ++strtarget; | ||
9279 | } | ||
9280 | else { | ||
9281 | cp = dr.codepoint; | ||
9282 | strtarget = dr.next; | ||
9283 | } | ||
9284 | auto er = unicode::code_point_to_utf16(cp); | ||
9285 | f(er); | ||
9286 | } | ||
9287 | } | ||
9288 | |||
9289 | template <typename S> | ||
9290 | static S get_into(lua_State* L, int index, record& tracking) { | ||
9291 | typedef typename S::value_type Ch; | ||
9292 | tracking.use(1); | ||
9293 | size_t len; | ||
9294 | auto utf8p = lua_tolstring(L, index, &len); | ||
9295 | if (len < 1) | ||
9296 | return S(); | ||
9297 | std::size_t needed_size = 0; | ||
9298 | const char* strb = utf8p; | ||
9299 | const char* stre = utf8p + len; | ||
9300 | auto count_units = [&needed_size](const unicode::encoded_result<char16_t> er) { | ||
9301 | needed_size += er.code_units_size; | ||
9302 | }; | ||
9303 | convert(strb, stre, count_units); | ||
9304 | S r(needed_size, static_cast<Ch>(0)); | ||
9305 | r.resize(needed_size); | ||
9306 | Ch* target = &r[0]; | ||
9307 | auto copy_units = [&target](const unicode::encoded_result<char16_t> er) { | ||
9308 | std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch)); | ||
9309 | target += er.code_units_size; | ||
9310 | }; | ||
9311 | convert(strb, stre, copy_units); | ||
9312 | return r; | ||
9313 | } | ||
9314 | |||
9315 | static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) { | ||
9316 | return get_into<std::basic_string<char16_t, Traits, Al>>(L, index, tracking); | ||
9317 | } | ||
9318 | }; | ||
9319 | |||
9320 | template <typename Traits, typename Al> | ||
9321 | struct getter<std::basic_string<char32_t, Traits, Al>> { | ||
9322 | template <typename F> | ||
9323 | static void convert(const char* strb, const char* stre, F&& f) { | ||
9324 | char32_t cp = 0; | ||
9325 | for (const char* strtarget = strb; strtarget < stre;) { | ||
9326 | auto dr = unicode::utf8_to_code_point(strtarget, stre); | ||
9327 | if (dr.error != unicode::error_code::ok) { | ||
9328 | cp = unicode::unicode_detail::replacement; | ||
9329 | ++strtarget; | ||
9330 | } | ||
9331 | else { | ||
9332 | cp = dr.codepoint; | ||
9333 | strtarget = dr.next; | ||
9334 | } | ||
9335 | auto er = unicode::code_point_to_utf32(cp); | ||
9336 | f(er); | ||
9337 | } | ||
9338 | } | ||
9339 | |||
9340 | template <typename S> | ||
9341 | static S get_into(lua_State* L, int index, record& tracking) { | ||
9342 | typedef typename S::value_type Ch; | ||
9343 | tracking.use(1); | ||
9344 | size_t len; | ||
9345 | auto utf8p = lua_tolstring(L, index, &len); | ||
9346 | if (len < 1) | ||
9347 | return S(); | ||
9348 | std::size_t needed_size = 0; | ||
9349 | const char* strb = utf8p; | ||
9350 | const char* stre = utf8p + len; | ||
9351 | auto count_units = [&needed_size](const unicode::encoded_result<char32_t> er) { | ||
9352 | needed_size += er.code_units_size; | ||
9353 | }; | ||
9354 | convert(strb, stre, count_units); | ||
9355 | S r(needed_size, static_cast<Ch>(0)); | ||
9356 | r.resize(needed_size); | ||
9357 | Ch* target = &r[0]; | ||
9358 | auto copy_units = [&target](const unicode::encoded_result<char32_t> er) { | ||
9359 | std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch)); | ||
9360 | target += er.code_units_size; | ||
9361 | }; | ||
9362 | convert(strb, stre, copy_units); | ||
9363 | return r; | ||
9364 | } | ||
9365 | |||
9366 | static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) { | ||
9367 | return get_into<std::basic_string<char32_t, Traits, Al>>(L, index, tracking); | ||
9368 | } | ||
9369 | }; | ||
9370 | |||
9371 | template <> | ||
9372 | struct getter<char16_t> { | ||
9373 | static char16_t get(lua_State* L, int index, record& tracking) { | ||
9374 | string_view utf8 = stack::get<string_view>(L, index, tracking); | ||
9375 | const char* strb = utf8.data(); | ||
9376 | const char* stre = utf8.data() + utf8.size(); | ||
9377 | char32_t cp = 0; | ||
9378 | auto dr = unicode::utf8_to_code_point(strb, stre); | ||
9379 | if (dr.error != unicode::error_code::ok) { | ||
9380 | cp = unicode::unicode_detail::replacement; | ||
9381 | } | ||
9382 | else { | ||
9383 | cp = dr.codepoint; | ||
9384 | } | ||
9385 | auto er = unicode::code_point_to_utf16(cp); | ||
9386 | return er.code_units[0]; | ||
9387 | } | ||
9388 | }; | ||
9389 | |||
9390 | template <> | ||
9391 | struct getter<char32_t> { | ||
9392 | static char32_t get(lua_State* L, int index, record& tracking) { | ||
9393 | string_view utf8 = stack::get<string_view>(L, index, tracking); | ||
9394 | const char* strb = utf8.data(); | ||
9395 | const char* stre = utf8.data() + utf8.size(); | ||
9396 | char32_t cp = 0; | ||
9397 | auto dr = unicode::utf8_to_code_point(strb, stre); | ||
9398 | if (dr.error != unicode::error_code::ok) { | ||
9399 | cp = unicode::unicode_detail::replacement; | ||
9400 | } | ||
9401 | else { | ||
9402 | cp = dr.codepoint; | ||
9403 | } | ||
9404 | auto er = unicode::code_point_to_utf32(cp); | ||
9405 | return er.code_units[0]; | ||
9406 | } | ||
9407 | }; | ||
9408 | |||
9409 | template <> | ||
9410 | struct getter<wchar_t> { | ||
9411 | static wchar_t get(lua_State* L, int index, record& tracking) { | ||
9412 | typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch; | ||
9413 | getter<Ch> g; | ||
9414 | (void)g; | ||
9415 | auto c = g.get(L, index, tracking); | ||
9416 | return static_cast<wchar_t>(c); | ||
9417 | } | ||
9418 | }; | ||
9419 | |||
9420 | template <> | ||
9421 | struct getter<meta_function> { | ||
9422 | static meta_function get(lua_State* L, int index, record& tracking) { | ||
9423 | tracking.use(1); | ||
9424 | const char* name = getter<const char*>{}.get(L, index, tracking); | ||
9425 | const auto& mfnames = meta_function_names(); | ||
9426 | for (std::size_t i = 0; i < mfnames.size(); ++i) | ||
9427 | if (mfnames[i] == name) | ||
9428 | return static_cast<meta_function>(i); | ||
9429 | return meta_function::construct; | ||
9430 | } | ||
9431 | }; | ||
9432 | |||
9433 | template <> | ||
9434 | struct getter<lua_nil_t> { | ||
9435 | static lua_nil_t get(lua_State*, int, record& tracking) { | ||
9436 | tracking.use(1); | ||
9437 | return lua_nil; | ||
9438 | } | ||
9439 | }; | ||
9440 | |||
9441 | template <> | ||
9442 | struct getter<std::nullptr_t> { | ||
9443 | static std::nullptr_t get(lua_State*, int, record& tracking) { | ||
9444 | tracking.use(1); | ||
9445 | return nullptr; | ||
9446 | } | ||
9447 | }; | ||
9448 | |||
9449 | template <> | ||
9450 | struct getter<nullopt_t> { | ||
9451 | static nullopt_t get(lua_State*, int, record& tracking) { | ||
9452 | tracking.use(1); | ||
9453 | return nullopt; | ||
9454 | } | ||
9455 | }; | ||
9456 | |||
9457 | template <> | ||
9458 | struct getter<this_state> { | ||
9459 | static this_state get(lua_State* L, int, record& tracking) { | ||
9460 | tracking.use(0); | ||
9461 | return this_state(L); | ||
9462 | } | ||
9463 | }; | ||
9464 | |||
9465 | template <> | ||
9466 | struct getter<this_main_state> { | ||
9467 | static this_main_state get(lua_State* L, int, record& tracking) { | ||
9468 | tracking.use(0); | ||
9469 | return this_main_state(main_thread(L, L)); | ||
9470 | } | ||
9471 | }; | ||
9472 | |||
9473 | template <> | ||
9474 | struct getter<lua_CFunction> { | ||
9475 | static lua_CFunction get(lua_State* L, int index, record& tracking) { | ||
9476 | tracking.use(1); | ||
9477 | return lua_tocfunction(L, index); | ||
9478 | } | ||
9479 | }; | ||
9480 | |||
9481 | template <> | ||
9482 | struct getter<c_closure> { | ||
9483 | static c_closure get(lua_State* L, int index, record& tracking) { | ||
9484 | tracking.use(1); | ||
9485 | return c_closure(lua_tocfunction(L, index), -1); | ||
9486 | } | ||
9487 | }; | ||
9488 | |||
9489 | template <> | ||
9490 | struct getter<error> { | ||
9491 | static error get(lua_State* L, int index, record& tracking) { | ||
9492 | tracking.use(1); | ||
9493 | size_t sz = 0; | ||
9494 | const char* err = lua_tolstring(L, index, &sz); | ||
9495 | if (err == nullptr) { | ||
9496 | return error(detail::direct_error, ""); | ||
9497 | } | ||
9498 | return error(detail::direct_error, std::string(err, sz)); | ||
9499 | } | ||
9500 | }; | ||
9501 | |||
9502 | template <> | ||
9503 | struct getter<void*> { | ||
9504 | static void* get(lua_State* L, int index, record& tracking) { | ||
9505 | tracking.use(1); | ||
9506 | return lua_touserdata(L, index); | ||
9507 | } | ||
9508 | }; | ||
9509 | |||
9510 | template <typename T> | ||
9511 | struct getter<detail::as_value_tag<T>> { | ||
9512 | static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { | ||
9513 | void* memory = lua_touserdata(L, index); | ||
9514 | #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP | ||
9515 | userdata_getter<extensible<T>> ug; | ||
9516 | (void)ug; | ||
9517 | auto ugr = ug.get(L, index, memory, tracking); | ||
9518 | if (ugr.first) { | ||
9519 | return ugr.second; | ||
9520 | } | ||
9521 | #endif // interop extensibility | ||
9522 | tracking.use(1); | ||
9523 | void* rawdata = detail::align_usertype_pointer(memory); | ||
9524 | void** pudata = static_cast<void**>(rawdata); | ||
9525 | void* udata = *pudata; | ||
9526 | return get_no_lua_nil_from(L, udata, index, tracking); | ||
9527 | } | ||
9528 | |||
9529 | static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) { | ||
9530 | if (detail::has_derived<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) { | ||
9531 | void* basecastdata = lua_touserdata(L, -1); | ||
9532 | detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata); | ||
9533 | // use the casting function to properly adjust the pointer for the desired T | ||
9534 | udata = ic(udata, usertype_traits<T>::qualified_name()); | ||
9535 | lua_pop(L, 1); | ||
9536 | } | ||
9537 | T* obj = static_cast<T*>(udata); | ||
9538 | return obj; | ||
9539 | } | ||
9540 | |||
9541 | static T& get(lua_State* L, int index, record& tracking) { | ||
9542 | return *get_no_lua_nil(L, index, tracking); | ||
9543 | } | ||
9544 | }; | ||
9545 | |||
9546 | template <typename T> | ||
9547 | struct getter<detail::as_pointer_tag<T>> { | ||
9548 | static T* get(lua_State* L, int index, record& tracking) { | ||
9549 | type t = type_of(L, index); | ||
9550 | if (t == type::lua_nil) { | ||
9551 | tracking.use(1); | ||
9552 | return nullptr; | ||
9553 | } | ||
9554 | getter<detail::as_value_tag<T>> g; | ||
9555 | // Avoid VC++ warning | ||
9556 | (void)g; | ||
9557 | return g.get_no_lua_nil(L, index, tracking); | ||
9558 | } | ||
9559 | }; | ||
9560 | |||
9561 | template <typename T> | ||
9562 | struct getter<non_null<T*>> { | ||
9563 | static T* get(lua_State* L, int index, record& tracking) { | ||
9564 | getter<detail::as_value_tag<T>> g; | ||
9565 | // Avoid VC++ warning | ||
9566 | (void)g; | ||
9567 | return g.get_no_lua_nil(L, index, tracking); | ||
9568 | } | ||
9569 | }; | ||
9570 | |||
9571 | template <typename T> | ||
9572 | struct getter<T&> { | ||
9573 | static T& get(lua_State* L, int index, record& tracking) { | ||
9574 | getter<detail::as_value_tag<T>> g; | ||
9575 | // Avoid VC++ warning | ||
9576 | (void)g; | ||
9577 | return g.get(L, index, tracking); | ||
9578 | } | ||
9579 | }; | ||
9580 | |||
9581 | template <typename T> | ||
9582 | struct getter<std::reference_wrapper<T>> { | ||
9583 | static T& get(lua_State* L, int index, record& tracking) { | ||
9584 | getter<T&> g; | ||
9585 | // Avoid VC++ warning | ||
9586 | (void)g; | ||
9587 | return g.get(L, index, tracking); | ||
9588 | } | ||
9589 | }; | ||
9590 | |||
9591 | template <typename T> | ||
9592 | struct getter<T*> { | ||
9593 | static T* get(lua_State* L, int index, record& tracking) { | ||
9594 | getter<detail::as_pointer_tag<T>> g; | ||
9595 | // Avoid VC++ warning | ||
9596 | (void)g; | ||
9597 | return g.get(L, index, tracking); | ||
9598 | } | ||
9599 | }; | ||
9600 | |||
9601 | template <typename T> | ||
9602 | struct getter<T, std::enable_if_t<is_unique_usertype<T>::value>> { | ||
9603 | typedef typename unique_usertype_traits<T>::type P; | ||
9604 | typedef typename unique_usertype_traits<T>::actual_type Real; | ||
9605 | |||
9606 | static Real& get(lua_State* L, int index, record& tracking) { | ||
9607 | tracking.use(1); | ||
9608 | void* memory = lua_touserdata(L, index); | ||
9609 | memory = detail::align_usertype_unique<Real>(memory); | ||
9610 | Real* mem = static_cast<Real*>(memory); | ||
9611 | return *mem; | ||
9612 | } | ||
9613 | }; | ||
9614 | |||
9615 | template <typename... Tn> | ||
9616 | struct getter<std::tuple<Tn...>> { | ||
9617 | typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R; | ||
9618 | |||
9619 | template <typename... Args> | ||
9620 | static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) { | ||
9621 | // Fuck you too, VC++ | ||
9622 | return R{ std::forward<Args>(args)... }; | ||
9623 | } | ||
9624 | |||
9625 | template <std::size_t I, std::size_t... Ix, typename... Args> | ||
9626 | static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) { | ||
9627 | // Fuck you too, VC++ | ||
9628 | typedef std::tuple_element_t<I, std::tuple<Tn...>> T; | ||
9629 | return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking)); | ||
9630 | } | ||
9631 | |||
9632 | static R get(lua_State* L, int index, record& tracking) { | ||
9633 | return apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking); | ||
9634 | } | ||
9635 | }; | ||
9636 | |||
9637 | template <typename A, typename B> | ||
9638 | struct getter<std::pair<A, B>> { | ||
9639 | static decltype(auto) get(lua_State* L, int index, record& tracking) { | ||
9640 | return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{ stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking) }; | ||
9641 | } | ||
9642 | }; | ||
9643 | |||
9644 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
9645 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
9646 | template <typename... Tn> | ||
9647 | struct getter<std::variant<Tn...>> { | ||
9648 | typedef std::variant<Tn...> V; | ||
9649 | typedef std::variant_size<V> V_size; | ||
9650 | typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; | ||
9651 | |||
9652 | static V get_empty(std::true_type, lua_State*, int, record&) { | ||
9653 | return V(); | ||
9654 | } | ||
9655 | |||
9656 | static V get_empty(std::false_type, lua_State* L, int index, record& tracking) { | ||
9657 | typedef std::variant_alternative_t<0, V> T; | ||
9658 | // This should never be reached... | ||
9659 | // please check your code and understand what you did to bring yourself here | ||
9660 | std::abort(); | ||
9661 | return V(std::in_place_index<0>, stack::get<T>(L, index, tracking)); | ||
9662 | } | ||
9663 | |||
9664 | static V get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, record& tracking) { | ||
9665 | return get_empty(V_is_empty(), L, index, tracking); | ||
9666 | } | ||
9667 | |||
9668 | template <std::size_t I> | ||
9669 | static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) { | ||
9670 | typedef std::variant_alternative_t<I - 1, V> T; | ||
9671 | if (stack::check<T>(L, index, no_panic, tracking)) { | ||
9672 | return V(std::in_place_index<I - 1>, stack::get<T>(L, index)); | ||
9673 | } | ||
9674 | return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, tracking); | ||
9675 | } | ||
9676 | |||
9677 | static V get(lua_State* L, int index, record& tracking) { | ||
9678 | return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, tracking); | ||
9679 | } | ||
9680 | }; | ||
9681 | #endif // SOL_STD_VARIANT | ||
9682 | #endif // SOL_CXX17_FEATURES | ||
9683 | } | ||
9684 | } // namespace sol::stack | ||
9685 | |||
9686 | // end of sol/stack_get.hpp | ||
9687 | |||
9688 | // beginning of sol/stack_check_get.hpp | ||
9689 | |||
9690 | namespace sol { | ||
9691 | namespace stack { | ||
9692 | template <typename T, typename> | ||
9693 | struct check_getter { | ||
9694 | typedef decltype(stack_detail::unchecked_get<T>(nullptr, 0, std::declval<record&>())) R; | ||
9695 | |||
9696 | template <typename Handler> | ||
9697 | static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9698 | if (!check<T>(L, index, std::forward<Handler>(handler))) { | ||
9699 | tracking.use(static_cast<int>(!lua_isnone(L, index))); | ||
9700 | return nullopt; | ||
9701 | } | ||
9702 | return stack_detail::unchecked_get<T>(L, index, tracking); | ||
9703 | } | ||
9704 | }; | ||
9705 | |||
9706 | template <typename T> | ||
9707 | struct check_getter<T, std::enable_if_t<is_lua_reference<T>::value>> { | ||
9708 | template <typename Handler> | ||
9709 | static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9710 | // actually check if it's none here, otherwise | ||
9711 | // we'll have a none object inside an optional! | ||
9712 | bool success = !lua_isnone(L, index); | ||
9713 | if (!success) { | ||
9714 | // expected type, actual type | ||
9715 | tracking.use(static_cast<int>(success)); | ||
9716 | handler(L, index, type::poly, type_of(L, index), ""); | ||
9717 | return nullopt; | ||
9718 | } | ||
9719 | return stack_detail::unchecked_get<T>(L, index, tracking); | ||
9720 | } | ||
9721 | }; | ||
9722 | |||
9723 | template <typename T> | ||
9724 | struct check_getter<optional<T>> { | ||
9725 | template <typename Handler> | ||
9726 | static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) { | ||
9727 | return check_get<T>(L, index, no_panic, tracking); | ||
9728 | } | ||
9729 | }; | ||
9730 | |||
9731 | template <typename T> | ||
9732 | struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> { | ||
9733 | template <typename Handler> | ||
9734 | static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9735 | #if SOL_LUA_VERSION >= 503 | ||
9736 | if (lua_isinteger(L, index) != 0) { | ||
9737 | tracking.use(1); | ||
9738 | return static_cast<T>(lua_tointeger(L, index)); | ||
9739 | } | ||
9740 | #endif | ||
9741 | int isnum = 0; | ||
9742 | const lua_Number value = lua_tonumberx(L, index, &isnum); | ||
9743 | if (isnum != 0) { | ||
9744 | #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) | ||
9745 | const auto integer_value = llround(value); | ||
9746 | if (static_cast<lua_Number>(integer_value) == value) { | ||
9747 | tracking.use(1); | ||
9748 | return static_cast<T>(integer_value); | ||
9749 | } | ||
9750 | #else | ||
9751 | tracking.use(1); | ||
9752 | return static_cast<T>(value); | ||
9753 | #endif | ||
9754 | } | ||
9755 | const type t = type_of(L, index); | ||
9756 | tracking.use(static_cast<int>(t != type::none)); | ||
9757 | handler(L, index, type::number, t, "not an integer"); | ||
9758 | return nullopt; | ||
9759 | } | ||
9760 | }; | ||
9761 | |||
9762 | template <typename T> | ||
9763 | struct check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> { | ||
9764 | template <typename Handler> | ||
9765 | static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9766 | int isnum = 0; | ||
9767 | lua_Integer value = lua_tointegerx(L, index, &isnum); | ||
9768 | if (isnum == 0) { | ||
9769 | type t = type_of(L, index); | ||
9770 | tracking.use(static_cast<int>(t != type::none)); | ||
9771 | handler(L, index, type::number, t, "not a valid enumeration value"); | ||
9772 | return nullopt; | ||
9773 | } | ||
9774 | tracking.use(1); | ||
9775 | return static_cast<T>(value); | ||
9776 | } | ||
9777 | }; | ||
9778 | |||
9779 | template <typename T> | ||
9780 | struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> { | ||
9781 | template <typename Handler> | ||
9782 | static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9783 | int isnum = 0; | ||
9784 | lua_Number value = lua_tonumberx(L, index, &isnum); | ||
9785 | if (isnum == 0) { | ||
9786 | type t = type_of(L, index); | ||
9787 | tracking.use(static_cast<int>(t != type::none)); | ||
9788 | handler(L, index, type::number, t, "not a valid floating point number"); | ||
9789 | return nullopt; | ||
9790 | } | ||
9791 | tracking.use(1); | ||
9792 | return static_cast<T>(value); | ||
9793 | } | ||
9794 | }; | ||
9795 | |||
9796 | template <typename T> | ||
9797 | struct getter<optional<T>> { | ||
9798 | static decltype(auto) get(lua_State* L, int index, record& tracking) { | ||
9799 | return check_get<T>(L, index, no_panic, tracking); | ||
9800 | } | ||
9801 | }; | ||
9802 | |||
9803 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
9804 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
9805 | template <typename... Tn> | ||
9806 | struct check_getter<std::variant<Tn...>> { | ||
9807 | typedef std::variant<Tn...> V; | ||
9808 | typedef std::variant_size<V> V_size; | ||
9809 | typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; | ||
9810 | |||
9811 | template <typename Handler> | ||
9812 | static optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) { | ||
9813 | return nullopt; | ||
9814 | } | ||
9815 | |||
9816 | template <typename Handler> | ||
9817 | static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) { | ||
9818 | // This should never be reached... | ||
9819 | // please check your code and understand what you did to bring yourself here | ||
9820 | // maybe file a bug report, or 5 | ||
9821 | handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong"); | ||
9822 | return nullopt; | ||
9823 | } | ||
9824 | |||
9825 | template <typename Handler> | ||
9826 | static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9827 | return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking); | ||
9828 | } | ||
9829 | |||
9830 | template <std::size_t I, typename Handler> | ||
9831 | static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9832 | typedef std::variant_alternative_t<I - 1, V> T; | ||
9833 | if (stack::check<T>(L, index, no_panic, tracking)) { | ||
9834 | return V(std::in_place_index<I - 1>, stack::get<T>(L, index)); | ||
9835 | } | ||
9836 | return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); | ||
9837 | } | ||
9838 | |||
9839 | template <typename Handler> | ||
9840 | static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
9841 | return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking); | ||
9842 | } | ||
9843 | }; | ||
9844 | #endif // SOL_STD_VARIANT | ||
9845 | #endif // SOL_CXX17_FEATURES | ||
9846 | } | ||
9847 | } // namespace sol::stack | ||
9848 | |||
9849 | // end of sol/stack_check_get.hpp | ||
9850 | |||
9851 | // beginning of sol/stack_push.hpp | ||
9852 | |||
9853 | #include <limits> | ||
9854 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
9855 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
9856 | #endif // Can use variant | ||
9857 | #endif // C++17 | ||
9858 | |||
9859 | namespace sol { | ||
9860 | namespace stack { | ||
9861 | inline int push_environment_of(lua_State* L, int index = -1) { | ||
9862 | #if SOL_LUA_VERSION < 502 | ||
9863 | // Use lua_getfenv | ||
9864 | lua_getfenv(L, index); | ||
9865 | return 1; | ||
9866 | #else | ||
9867 | // Use upvalues as explained in Lua 5.2 and beyond's manual | ||
9868 | if (lua_getupvalue(L, index, 1) == nullptr) { | ||
9869 | push(L, lua_nil); | ||
9870 | return 1; | ||
9871 | } | ||
9872 | #endif | ||
9873 | return 1; | ||
9874 | } | ||
9875 | |||
9876 | template <typename T> | ||
9877 | int push_environment_of(const T& target) { | ||
9878 | target.push(); | ||
9879 | return push_environment_of(target.lua_state(), -1) + 1; | ||
9880 | } | ||
9881 | |||
9882 | template <typename T> | ||
9883 | struct pusher<detail::as_value_tag<T>> { | ||
9884 | template <typename F, typename... Args> | ||
9885 | static int push_fx(lua_State* L, F&& f, Args&&... args) { | ||
9886 | // Basically, we store all user-data like this: | ||
9887 | // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new | ||
9888 | // data in the first sizeof(T*) bytes, and then however many bytes it takes to | ||
9889 | // do the actual object. Things that are std::ref or plain T* are stored as | ||
9890 | // just the sizeof(T*), and nothing else. | ||
9891 | T* obj = detail::usertype_allocate<T>(L); | ||
9892 | std::allocator<T> alloc{}; | ||
9893 | std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...); | ||
9894 | f(); | ||
9895 | return 1; | ||
9896 | } | ||
9897 | |||
9898 | template <typename K, typename... Args> | ||
9899 | static int push_keyed(lua_State* L, K&& k, Args&&... args) { | ||
9900 | stack_detail::undefined_metatable<T> fx(L, &k[0]); | ||
9901 | return push_fx(L, fx, std::forward<Args>(args)...); | ||
9902 | } | ||
9903 | |||
9904 | template <typename... Args> | ||
9905 | static int push(lua_State* L, Args&&... args) { | ||
9906 | return push_keyed(L, usertype_traits<T>::metatable(), std::forward<Args>(args)...); | ||
9907 | } | ||
9908 | }; | ||
9909 | |||
9910 | template <typename T> | ||
9911 | struct pusher<detail::as_pointer_tag<T>> { | ||
9912 | typedef meta::unqualified_t<T> U; | ||
9913 | |||
9914 | template <typename F> | ||
9915 | static int push_fx(lua_State* L, F&& f, T* obj) { | ||
9916 | if (obj == nullptr) | ||
9917 | return stack::push(L, lua_nil); | ||
9918 | T** pref = detail::usertype_allocate_pointer<T>(L); | ||
9919 | *pref = obj; | ||
9920 | f(); | ||
9921 | return 1; | ||
9922 | } | ||
9923 | |||
9924 | template <typename K> | ||
9925 | static int push_keyed(lua_State* L, K&& k, T* obj) { | ||
9926 | stack_detail::undefined_metatable<U*> fx(L, &k[0]); | ||
9927 | return push_fx(L, fx, obj); | ||
9928 | } | ||
9929 | |||
9930 | static int push(lua_State* L, T* obj) { | ||
9931 | return push_keyed(L, usertype_traits<U*>::metatable(), obj); | ||
9932 | } | ||
9933 | }; | ||
9934 | |||
9935 | template <> | ||
9936 | struct pusher<detail::as_reference_tag> { | ||
9937 | template <typename T> | ||
9938 | static int push(lua_State* L, T&& obj) { | ||
9939 | return stack::push(L, detail::ptr(obj)); | ||
9940 | } | ||
9941 | }; | ||
9942 | |||
9943 | template <typename T, typename> | ||
9944 | struct pusher { | ||
9945 | template <typename... Args> | ||
9946 | static int push(lua_State* L, Args&&... args) { | ||
9947 | return pusher<detail::as_value_tag<T>>{}.push(L, std::forward<Args>(args)...); | ||
9948 | } | ||
9949 | }; | ||
9950 | |||
9951 | template <typename T> | ||
9952 | struct pusher<T*, meta::disable_if_t<meta::any<is_container<meta::unqualified_t<T>>, std::is_function<meta::unqualified_t<T>>, is_lua_reference<meta::unqualified_t<T>>>::value>> { | ||
9953 | template <typename... Args> | ||
9954 | static int push(lua_State* L, Args&&... args) { | ||
9955 | return pusher<detail::as_pointer_tag<T>>{}.push(L, std::forward<Args>(args)...); | ||
9956 | } | ||
9957 | }; | ||
9958 | |||
9959 | template <typename T> | ||
9960 | struct pusher<T, std::enable_if_t<is_unique_usertype<T>::value>> { | ||
9961 | typedef typename unique_usertype_traits<T>::type P; | ||
9962 | typedef typename unique_usertype_traits<T>::actual_type Real; | ||
9963 | |||
9964 | template <typename Arg, meta::enable<std::is_base_of<Real, meta::unqualified_t<Arg>>> = meta::enabler> | ||
9965 | static int push(lua_State* L, Arg&& arg) { | ||
9966 | if (unique_usertype_traits<T>::is_null(arg)) { | ||
9967 | return stack::push(L, lua_nil); | ||
9968 | } | ||
9969 | return push_deep(L, std::forward<Arg>(arg)); | ||
9970 | } | ||
9971 | |||
9972 | template <typename Arg0, typename Arg1, typename... Args> | ||
9973 | static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) { | ||
9974 | return push_deep(L, std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...); | ||
9975 | } | ||
9976 | |||
9977 | template <typename... Args> | ||
9978 | static int push_deep(lua_State* L, Args&&... args) { | ||
9979 | P** pref = nullptr; | ||
9980 | detail::unique_destructor* fx = nullptr; | ||
9981 | Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx); | ||
9982 | *fx = detail::usertype_unique_alloc_destroy<P, Real>; | ||
9983 | detail::default_construct::construct(mem, std::forward<Args>(args)...); | ||
9984 | *pref = unique_usertype_traits<T>::get(*mem); | ||
9985 | if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<P>>::metatable()[0]) == 1) { | ||
9986 | luaL_Reg l[32]{}; | ||
9987 | int index = 0; | ||
9988 | auto prop_fx = [](meta_function) { return true; }; | ||
9989 | usertype_detail::insert_default_registrations<P>(l, index, prop_fx); | ||
9990 | usertype_detail::make_destructor<T>(l, index); | ||
9991 | luaL_setfuncs(L, l, 0); | ||
9992 | } | ||
9993 | lua_setmetatable(L, -2); | ||
9994 | return 1; | ||
9995 | } | ||
9996 | }; | ||
9997 | |||
9998 | template <typename T> | ||
9999 | struct pusher<std::reference_wrapper<T>> { | ||
10000 | static int push(lua_State* L, const std::reference_wrapper<T>& t) { | ||
10001 | return stack::push(L, std::addressof(detail::deref(t.get()))); | ||
10002 | } | ||
10003 | }; | ||
10004 | |||
10005 | template <typename T> | ||
10006 | struct pusher<T, std::enable_if_t<std::is_floating_point<T>::value>> { | ||
10007 | static int push(lua_State* L, const T& value) { | ||
10008 | lua_pushnumber(L, value); | ||
10009 | return 1; | ||
10010 | } | ||
10011 | }; | ||
10012 | |||
10013 | template <typename T> | ||
10014 | struct pusher<T, std::enable_if_t<std::is_integral<T>::value>> { | ||
10015 | static int push(lua_State* L, const T& value) { | ||
10016 | #if SOL_LUA_VERSION >= 503 | ||
10017 | static auto integer_value_fits = [](T const& value) { | ||
10018 | if (sizeof(T) < sizeof(lua_Integer) || (std::is_signed<T>::value && sizeof(T) == sizeof(lua_Integer))) { | ||
10019 | return true; | ||
10020 | } | ||
10021 | auto u_min = static_cast<std::intmax_t>((std::numeric_limits<lua_Integer>::min)()); | ||
10022 | auto u_max = static_cast<std::uintmax_t>((std::numeric_limits<lua_Integer>::max)()); | ||
10023 | auto t_min = static_cast<std::intmax_t>((std::numeric_limits<T>::min)()); | ||
10024 | auto t_max = static_cast<std::uintmax_t>((std::numeric_limits<T>::max)()); | ||
10025 | return (u_min <= t_min || value >= static_cast<T>(u_min)) && (u_max >= t_max || value <= static_cast<T>(u_max)); | ||
10026 | }; | ||
10027 | if (integer_value_fits(value)) { | ||
10028 | lua_pushinteger(L, static_cast<lua_Integer>(value)); | ||
10029 | return 1; | ||
10030 | } | ||
10031 | #endif // Lua 5.3 and above | ||
10032 | #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) | ||
10033 | if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { | ||
10034 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
10035 | // Is this really worth it? | ||
10036 | assert(false && "integer value will be misrepresented in lua"); | ||
10037 | lua_pushnumber(L, static_cast<lua_Number>(value)); | ||
10038 | return 1; | ||
10039 | #else | ||
10040 | throw error(detail::direct_error, "integer value will be misrepresented in lua"); | ||
10041 | #endif // No Exceptions | ||
10042 | } | ||
10043 | #endif // Safe Numerics and Number Precision Check | ||
10044 | lua_pushnumber(L, static_cast<lua_Number>(value)); | ||
10045 | return 1; | ||
10046 | } | ||
10047 | }; | ||
10048 | |||
10049 | template <typename T> | ||
10050 | struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> { | ||
10051 | static int push(lua_State* L, const T& value) { | ||
10052 | if (std::is_same<char, std::underlying_type_t<T>>::value) { | ||
10053 | return stack::push(L, static_cast<int>(value)); | ||
10054 | } | ||
10055 | return stack::push(L, static_cast<std::underlying_type_t<T>>(value)); | ||
10056 | } | ||
10057 | }; | ||
10058 | |||
10059 | template <typename T> | ||
10060 | struct pusher<detail::as_table_tag<T>> { | ||
10061 | static int push(lua_State* L, const T& tablecont) { | ||
10062 | typedef meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>> has_kvp; | ||
10063 | return push(has_kvp(), L, tablecont); | ||
10064 | } | ||
10065 | |||
10066 | static int push(std::true_type, lua_State* L, const T& tablecont) { | ||
10067 | auto& cont = detail::deref(detail::unwrap(tablecont)); | ||
10068 | lua_createtable(L, static_cast<int>(cont.size()), 0); | ||
10069 | int tableindex = lua_gettop(L); | ||
10070 | for (const auto& pair : cont) { | ||
10071 | set_field(L, pair.first, pair.second, tableindex); | ||
10072 | } | ||
10073 | return 1; | ||
10074 | } | ||
10075 | |||
10076 | static int push(std::false_type, lua_State* L, const T& tablecont) { | ||
10077 | auto& cont = detail::deref(detail::unwrap(tablecont)); | ||
10078 | lua_createtable(L, stack_detail::get_size_hint(cont), 0); | ||
10079 | int tableindex = lua_gettop(L); | ||
10080 | std::size_t index = 1; | ||
10081 | for (const auto& i : cont) { | ||
10082 | #if SOL_LUA_VERSION >= 503 | ||
10083 | int p = stack::push(L, i); | ||
10084 | for (int pi = 0; pi < p; ++pi) { | ||
10085 | lua_seti(L, tableindex, static_cast<lua_Integer>(index++)); | ||
10086 | } | ||
10087 | #else | ||
10088 | lua_pushinteger(L, static_cast<lua_Integer>(index)); | ||
10089 | int p = stack::push(L, i); | ||
10090 | if (p == 1) { | ||
10091 | ++index; | ||
10092 | lua_settable(L, tableindex); | ||
10093 | } | ||
10094 | else { | ||
10095 | int firstindex = tableindex + 1 + 1; | ||
10096 | for (int pi = 0; pi < p; ++pi) { | ||
10097 | stack::push(L, index); | ||
10098 | lua_pushvalue(L, firstindex); | ||
10099 | lua_settable(L, tableindex); | ||
10100 | ++index; | ||
10101 | ++firstindex; | ||
10102 | } | ||
10103 | lua_pop(L, 1 + p); | ||
10104 | } | ||
10105 | #endif // Lua Version 5.3 and others | ||
10106 | } | ||
10107 | // TODO: figure out a better way to do this...? | ||
10108 | //set_field(L, -1, cont.size()); | ||
10109 | return 1; | ||
10110 | } | ||
10111 | }; | ||
10112 | |||
10113 | template <typename T> | ||
10114 | struct pusher<as_table_t<T>, std::enable_if_t<is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { | ||
10115 | static int push(lua_State* L, const T& tablecont) { | ||
10116 | return stack::push<detail::as_table_tag<T>>(L, tablecont); | ||
10117 | } | ||
10118 | }; | ||
10119 | |||
10120 | template <typename T> | ||
10121 | struct pusher<as_table_t<T>, std::enable_if_t<!is_container<std::remove_pointer_t<meta::unwrap_unqualified_t<T>>>::value>> { | ||
10122 | static int push(lua_State* L, const T& v) { | ||
10123 | return stack::push(L, v); | ||
10124 | } | ||
10125 | }; | ||
10126 | |||
10127 | template <typename T> | ||
10128 | struct pusher<nested<T>> { | ||
10129 | static int push(lua_State* L, const T& tablecont) { | ||
10130 | pusher<as_table_t<T>> p{}; | ||
10131 | // silence annoying VC++ warning | ||
10132 | (void)p; | ||
10133 | return p.push(L, tablecont); | ||
10134 | } | ||
10135 | }; | ||
10136 | |||
10137 | template <typename T> | ||
10138 | struct pusher<std::initializer_list<T>> { | ||
10139 | static int push(lua_State* L, const std::initializer_list<T>& il) { | ||
10140 | pusher<detail::as_table_tag<std::initializer_list<T>>> p{}; | ||
10141 | // silence annoying VC++ warning | ||
10142 | (void)p; | ||
10143 | return p.push(L, il); | ||
10144 | } | ||
10145 | }; | ||
10146 | |||
10147 | template <typename T> | ||
10148 | struct pusher<T, std::enable_if_t<is_lua_reference<T>::value>> { | ||
10149 | static int push(lua_State* L, const T& ref) { | ||
10150 | return ref.push(L); | ||
10151 | } | ||
10152 | |||
10153 | static int push(lua_State* L, T&& ref) { | ||
10154 | return ref.push(L); | ||
10155 | } | ||
10156 | }; | ||
10157 | |||
10158 | template <> | ||
10159 | struct pusher<bool> { | ||
10160 | static int push(lua_State* L, bool b) { | ||
10161 | lua_pushboolean(L, b); | ||
10162 | return 1; | ||
10163 | } | ||
10164 | }; | ||
10165 | |||
10166 | template <> | ||
10167 | struct pusher<lua_nil_t> { | ||
10168 | static int push(lua_State* L, lua_nil_t) { | ||
10169 | lua_pushnil(L); | ||
10170 | return 1; | ||
10171 | } | ||
10172 | }; | ||
10173 | |||
10174 | template <> | ||
10175 | struct pusher<stack_count> { | ||
10176 | static int push(lua_State*, stack_count st) { | ||
10177 | return st.count; | ||
10178 | } | ||
10179 | }; | ||
10180 | |||
10181 | template <> | ||
10182 | struct pusher<metatable_t> { | ||
10183 | static int push(lua_State* L, metatable_t) { | ||
10184 | lua_pushlstring(L, "__mt", 4); | ||
10185 | return 1; | ||
10186 | } | ||
10187 | }; | ||
10188 | |||
10189 | template <> | ||
10190 | struct pusher<std::remove_pointer_t<lua_CFunction>> { | ||
10191 | static int push(lua_State* L, lua_CFunction func, int n = 0) { | ||
10192 | lua_pushcclosure(L, func, n); | ||
10193 | return 1; | ||
10194 | } | ||
10195 | }; | ||
10196 | |||
10197 | template <> | ||
10198 | struct pusher<lua_CFunction> { | ||
10199 | static int push(lua_State* L, lua_CFunction func, int n = 0) { | ||
10200 | lua_pushcclosure(L, func, n); | ||
10201 | return 1; | ||
10202 | } | ||
10203 | }; | ||
10204 | |||
10205 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
10206 | template <> | ||
10207 | struct pusher<std::remove_pointer_t<detail::lua_CFunction_noexcept>> { | ||
10208 | static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { | ||
10209 | lua_pushcclosure(L, func, n); | ||
10210 | return 1; | ||
10211 | } | ||
10212 | }; | ||
10213 | |||
10214 | template <> | ||
10215 | struct pusher<detail::lua_CFunction_noexcept> { | ||
10216 | static int push(lua_State* L, detail::lua_CFunction_noexcept func, int n = 0) { | ||
10217 | lua_pushcclosure(L, func, n); | ||
10218 | return 1; | ||
10219 | } | ||
10220 | }; | ||
10221 | #endif // noexcept function type | ||
10222 | |||
10223 | template <> | ||
10224 | struct pusher<c_closure> { | ||
10225 | static int push(lua_State* L, c_closure cc) { | ||
10226 | lua_pushcclosure(L, cc.c_function, cc.upvalues); | ||
10227 | return 1; | ||
10228 | } | ||
10229 | }; | ||
10230 | |||
10231 | template <typename Arg, typename... Args> | ||
10232 | struct pusher<closure<Arg, Args...>> { | ||
10233 | template <std::size_t... I, typename T> | ||
10234 | static int push(std::index_sequence<I...>, lua_State* L, T&& c) { | ||
10235 | int pushcount = multi_push(L, detail::forward_get<I>(c.upvalues)...); | ||
10236 | return stack::push(L, c_closure(c.c_function, pushcount)); | ||
10237 | } | ||
10238 | |||
10239 | template <typename T> | ||
10240 | static int push(lua_State* L, T&& c) { | ||
10241 | return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c)); | ||
10242 | } | ||
10243 | }; | ||
10244 | |||
10245 | template <> | ||
10246 | struct pusher<void*> { | ||
10247 | static int push(lua_State* L, void* userdata) { | ||
10248 | lua_pushlightuserdata(L, userdata); | ||
10249 | return 1; | ||
10250 | } | ||
10251 | }; | ||
10252 | |||
10253 | template <> | ||
10254 | struct pusher<lightuserdata_value> { | ||
10255 | static int push(lua_State* L, lightuserdata_value userdata) { | ||
10256 | lua_pushlightuserdata(L, userdata); | ||
10257 | return 1; | ||
10258 | } | ||
10259 | }; | ||
10260 | |||
10261 | template <typename T> | ||
10262 | struct pusher<light<T>> { | ||
10263 | static int push(lua_State* L, light<T> l) { | ||
10264 | lua_pushlightuserdata(L, static_cast<void*>(l.value)); | ||
10265 | return 1; | ||
10266 | } | ||
10267 | }; | ||
10268 | |||
10269 | template <typename T> | ||
10270 | struct pusher<user<T>> { | ||
10271 | template <bool with_meta = true, typename Key, typename... Args> | ||
10272 | static int push_with(lua_State* L, Key&& name, Args&&... args) { | ||
10273 | // A dumb pusher | ||
10274 | T* data = detail::user_allocate<T>(L); | ||
10275 | std::allocator<T> alloc{}; | ||
10276 | std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...); | ||
10277 | if (with_meta) { | ||
10278 | // Make sure we have a plain GC set for this data | ||
10279 | if (luaL_newmetatable(L, name) != 0) { | ||
10280 | lua_CFunction cdel = detail::user_alloc_destruct<T>; | ||
10281 | lua_pushcclosure(L, cdel, 0); | ||
10282 | lua_setfield(L, -2, "__gc"); | ||
10283 | } | ||
10284 | lua_setmetatable(L, -2); | ||
10285 | } | ||
10286 | return 1; | ||
10287 | } | ||
10288 | |||
10289 | template <typename Arg, typename... Args, meta::disable<meta::any_same<meta::unqualified_t<Arg>, no_metatable_t, metatable_t>> = meta::enabler> | ||
10290 | static int push(lua_State* L, Arg&& arg, Args&&... args) { | ||
10291 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10292 | return push_with(L, name, std::forward<Arg>(arg), std::forward<Args>(args)...); | ||
10293 | } | ||
10294 | |||
10295 | template <typename... Args> | ||
10296 | static int push(lua_State* L, no_metatable_t, Args&&... args) { | ||
10297 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10298 | return push_with<false>(L, name, std::forward<Args>(args)...); | ||
10299 | } | ||
10300 | |||
10301 | template <typename Key, typename... Args> | ||
10302 | static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { | ||
10303 | const auto name = &key[0]; | ||
10304 | return push_with<true>(L, name, std::forward<Args>(args)...); | ||
10305 | } | ||
10306 | |||
10307 | static int push(lua_State* L, const user<T>& u) { | ||
10308 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10309 | return push_with(L, name, u.value); | ||
10310 | } | ||
10311 | |||
10312 | static int push(lua_State* L, user<T>&& u) { | ||
10313 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10314 | return push_with(L, name, std::move(u.value)); | ||
10315 | } | ||
10316 | |||
10317 | static int push(lua_State* L, no_metatable_t, const user<T>& u) { | ||
10318 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10319 | return push_with<false>(L, name, u.value); | ||
10320 | } | ||
10321 | |||
10322 | static int push(lua_State* L, no_metatable_t, user<T>&& u) { | ||
10323 | const auto name = &usertype_traits<meta::unqualified_t<T>>::user_gc_metatable()[0]; | ||
10324 | return push_with<false>(L, name, std::move(u.value)); | ||
10325 | } | ||
10326 | }; | ||
10327 | |||
10328 | template <> | ||
10329 | struct pusher<userdata_value> { | ||
10330 | static int push(lua_State* L, userdata_value data) { | ||
10331 | void** ud = detail::usertype_allocate_pointer<void>(L); | ||
10332 | *ud = data.value; | ||
10333 | return 1; | ||
10334 | } | ||
10335 | }; | ||
10336 | |||
10337 | template <> | ||
10338 | struct pusher<const char*> { | ||
10339 | static int push_sized(lua_State* L, const char* str, std::size_t len) { | ||
10340 | lua_pushlstring(L, str, len); | ||
10341 | return 1; | ||
10342 | } | ||
10343 | |||
10344 | static int push(lua_State* L, const char* str) { | ||
10345 | if (str == nullptr) | ||
10346 | return stack::push(L, lua_nil); | ||
10347 | return push_sized(L, str, std::char_traits<char>::length(str)); | ||
10348 | } | ||
10349 | |||
10350 | static int push(lua_State* L, const char* strb, const char* stre) { | ||
10351 | return push_sized(L, strb, stre - strb); | ||
10352 | } | ||
10353 | |||
10354 | static int push(lua_State* L, const char* str, std::size_t len) { | ||
10355 | return push_sized(L, str, len); | ||
10356 | } | ||
10357 | }; | ||
10358 | |||
10359 | template <> | ||
10360 | struct pusher<char*> { | ||
10361 | static int push_sized(lua_State* L, const char* str, std::size_t len) { | ||
10362 | pusher<const char*> p{}; | ||
10363 | (void)p; | ||
10364 | return p.push_sized(L, str, len); | ||
10365 | } | ||
10366 | |||
10367 | static int push(lua_State* L, const char* str) { | ||
10368 | pusher<const char*> p{}; | ||
10369 | (void)p; | ||
10370 | return p.push(L, str); | ||
10371 | } | ||
10372 | |||
10373 | static int push(lua_State* L, const char* strb, const char* stre) { | ||
10374 | pusher<const char*> p{}; | ||
10375 | (void)p; | ||
10376 | return p.push(L, strb, stre); | ||
10377 | } | ||
10378 | |||
10379 | static int push(lua_State* L, const char* str, std::size_t len) { | ||
10380 | pusher<const char*> p{}; | ||
10381 | (void)p; | ||
10382 | return p.push(L, str, len); | ||
10383 | } | ||
10384 | }; | ||
10385 | |||
10386 | template <size_t N> | ||
10387 | struct pusher<char[N]> { | ||
10388 | static int push(lua_State* L, const char (&str)[N]) { | ||
10389 | lua_pushlstring(L, str, N - 1); | ||
10390 | return 1; | ||
10391 | } | ||
10392 | |||
10393 | static int push(lua_State* L, const char (&str)[N], std::size_t sz) { | ||
10394 | lua_pushlstring(L, str, sz); | ||
10395 | return 1; | ||
10396 | } | ||
10397 | }; | ||
10398 | |||
10399 | template <> | ||
10400 | struct pusher<char> { | ||
10401 | static int push(lua_State* L, char c) { | ||
10402 | const char str[2] = { c, '\0' }; | ||
10403 | return stack::push(L, str, 1); | ||
10404 | } | ||
10405 | }; | ||
10406 | |||
10407 | template <typename Traits, typename Al> | ||
10408 | struct pusher<std::basic_string<char, Traits, Al>> { | ||
10409 | static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str) { | ||
10410 | lua_pushlstring(L, str.c_str(), str.size()); | ||
10411 | return 1; | ||
10412 | } | ||
10413 | |||
10414 | static int push(lua_State* L, const std::basic_string<char, Traits, Al>& str, std::size_t sz) { | ||
10415 | lua_pushlstring(L, str.c_str(), sz); | ||
10416 | return 1; | ||
10417 | } | ||
10418 | }; | ||
10419 | |||
10420 | template <typename Ch, typename Traits> | ||
10421 | struct pusher<basic_string_view<Ch, Traits>> { | ||
10422 | static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv) { | ||
10423 | return stack::push(L, sv.data(), sv.length()); | ||
10424 | } | ||
10425 | |||
10426 | static int push(lua_State* L, const basic_string_view<Ch, Traits>& sv, std::size_t n) { | ||
10427 | return stack::push(L, sv.data(), n); | ||
10428 | } | ||
10429 | }; | ||
10430 | |||
10431 | template <> | ||
10432 | struct pusher<meta_function> { | ||
10433 | static int push(lua_State* L, meta_function m) { | ||
10434 | const std::string& str = to_string(m); | ||
10435 | lua_pushlstring(L, str.c_str(), str.size()); | ||
10436 | return 1; | ||
10437 | } | ||
10438 | }; | ||
10439 | |||
10440 | template <> | ||
10441 | struct pusher<absolute_index> { | ||
10442 | static int push(lua_State* L, absolute_index ai) { | ||
10443 | lua_pushvalue(L, ai); | ||
10444 | return 1; | ||
10445 | } | ||
10446 | }; | ||
10447 | |||
10448 | template <> | ||
10449 | struct pusher<raw_index> { | ||
10450 | static int push(lua_State* L, raw_index ri) { | ||
10451 | lua_pushvalue(L, ri); | ||
10452 | return 1; | ||
10453 | } | ||
10454 | }; | ||
10455 | |||
10456 | template <> | ||
10457 | struct pusher<ref_index> { | ||
10458 | static int push(lua_State* L, ref_index ri) { | ||
10459 | lua_rawgeti(L, LUA_REGISTRYINDEX, ri); | ||
10460 | return 1; | ||
10461 | } | ||
10462 | }; | ||
10463 | |||
10464 | template <> | ||
10465 | struct pusher<const wchar_t*> { | ||
10466 | static int push(lua_State* L, const wchar_t* wstr) { | ||
10467 | return push(L, wstr, std::char_traits<wchar_t>::length(wstr)); | ||
10468 | } | ||
10469 | |||
10470 | static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { | ||
10471 | return push(L, wstr, wstr + sz); | ||
10472 | } | ||
10473 | |||
10474 | static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { | ||
10475 | if (sizeof(wchar_t) == 2) { | ||
10476 | const char16_t* sb = reinterpret_cast<const char16_t*>(strb); | ||
10477 | const char16_t* se = reinterpret_cast<const char16_t*>(stre); | ||
10478 | return stack::push(L, sb, se); | ||
10479 | } | ||
10480 | const char32_t* sb = reinterpret_cast<const char32_t*>(strb); | ||
10481 | const char32_t* se = reinterpret_cast<const char32_t*>(stre); | ||
10482 | return stack::push(L, sb, se); | ||
10483 | } | ||
10484 | }; | ||
10485 | |||
10486 | template <> | ||
10487 | struct pusher<wchar_t*> { | ||
10488 | static int push(lua_State* L, const wchar_t* str) { | ||
10489 | pusher<const wchar_t*> p{}; | ||
10490 | (void)p; | ||
10491 | return p.push(L, str); | ||
10492 | } | ||
10493 | |||
10494 | static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { | ||
10495 | pusher<const wchar_t*> p{}; | ||
10496 | (void)p; | ||
10497 | return p.push(L, strb, stre); | ||
10498 | } | ||
10499 | |||
10500 | static int push(lua_State* L, const wchar_t* str, std::size_t len) { | ||
10501 | pusher<const wchar_t*> p{}; | ||
10502 | (void)p; | ||
10503 | return p.push(L, str, len); | ||
10504 | } | ||
10505 | }; | ||
10506 | |||
10507 | template <> | ||
10508 | struct pusher<const char16_t*> { | ||
10509 | static int convert_into(lua_State* L, char* start, std::size_t, const char16_t* strb, const char16_t* stre) { | ||
10510 | char* target = start; | ||
10511 | char32_t cp = 0; | ||
10512 | for (const char16_t* strtarget = strb; strtarget < stre;) { | ||
10513 | auto dr = unicode::utf16_to_code_point(strtarget, stre); | ||
10514 | if (dr.error != unicode::error_code::ok) { | ||
10515 | cp = unicode::unicode_detail::replacement; | ||
10516 | } | ||
10517 | else { | ||
10518 | cp = dr.codepoint; | ||
10519 | } | ||
10520 | auto er = unicode::code_point_to_utf8(cp); | ||
10521 | const char* utf8data = er.code_units.data(); | ||
10522 | std::memcpy(target, utf8data, er.code_units_size); | ||
10523 | target += er.code_units_size; | ||
10524 | strtarget = dr.next; | ||
10525 | } | ||
10526 | |||
10527 | return stack::push(L, start, target); | ||
10528 | } | ||
10529 | |||
10530 | static int push(lua_State* L, const char16_t* u16str) { | ||
10531 | return push(L, u16str, std::char_traits<char16_t>::length(u16str)); | ||
10532 | } | ||
10533 | |||
10534 | static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { | ||
10535 | return push(L, u16str, u16str + sz); | ||
10536 | } | ||
10537 | |||
10538 | static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { | ||
10539 | // TODO: use new unicode methods | ||
10540 | // TODO: use new unicode methods | ||
10541 | char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; | ||
10542 | // if our max string space is small enough, use SBO | ||
10543 | // right off the bat | ||
10544 | std::size_t max_possible_code_units = (stre - strb) * 4; | ||
10545 | if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { | ||
10546 | return convert_into(L, sbo, max_possible_code_units, strb, stre); | ||
10547 | } | ||
10548 | // otherwise, we must manually count/check size | ||
10549 | std::size_t needed_size = 0; | ||
10550 | for (const char16_t* strtarget = strb; strtarget < stre;) { | ||
10551 | auto dr = unicode::utf16_to_code_point(strtarget, stre); | ||
10552 | auto er = unicode::code_point_to_utf8(dr.codepoint); | ||
10553 | needed_size += er.code_units_size; | ||
10554 | strtarget = dr.next; | ||
10555 | } | ||
10556 | if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { | ||
10557 | return convert_into(L, sbo, needed_size, strb, stre); | ||
10558 | } | ||
10559 | std::string u8str("", 0); | ||
10560 | u8str.resize(needed_size); | ||
10561 | char* target = &u8str[0]; | ||
10562 | return convert_into(L, target, needed_size, strb, stre); | ||
10563 | } | ||
10564 | }; | ||
10565 | |||
10566 | template <> | ||
10567 | struct pusher<char16_t*> { | ||
10568 | static int push(lua_State* L, const char16_t* str) { | ||
10569 | pusher<const char16_t*> p{}; | ||
10570 | (void)p; | ||
10571 | return p.push(L, str); | ||
10572 | } | ||
10573 | |||
10574 | static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { | ||
10575 | pusher<const char16_t*> p{}; | ||
10576 | (void)p; | ||
10577 | return p.push(L, strb, stre); | ||
10578 | } | ||
10579 | |||
10580 | static int push(lua_State* L, const char16_t* str, std::size_t len) { | ||
10581 | pusher<const char16_t*> p{}; | ||
10582 | (void)p; | ||
10583 | return p.push(L, str, len); | ||
10584 | } | ||
10585 | }; | ||
10586 | |||
10587 | template <> | ||
10588 | struct pusher<const char32_t*> { | ||
10589 | static int convert_into(lua_State* L, char* start, std::size_t, const char32_t* strb, const char32_t* stre) { | ||
10590 | char* target = start; | ||
10591 | char32_t cp = 0; | ||
10592 | for (const char32_t* strtarget = strb; strtarget < stre;) { | ||
10593 | auto dr = unicode::utf32_to_code_point(strtarget, stre); | ||
10594 | if (dr.error != unicode::error_code::ok) { | ||
10595 | cp = unicode::unicode_detail::replacement; | ||
10596 | } | ||
10597 | else { | ||
10598 | cp = dr.codepoint; | ||
10599 | } | ||
10600 | auto er = unicode::code_point_to_utf8(cp); | ||
10601 | const char* data = er.code_units.data(); | ||
10602 | std::memcpy(target, data, er.code_units_size); | ||
10603 | target += er.code_units_size; | ||
10604 | strtarget = dr.next; | ||
10605 | } | ||
10606 | return stack::push(L, start, target); | ||
10607 | } | ||
10608 | |||
10609 | static int push(lua_State* L, const char32_t* u32str) { | ||
10610 | return push(L, u32str, u32str + std::char_traits<char32_t>::length(u32str)); | ||
10611 | } | ||
10612 | |||
10613 | static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { | ||
10614 | return push(L, u32str, u32str + sz); | ||
10615 | } | ||
10616 | |||
10617 | static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { | ||
10618 | // TODO: use new unicode methods | ||
10619 | char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; | ||
10620 | // if our max string space is small enough, use SBO | ||
10621 | // right off the bat | ||
10622 | std::size_t max_possible_code_units = (stre - strb) * 4; | ||
10623 | if (max_possible_code_units <= SOL_STACK_STRING_OPTIMIZATION_SIZE) { | ||
10624 | return convert_into(L, sbo, max_possible_code_units, strb, stre); | ||
10625 | } | ||
10626 | // otherwise, we must manually count/check size | ||
10627 | std::size_t needed_size = 0; | ||
10628 | for (const char32_t* strtarget = strb; strtarget < stre;) { | ||
10629 | auto dr = unicode::utf32_to_code_point(strtarget, stre); | ||
10630 | auto er = unicode::code_point_to_utf8(dr.codepoint); | ||
10631 | needed_size += er.code_units_size; | ||
10632 | strtarget = dr.next; | ||
10633 | } | ||
10634 | if (needed_size < SOL_STACK_STRING_OPTIMIZATION_SIZE) { | ||
10635 | return convert_into(L, sbo, needed_size, strb, stre); | ||
10636 | } | ||
10637 | std::string u8str("", 0); | ||
10638 | u8str.resize(needed_size); | ||
10639 | char* target = &u8str[0]; | ||
10640 | return convert_into(L, target, needed_size, strb, stre); | ||
10641 | } | ||
10642 | }; | ||
10643 | |||
10644 | template <> | ||
10645 | struct pusher<char32_t*> { | ||
10646 | static int push(lua_State* L, const char32_t* str) { | ||
10647 | pusher<const char32_t*> p{}; | ||
10648 | (void)p; | ||
10649 | return p.push(L, str); | ||
10650 | } | ||
10651 | |||
10652 | static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { | ||
10653 | pusher<const char32_t*> p{}; | ||
10654 | (void)p; | ||
10655 | return p.push(L, strb, stre); | ||
10656 | } | ||
10657 | |||
10658 | static int push(lua_State* L, const char32_t* str, std::size_t len) { | ||
10659 | pusher<const char32_t*> p{}; | ||
10660 | (void)p; | ||
10661 | return p.push(L, str, len); | ||
10662 | } | ||
10663 | }; | ||
10664 | |||
10665 | template <size_t N> | ||
10666 | struct pusher<wchar_t[N]> { | ||
10667 | static int push(lua_State* L, const wchar_t (&str)[N]) { | ||
10668 | return push(L, str, N - 1); | ||
10669 | } | ||
10670 | |||
10671 | static int push(lua_State* L, const wchar_t (&str)[N], std::size_t sz) { | ||
10672 | return stack::push<const wchar_t*>(L, str, str + sz); | ||
10673 | } | ||
10674 | }; | ||
10675 | |||
10676 | template <size_t N> | ||
10677 | struct pusher<char16_t[N]> { | ||
10678 | static int push(lua_State* L, const char16_t (&str)[N]) { | ||
10679 | return push(L, str, N - 1); | ||
10680 | } | ||
10681 | |||
10682 | static int push(lua_State* L, const char16_t (&str)[N], std::size_t sz) { | ||
10683 | return stack::push<const char16_t*>(L, str, str + sz); | ||
10684 | } | ||
10685 | }; | ||
10686 | |||
10687 | template <size_t N> | ||
10688 | struct pusher<char32_t[N]> { | ||
10689 | static int push(lua_State* L, const char32_t (&str)[N]) { | ||
10690 | return push(L, str, N - 1); | ||
10691 | } | ||
10692 | |||
10693 | static int push(lua_State* L, const char32_t (&str)[N], std::size_t sz) { | ||
10694 | return stack::push<const char32_t*>(L, str, str + sz); | ||
10695 | } | ||
10696 | }; | ||
10697 | |||
10698 | template <> | ||
10699 | struct pusher<wchar_t> { | ||
10700 | static int push(lua_State* L, wchar_t c) { | ||
10701 | const wchar_t str[2] = { c, '\0' }; | ||
10702 | return stack::push(L, &str[0], 1); | ||
10703 | } | ||
10704 | }; | ||
10705 | |||
10706 | template <> | ||
10707 | struct pusher<char16_t> { | ||
10708 | static int push(lua_State* L, char16_t c) { | ||
10709 | const char16_t str[2] = { c, '\0' }; | ||
10710 | return stack::push(L, &str[0], 1); | ||
10711 | } | ||
10712 | }; | ||
10713 | |||
10714 | template <> | ||
10715 | struct pusher<char32_t> { | ||
10716 | static int push(lua_State* L, char32_t c) { | ||
10717 | const char32_t str[2] = { c, '\0' }; | ||
10718 | return stack::push(L, &str[0], 1); | ||
10719 | } | ||
10720 | }; | ||
10721 | |||
10722 | template <typename Ch, typename Traits, typename Al> | ||
10723 | struct pusher<std::basic_string<Ch, Traits, Al>, std::enable_if_t<!std::is_same<Ch, char>::value>> { | ||
10724 | static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr) { | ||
10725 | return push(L, wstr, wstr.size()); | ||
10726 | } | ||
10727 | |||
10728 | static int push(lua_State* L, const std::basic_string<Ch, Traits, Al>& wstr, std::size_t sz) { | ||
10729 | return stack::push(L, wstr.data(), wstr.data() + sz); | ||
10730 | } | ||
10731 | }; | ||
10732 | |||
10733 | template <typename... Args> | ||
10734 | struct pusher<std::tuple<Args...>> { | ||
10735 | template <std::size_t... I, typename T> | ||
10736 | static int push(std::index_sequence<I...>, lua_State* L, T&& t) { | ||
10737 | int pushcount = 0; | ||
10738 | (void)detail::swallow{ 0, (pushcount += stack::push(L, detail::forward_get<I>(t)), 0)... }; | ||
10739 | return pushcount; | ||
10740 | } | ||
10741 | |||
10742 | template <typename T> | ||
10743 | static int push(lua_State* L, T&& t) { | ||
10744 | return push(std::index_sequence_for<Args...>(), L, std::forward<T>(t)); | ||
10745 | } | ||
10746 | }; | ||
10747 | |||
10748 | template <typename A, typename B> | ||
10749 | struct pusher<std::pair<A, B>> { | ||
10750 | template <typename T> | ||
10751 | static int push(lua_State* L, T&& t) { | ||
10752 | int pushcount = stack::push(L, detail::forward_get<0>(t)); | ||
10753 | pushcount += stack::push(L, detail::forward_get<1>(t)); | ||
10754 | return pushcount; | ||
10755 | } | ||
10756 | }; | ||
10757 | |||
10758 | template <typename O> | ||
10759 | struct pusher<optional<O>> { | ||
10760 | template <typename T> | ||
10761 | static int push(lua_State* L, T&& t) { | ||
10762 | if (t == nullopt) { | ||
10763 | return stack::push(L, nullopt); | ||
10764 | } | ||
10765 | return stack::push(L, static_cast<std::conditional_t<std::is_lvalue_reference<T>::value, O&, O&&>>(t.value())); | ||
10766 | } | ||
10767 | }; | ||
10768 | |||
10769 | template <> | ||
10770 | struct pusher<nullopt_t> { | ||
10771 | static int push(lua_State* L, nullopt_t) { | ||
10772 | return stack::push(L, lua_nil); | ||
10773 | } | ||
10774 | }; | ||
10775 | |||
10776 | template <> | ||
10777 | struct pusher<std::nullptr_t> { | ||
10778 | static int push(lua_State* L, std::nullptr_t) { | ||
10779 | return stack::push(L, lua_nil); | ||
10780 | } | ||
10781 | }; | ||
10782 | |||
10783 | template <> | ||
10784 | struct pusher<this_state> { | ||
10785 | static int push(lua_State*, const this_state&) { | ||
10786 | return 0; | ||
10787 | } | ||
10788 | }; | ||
10789 | |||
10790 | template <> | ||
10791 | struct pusher<this_main_state> { | ||
10792 | static int push(lua_State*, const this_main_state&) { | ||
10793 | return 0; | ||
10794 | } | ||
10795 | }; | ||
10796 | |||
10797 | template <> | ||
10798 | struct pusher<new_table> { | ||
10799 | static int push(lua_State* L, const new_table& nt) { | ||
10800 | lua_createtable(L, nt.sequence_hint, nt.map_hint); | ||
10801 | return 1; | ||
10802 | } | ||
10803 | }; | ||
10804 | |||
10805 | #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES | ||
10806 | #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT | ||
10807 | namespace stack_detail { | ||
10808 | |||
10809 | struct push_function { | ||
10810 | lua_State* L; | ||
10811 | |||
10812 | push_function(lua_State* L) | ||
10813 | : L(L) { | ||
10814 | } | ||
10815 | |||
10816 | template <typename T> | ||
10817 | int operator()(T&& value) const { | ||
10818 | return stack::push<T>(L, std::forward<T>(value)); | ||
10819 | } | ||
10820 | }; | ||
10821 | |||
10822 | } // namespace stack_detail | ||
10823 | |||
10824 | template <typename... Tn> | ||
10825 | struct pusher<std::variant<Tn...>> { | ||
10826 | static int push(lua_State* L, const std::variant<Tn...>& v) { | ||
10827 | return std::visit(stack_detail::push_function(L), v); | ||
10828 | } | ||
10829 | |||
10830 | static int push(lua_State* L, std::variant<Tn...>&& v) { | ||
10831 | return std::visit(stack_detail::push_function(L), std::move(v)); | ||
10832 | } | ||
10833 | }; | ||
10834 | #endif // Variant because Clang is terrible | ||
10835 | #endif // C++17 Support | ||
10836 | } | ||
10837 | } // namespace sol::stack | ||
10838 | |||
10839 | // end of sol/stack_push.hpp | ||
10840 | |||
10841 | // beginning of sol/stack_pop.hpp | ||
10842 | |||
10843 | namespace sol { | ||
10844 | namespace stack { | ||
10845 | template <typename T, typename> | ||
10846 | struct popper { | ||
10847 | inline static decltype(auto) pop(lua_State* L) { | ||
10848 | record tracking{}; | ||
10849 | #ifdef __INTEL_COMPILER | ||
10850 | auto&& r = get<T>(L, -lua_size<T>::value, tracking); | ||
10851 | #else | ||
10852 | decltype(auto) r = get<T>(L, -lua_size<T>::value, tracking); | ||
10853 | #endif | ||
10854 | lua_pop(L, tracking.used); | ||
10855 | return r; | ||
10856 | } | ||
10857 | }; | ||
10858 | |||
10859 | template <typename T> | ||
10860 | struct popper<T, std::enable_if_t<is_stack_based<meta::unqualified_t<T>>::value>> { | ||
10861 | static_assert(meta::neg<is_stack_based<meta::unqualified_t<T>>>::value, "You cannot pop something that lives solely on the stack: it will not remain on the stack when popped and thusly will go out of scope!"); | ||
10862 | }; | ||
10863 | } | ||
10864 | } // namespace sol::stack | ||
10865 | |||
10866 | // end of sol/stack_pop.hpp | ||
10867 | |||
10868 | // beginning of sol/stack_field.hpp | ||
10869 | |||
10870 | namespace sol { | ||
10871 | namespace stack { | ||
10872 | template <typename T, bool, bool, typename> | ||
10873 | struct field_getter { | ||
10874 | template <typename Key> | ||
10875 | void get(lua_State* L, Key&& key, int tableindex = -2) { | ||
10876 | push(L, std::forward<Key>(key)); | ||
10877 | lua_gettable(L, tableindex); | ||
10878 | } | ||
10879 | }; | ||
10880 | |||
10881 | template <typename T, bool global, typename C> | ||
10882 | struct field_getter<T, global, true, C> { | ||
10883 | template <typename Key> | ||
10884 | void get(lua_State* L, Key&& key, int tableindex = -2) { | ||
10885 | push(L, std::forward<Key>(key)); | ||
10886 | lua_rawget(L, tableindex); | ||
10887 | } | ||
10888 | }; | ||
10889 | |||
10890 | template <bool b, bool raw, typename C> | ||
10891 | struct field_getter<metatable_t, b, raw, C> { | ||
10892 | void get(lua_State* L, metatable_t, int tableindex = -1) { | ||
10893 | if (lua_getmetatable(L, tableindex) == 0) | ||
10894 | push(L, lua_nil); | ||
10895 | } | ||
10896 | }; | ||
10897 | |||
10898 | template <bool b, bool raw, typename C> | ||
10899 | struct field_getter<env_t, b, raw, C> { | ||
10900 | void get(lua_State* L, env_t, int tableindex = -1) { | ||
10901 | #if SOL_LUA_VERSION < 502 | ||
10902 | // Use lua_setfenv | ||
10903 | lua_getfenv(L, tableindex); | ||
10904 | #else | ||
10905 | // Use upvalues as explained in Lua 5.2 and beyond's manual | ||
10906 | if (lua_getupvalue(L, tableindex, 1) == nullptr) { | ||
10907 | push(L, lua_nil); | ||
10908 | } | ||
10909 | #endif | ||
10910 | } | ||
10911 | }; | ||
10912 | |||
10913 | template <typename T, bool raw> | ||
10914 | struct field_getter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> { | ||
10915 | template <typename Key> | ||
10916 | void get(lua_State* L, Key&& key, int = -1) { | ||
10917 | lua_getglobal(L, &key[0]); | ||
10918 | } | ||
10919 | }; | ||
10920 | |||
10921 | template <typename T> | ||
10922 | struct field_getter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> { | ||
10923 | template <typename Key> | ||
10924 | void get(lua_State* L, Key&& key, int tableindex = -1) { | ||
10925 | lua_getfield(L, tableindex, &key[0]); | ||
10926 | } | ||
10927 | }; | ||
10928 | |||
10929 | #if SOL_LUA_VERSION >= 503 | ||
10930 | template <typename T> | ||
10931 | struct field_getter<T, false, false, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> { | ||
10932 | template <typename Key> | ||
10933 | void get(lua_State* L, Key&& key, int tableindex = -1) { | ||
10934 | lua_geti(L, tableindex, static_cast<lua_Integer>(key)); | ||
10935 | } | ||
10936 | }; | ||
10937 | #endif // Lua 5.3.x | ||
10938 | |||
10939 | #if SOL_LUA_VERSION >= 502 | ||
10940 | template <typename C> | ||
10941 | struct field_getter<void*, false, true, C> { | ||
10942 | void get(lua_State* L, void* key, int tableindex = -1) { | ||
10943 | lua_rawgetp(L, tableindex, key); | ||
10944 | } | ||
10945 | }; | ||
10946 | #endif // Lua 5.3.x | ||
10947 | |||
10948 | template <typename T> | ||
10949 | struct field_getter<T, false, true, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> { | ||
10950 | template <typename Key> | ||
10951 | void get(lua_State* L, Key&& key, int tableindex = -1) { | ||
10952 | lua_rawgeti(L, tableindex, static_cast<lua_Integer>(key)); | ||
10953 | } | ||
10954 | }; | ||
10955 | |||
10956 | template <typename... Args, bool b, bool raw, typename C> | ||
10957 | struct field_getter<std::tuple<Args...>, b, raw, C> { | ||
10958 | template <std::size_t... I, typename Keys> | ||
10959 | void apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) { | ||
10960 | get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex); | ||
10961 | void(detail::swallow{(get_field<false, raw>(L, detail::forward_get<I>(keys)), 0)...}); | ||
10962 | reference saved(L, -1); | ||
10963 | lua_pop(L, static_cast<int>(sizeof...(I))); | ||
10964 | saved.push(); | ||
10965 | } | ||
10966 | |||
10967 | template <typename Keys> | ||
10968 | void get(lua_State* L, Keys&& keys) { | ||
10969 | apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), lua_absindex(L, -1)); | ||
10970 | } | ||
10971 | |||
10972 | template <typename Keys> | ||
10973 | void get(lua_State* L, Keys&& keys, int tableindex) { | ||
10974 | apply(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), tableindex); | ||
10975 | } | ||
10976 | }; | ||
10977 | |||
10978 | template <typename A, typename B, bool b, bool raw, typename C> | ||
10979 | struct field_getter<std::pair<A, B>, b, raw, C> { | ||
10980 | template <typename Keys> | ||
10981 | void get(lua_State* L, Keys&& keys, int tableindex) { | ||
10982 | get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex); | ||
10983 | get_field<false, raw>(L, detail::forward_get<1>(keys)); | ||
10984 | reference saved(L, -1); | ||
10985 | lua_pop(L, static_cast<int>(2)); | ||
10986 | saved.push(); | ||
10987 | } | ||
10988 | |||
10989 | template <typename Keys> | ||
10990 | void get(lua_State* L, Keys&& keys) { | ||
10991 | get_field<b, raw>(L, detail::forward_get<0>(keys)); | ||
10992 | get_field<false, raw>(L, detail::forward_get<1>(keys)); | ||
10993 | reference saved(L, -1); | ||
10994 | lua_pop(L, static_cast<int>(2)); | ||
10995 | saved.push(); | ||
10996 | } | ||
10997 | }; | ||
10998 | |||
10999 | template <typename T, bool, bool, typename> | ||
11000 | struct field_setter { | ||
11001 | template <typename Key, typename Value> | ||
11002 | void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { | ||
11003 | push(L, std::forward<Key>(key)); | ||
11004 | push(L, std::forward<Value>(value)); | ||
11005 | lua_settable(L, tableindex); | ||
11006 | } | ||
11007 | }; | ||
11008 | |||
11009 | template <typename T, bool b, typename C> | ||
11010 | struct field_setter<T, b, true, C> { | ||
11011 | template <typename Key, typename Value> | ||
11012 | void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { | ||
11013 | push(L, std::forward<Key>(key)); | ||
11014 | push(L, std::forward<Value>(value)); | ||
11015 | lua_rawset(L, tableindex); | ||
11016 | } | ||
11017 | }; | ||
11018 | |||
11019 | template <bool b, bool raw, typename C> | ||
11020 | struct field_setter<metatable_t, b, raw, C> { | ||
11021 | template <typename Value> | ||
11022 | void set(lua_State* L, metatable_t, Value&& value, int tableindex = -2) { | ||
11023 | push(L, std::forward<Value>(value)); | ||
11024 | lua_setmetatable(L, tableindex); | ||
11025 | } | ||
11026 | }; | ||
11027 | |||
11028 | template <typename T, bool raw> | ||
11029 | struct field_setter<T, true, raw, std::enable_if_t<meta::is_c_str<T>::value>> { | ||
11030 | template <typename Key, typename Value> | ||
11031 | void set(lua_State* L, Key&& key, Value&& value, int = -2) { | ||
11032 | push(L, std::forward<Value>(value)); | ||
11033 | lua_setglobal(L, &key[0]); | ||
11034 | } | ||
11035 | }; | ||
11036 | |||
11037 | template <typename T> | ||
11038 | struct field_setter<T, false, false, std::enable_if_t<meta::is_c_str<T>::value>> { | ||
11039 | template <typename Key, typename Value> | ||
11040 | void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { | ||
11041 | push(L, std::forward<Value>(value)); | ||
11042 | lua_setfield(L, tableindex, &key[0]); | ||
11043 | } | ||
11044 | }; | ||
11045 | |||
11046 | #if SOL_LUA_VERSION >= 503 | ||
11047 | template <typename T> | ||
11048 | struct field_setter<T, false, false, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> { | ||
11049 | template <typename Key, typename Value> | ||
11050 | void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { | ||
11051 | push(L, std::forward<Value>(value)); | ||
11052 | lua_seti(L, tableindex, static_cast<lua_Integer>(key)); | ||
11053 | } | ||
11054 | }; | ||
11055 | #endif // Lua 5.3.x | ||
11056 | |||
11057 | template <typename T> | ||
11058 | struct field_setter<T, false, true, std::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>> { | ||
11059 | template <typename Key, typename Value> | ||
11060 | void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { | ||
11061 | push(L, std::forward<Value>(value)); | ||
11062 | lua_rawseti(L, tableindex, static_cast<lua_Integer>(key)); | ||
11063 | } | ||
11064 | }; | ||
11065 | |||
11066 | #if SOL_LUA_VERSION >= 502 | ||
11067 | template <typename C> | ||
11068 | struct field_setter<void*, false, true, C> { | ||
11069 | template <typename Key, typename Value> | ||
11070 | void set(lua_State* L, void* key, Value&& value, int tableindex = -2) { | ||
11071 | push(L, std::forward<Value>(value)); | ||
11072 | lua_rawsetp(L, tableindex, key); | ||
11073 | } | ||
11074 | }; | ||
11075 | #endif // Lua 5.2.x | ||
11076 | |||
11077 | template <typename... Args, bool b, bool raw, typename C> | ||
11078 | struct field_setter<std::tuple<Args...>, b, raw, C> { | ||
11079 | template <bool g, std::size_t I, typename Key, typename Value> | ||
11080 | void apply(std::index_sequence<I>, lua_State* L, Key&& keys, Value&& value, int tableindex) { | ||
11081 | I < 1 ? set_field<g, raw>(L, detail::forward_get<I>(keys), std::forward<Value>(value), tableindex) : set_field<g, raw>(L, detail::forward_get<I>(keys), std::forward<Value>(value)); | ||
11082 | } | ||
11083 | |||
11084 | template <bool g, std::size_t I0, std::size_t I1, std::size_t... I, typename Keys, typename Value> | ||
11085 | void apply(std::index_sequence<I0, I1, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) { | ||
11086 | I0 < 1 ? get_field<g, raw>(L, detail::forward_get<I0>(keys), tableindex) : get_field<g, raw>(L, detail::forward_get<I0>(keys), -1); | ||
11087 | apply<false>(std::index_sequence<I1, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), -1); | ||
11088 | } | ||
11089 | |||
11090 | template <bool g, std::size_t I0, std::size_t... I, typename Keys, typename Value> | ||
11091 | void top_apply(std::index_sequence<I0, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) { | ||
11092 | apply<g>(std::index_sequence<I0, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex); | ||
11093 | lua_pop(L, static_cast<int>(sizeof...(I))); | ||
11094 | } | ||
11095 | |||
11096 | template <typename Keys, typename Value> | ||
11097 | void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) { | ||
11098 | top_apply<b>(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex); | ||
11099 | } | ||
11100 | }; | ||
11101 | |||
11102 | template <typename A, typename B, bool b, bool raw, typename C> | ||
11103 | struct field_setter<std::pair<A, B>, b, raw, C> { | ||
11104 | template <typename Keys, typename Value> | ||
11105 | void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) { | ||
11106 | get_field<b, raw>(L, detail::forward_get<0>(keys), tableindex); | ||
11107 | set_field<false, raw>(L, detail::forward_get<1>(keys), std::forward<Value>(value)); | ||
11108 | lua_pop(L, 1); | ||
11109 | } | ||
11110 | }; | ||
11111 | } | ||
11112 | } // namespace sol::stack | ||
11113 | |||
11114 | // end of sol/stack_field.hpp | ||
11115 | |||
11116 | // beginning of sol/stack_probe.hpp | ||
11117 | |||
11118 | namespace sol { | ||
11119 | namespace stack { | ||
11120 | template <typename T, bool b, bool raw, typename> | ||
11121 | struct probe_field_getter { | ||
11122 | template <typename Key> | ||
11123 | probe get(lua_State* L, Key&& key, int tableindex = -2) { | ||
11124 | if (!b && !maybe_indexable(L, tableindex)) { | ||
11125 | return probe(false, 0); | ||
11126 | } | ||
11127 | get_field<b, raw>(L, std::forward<Key>(key), tableindex); | ||
11128 | return probe(!check<lua_nil_t>(L), 1); | ||
11129 | } | ||
11130 | }; | ||
11131 | |||
11132 | template <typename A, typename B, bool b, bool raw, typename C> | ||
11133 | struct probe_field_getter<std::pair<A, B>, b, raw, C> { | ||
11134 | template <typename Keys> | ||
11135 | probe get(lua_State* L, Keys&& keys, int tableindex = -2) { | ||
11136 | if (!b && !maybe_indexable(L, tableindex)) { | ||
11137 | return probe(false, 0); | ||
11138 | } | ||
11139 | get_field<b, raw>(L, std::get<0>(keys), tableindex); | ||
11140 | if (!maybe_indexable(L)) { | ||
11141 | return probe(false, 1); | ||
11142 | } | ||
11143 | get_field<false, raw>(L, std::get<1>(keys), tableindex); | ||
11144 | return probe(!check<lua_nil_t>(L), 2); | ||
11145 | } | ||
11146 | }; | ||
11147 | |||
11148 | template <typename... Args, bool b, bool raw, typename C> | ||
11149 | struct probe_field_getter<std::tuple<Args...>, b, raw, C> { | ||
11150 | template <std::size_t I, typename Keys> | ||
11151 | probe apply(std::index_sequence<I>, int sofar, lua_State* L, Keys&& keys, int tableindex) { | ||
11152 | get_field < I<1 && b, raw>(L, std::get<I>(keys), tableindex); | ||
11153 | return probe(!check<lua_nil_t>(L), sofar); | ||
11154 | } | ||
11155 | |||
11156 | template <std::size_t I, std::size_t I1, std::size_t... In, typename Keys> | ||
11157 | probe apply(std::index_sequence<I, I1, In...>, int sofar, lua_State* L, Keys&& keys, int tableindex) { | ||
11158 | get_field < I<1 && b, raw>(L, std::get<I>(keys), tableindex); | ||
11159 | if (!maybe_indexable(L)) { | ||
11160 | return probe(false, sofar); | ||
11161 | } | ||
11162 | return apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), -1); | ||
11163 | } | ||
11164 | |||
11165 | template <typename Keys> | ||
11166 | probe get(lua_State* L, Keys&& keys, int tableindex = -2) { | ||
11167 | if (!b && !maybe_indexable(L, tableindex)) { | ||
11168 | return probe(false, 0); | ||
11169 | } | ||
11170 | return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex); | ||
11171 | } | ||
11172 | }; | ||
11173 | } | ||
11174 | } // namespace sol::stack | ||
11175 | |||
11176 | // end of sol/stack_probe.hpp | ||
11177 | |||
11178 | namespace sol { | ||
11179 | namespace detail { | ||
11180 | using typical_chunk_name_t = char[32]; | ||
11181 | |||
11182 | inline const std::string& default_chunk_name() { | ||
11183 | static const std::string name = ""; | ||
11184 | return name; | ||
11185 | } | ||
11186 | |||
11187 | template <std::size_t N> | ||
11188 | const char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) { | ||
11189 | if (chunkname.empty()) { | ||
11190 | auto it = code.cbegin(); | ||
11191 | auto e = code.cend(); | ||
11192 | std::size_t i = 0; | ||
11193 | static const std::size_t n = N - 4; | ||
11194 | for (i = 0; i < n && it != e; ++i, ++it) { | ||
11195 | basechunkname[i] = *it; | ||
11196 | } | ||
11197 | if (it != e) { | ||
11198 | for (std::size_t c = 0; c < 3; ++i, ++c) { | ||
11199 | basechunkname[i] = '.'; | ||
11200 | } | ||
11201 | } | ||
11202 | basechunkname[i] = '\0'; | ||
11203 | return &basechunkname[0]; | ||
11204 | } | ||
11205 | else { | ||
11206 | return chunkname.c_str(); | ||
11207 | } | ||
11208 | } | ||
11209 | } // namespace detail | ||
11210 | |||
11211 | namespace stack { | ||
11212 | namespace stack_detail { | ||
11213 | template <typename T> | ||
11214 | inline int push_as_upvalues(lua_State* L, T& item) { | ||
11215 | typedef std::decay_t<T> TValue; | ||
11216 | static const std::size_t itemsize = sizeof(TValue); | ||
11217 | static const std::size_t voidsize = sizeof(void*); | ||
11218 | static const std::size_t voidsizem1 = voidsize - 1; | ||
11219 | static const std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; | ||
11220 | typedef std::array<void*, data_t_count> data_t; | ||
11221 | |||
11222 | data_t data{ {} }; | ||
11223 | std::memcpy(&data[0], std::addressof(item), itemsize); | ||
11224 | int pushcount = 0; | ||
11225 | for (auto&& v : data) { | ||
11226 | pushcount += push(L, lightuserdata_value(v)); | ||
11227 | } | ||
11228 | return pushcount; | ||
11229 | } | ||
11230 | |||
11231 | template <typename T> | ||
11232 | inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 2) { | ||
11233 | static const std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); | ||
11234 | typedef std::array<void*, data_t_count> data_t; | ||
11235 | data_t voiddata{ {} }; | ||
11236 | for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { | ||
11237 | voiddata[i] = get<lightuserdata_value>(L, upvalue_index(index++)); | ||
11238 | } | ||
11239 | return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); | ||
11240 | } | ||
11241 | |||
11242 | struct evaluator { | ||
11243 | template <typename Fx, typename... Args> | ||
11244 | static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) { | ||
11245 | return std::forward<Fx>(fx)(std::forward<Args>(args)...); | ||
11246 | } | ||
11247 | |||
11248 | template <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs> | ||
11249 | static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) { | ||
11250 | return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking)); | ||
11251 | } | ||
11252 | }; | ||
11253 | |||
11254 | template <bool checkargs = detail::default_safe_function_calls , std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value >> | ||
11255 | inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { | ||
11256 | #ifndef _MSC_VER | ||
11257 | static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); | ||
11258 | #endif // This compiler make me so sad | ||
11259 | argument_handler<types<R, Args...>> handler{}; | ||
11260 | multi_check<checkargs, Args...>(L, start, handler); | ||
11261 | record tracking{}; | ||
11262 | return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11263 | } | ||
11264 | |||
11265 | template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename... Args, typename Fx, typename... FxArgs> | ||
11266 | inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { | ||
11267 | #ifndef _MSC_VER | ||
11268 | static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); | ||
11269 | #endif // This compiler make me so fucking sad | ||
11270 | argument_handler<types<void, Args...>> handler{}; | ||
11271 | multi_check<checkargs, Args...>(L, start, handler); | ||
11272 | record tracking{}; | ||
11273 | evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11274 | } | ||
11275 | } // namespace stack_detail | ||
11276 | |||
11277 | template <typename T> | ||
11278 | int set_ref(lua_State* L, T&& arg, int tableindex = -2) { | ||
11279 | push(L, std::forward<T>(arg)); | ||
11280 | return luaL_ref(L, tableindex); | ||
11281 | } | ||
11282 | |||
11283 | template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> | ||
11284 | inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { | ||
11285 | typedef std::make_index_sequence<sizeof...(Args)> args_indices; | ||
11286 | return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11287 | } | ||
11288 | |||
11289 | template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> | ||
11290 | inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { | ||
11291 | return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11292 | } | ||
11293 | |||
11294 | template <bool check_args = detail::default_safe_function_calls, typename... Args, typename Fx, typename... FxArgs> | ||
11295 | inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { | ||
11296 | typedef std::make_index_sequence<sizeof...(Args)> args_indices; | ||
11297 | stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11298 | } | ||
11299 | |||
11300 | template <bool check_args = detail::default_safe_function_calls, typename... Args, typename Fx, typename... FxArgs> | ||
11301 | inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { | ||
11302 | call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11303 | } | ||
11304 | |||
11305 | template <bool check_args = detail::default_safe_function_calls, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> | ||
11306 | inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { | ||
11307 | typedef meta::count_for_pack<lua_size, Args...> expected_count; | ||
11308 | return call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11309 | } | ||
11310 | |||
11311 | template <bool check_args = detail::default_safe_function_calls, typename... Args, typename Fx, typename... FxArgs> | ||
11312 | inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) { | ||
11313 | typedef meta::count_for_pack<lua_size, Args...> expected_count; | ||
11314 | call<check_args>(tr, ta, L, (std::max)(static_cast<int>(lua_gettop(L) - expected_count::value), static_cast<int>(0)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...); | ||
11315 | } | ||
11316 | |||
11317 | template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename... Args, typename Fx, typename... FxArgs> | ||
11318 | inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { | ||
11319 | call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); | ||
11320 | if (clean_stack) { | ||
11321 | lua_settop(L, 0); | ||
11322 | } | ||
11323 | return 0; | ||
11324 | } | ||
11325 | |||
11326 | template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>> | ||
11327 | inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { | ||
11328 | decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); | ||
11329 | typedef meta::unqualified_t<decltype(r)> R; | ||
11330 | typedef meta::any<is_stack_based<R>, | ||
11331 | std::is_same<R, absolute_index>, | ||
11332 | std::is_same<R, ref_index>, | ||
11333 | std::is_same<R, raw_index>> | ||
11334 | is_stack; | ||
11335 | if (clean_stack && !is_stack::value) { | ||
11336 | lua_settop(L, 0); | ||
11337 | } | ||
11338 | return push_reference(L, std::forward<decltype(r)>(r)); | ||
11339 | } | ||
11340 | |||
11341 | template <bool check_args = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... FxArgs> | ||
11342 | inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { | ||
11343 | typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type; | ||
11344 | typedef typename traits_type::args_list args_list; | ||
11345 | typedef typename traits_type::returns_list returns_list; | ||
11346 | return call_into_lua<check_args, clean_stack>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...); | ||
11347 | } | ||
11348 | |||
11349 | inline call_syntax get_call_syntax(lua_State* L, const string_view& key, int index) { | ||
11350 | if (lua_gettop(L) == 0) { | ||
11351 | return call_syntax::dot; | ||
11352 | } | ||
11353 | luaL_getmetatable(L, key.data()); | ||
11354 | auto pn = pop_n(L, 1); | ||
11355 | if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { | ||
11356 | return call_syntax::dot; | ||
11357 | } | ||
11358 | return call_syntax::colon; | ||
11359 | } | ||
11360 | |||
11361 | inline void script(lua_State* L, const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
11362 | detail::typical_chunk_name_t basechunkname = {}; | ||
11363 | const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); | ||
11364 | if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { | ||
11365 | lua_error(L); | ||
11366 | } | ||
11367 | } | ||
11368 | |||
11369 | inline void script_file(lua_State* L, const std::string& filename, load_mode mode = load_mode::any) { | ||
11370 | if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { | ||
11371 | lua_error(L); | ||
11372 | } | ||
11373 | } | ||
11374 | |||
11375 | inline void luajit_exception_handler(lua_State* L, int (*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { | ||
11376 | #if defined(SOL_LUAJIT) && !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) | ||
11377 | if (L == nullptr) { | ||
11378 | return; | ||
11379 | } | ||
11380 | lua_pushlightuserdata(L, (void*)handler); | ||
11381 | auto pn = pop_n(L, 1); | ||
11382 | luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); | ||
11383 | #else | ||
11384 | (void)L; | ||
11385 | (void)handler; | ||
11386 | #endif | ||
11387 | } | ||
11388 | |||
11389 | inline void luajit_exception_off(lua_State* L) { | ||
11390 | #if defined(SOL_LUAJIT) | ||
11391 | if (L == nullptr) { | ||
11392 | return; | ||
11393 | } | ||
11394 | luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); | ||
11395 | #else | ||
11396 | (void)L; | ||
11397 | #endif | ||
11398 | } | ||
11399 | } // namespace stack | ||
11400 | } // namespace sol | ||
11401 | |||
11402 | // end of sol/stack.hpp | ||
11403 | |||
11404 | // beginning of sol/unsafe_function.hpp | ||
11405 | |||
11406 | // beginning of sol/function_result.hpp | ||
11407 | |||
11408 | // beginning of sol/protected_function_result.hpp | ||
11409 | |||
11410 | // beginning of sol/proxy_base.hpp | ||
11411 | |||
11412 | namespace sol { | ||
11413 | struct proxy_base_tag {}; | ||
11414 | |||
11415 | template <typename Super> | ||
11416 | struct proxy_base : proxy_base_tag { | ||
11417 | operator std::string() const { | ||
11418 | const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); | ||
11419 | return super.template get<std::string>(); | ||
11420 | } | ||
11421 | |||
11422 | template <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, is_proxy_primitive<meta::unqualified_t<T>>> = meta::enabler> | ||
11423 | operator T() const { | ||
11424 | const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); | ||
11425 | return super.template get<T>(); | ||
11426 | } | ||
11427 | |||
11428 | template <typename T, meta::enable<meta::neg<meta::is_string_constructible<T>>, meta::neg<is_proxy_primitive<meta::unqualified_t<T>>>> = meta::enabler> | ||
11429 | operator T&() const { | ||
11430 | const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); | ||
11431 | return super.template get<T&>(); | ||
11432 | } | ||
11433 | |||
11434 | lua_State* lua_state() const { | ||
11435 | const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); | ||
11436 | return super.lua_state(); | ||
11437 | } | ||
11438 | }; | ||
11439 | } // namespace sol | ||
11440 | |||
11441 | // end of sol/proxy_base.hpp | ||
11442 | |||
11443 | // beginning of sol/stack_iterator.hpp | ||
11444 | |||
11445 | namespace sol { | ||
11446 | template <typename proxy_t, bool is_const> | ||
11447 | struct stack_iterator { | ||
11448 | typedef std::conditional_t<is_const, const proxy_t, proxy_t> reference; | ||
11449 | typedef std::conditional_t<is_const, const proxy_t*, proxy_t*> pointer; | ||
11450 | typedef proxy_t value_type; | ||
11451 | typedef std::ptrdiff_t difference_type; | ||
11452 | typedef std::random_access_iterator_tag iterator_category; | ||
11453 | lua_State* L; | ||
11454 | int index; | ||
11455 | int stacktop; | ||
11456 | proxy_t sp; | ||
11457 | |||
11458 | stack_iterator() | ||
11459 | : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() { | ||
11460 | } | ||
11461 | stack_iterator(const stack_iterator<proxy_t, true>& r) | ||
11462 | : L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) { | ||
11463 | } | ||
11464 | stack_iterator(lua_State* luastate, int idx, int topidx) | ||
11465 | : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) { | ||
11466 | } | ||
11467 | |||
11468 | reference operator*() { | ||
11469 | return proxy_t(L, index); | ||
11470 | } | ||
11471 | |||
11472 | reference operator*() const { | ||
11473 | return proxy_t(L, index); | ||
11474 | } | ||
11475 | |||
11476 | pointer operator->() { | ||
11477 | sp = proxy_t(L, index); | ||
11478 | return &sp; | ||
11479 | } | ||
11480 | |||
11481 | pointer operator->() const { | ||
11482 | const_cast<proxy_t&>(sp) = proxy_t(L, index); | ||
11483 | return &sp; | ||
11484 | } | ||
11485 | |||
11486 | stack_iterator& operator++() { | ||
11487 | ++index; | ||
11488 | return *this; | ||
11489 | } | ||
11490 | |||
11491 | stack_iterator operator++(int) { | ||
11492 | auto r = *this; | ||
11493 | this->operator++(); | ||
11494 | return r; | ||
11495 | } | ||
11496 | |||
11497 | stack_iterator& operator--() { | ||
11498 | --index; | ||
11499 | return *this; | ||
11500 | } | ||
11501 | |||
11502 | stack_iterator operator--(int) { | ||
11503 | auto r = *this; | ||
11504 | this->operator--(); | ||
11505 | return r; | ||
11506 | } | ||
11507 | |||
11508 | stack_iterator& operator+=(difference_type idx) { | ||
11509 | index += static_cast<int>(idx); | ||
11510 | return *this; | ||
11511 | } | ||
11512 | |||
11513 | stack_iterator& operator-=(difference_type idx) { | ||
11514 | index -= static_cast<int>(idx); | ||
11515 | return *this; | ||
11516 | } | ||
11517 | |||
11518 | difference_type operator-(const stack_iterator& r) const { | ||
11519 | return index - r.index; | ||
11520 | } | ||
11521 | |||
11522 | stack_iterator operator+(difference_type idx) const { | ||
11523 | stack_iterator r = *this; | ||
11524 | r += idx; | ||
11525 | return r; | ||
11526 | } | ||
11527 | |||
11528 | reference operator[](difference_type idx) const { | ||
11529 | return proxy_t(L, index + static_cast<int>(idx)); | ||
11530 | } | ||
11531 | |||
11532 | bool operator==(const stack_iterator& r) const { | ||
11533 | if (stacktop == (std::numeric_limits<int>::max)()) { | ||
11534 | return r.index == r.stacktop; | ||
11535 | } | ||
11536 | else if (r.stacktop == (std::numeric_limits<int>::max)()) { | ||
11537 | return index == stacktop; | ||
11538 | } | ||
11539 | return index == r.index; | ||
11540 | } | ||
11541 | |||
11542 | bool operator!=(const stack_iterator& r) const { | ||
11543 | return !(this->operator==(r)); | ||
11544 | } | ||
11545 | |||
11546 | bool operator<(const stack_iterator& r) const { | ||
11547 | return index < r.index; | ||
11548 | } | ||
11549 | |||
11550 | bool operator>(const stack_iterator& r) const { | ||
11551 | return index > r.index; | ||
11552 | } | ||
11553 | |||
11554 | bool operator<=(const stack_iterator& r) const { | ||
11555 | return index <= r.index; | ||
11556 | } | ||
11557 | |||
11558 | bool operator>=(const stack_iterator& r) const { | ||
11559 | return index >= r.index; | ||
11560 | } | ||
11561 | }; | ||
11562 | |||
11563 | template <typename proxy_t, bool is_const> | ||
11564 | inline stack_iterator<proxy_t, is_const> operator+(typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) { | ||
11565 | return r + n; | ||
11566 | } | ||
11567 | } // namespace sol | ||
11568 | |||
11569 | // end of sol/stack_iterator.hpp | ||
11570 | |||
11571 | // beginning of sol/stack_proxy.hpp | ||
11572 | |||
11573 | // beginning of sol/stack_proxy_base.hpp | ||
11574 | |||
11575 | namespace sol { | ||
11576 | struct stack_proxy_base : public proxy_base<stack_proxy_base> { | ||
11577 | private: | ||
11578 | lua_State* L; | ||
11579 | int index; | ||
11580 | |||
11581 | public: | ||
11582 | stack_proxy_base() | ||
11583 | : L(nullptr), index(0) { | ||
11584 | } | ||
11585 | stack_proxy_base(lua_State* L, int index) | ||
11586 | : L(L), index(index) { | ||
11587 | } | ||
11588 | |||
11589 | template <typename T> | ||
11590 | decltype(auto) get() const { | ||
11591 | return stack::get<T>(L, stack_index()); | ||
11592 | } | ||
11593 | |||
11594 | template <typename T> | ||
11595 | bool is() const { | ||
11596 | return stack::check<T>(L, stack_index()); | ||
11597 | } | ||
11598 | |||
11599 | template <typename T> | ||
11600 | decltype(auto) as() const { | ||
11601 | return get<T>(); | ||
11602 | } | ||
11603 | |||
11604 | type get_type() const noexcept { | ||
11605 | return type_of(lua_state(), stack_index()); | ||
11606 | } | ||
11607 | |||
11608 | int push() const { | ||
11609 | return push(L); | ||
11610 | } | ||
11611 | |||
11612 | int push(lua_State* Ls) const { | ||
11613 | lua_pushvalue(Ls, index); | ||
11614 | return 1; | ||
11615 | } | ||
11616 | |||
11617 | lua_State* lua_state() const { | ||
11618 | return L; | ||
11619 | } | ||
11620 | int stack_index() const { | ||
11621 | return index; | ||
11622 | } | ||
11623 | }; | ||
11624 | |||
11625 | namespace stack { | ||
11626 | template <> | ||
11627 | struct getter<stack_proxy_base> { | ||
11628 | static stack_proxy_base get(lua_State* L, int index = -1) { | ||
11629 | return stack_proxy_base(L, index); | ||
11630 | } | ||
11631 | }; | ||
11632 | |||
11633 | template <> | ||
11634 | struct pusher<stack_proxy_base> { | ||
11635 | static int push(lua_State*, const stack_proxy_base& ref) { | ||
11636 | return ref.push(); | ||
11637 | } | ||
11638 | }; | ||
11639 | } // namespace stack | ||
11640 | |||
11641 | } // namespace sol | ||
11642 | |||
11643 | // end of sol/stack_proxy_base.hpp | ||
11644 | |||
11645 | namespace sol { | ||
11646 | struct stack_proxy : public stack_proxy_base { | ||
11647 | public: | ||
11648 | stack_proxy() | ||
11649 | : stack_proxy_base() { | ||
11650 | } | ||
11651 | stack_proxy(lua_State* L, int index) | ||
11652 | : stack_proxy_base(L, index) { | ||
11653 | } | ||
11654 | |||
11655 | template <typename... Ret, typename... Args> | ||
11656 | decltype(auto) call(Args&&... args); | ||
11657 | |||
11658 | template <typename... Args> | ||
11659 | decltype(auto) operator()(Args&&... args) { | ||
11660 | return call<>(std::forward<Args>(args)...); | ||
11661 | } | ||
11662 | }; | ||
11663 | |||
11664 | namespace stack { | ||
11665 | template <> | ||
11666 | struct getter<stack_proxy> { | ||
11667 | static stack_proxy get(lua_State* L, int index = -1) { | ||
11668 | return stack_proxy(L, index); | ||
11669 | } | ||
11670 | }; | ||
11671 | |||
11672 | template <> | ||
11673 | struct pusher<stack_proxy> { | ||
11674 | static int push(lua_State*, const stack_proxy& ref) { | ||
11675 | return ref.push(); | ||
11676 | } | ||
11677 | }; | ||
11678 | } // namespace stack | ||
11679 | } // namespace sol | ||
11680 | |||
11681 | // end of sol/stack_proxy.hpp | ||
11682 | |||
11683 | namespace sol { | ||
11684 | struct protected_function_result : public proxy_base<protected_function_result> { | ||
11685 | private: | ||
11686 | lua_State* L; | ||
11687 | int index; | ||
11688 | int returncount; | ||
11689 | int popcount; | ||
11690 | call_status err; | ||
11691 | |||
11692 | template <typename T> | ||
11693 | decltype(auto) tagged_get(types<optional<T>>, int index_offset) const { | ||
11694 | typedef decltype(stack::get<optional<T>>(L, index)) ret_t; | ||
11695 | int target = index + index_offset; | ||
11696 | if (!valid()) { | ||
11697 | return ret_t(nullopt); | ||
11698 | } | ||
11699 | return stack::get<optional<T>>(L, target); | ||
11700 | } | ||
11701 | |||
11702 | template <typename T> | ||
11703 | decltype(auto) tagged_get(types<T>, int index_offset) const { | ||
11704 | int target = index + index_offset; | ||
11705 | #if defined(SOL_SAFE_PROXIES) && SOL_SAFE_PROXIES | ||
11706 | if (!valid()) { | ||
11707 | type t = type_of(L, target); | ||
11708 | type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is not an error)"); | ||
11709 | } | ||
11710 | #endif // Check Argument Safety | ||
11711 | return stack::get<T>(L, target); | ||
11712 | } | ||
11713 | |||
11714 | optional<error> tagged_get(types<optional<error>>, int index_offset) const { | ||
11715 | int target = index + index_offset; | ||
11716 | if (valid()) { | ||
11717 | return nullopt; | ||
11718 | } | ||
11719 | return error(detail::direct_error, stack::get<std::string>(L, target)); | ||
11720 | } | ||
11721 | |||
11722 | error tagged_get(types<error>, int index_offset) const { | ||
11723 | int target = index + index_offset; | ||
11724 | #if defined(SOL_SAFE_PROXIES) && SOL_SAFE_PROXIES | ||
11725 | if (valid()) { | ||
11726 | type t = type_of(L, target); | ||
11727 | type_panic_c_str(L, target, t, type::none, "bad get from protected_function_result (is an error)"); | ||
11728 | } | ||
11729 | #endif // Check Argument Safety | ||
11730 | return error(detail::direct_error, stack::get<std::string>(L, target)); | ||
11731 | } | ||
11732 | |||
11733 | public: | ||
11734 | typedef stack_proxy reference_type; | ||
11735 | typedef stack_proxy value_type; | ||
11736 | typedef stack_proxy* pointer; | ||
11737 | typedef std::ptrdiff_t difference_type; | ||
11738 | typedef std::size_t size_type; | ||
11739 | typedef stack_iterator<stack_proxy, false> iterator; | ||
11740 | typedef stack_iterator<stack_proxy, true> const_iterator; | ||
11741 | typedef std::reverse_iterator<iterator> reverse_iterator; | ||
11742 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | ||
11743 | |||
11744 | protected_function_result() = default; | ||
11745 | protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept | ||
11746 | : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) { | ||
11747 | } | ||
11748 | protected_function_result(const protected_function_result&) = default; | ||
11749 | protected_function_result& operator=(const protected_function_result&) = default; | ||
11750 | protected_function_result(protected_function_result&& o) noexcept | ||
11751 | : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { | ||
11752 | // Must be manual, otherwise destructor will screw us | ||
11753 | // return count being 0 is enough to keep things clean | ||
11754 | // but we will be thorough | ||
11755 | o.abandon(); | ||
11756 | } | ||
11757 | protected_function_result& operator=(protected_function_result&& o) noexcept { | ||
11758 | L = o.L; | ||
11759 | index = o.index; | ||
11760 | returncount = o.returncount; | ||
11761 | popcount = o.popcount; | ||
11762 | err = o.err; | ||
11763 | // Must be manual, otherwise destructor will screw us | ||
11764 | // return count being 0 is enough to keep things clean | ||
11765 | // but we will be thorough | ||
11766 | o.abandon(); | ||
11767 | return *this; | ||
11768 | } | ||
11769 | |||
11770 | protected_function_result(const unsafe_function_result& o) = delete; | ||
11771 | protected_function_result& operator=(const unsafe_function_result& o) = delete; | ||
11772 | protected_function_result(unsafe_function_result&& o) noexcept; | ||
11773 | protected_function_result& operator=(unsafe_function_result&& o) noexcept; | ||
11774 | |||
11775 | call_status status() const noexcept { | ||
11776 | return err; | ||
11777 | } | ||
11778 | |||
11779 | bool valid() const noexcept { | ||
11780 | return status() == call_status::ok || status() == call_status::yielded; | ||
11781 | } | ||
11782 | |||
11783 | template <typename T> | ||
11784 | decltype(auto) get(int index_offset = 0) const { | ||
11785 | return tagged_get(types<meta::unqualified_t<T>>(), index_offset); | ||
11786 | } | ||
11787 | |||
11788 | type get_type(difference_type index_offset = 0) const noexcept { | ||
11789 | return type_of(L, index + static_cast<int>(index_offset)); | ||
11790 | } | ||
11791 | |||
11792 | stack_proxy operator[](difference_type index_offset) const { | ||
11793 | return stack_proxy(L, index + static_cast<int>(index_offset)); | ||
11794 | } | ||
11795 | |||
11796 | iterator begin() { | ||
11797 | return iterator(L, index, stack_index() + return_count()); | ||
11798 | } | ||
11799 | iterator end() { | ||
11800 | return iterator(L, stack_index() + return_count(), stack_index() + return_count()); | ||
11801 | } | ||
11802 | const_iterator begin() const { | ||
11803 | return const_iterator(L, index, stack_index() + return_count()); | ||
11804 | } | ||
11805 | const_iterator end() const { | ||
11806 | return const_iterator(L, stack_index() + return_count(), stack_index() + return_count()); | ||
11807 | } | ||
11808 | const_iterator cbegin() const { | ||
11809 | return begin(); | ||
11810 | } | ||
11811 | const_iterator cend() const { | ||
11812 | return end(); | ||
11813 | } | ||
11814 | |||
11815 | reverse_iterator rbegin() { | ||
11816 | return std::reverse_iterator<iterator>(begin()); | ||
11817 | } | ||
11818 | reverse_iterator rend() { | ||
11819 | return std::reverse_iterator<iterator>(end()); | ||
11820 | } | ||
11821 | const_reverse_iterator rbegin() const { | ||
11822 | return std::reverse_iterator<const_iterator>(begin()); | ||
11823 | } | ||
11824 | const_reverse_iterator rend() const { | ||
11825 | return std::reverse_iterator<const_iterator>(end()); | ||
11826 | } | ||
11827 | const_reverse_iterator crbegin() const { | ||
11828 | return std::reverse_iterator<const_iterator>(cbegin()); | ||
11829 | } | ||
11830 | const_reverse_iterator crend() const { | ||
11831 | return std::reverse_iterator<const_iterator>(cend()); | ||
11832 | } | ||
11833 | |||
11834 | lua_State* lua_state() const noexcept { | ||
11835 | return L; | ||
11836 | }; | ||
11837 | int stack_index() const noexcept { | ||
11838 | return index; | ||
11839 | }; | ||
11840 | int return_count() const noexcept { | ||
11841 | return returncount; | ||
11842 | }; | ||
11843 | int pop_count() const noexcept { | ||
11844 | return popcount; | ||
11845 | }; | ||
11846 | void abandon() noexcept { | ||
11847 | //L = nullptr; | ||
11848 | index = 0; | ||
11849 | returncount = 0; | ||
11850 | popcount = 0; | ||
11851 | err = call_status::runtime; | ||
11852 | } | ||
11853 | ~protected_function_result() { | ||
11854 | stack::remove(L, index, popcount); | ||
11855 | } | ||
11856 | }; | ||
11857 | |||
11858 | namespace stack { | ||
11859 | template <> | ||
11860 | struct pusher<protected_function_result> { | ||
11861 | static int push(lua_State* L, const protected_function_result& pfr) { | ||
11862 | int p = 0; | ||
11863 | for (int i = 0; i < pfr.pop_count(); ++i) { | ||
11864 | lua_pushvalue(L, i + pfr.stack_index()); | ||
11865 | ++p; | ||
11866 | } | ||
11867 | return p; | ||
11868 | } | ||
11869 | }; | ||
11870 | } // namespace stack | ||
11871 | } // namespace sol | ||
11872 | |||
11873 | // end of sol/protected_function_result.hpp | ||
11874 | |||
11875 | // beginning of sol/unsafe_function_result.hpp | ||
11876 | |||
11877 | namespace sol { | ||
11878 | struct unsafe_function_result : public proxy_base<unsafe_function_result> { | ||
11879 | private: | ||
11880 | lua_State* L; | ||
11881 | int index; | ||
11882 | int returncount; | ||
11883 | |||
11884 | public: | ||
11885 | typedef stack_proxy reference_type; | ||
11886 | typedef stack_proxy value_type; | ||
11887 | typedef stack_proxy* pointer; | ||
11888 | typedef std::ptrdiff_t difference_type; | ||
11889 | typedef std::size_t size_type; | ||
11890 | typedef stack_iterator<stack_proxy, false> iterator; | ||
11891 | typedef stack_iterator<stack_proxy, true> const_iterator; | ||
11892 | typedef std::reverse_iterator<iterator> reverse_iterator; | ||
11893 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | ||
11894 | |||
11895 | unsafe_function_result() = default; | ||
11896 | unsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0) | ||
11897 | : L(Ls), index(idx), returncount(retnum) { | ||
11898 | } | ||
11899 | unsafe_function_result(const unsafe_function_result&) = default; | ||
11900 | unsafe_function_result& operator=(const unsafe_function_result&) = default; | ||
11901 | unsafe_function_result(unsafe_function_result&& o) | ||
11902 | : L(o.L), index(o.index), returncount(o.returncount) { | ||
11903 | // Must be manual, otherwise destructor will screw us | ||
11904 | // return count being 0 is enough to keep things clean | ||
11905 | // but will be thorough | ||
11906 | o.abandon(); | ||
11907 | } | ||
11908 | unsafe_function_result& operator=(unsafe_function_result&& o) { | ||
11909 | L = o.L; | ||
11910 | index = o.index; | ||
11911 | returncount = o.returncount; | ||
11912 | // Must be manual, otherwise destructor will screw us | ||
11913 | // return count being 0 is enough to keep things clean | ||
11914 | // but will be thorough | ||
11915 | o.abandon(); | ||
11916 | return *this; | ||
11917 | } | ||
11918 | |||
11919 | unsafe_function_result(const protected_function_result& o) = delete; | ||
11920 | unsafe_function_result& operator=(const protected_function_result& o) = delete; | ||
11921 | unsafe_function_result(protected_function_result&& o) noexcept; | ||
11922 | unsafe_function_result& operator=(protected_function_result&& o) noexcept; | ||
11923 | |||
11924 | template <typename T> | ||
11925 | decltype(auto) get(difference_type index_offset = 0) const { | ||
11926 | return stack::get<T>(L, index + static_cast<int>(index_offset)); | ||
11927 | } | ||
11928 | |||
11929 | type get_type(difference_type index_offset = 0) const noexcept { | ||
11930 | return type_of(L, index + static_cast<int>(index_offset)); | ||
11931 | } | ||
11932 | |||
11933 | stack_proxy operator[](difference_type index_offset) const { | ||
11934 | return stack_proxy(L, index + static_cast<int>(index_offset)); | ||
11935 | } | ||
11936 | |||
11937 | iterator begin() { | ||
11938 | return iterator(L, index, stack_index() + return_count()); | ||
11939 | } | ||
11940 | iterator end() { | ||
11941 | return iterator(L, stack_index() + return_count(), stack_index() + return_count()); | ||
11942 | } | ||
11943 | const_iterator begin() const { | ||
11944 | return const_iterator(L, index, stack_index() + return_count()); | ||
11945 | } | ||
11946 | const_iterator end() const { | ||
11947 | return const_iterator(L, stack_index() + return_count(), stack_index() + return_count()); | ||
11948 | } | ||
11949 | const_iterator cbegin() const { | ||
11950 | return begin(); | ||
11951 | } | ||
11952 | const_iterator cend() const { | ||
11953 | return end(); | ||
11954 | } | ||
11955 | |||
11956 | reverse_iterator rbegin() { | ||
11957 | return std::reverse_iterator<iterator>(begin()); | ||
11958 | } | ||
11959 | reverse_iterator rend() { | ||
11960 | return std::reverse_iterator<iterator>(end()); | ||
11961 | } | ||
11962 | const_reverse_iterator rbegin() const { | ||
11963 | return std::reverse_iterator<const_iterator>(begin()); | ||
11964 | } | ||
11965 | const_reverse_iterator rend() const { | ||
11966 | return std::reverse_iterator<const_iterator>(end()); | ||
11967 | } | ||
11968 | const_reverse_iterator crbegin() const { | ||
11969 | return std::reverse_iterator<const_iterator>(cbegin()); | ||
11970 | } | ||
11971 | const_reverse_iterator crend() const { | ||
11972 | return std::reverse_iterator<const_iterator>(cend()); | ||
11973 | } | ||
11974 | |||
11975 | call_status status() const noexcept { | ||
11976 | return call_status::ok; | ||
11977 | } | ||
11978 | |||
11979 | bool valid() const noexcept { | ||
11980 | return status() == call_status::ok || status() == call_status::yielded; | ||
11981 | } | ||
11982 | |||
11983 | lua_State* lua_state() const { | ||
11984 | return L; | ||
11985 | }; | ||
11986 | int stack_index() const { | ||
11987 | return index; | ||
11988 | }; | ||
11989 | int return_count() const { | ||
11990 | return returncount; | ||
11991 | }; | ||
11992 | void abandon() noexcept { | ||
11993 | //L = nullptr; | ||
11994 | index = 0; | ||
11995 | returncount = 0; | ||
11996 | } | ||
11997 | ~unsafe_function_result() { | ||
11998 | lua_pop(L, returncount); | ||
11999 | } | ||
12000 | }; | ||
12001 | |||
12002 | namespace stack { | ||
12003 | template <> | ||
12004 | struct pusher<unsafe_function_result> { | ||
12005 | static int push(lua_State* L, const unsafe_function_result& fr) { | ||
12006 | int p = 0; | ||
12007 | for (int i = 0; i < fr.return_count(); ++i) { | ||
12008 | lua_pushvalue(L, i + fr.stack_index()); | ||
12009 | ++p; | ||
12010 | } | ||
12011 | return p; | ||
12012 | } | ||
12013 | }; | ||
12014 | } // namespace stack | ||
12015 | } // namespace sol | ||
12016 | |||
12017 | // end of sol/unsafe_function_result.hpp | ||
12018 | |||
12019 | namespace sol { | ||
12020 | |||
12021 | namespace detail { | ||
12022 | template <> | ||
12023 | struct is_speshul<unsafe_function_result> : std::true_type {}; | ||
12024 | template <> | ||
12025 | struct is_speshul<protected_function_result> : std::true_type {}; | ||
12026 | |||
12027 | template <std::size_t I, typename... Args, typename T> | ||
12028 | stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) { | ||
12029 | return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); | ||
12030 | } | ||
12031 | |||
12032 | template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler> | ||
12033 | stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) { | ||
12034 | return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr); | ||
12035 | } | ||
12036 | } // namespace detail | ||
12037 | |||
12038 | template <> | ||
12039 | struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; | ||
12040 | |||
12041 | template <> | ||
12042 | struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {}; | ||
12043 | |||
12044 | template <std::size_t I> | ||
12045 | stack_proxy get(const unsafe_function_result& fr) { | ||
12046 | return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); | ||
12047 | } | ||
12048 | |||
12049 | template <std::size_t I, typename... Args> | ||
12050 | stack_proxy get(types<Args...> t, const unsafe_function_result& fr) { | ||
12051 | return detail::get(t, index_value<I>(), index_value<0>(), fr); | ||
12052 | } | ||
12053 | |||
12054 | template <std::size_t I> | ||
12055 | stack_proxy get(const protected_function_result& fr) { | ||
12056 | return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I)); | ||
12057 | } | ||
12058 | |||
12059 | template <std::size_t I, typename... Args> | ||
12060 | stack_proxy get(types<Args...> t, const protected_function_result& fr) { | ||
12061 | return detail::get(t, index_value<I>(), index_value<0>(), fr); | ||
12062 | } | ||
12063 | } // namespace sol | ||
12064 | |||
12065 | // end of sol/function_result.hpp | ||
12066 | |||
12067 | // beginning of sol/function_types.hpp | ||
12068 | |||
12069 | // beginning of sol/function_types_core.hpp | ||
12070 | |||
12071 | // beginning of sol/wrapper.hpp | ||
12072 | |||
12073 | namespace sol { | ||
12074 | |||
12075 | namespace detail { | ||
12076 | template <typename T> | ||
12077 | using array_return_type = std::conditional_t<std::is_array<T>::value, std::add_lvalue_reference_t<T>, T>; | ||
12078 | } | ||
12079 | |||
12080 | template <typename F, typename = void> | ||
12081 | struct wrapper { | ||
12082 | typedef lua_bind_traits<meta::unqualified_t<F>> traits_type; | ||
12083 | typedef typename traits_type::args_list args_list; | ||
12084 | typedef typename traits_type::args_list free_args_list; | ||
12085 | typedef typename traits_type::returns_list returns_list; | ||
12086 | |||
12087 | template <typename... Args> | ||
12088 | static decltype(auto) call(F& f, Args&&... args) { | ||
12089 | return f(std::forward<Args>(args)...); | ||
12090 | } | ||
12091 | |||
12092 | struct caller { | ||
12093 | template <typename... Args> | ||
12094 | decltype(auto) operator()(F& fx, Args&&... args) const { | ||
12095 | return call(fx, std::forward<Args>(args)...); | ||
12096 | } | ||
12097 | }; | ||
12098 | }; | ||
12099 | |||
12100 | template <typename F> | ||
12101 | struct wrapper<F, std::enable_if_t<std::is_function<std::remove_pointer_t<meta::unqualified_t<F>>>::value>> { | ||
12102 | typedef lua_bind_traits<std::remove_pointer_t<meta::unqualified_t<F>>> traits_type; | ||
12103 | typedef typename traits_type::args_list args_list; | ||
12104 | typedef typename traits_type::args_list free_args_list; | ||
12105 | typedef typename traits_type::returns_list returns_list; | ||
12106 | |||
12107 | template <F fx, typename... Args> | ||
12108 | static decltype(auto) invoke(Args&&... args) { | ||
12109 | return fx(std::forward<Args>(args)...); | ||
12110 | } | ||
12111 | |||
12112 | template <typename... Args> | ||
12113 | static decltype(auto) call(F& fx, Args&&... args) { | ||
12114 | return fx(std::forward<Args>(args)...); | ||
12115 | } | ||
12116 | |||
12117 | struct caller { | ||
12118 | template <typename... Args> | ||
12119 | decltype(auto) operator()(F& fx, Args&&... args) const { | ||
12120 | return call(fx, std::forward<Args>(args)...); | ||
12121 | } | ||
12122 | }; | ||
12123 | |||
12124 | template <F fx> | ||
12125 | struct invoker { | ||
12126 | template <typename... Args> | ||
12127 | decltype(auto) operator()(Args&&... args) const { | ||
12128 | return invoke<fx>(std::forward<Args>(args)...); | ||
12129 | } | ||
12130 | }; | ||
12131 | }; | ||
12132 | |||
12133 | template <typename F> | ||
12134 | struct wrapper<F, std::enable_if_t<std::is_member_object_pointer<meta::unqualified_t<F>>::value>> { | ||
12135 | typedef lua_bind_traits<meta::unqualified_t<F>> traits_type; | ||
12136 | typedef typename traits_type::object_type object_type; | ||
12137 | typedef typename traits_type::return_type return_type; | ||
12138 | typedef typename traits_type::args_list args_list; | ||
12139 | typedef types<object_type&, return_type> free_args_list; | ||
12140 | typedef typename traits_type::returns_list returns_list; | ||
12141 | |||
12142 | template <F fx> | ||
12143 | static auto call(object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> { | ||
12144 | return mem.*fx; | ||
12145 | } | ||
12146 | |||
12147 | template <F fx, typename Arg, typename... Args> | ||
12148 | static decltype(auto) invoke(object_type& mem, Arg&& arg, Args&&...) { | ||
12149 | return mem.*fx = std::forward<Arg>(arg); | ||
12150 | } | ||
12151 | |||
12152 | template <typename Fx> | ||
12153 | static auto call(Fx&& fx, object_type& mem) -> detail::array_return_type<decltype(mem.*fx)> { | ||
12154 | return mem.*fx; | ||
12155 | } | ||
12156 | |||
12157 | template <typename Fx, typename Arg, typename... Args> | ||
12158 | static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) { | ||
12159 | (mem.*fx) = std::forward<Arg>(arg); | ||
12160 | } | ||
12161 | |||
12162 | struct caller { | ||
12163 | template <typename Fx, typename... Args> | ||
12164 | decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const { | ||
12165 | return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...); | ||
12166 | } | ||
12167 | }; | ||
12168 | |||
12169 | template <F fx> | ||
12170 | struct invoker { | ||
12171 | template <typename... Args> | ||
12172 | decltype(auto) operator()(Args&&... args) const { | ||
12173 | return invoke<fx>(std::forward<Args>(args)...); | ||
12174 | } | ||
12175 | }; | ||
12176 | }; | ||
12177 | |||
12178 | template <typename F, typename R, typename O, typename... FArgs> | ||
12179 | struct member_function_wrapper { | ||
12180 | typedef O object_type; | ||
12181 | typedef lua_bind_traits<F> traits_type; | ||
12182 | typedef typename traits_type::args_list args_list; | ||
12183 | typedef types<object_type&, FArgs...> free_args_list; | ||
12184 | typedef meta::tuple_types<R> returns_list; | ||
12185 | |||
12186 | template <F fx, typename... Args> | ||
12187 | static R invoke(O& mem, Args&&... args) { | ||
12188 | return (mem.*fx)(std::forward<Args>(args)...); | ||
12189 | } | ||
12190 | |||
12191 | template <typename Fx, typename... Args> | ||
12192 | static R call(Fx&& fx, O& mem, Args&&... args) { | ||
12193 | return (mem.*fx)(std::forward<Args>(args)...); | ||
12194 | } | ||
12195 | |||
12196 | struct caller { | ||
12197 | template <typename Fx, typename... Args> | ||
12198 | decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const { | ||
12199 | return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...); | ||
12200 | } | ||
12201 | }; | ||
12202 | |||
12203 | template <F fx> | ||
12204 | struct invoker { | ||
12205 | template <typename... Args> | ||
12206 | decltype(auto) operator()(O& mem, Args&&... args) const { | ||
12207 | return invoke<fx>(mem, std::forward<Args>(args)...); | ||
12208 | } | ||
12209 | }; | ||
12210 | }; | ||
12211 | |||
12212 | template <typename R, typename O, typename... Args> | ||
12213 | struct wrapper<R (O::*)(Args...)> : public member_function_wrapper<R (O::*)(Args...), R, O, Args...> { | ||
12214 | }; | ||
12215 | |||
12216 | template <typename R, typename O, typename... Args> | ||
12217 | struct wrapper<R (O::*)(Args...) const> : public member_function_wrapper<R (O::*)(Args...) const, R, O, Args...> { | ||
12218 | }; | ||
12219 | |||
12220 | template <typename R, typename O, typename... Args> | ||
12221 | struct wrapper<R (O::*)(Args...) const volatile> : public member_function_wrapper<R (O::*)(Args...) const volatile, R, O, Args...> { | ||
12222 | }; | ||
12223 | |||
12224 | template <typename R, typename O, typename... Args> | ||
12225 | struct wrapper<R (O::*)(Args...)&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { | ||
12226 | }; | ||
12227 | |||
12228 | template <typename R, typename O, typename... Args> | ||
12229 | struct wrapper<R (O::*)(Args...) const&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { | ||
12230 | }; | ||
12231 | |||
12232 | template <typename R, typename O, typename... Args> | ||
12233 | struct wrapper<R (O::*)(Args...) const volatile&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { | ||
12234 | }; | ||
12235 | |||
12236 | template <typename R, typename O, typename... Args> | ||
12237 | struct wrapper<R (O::*)(Args..., ...)&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { | ||
12238 | }; | ||
12239 | |||
12240 | template <typename R, typename O, typename... Args> | ||
12241 | struct wrapper<R (O::*)(Args..., ...) const&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { | ||
12242 | }; | ||
12243 | |||
12244 | template <typename R, typename O, typename... Args> | ||
12245 | struct wrapper<R (O::*)(Args..., ...) const volatile&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { | ||
12246 | }; | ||
12247 | |||
12248 | template <typename R, typename O, typename... Args> | ||
12249 | struct wrapper<R (O::*)(Args...) &&> : public member_function_wrapper<R (O::*)(Args...)&, R, O, Args...> { | ||
12250 | }; | ||
12251 | |||
12252 | template <typename R, typename O, typename... Args> | ||
12253 | struct wrapper<R (O::*)(Args...) const&&> : public member_function_wrapper<R (O::*)(Args...) const&, R, O, Args...> { | ||
12254 | }; | ||
12255 | |||
12256 | template <typename R, typename O, typename... Args> | ||
12257 | struct wrapper<R (O::*)(Args...) const volatile&&> : public member_function_wrapper<R (O::*)(Args...) const volatile&, R, O, Args...> { | ||
12258 | }; | ||
12259 | |||
12260 | template <typename R, typename O, typename... Args> | ||
12261 | struct wrapper<R (O::*)(Args..., ...) &&> : public member_function_wrapper<R (O::*)(Args..., ...)&, R, O, Args...> { | ||
12262 | }; | ||
12263 | |||
12264 | template <typename R, typename O, typename... Args> | ||
12265 | struct wrapper<R (O::*)(Args..., ...) const&&> : public member_function_wrapper<R (O::*)(Args..., ...) const&, R, O, Args...> { | ||
12266 | }; | ||
12267 | |||
12268 | template <typename R, typename O, typename... Args> | ||
12269 | struct wrapper<R (O::*)(Args..., ...) const volatile&&> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile&, R, O, Args...> { | ||
12270 | }; | ||
12271 | |||
12272 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
12273 | //noexcept has become a part of a function's type | ||
12274 | |||
12275 | template <typename R, typename O, typename... Args> | ||
12276 | struct wrapper<R (O::*)(Args...) noexcept> : public member_function_wrapper<R (O::*)(Args...) noexcept, R, O, Args...> { | ||
12277 | }; | ||
12278 | |||
12279 | template <typename R, typename O, typename... Args> | ||
12280 | struct wrapper<R (O::*)(Args...) const noexcept> : public member_function_wrapper<R (O::*)(Args...) const noexcept, R, O, Args...> { | ||
12281 | }; | ||
12282 | |||
12283 | template <typename R, typename O, typename... Args> | ||
12284 | struct wrapper<R (O::*)(Args...) const volatile noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile noexcept, R, O, Args...> { | ||
12285 | }; | ||
12286 | |||
12287 | template <typename R, typename O, typename... Args> | ||
12288 | struct wrapper<R (O::*)(Args...) & noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> { | ||
12289 | }; | ||
12290 | |||
12291 | template <typename R, typename O, typename... Args> | ||
12292 | struct wrapper<R (O::*)(Args...) const& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { | ||
12293 | }; | ||
12294 | |||
12295 | template <typename R, typename O, typename... Args> | ||
12296 | struct wrapper<R (O::*)(Args...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { | ||
12297 | }; | ||
12298 | |||
12299 | template <typename R, typename O, typename... Args> | ||
12300 | struct wrapper<R (O::*)(Args..., ...) & noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> { | ||
12301 | }; | ||
12302 | |||
12303 | template <typename R, typename O, typename... Args> | ||
12304 | struct wrapper<R (O::*)(Args..., ...) const& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { | ||
12305 | }; | ||
12306 | |||
12307 | template <typename R, typename O, typename... Args> | ||
12308 | struct wrapper<R (O::*)(Args..., ...) const volatile& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { | ||
12309 | }; | ||
12310 | |||
12311 | template <typename R, typename O, typename... Args> | ||
12312 | struct wrapper<R (O::*)(Args...) && noexcept> : public member_function_wrapper<R (O::*)(Args...) & noexcept, R, O, Args...> { | ||
12313 | }; | ||
12314 | |||
12315 | template <typename R, typename O, typename... Args> | ||
12316 | struct wrapper<R (O::*)(Args...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const& noexcept, R, O, Args...> { | ||
12317 | }; | ||
12318 | |||
12319 | template <typename R, typename O, typename... Args> | ||
12320 | struct wrapper<R (O::*)(Args...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args...) const volatile& noexcept, R, O, Args...> { | ||
12321 | }; | ||
12322 | |||
12323 | template <typename R, typename O, typename... Args> | ||
12324 | struct wrapper<R (O::*)(Args..., ...) && noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) & noexcept, R, O, Args...> { | ||
12325 | }; | ||
12326 | |||
12327 | template <typename R, typename O, typename... Args> | ||
12328 | struct wrapper<R (O::*)(Args..., ...) const&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const& noexcept, R, O, Args...> { | ||
12329 | }; | ||
12330 | |||
12331 | template <typename R, typename O, typename... Args> | ||
12332 | struct wrapper<R (O::*)(Args..., ...) const volatile&& noexcept> : public member_function_wrapper<R (O::*)(Args..., ...) const volatile& noexcept, R, O, Args...> { | ||
12333 | }; | ||
12334 | |||
12335 | #endif // noexcept is part of a function's type | ||
12336 | |||
12337 | } // namespace sol | ||
12338 | |||
12339 | // end of sol/wrapper.hpp | ||
12340 | |||
12341 | namespace sol { | ||
12342 | namespace function_detail { | ||
12343 | template <typename Fx, int start = 1, bool is_yielding = false> | ||
12344 | inline int call(lua_State* L) { | ||
12345 | Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start)); | ||
12346 | int nr = fx(L); | ||
12347 | if (is_yielding) { | ||
12348 | return lua_yield(L, nr); | ||
12349 | } | ||
12350 | else { | ||
12351 | return nr; | ||
12352 | } | ||
12353 | } | ||
12354 | } | ||
12355 | } // namespace sol::function_detail | ||
12356 | |||
12357 | // end of sol/function_types_core.hpp | ||
12358 | |||
12359 | // beginning of sol/function_types_templated.hpp | ||
12360 | |||
12361 | // beginning of sol/call.hpp | ||
12362 | |||
12363 | // beginning of sol/protect.hpp | ||
12364 | |||
12365 | namespace sol { | ||
12366 | |||
12367 | template <typename T> | ||
12368 | struct protect_t { | ||
12369 | T value; | ||
12370 | |||
12371 | template <typename Arg, typename... Args, meta::disable<std::is_same<protect_t, meta::unqualified_t<Arg>>> = meta::enabler> | ||
12372 | protect_t(Arg&& arg, Args&&... args) | ||
12373 | : value(std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
12374 | } | ||
12375 | |||
12376 | protect_t(const protect_t&) = default; | ||
12377 | protect_t(protect_t&&) = default; | ||
12378 | protect_t& operator=(const protect_t&) = default; | ||
12379 | protect_t& operator=(protect_t&&) = default; | ||
12380 | }; | ||
12381 | |||
12382 | template <typename T> | ||
12383 | auto protect(T&& value) { | ||
12384 | return protect_t<std::decay_t<T>>(std::forward<T>(value)); | ||
12385 | } | ||
12386 | |||
12387 | } // namespace sol | ||
12388 | |||
12389 | // end of sol/protect.hpp | ||
12390 | |||
12391 | // beginning of sol/property.hpp | ||
12392 | |||
12393 | namespace sol { | ||
12394 | |||
12395 | struct no_prop {}; | ||
12396 | |||
12397 | template <typename R, typename W> | ||
12398 | struct property_wrapper { | ||
12399 | typedef std::integral_constant<bool, !std::is_void<R>::value> can_read; | ||
12400 | typedef std::integral_constant<bool, !std::is_void<W>::value> can_write; | ||
12401 | typedef std::conditional_t<can_read::value, R, no_prop> Read; | ||
12402 | typedef std::conditional_t<can_write::value, W, no_prop> Write; | ||
12403 | Read read; | ||
12404 | Write write; | ||
12405 | |||
12406 | template <typename Rx, typename Wx> | ||
12407 | property_wrapper(Rx&& r, Wx&& w) | ||
12408 | : read(std::forward<Rx>(r)), write(std::forward<Wx>(w)) { | ||
12409 | } | ||
12410 | }; | ||
12411 | |||
12412 | namespace property_detail { | ||
12413 | template <typename R, typename W> | ||
12414 | inline decltype(auto) property(std::true_type, R&& read, W&& write) { | ||
12415 | return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write)); | ||
12416 | } | ||
12417 | template <typename W, typename R> | ||
12418 | inline decltype(auto) property(std::false_type, W&& write, R&& read) { | ||
12419 | return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write)); | ||
12420 | } | ||
12421 | template <typename R> | ||
12422 | inline decltype(auto) property(std::true_type, R&& read) { | ||
12423 | return property_wrapper<std::decay_t<R>, void>(std::forward<R>(read), no_prop()); | ||
12424 | } | ||
12425 | template <typename W> | ||
12426 | inline decltype(auto) property(std::false_type, W&& write) { | ||
12427 | return property_wrapper<void, std::decay_t<W>>(no_prop(), std::forward<W>(write)); | ||
12428 | } | ||
12429 | } // namespace property_detail | ||
12430 | |||
12431 | template <typename F, typename G> | ||
12432 | inline decltype(auto) property(F&& f, G&& g) { | ||
12433 | typedef lua_bind_traits<meta::unqualified_t<F>> left_traits; | ||
12434 | typedef lua_bind_traits<meta::unqualified_t<G>> right_traits; | ||
12435 | return property_detail::property(meta::boolean<(left_traits::free_arity < right_traits::free_arity)>(), std::forward<F>(f), std::forward<G>(g)); | ||
12436 | } | ||
12437 | |||
12438 | template <typename F> | ||
12439 | inline decltype(auto) property(F&& f) { | ||
12440 | typedef lua_bind_traits<meta::unqualified_t<F>> left_traits; | ||
12441 | return property_detail::property(meta::boolean<(left_traits::free_arity < 2)>(), std::forward<F>(f)); | ||
12442 | } | ||
12443 | |||
12444 | template <typename F> | ||
12445 | inline decltype(auto) readonly_property(F&& f) { | ||
12446 | return property_detail::property(std::true_type(), std::forward<F>(f)); | ||
12447 | } | ||
12448 | |||
12449 | template <typename F> | ||
12450 | inline decltype(auto) writeonly_property(F&& f) { | ||
12451 | return property_detail::property(std::false_type(), std::forward<F>(f)); | ||
12452 | } | ||
12453 | |||
12454 | template <typename T> | ||
12455 | struct readonly_wrapper { | ||
12456 | T v; | ||
12457 | |||
12458 | readonly_wrapper(T v) | ||
12459 | : v(std::move(v)) { | ||
12460 | } | ||
12461 | |||
12462 | operator T&() { | ||
12463 | return v; | ||
12464 | } | ||
12465 | operator const T&() const { | ||
12466 | return v; | ||
12467 | } | ||
12468 | }; | ||
12469 | |||
12470 | // Allow someone to make a member variable readonly (const) | ||
12471 | template <typename R, typename T> | ||
12472 | inline auto readonly(R T::*v) { | ||
12473 | return readonly_wrapper<meta::unqualified_t<decltype(v)>>(v); | ||
12474 | } | ||
12475 | |||
12476 | template <typename T> | ||
12477 | struct var_wrapper { | ||
12478 | T value; | ||
12479 | template <typename... Args> | ||
12480 | var_wrapper(Args&&... args) | ||
12481 | : value(std::forward<Args>(args)...) { | ||
12482 | } | ||
12483 | var_wrapper(const var_wrapper&) = default; | ||
12484 | var_wrapper(var_wrapper&&) = default; | ||
12485 | var_wrapper& operator=(const var_wrapper&) = default; | ||
12486 | var_wrapper& operator=(var_wrapper&&) = default; | ||
12487 | }; | ||
12488 | |||
12489 | template <typename V> | ||
12490 | inline auto var(V&& v) { | ||
12491 | typedef meta::unqualified_t<V> T; | ||
12492 | return var_wrapper<T>(std::forward<V>(v)); | ||
12493 | } | ||
12494 | |||
12495 | namespace meta { | ||
12496 | template <typename T> | ||
12497 | struct is_member_object : std::is_member_object_pointer<T> {}; | ||
12498 | |||
12499 | template <typename T> | ||
12500 | struct is_member_object<readonly_wrapper<T>> : std::true_type {}; | ||
12501 | } // namespace meta | ||
12502 | |||
12503 | } // namespace sol | ||
12504 | |||
12505 | // end of sol/property.hpp | ||
12506 | |||
12507 | namespace sol { | ||
12508 | namespace usertype_detail { | ||
12509 | |||
12510 | } // namespace usertype_detail | ||
12511 | |||
12512 | namespace filter_detail { | ||
12513 | template <int I, int... In> | ||
12514 | inline void handle_filter(static_stack_dependencies<I, In...>, lua_State* L, int&) { | ||
12515 | if (sizeof...(In) == 0) { | ||
12516 | return; | ||
12517 | } | ||
12518 | absolute_index ai(L, I); | ||
12519 | if (type_of(L, ai) != type::userdata) { | ||
12520 | return; | ||
12521 | } | ||
12522 | lua_createtable(L, static_cast<int>(sizeof...(In)), 0); | ||
12523 | stack_reference deps(L, -1); | ||
12524 | auto per_dep = [&L, &deps](int i) { | ||
12525 | lua_pushvalue(L, i); | ||
12526 | luaL_ref(L, deps.stack_index()); | ||
12527 | }; | ||
12528 | (void)per_dep; | ||
12529 | (void)detail::swallow{ int(), (per_dep(In), int())... }; | ||
12530 | lua_setuservalue(L, ai); | ||
12531 | } | ||
12532 | |||
12533 | template <int... In> | ||
12534 | inline void handle_filter(returns_self_with<In...>, lua_State* L, int& pushed) { | ||
12535 | pushed = stack::push(L, raw_index(1)); | ||
12536 | handle_filter(static_stack_dependencies<-1, In...>(), L, pushed); | ||
12537 | } | ||
12538 | |||
12539 | inline void handle_filter(const stack_dependencies& sdeps, lua_State* L, int&) { | ||
12540 | absolute_index ai(L, sdeps.target); | ||
12541 | if (type_of(L, ai) != type::userdata) { | ||
12542 | return; | ||
12543 | } | ||
12544 | lua_createtable(L, static_cast<int>(sdeps.size()), 0); | ||
12545 | stack_reference deps(L, -1); | ||
12546 | for (std::size_t i = 0; i < sdeps.size(); ++i) { | ||
12547 | lua_pushvalue(L, sdeps.stack_indices[i]); | ||
12548 | luaL_ref(L, deps.stack_index()); | ||
12549 | } | ||
12550 | lua_setuservalue(L, ai); | ||
12551 | } | ||
12552 | |||
12553 | template <typename P, meta::disable<std::is_base_of<detail::filter_base_tag, meta::unqualified_t<P>>> = meta::enabler> | ||
12554 | inline void handle_filter(P&& p, lua_State* L, int& pushed) { | ||
12555 | pushed = std::forward<P>(p)(L, pushed); | ||
12556 | } | ||
12557 | } // namespace filter_detail | ||
12558 | |||
12559 | namespace function_detail { | ||
12560 | inline int no_construction_error(lua_State* L) { | ||
12561 | return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); | ||
12562 | } | ||
12563 | } // namespace function_detail | ||
12564 | |||
12565 | namespace call_detail { | ||
12566 | |||
12567 | template <typename R, typename W> | ||
12568 | inline auto& pick(std::true_type, property_wrapper<R, W>& f) { | ||
12569 | return f.read; | ||
12570 | } | ||
12571 | |||
12572 | template <typename R, typename W> | ||
12573 | inline auto& pick(std::false_type, property_wrapper<R, W>& f) { | ||
12574 | return f.write; | ||
12575 | } | ||
12576 | |||
12577 | template <typename T, typename List> | ||
12578 | struct void_call : void_call<T, meta::function_args_t<List>> {}; | ||
12579 | |||
12580 | template <typename T, typename... Args> | ||
12581 | struct void_call<T, types<Args...>> { | ||
12582 | static void call(Args...) { | ||
12583 | } | ||
12584 | }; | ||
12585 | |||
12586 | template <typename T, bool checked, bool clean_stack> | ||
12587 | struct constructor_match { | ||
12588 | T* obj; | ||
12589 | |||
12590 | constructor_match(T* o) | ||
12591 | : obj(o) { | ||
12592 | } | ||
12593 | |||
12594 | template <typename Fx, std::size_t I, typename... R, typename... Args> | ||
12595 | int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const { | ||
12596 | detail::default_construct func{}; | ||
12597 | return stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, obj); | ||
12598 | } | ||
12599 | }; | ||
12600 | |||
12601 | namespace overload_detail { | ||
12602 | template <std::size_t... M, typename Match, typename... Args> | ||
12603 | inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) { | ||
12604 | return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types"); | ||
12605 | } | ||
12606 | |||
12607 | template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args> | ||
12608 | inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12609 | typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; | ||
12610 | typedef meta::tuple_types<typename traits::return_type> return_types; | ||
12611 | typedef typename traits::free_args_list args_list; | ||
12612 | // compile-time eliminate any functions that we know ahead of time are of improper arity | ||
12613 | if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) { | ||
12614 | return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12615 | } | ||
12616 | if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { | ||
12617 | return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12618 | } | ||
12619 | stack::record tracking{}; | ||
12620 | if (!stack::stack_detail::check_types<true>{}.check(args_list(), L, start, no_panic, tracking)) { | ||
12621 | return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12622 | } | ||
12623 | return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); | ||
12624 | } | ||
12625 | |||
12626 | template <std::size_t... M, typename Match, typename... Args> | ||
12627 | inline int overload_match_arity_single(types<>, std::index_sequence<>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12628 | return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12629 | } | ||
12630 | |||
12631 | template <typename Fx, std::size_t I, std::size_t... M, typename Match, typename... Args> | ||
12632 | inline int overload_match_arity_single(types<Fx>, std::index_sequence<I>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12633 | typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; | ||
12634 | typedef meta::tuple_types<typename traits::return_type> return_types; | ||
12635 | typedef typename traits::free_args_list args_list; | ||
12636 | // compile-time eliminate any functions that we know ahead of time are of improper arity | ||
12637 | if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) { | ||
12638 | return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12639 | } | ||
12640 | if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { | ||
12641 | return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12642 | } | ||
12643 | return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); | ||
12644 | } | ||
12645 | |||
12646 | template <typename Fx, typename Fx1, typename... Fxs, std::size_t I, std::size_t I1, std::size_t... In, std::size_t... M, typename Match, typename... Args> | ||
12647 | inline int overload_match_arity_single(types<Fx, Fx1, Fxs...>, std::index_sequence<I, I1, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12648 | typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits; | ||
12649 | typedef meta::tuple_types<typename traits::return_type> return_types; | ||
12650 | typedef typename traits::free_args_list args_list; | ||
12651 | // compile-time eliminate any functions that we know ahead of time are of improper arity | ||
12652 | if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) { | ||
12653 | return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12654 | } | ||
12655 | if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { | ||
12656 | return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12657 | } | ||
12658 | stack::record tracking{}; | ||
12659 | if (!stack::stack_detail::check_types<true>{}.check(args_list(), L, start, no_panic, tracking)) { | ||
12660 | return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12661 | } | ||
12662 | return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...); | ||
12663 | } | ||
12664 | } // namespace overload_detail | ||
12665 | |||
12666 | template <typename... Functions, typename Match, typename... Args> | ||
12667 | inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12668 | return overload_detail::overload_match_arity_single(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12669 | } | ||
12670 | |||
12671 | template <typename... Functions, typename Match, typename... Args> | ||
12672 | inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) { | ||
12673 | int fxarity = lua_gettop(L) - (start - 1); | ||
12674 | return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12675 | } | ||
12676 | |||
12677 | template <typename T, typename... TypeLists, typename Match, typename... Args> | ||
12678 | inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { | ||
12679 | // use same overload resolution matching as all other parts of the framework | ||
12680 | return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); | ||
12681 | } | ||
12682 | |||
12683 | template <typename T, bool checked, bool clean_stack, typename... TypeLists> | ||
12684 | inline int construct(lua_State* L) { | ||
12685 | static const auto& meta = usertype_traits<T>::metatable(); | ||
12686 | int argcount = lua_gettop(L); | ||
12687 | call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot; | ||
12688 | argcount -= static_cast<int>(syntax); | ||
12689 | |||
12690 | T* obj = detail::usertype_allocate<T>(L); | ||
12691 | reference userdataref(L, -1); | ||
12692 | userdataref.pop(); | ||
12693 | |||
12694 | construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax)); | ||
12695 | |||
12696 | userdataref.push(); | ||
12697 | stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]); | ||
12698 | umf(); | ||
12699 | |||
12700 | return 1; | ||
12701 | } | ||
12702 | |||
12703 | template <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void> | ||
12704 | struct agnostic_lua_call_wrapper { | ||
12705 | typedef wrapper<meta::unqualified_t<F>> wrap; | ||
12706 | |||
12707 | template <typename Fx, typename... Args> | ||
12708 | static int convertible_call(std::true_type, lua_State* L, Fx&& f, Args&&... args) { | ||
12709 | typedef typename wrap::traits_type traits_type; | ||
12710 | typedef typename traits_type::function_pointer_type fp_t; | ||
12711 | fp_t fx = f; | ||
12712 | return agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack>{}.call(L, fx, std::forward<Args>(args)...); | ||
12713 | } | ||
12714 | |||
12715 | template <typename Fx, typename... Args> | ||
12716 | static int convertible_call(std::false_type, lua_State* L, Fx&& f, Args&&... args) { | ||
12717 | typedef typename wrap::returns_list returns_list; | ||
12718 | typedef typename wrap::free_args_list args_list; | ||
12719 | typedef typename wrap::caller caller; | ||
12720 | return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...); | ||
12721 | } | ||
12722 | |||
12723 | template <typename Fx, typename... Args> | ||
12724 | static int call(lua_State* L, Fx&& f, Args&&... args) { | ||
12725 | typedef typename wrap::traits_type traits_type; | ||
12726 | typedef typename traits_type::function_pointer_type fp_t; | ||
12727 | return convertible_call(std::conditional_t<std::is_class<meta::unqualified_t<F>>::value, std::is_convertible<std::decay_t<Fx>, fp_t>, std::false_type>(), L, std::forward<Fx>(f), std::forward<Args>(args)...); | ||
12728 | } | ||
12729 | }; | ||
12730 | |||
12731 | template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12732 | struct agnostic_lua_call_wrapper<var_wrapper<T>, true, is_variable, checked, boost, clean_stack, C> { | ||
12733 | template <typename F> | ||
12734 | static int call(lua_State* L, F&& f) { | ||
12735 | typedef is_stack_based<meta::unqualified_t<decltype(detail::unwrap(f.value))>> is_stack; | ||
12736 | if (clean_stack && !is_stack::value) { | ||
12737 | lua_settop(L, 0); | ||
12738 | } | ||
12739 | return stack::push_reference(L, detail::unwrap(f.value)); | ||
12740 | } | ||
12741 | }; | ||
12742 | |||
12743 | template <typename T, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12744 | struct agnostic_lua_call_wrapper<var_wrapper<T>, false, is_variable, checked, boost, clean_stack, C> { | ||
12745 | template <typename V> | ||
12746 | static int call_assign(std::true_type, lua_State* L, V&& f) { | ||
12747 | detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, boost + (is_variable ? 3 : 1)); | ||
12748 | if (clean_stack) { | ||
12749 | lua_settop(L, 0); | ||
12750 | } | ||
12751 | return 0; | ||
12752 | } | ||
12753 | |||
12754 | template <typename... Args> | ||
12755 | static int call_assign(std::false_type, lua_State* L, Args&&...) { | ||
12756 | return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); | ||
12757 | } | ||
12758 | |||
12759 | template <typename... Args> | ||
12760 | static int call_const(std::false_type, lua_State* L, Args&&... args) { | ||
12761 | typedef meta::unwrapped_t<T> R; | ||
12762 | return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, std::forward<Args>(args)...); | ||
12763 | } | ||
12764 | |||
12765 | template <typename... Args> | ||
12766 | static int call_const(std::true_type, lua_State* L, Args&&...) { | ||
12767 | return luaL_error(L, "sol: cannot write to a readonly (const) variable"); | ||
12768 | } | ||
12769 | |||
12770 | template <typename V> | ||
12771 | static int call(lua_State* L, V&& f) { | ||
12772 | return call_const(std::is_const<meta::unwrapped_t<T>>(), L, f); | ||
12773 | } | ||
12774 | }; | ||
12775 | |||
12776 | template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12777 | struct agnostic_lua_call_wrapper<lua_CFunction_ref, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12778 | static int call(lua_State* L, lua_CFunction_ref f) { | ||
12779 | return f(L); | ||
12780 | } | ||
12781 | }; | ||
12782 | |||
12783 | template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12784 | struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12785 | static int call(lua_State* L, lua_CFunction f) { | ||
12786 | return f(L); | ||
12787 | } | ||
12788 | }; | ||
12789 | |||
12790 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
12791 | template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12792 | struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12793 | static int call(lua_State* L, detail::lua_CFunction_noexcept f) { | ||
12794 | return f(L); | ||
12795 | } | ||
12796 | }; | ||
12797 | #endif // noexcept function types | ||
12798 | |||
12799 | template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12800 | struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12801 | static int call(lua_State* L, const no_prop&) { | ||
12802 | return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); | ||
12803 | } | ||
12804 | }; | ||
12805 | |||
12806 | template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12807 | struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12808 | static int call(lua_State* L, const no_construction&) { | ||
12809 | return function_detail::no_construction_error(L); | ||
12810 | } | ||
12811 | }; | ||
12812 | |||
12813 | template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12814 | struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12815 | static int call(lua_State*, const bases<Args...>&) { | ||
12816 | // Uh. How did you even call this, lul | ||
12817 | return 0; | ||
12818 | } | ||
12819 | }; | ||
12820 | |||
12821 | template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12822 | struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12823 | static int call(lua_State* L, std::reference_wrapper<T> f) { | ||
12824 | return agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.get()); | ||
12825 | } | ||
12826 | }; | ||
12827 | |||
12828 | template <typename T, typename F, bool is_index, bool is_variable, bool checked = detail::default_safe_function_calls, int boost = 0, bool clean_stack = true, typename = void> | ||
12829 | struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> {}; | ||
12830 | |||
12831 | template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack> | ||
12832 | struct lua_call_wrapper<T, F, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_function_pointer<F>::value>> { | ||
12833 | typedef wrapper<meta::unqualified_t<F>> wrap; | ||
12834 | typedef typename wrap::object_type object_type; | ||
12835 | |||
12836 | template <typename Fx> | ||
12837 | static int call(lua_State* L, Fx&& f, object_type& o) { | ||
12838 | typedef typename wrap::returns_list returns_list; | ||
12839 | typedef typename wrap::args_list args_list; | ||
12840 | typedef typename wrap::caller caller; | ||
12841 | return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(f), o); | ||
12842 | } | ||
12843 | |||
12844 | template <typename Fx> | ||
12845 | static int call(lua_State* L, Fx&& f) { | ||
12846 | typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta; | ||
12847 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
12848 | auto maybeo = stack::check_get<Ta*>(L, 1); | ||
12849 | if (!maybeo || maybeo.value() == nullptr) { | ||
12850 | return luaL_error(L, "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)"); | ||
12851 | } | ||
12852 | object_type* o = static_cast<object_type*>(maybeo.value()); | ||
12853 | return call(L, std::forward<Fx>(f), *o); | ||
12854 | #else | ||
12855 | object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1)); | ||
12856 | return call(L, std::forward<Fx>(f), o); | ||
12857 | #endif // Safety | ||
12858 | } | ||
12859 | }; | ||
12860 | |||
12861 | template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack> | ||
12862 | struct lua_call_wrapper<T, F, false, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> { | ||
12863 | typedef lua_bind_traits<F> traits_type; | ||
12864 | typedef wrapper<meta::unqualified_t<F>> wrap; | ||
12865 | typedef typename wrap::object_type object_type; | ||
12866 | |||
12867 | template <typename V> | ||
12868 | static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) { | ||
12869 | typedef typename wrap::args_list args_list; | ||
12870 | typedef typename wrap::caller caller; | ||
12871 | return stack::call_into_lua<checked, clean_stack>(types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, o); | ||
12872 | } | ||
12873 | |||
12874 | template <typename V> | ||
12875 | static int call_assign(std::true_type, lua_State* L, V&& f) { | ||
12876 | typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta; | ||
12877 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
12878 | auto maybeo = stack::check_get<Ta*>(L, 1); | ||
12879 | if (!maybeo || maybeo.value() == nullptr) { | ||
12880 | if (is_variable) { | ||
12881 | return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); | ||
12882 | } | ||
12883 | return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)"); | ||
12884 | } | ||
12885 | object_type* o = static_cast<object_type*>(maybeo.value()); | ||
12886 | return call_assign(std::true_type(), L, f, *o); | ||
12887 | #else | ||
12888 | object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1)); | ||
12889 | return call_assign(std::true_type(), L, f, o); | ||
12890 | #endif // Safety | ||
12891 | } | ||
12892 | |||
12893 | template <typename... Args> | ||
12894 | static int call_assign(std::false_type, lua_State* L, Args&&...) { | ||
12895 | return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); | ||
12896 | } | ||
12897 | |||
12898 | template <typename... Args> | ||
12899 | static int call_const(std::false_type, lua_State* L, Args&&... args) { | ||
12900 | typedef typename traits_type::return_type R; | ||
12901 | return call_assign(std::is_copy_assignable<meta::unqualified_t<R>>(), L, std::forward<Args>(args)...); | ||
12902 | } | ||
12903 | |||
12904 | template <typename... Args> | ||
12905 | static int call_const(std::true_type, lua_State* L, Args&&...) { | ||
12906 | return luaL_error(L, "sol: cannot write to a readonly (const) variable"); | ||
12907 | } | ||
12908 | |||
12909 | template <typename V> | ||
12910 | static int call(lua_State* L, V&& f) { | ||
12911 | return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f)); | ||
12912 | } | ||
12913 | |||
12914 | template <typename V> | ||
12915 | static int call(lua_State* L, V&& f, object_type& o) { | ||
12916 | return call_const(std::is_const<typename traits_type::return_type>(), L, std::forward<V>(f), o); | ||
12917 | } | ||
12918 | }; | ||
12919 | |||
12920 | template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack> | ||
12921 | struct lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_member_object_pointer<F>::value>> { | ||
12922 | typedef lua_bind_traits<F> traits_type; | ||
12923 | typedef wrapper<meta::unqualified_t<F>> wrap; | ||
12924 | typedef typename wrap::object_type object_type; | ||
12925 | |||
12926 | template <typename V> | ||
12927 | static int call(lua_State* L, V&& v, object_type& o) { | ||
12928 | typedef typename wrap::returns_list returns_list; | ||
12929 | typedef typename wrap::caller caller; | ||
12930 | F f(std::forward<V>(v)); | ||
12931 | return stack::call_into_lua<checked, clean_stack>(returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), f, o); | ||
12932 | } | ||
12933 | |||
12934 | template <typename V> | ||
12935 | static int call(lua_State* L, V&& f) { | ||
12936 | typedef std::conditional_t<std::is_void<T>::value, object_type, T> Ta; | ||
12937 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
12938 | auto maybeo = stack::check_get<Ta*>(L, 1); | ||
12939 | if (!maybeo || maybeo.value() == nullptr) { | ||
12940 | if (is_variable) { | ||
12941 | return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); | ||
12942 | } | ||
12943 | return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); | ||
12944 | } | ||
12945 | object_type* o = static_cast<object_type*>(maybeo.value()); | ||
12946 | return call(L, f, *o); | ||
12947 | #else | ||
12948 | object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1)); | ||
12949 | return call(L, f, o); | ||
12950 | #endif // Safety | ||
12951 | } | ||
12952 | }; | ||
12953 | |||
12954 | template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12955 | struct lua_call_wrapper<T, readonly_wrapper<F>, false, is_variable, checked, boost, clean_stack, C> { | ||
12956 | typedef lua_bind_traits<F> traits_type; | ||
12957 | typedef wrapper<meta::unqualified_t<F>> wrap; | ||
12958 | typedef typename wrap::object_type object_type; | ||
12959 | |||
12960 | template <typename V> | ||
12961 | static int call(lua_State* L, V&&) { | ||
12962 | return luaL_error(L, "sol: cannot write to a sol::readonly variable"); | ||
12963 | } | ||
12964 | |||
12965 | template <typename V> | ||
12966 | static int call(lua_State* L, V&&, object_type&) { | ||
12967 | return luaL_error(L, "sol: cannot write to a sol::readonly variable"); | ||
12968 | } | ||
12969 | }; | ||
12970 | |||
12971 | template <typename T, typename F, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12972 | struct lua_call_wrapper<T, readonly_wrapper<F>, true, is_variable, checked, boost, clean_stack, C> : lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> { | ||
12973 | }; | ||
12974 | |||
12975 | template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12976 | struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
12977 | typedef constructor_list<Args...> F; | ||
12978 | |||
12979 | static int call(lua_State* L, F&) { | ||
12980 | const auto& meta = usertype_traits<T>::metatable(); | ||
12981 | int argcount = lua_gettop(L); | ||
12982 | call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot; | ||
12983 | argcount -= static_cast<int>(syntax); | ||
12984 | |||
12985 | T* obj = detail::usertype_allocate<T>(L); | ||
12986 | reference userdataref(L, -1); | ||
12987 | |||
12988 | construct_match<T, Args...>(constructor_match<T, false, clean_stack>(obj), L, argcount, boost + 1 + static_cast<int>(syntax)); | ||
12989 | |||
12990 | userdataref.push(); | ||
12991 | stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]); | ||
12992 | umf(); | ||
12993 | |||
12994 | return 1; | ||
12995 | } | ||
12996 | }; | ||
12997 | |||
12998 | template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
12999 | struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13000 | typedef constructor_wrapper<Cxs...> F; | ||
13001 | |||
13002 | struct onmatch { | ||
13003 | template <typename Fx, std::size_t I, typename... R, typename... Args> | ||
13004 | int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) { | ||
13005 | const auto& meta = usertype_traits<T>::metatable(); | ||
13006 | T* obj = detail::usertype_allocate<T>(L); | ||
13007 | reference userdataref(L, -1); | ||
13008 | |||
13009 | auto& func = std::get<I>(f.functions); | ||
13010 | stack::call_into_lua<checked, clean_stack>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj)); | ||
13011 | |||
13012 | userdataref.push(); | ||
13013 | stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]); | ||
13014 | umf(); | ||
13015 | |||
13016 | return 1; | ||
13017 | } | ||
13018 | }; | ||
13019 | |||
13020 | static int call(lua_State* L, F& f) { | ||
13021 | call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1); | ||
13022 | int syntaxval = static_cast<int>(syntax); | ||
13023 | int argcount = lua_gettop(L) - syntaxval; | ||
13024 | return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f); | ||
13025 | } | ||
13026 | }; | ||
13027 | |||
13028 | template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack> | ||
13029 | struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<std::is_void<Fx>::value>> { | ||
13030 | typedef destructor_wrapper<Fx> F; | ||
13031 | |||
13032 | static int call(lua_State* L, const F&) { | ||
13033 | return detail::usertype_alloc_destruct<T>(L); | ||
13034 | } | ||
13035 | }; | ||
13036 | |||
13037 | template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack> | ||
13038 | struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<!std::is_void<Fx>::value>> { | ||
13039 | typedef destructor_wrapper<Fx> F; | ||
13040 | |||
13041 | static int call_void(std::true_type, lua_State* L, const F& f) { | ||
13042 | typedef meta::bind_traits<meta::unqualified_t<decltype(f.fx)>> bt; | ||
13043 | typedef typename bt::template arg_at<0> arg0; | ||
13044 | typedef meta::unqualified_t<arg0> O; | ||
13045 | |||
13046 | O& obj = stack::get<O>(L); | ||
13047 | f.fx(detail::implicit_wrapper<O>(obj)); | ||
13048 | return 0; | ||
13049 | } | ||
13050 | |||
13051 | static int call_void(std::false_type, lua_State* L, const F& f) { | ||
13052 | T& obj = stack::get<T>(L); | ||
13053 | f.fx(detail::implicit_wrapper<T>(obj)); | ||
13054 | return 0; | ||
13055 | } | ||
13056 | |||
13057 | static int call(lua_State* L, const F& f) { | ||
13058 | return call_void(std::is_void<T>(), L, f); | ||
13059 | } | ||
13060 | }; | ||
13061 | |||
13062 | template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13063 | struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13064 | typedef overload_set<Fs...> F; | ||
13065 | |||
13066 | struct on_match { | ||
13067 | template <typename Fx, std::size_t I, typename... R, typename... Args> | ||
13068 | int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { | ||
13069 | auto& f = std::get<I>(fx.functions); | ||
13070 | return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost>{}.call(L, f); | ||
13071 | } | ||
13072 | }; | ||
13073 | |||
13074 | static int call(lua_State* L, F& fx) { | ||
13075 | return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx); | ||
13076 | } | ||
13077 | }; | ||
13078 | |||
13079 | template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13080 | struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13081 | typedef factory_wrapper<Fs...> F; | ||
13082 | |||
13083 | struct on_match { | ||
13084 | template <typename Fx, std::size_t I, typename... R, typename... Args> | ||
13085 | int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { | ||
13086 | auto& f = std::get<I>(fx.functions); | ||
13087 | return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f); | ||
13088 | } | ||
13089 | }; | ||
13090 | |||
13091 | static int call(lua_State* L, F& fx) { | ||
13092 | return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); | ||
13093 | } | ||
13094 | }; | ||
13095 | |||
13096 | template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13097 | struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13098 | typedef std::conditional_t<is_index, R, W> P; | ||
13099 | typedef meta::unqualified_t<P> U; | ||
13100 | typedef wrapper<U> wrap; | ||
13101 | typedef lua_bind_traits<U> traits_type; | ||
13102 | typedef meta::unqualified_t<typename traits_type::template arg_at<0>> object_type; | ||
13103 | |||
13104 | template <typename F> | ||
13105 | static int self_call(std::true_type, lua_State* L, F&& f) { | ||
13106 | // The type being void means we don't have any arguments, so it might be a free functions? | ||
13107 | typedef typename traits_type::free_args_list args_list; | ||
13108 | typedef typename wrap::returns_list returns_list; | ||
13109 | typedef typename wrap::caller caller; | ||
13110 | return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); | ||
13111 | } | ||
13112 | |||
13113 | template <typename F> | ||
13114 | static int self_call(std::false_type, lua_State* L, F&& f) { | ||
13115 | typedef meta::pop_front_type_t<typename traits_type::free_args_list> args_list; | ||
13116 | typedef T Ta; | ||
13117 | typedef std::remove_pointer_t<object_type> Oa; | ||
13118 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
13119 | auto maybeo = stack::check_get<Ta*>(L, 1); | ||
13120 | if (!maybeo || maybeo.value() == nullptr) { | ||
13121 | if (is_variable) { | ||
13122 | return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); | ||
13123 | } | ||
13124 | return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); | ||
13125 | } | ||
13126 | Oa* o = static_cast<Oa*>(maybeo.value()); | ||
13127 | #else | ||
13128 | Oa* o = static_cast<Oa*>(stack::get<non_null<Ta*>>(L, 1)); | ||
13129 | #endif // Safety | ||
13130 | typedef typename wrap::returns_list returns_list; | ||
13131 | typedef typename wrap::caller caller; | ||
13132 | return stack::call_into_lua<checked, clean_stack>(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, detail::implicit_wrapper<Oa>(*o)); | ||
13133 | } | ||
13134 | |||
13135 | template <typename F, typename... Args> | ||
13136 | static int defer_call(std::false_type, lua_State* L, F&& f, Args&&... args) { | ||
13137 | return self_call(meta::any<std::is_void<object_type>, meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::value != type::userdata>>(), L, pick(meta::boolean<is_index>(), f), std::forward<Args>(args)...); | ||
13138 | } | ||
13139 | |||
13140 | template <typename F, typename... Args> | ||
13141 | static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) { | ||
13142 | auto& p = pick(meta::boolean<is_index>(), std::forward<F>(f)); | ||
13143 | return lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, p, std::forward<Args>(args)...); | ||
13144 | } | ||
13145 | |||
13146 | template <typename F, typename... Args> | ||
13147 | static int call(lua_State* L, F&& f, Args&&... args) { | ||
13148 | typedef meta::any< | ||
13149 | std::is_void<U>, | ||
13150 | std::is_same<U, no_prop>, | ||
13151 | meta::is_specialization_of<U, var_wrapper>, | ||
13152 | meta::is_specialization_of<U, constructor_wrapper>, | ||
13153 | meta::is_specialization_of<U, constructor_list>, | ||
13154 | std::is_member_pointer<U>> | ||
13155 | is_specialized; | ||
13156 | return defer_call(is_specialized(), L, std::forward<F>(f), std::forward<Args>(args)...); | ||
13157 | } | ||
13158 | }; | ||
13159 | |||
13160 | template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13161 | struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13162 | typedef protect_t<V> F; | ||
13163 | |||
13164 | template <typename... Args> | ||
13165 | static int call(lua_State* L, F& fx, Args&&... args) { | ||
13166 | return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack>{}.call(L, fx.value, std::forward<Args>(args)...); | ||
13167 | } | ||
13168 | }; | ||
13169 | |||
13170 | template <typename T, typename F, typename... Filters, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13171 | struct lua_call_wrapper<T, filter_wrapper<F, Filters...>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13172 | typedef filter_wrapper<F, Filters...> P; | ||
13173 | |||
13174 | template <std::size_t... In> | ||
13175 | static int call(std::index_sequence<In...>, lua_State* L, P& fx) { | ||
13176 | int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C>{}.call(L, fx.value); | ||
13177 | (void)detail::swallow{ int(), (filter_detail::handle_filter(std::get<In>(fx.filters), L, pushed), int())... }; | ||
13178 | return pushed; | ||
13179 | } | ||
13180 | |||
13181 | static int call(lua_State* L, P& fx) { | ||
13182 | typedef typename P::indices indices; | ||
13183 | return call(indices(), L, fx); | ||
13184 | } | ||
13185 | }; | ||
13186 | |||
13187 | template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> | ||
13188 | struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> { | ||
13189 | template <typename F> | ||
13190 | static int call(lua_State* L, F&& f) { | ||
13191 | return lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments)); | ||
13192 | } | ||
13193 | }; | ||
13194 | |||
13195 | template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... Args> | ||
13196 | inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { | ||
13197 | return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
13198 | } | ||
13199 | |||
13200 | template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true> | ||
13201 | inline int call_user(lua_State* L) { | ||
13202 | auto& fx = stack::get<user<F>>(L, upvalue_index(start)); | ||
13203 | return call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx); | ||
13204 | } | ||
13205 | |||
13206 | template <typename T, typename = void> | ||
13207 | struct is_var_bind : std::false_type {}; | ||
13208 | |||
13209 | template <typename T> | ||
13210 | struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {}; | ||
13211 | |||
13212 | template <> | ||
13213 | struct is_var_bind<no_prop> : std::true_type {}; | ||
13214 | |||
13215 | template <typename R, typename W> | ||
13216 | struct is_var_bind<property_wrapper<R, W>> : std::true_type {}; | ||
13217 | |||
13218 | template <typename T> | ||
13219 | struct is_var_bind<var_wrapper<T>> : std::true_type {}; | ||
13220 | |||
13221 | template <typename T> | ||
13222 | struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> {}; | ||
13223 | |||
13224 | template <typename F, typename... Filters> | ||
13225 | struct is_var_bind<filter_wrapper<F, Filters...>> : is_var_bind<meta::unqualified_t<F>> {}; | ||
13226 | } // namespace call_detail | ||
13227 | |||
13228 | template <typename T> | ||
13229 | struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {}; | ||
13230 | |||
13231 | template <typename T> | ||
13232 | struct is_function_binding : meta::neg<is_variable_binding<T>> {}; | ||
13233 | |||
13234 | } // namespace sol | ||
13235 | |||
13236 | // end of sol/call.hpp | ||
13237 | |||
13238 | namespace sol { | ||
13239 | namespace function_detail { | ||
13240 | template <typename F, F fx> | ||
13241 | inline int call_wrapper_variable(std::false_type, lua_State* L) { | ||
13242 | typedef meta::bind_traits<meta::unqualified_t<F>> traits_type; | ||
13243 | typedef typename traits_type::args_list args_list; | ||
13244 | typedef meta::tuple_types<typename traits_type::return_type> return_type; | ||
13245 | return stack::call_into_lua(return_type(), args_list(), L, 1, fx); | ||
13246 | } | ||
13247 | |||
13248 | template <typename R, typename V, V, typename T> | ||
13249 | inline int call_set_assignable(std::false_type, T&&, lua_State* L) { | ||
13250 | return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); | ||
13251 | } | ||
13252 | |||
13253 | template <typename R, typename V, V variable, typename T> | ||
13254 | inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) { | ||
13255 | (mem.*variable) = stack::get<R>(L, 2); | ||
13256 | return 0; | ||
13257 | } | ||
13258 | |||
13259 | template <typename R, typename V, V, typename T> | ||
13260 | inline int call_set_variable(std::false_type, lua_State* L, T&&) { | ||
13261 | return luaL_error(L, "cannot write to a const variable"); | ||
13262 | } | ||
13263 | |||
13264 | template <typename R, typename V, V variable, typename T> | ||
13265 | inline int call_set_variable(std::true_type, lua_State* L, T&& mem) { | ||
13266 | return call_set_assignable<R, V, variable>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, std::forward<T>(mem)); | ||
13267 | } | ||
13268 | |||
13269 | template <typename V, V variable> | ||
13270 | inline int call_wrapper_variable(std::true_type, lua_State* L) { | ||
13271 | typedef meta::bind_traits<meta::unqualified_t<V>> traits_type; | ||
13272 | typedef typename traits_type::object_type T; | ||
13273 | typedef typename traits_type::return_type R; | ||
13274 | auto& mem = stack::get<T>(L, 1); | ||
13275 | switch (lua_gettop(L)) { | ||
13276 | case 1: { | ||
13277 | decltype(auto) r = (mem.*variable); | ||
13278 | stack::push_reference(L, std::forward<decltype(r)>(r)); | ||
13279 | return 1; | ||
13280 | } | ||
13281 | case 2: | ||
13282 | return call_set_variable<R, V, variable>(meta::neg<std::is_const<R>>(), L, mem); | ||
13283 | default: | ||
13284 | return luaL_error(L, "incorrect number of arguments to member variable function call"); | ||
13285 | } | ||
13286 | } | ||
13287 | |||
13288 | template <typename F, F fx> | ||
13289 | inline int call_wrapper_function(std::false_type, lua_State* L) { | ||
13290 | return call_wrapper_variable<F, fx>(std::is_member_object_pointer<F>(), L); | ||
13291 | } | ||
13292 | |||
13293 | template <typename F, F fx> | ||
13294 | inline int call_wrapper_function(std::true_type, lua_State* L) { | ||
13295 | return call_detail::call_wrapped<void, false, false>(L, fx); | ||
13296 | } | ||
13297 | |||
13298 | template <typename F, F fx> | ||
13299 | int call_wrapper_entry(lua_State* L) noexcept(meta::bind_traits<F>::is_noexcept) { | ||
13300 | return call_wrapper_function<F, fx>(std::is_member_function_pointer<meta::unqualified_t<F>>(), L); | ||
13301 | } | ||
13302 | |||
13303 | template <typename... Fxs> | ||
13304 | struct c_call_matcher { | ||
13305 | template <typename Fx, std::size_t I, typename R, typename... Args> | ||
13306 | int operator()(types<Fx>, index_value<I>, types<R>, types<Args...>, lua_State* L, int, int) const { | ||
13307 | typedef meta::at_in_pack_t<I, Fxs...> target; | ||
13308 | return target::call(L); | ||
13309 | } | ||
13310 | }; | ||
13311 | |||
13312 | template <typename F, F fx> | ||
13313 | inline int c_call_raw(std::true_type, lua_State* L) { | ||
13314 | return fx(L); | ||
13315 | } | ||
13316 | |||
13317 | template <typename F, F fx> | ||
13318 | inline int c_call_raw(std::false_type, lua_State* L) { | ||
13319 | #ifdef __clang__ | ||
13320 | return detail::trampoline(L, function_detail::call_wrapper_entry<F, fx>); | ||
13321 | #else | ||
13322 | return detail::typed_static_trampoline<decltype(&function_detail::call_wrapper_entry<F, fx>), (&function_detail::call_wrapper_entry<F, fx>)>(L); | ||
13323 | #endif // fuck you clang :c | ||
13324 | } | ||
13325 | |||
13326 | } // namespace function_detail | ||
13327 | |||
13328 | template <typename F, F fx> | ||
13329 | inline int c_call(lua_State* L) { | ||
13330 | typedef meta::unqualified_t<F> Fu; | ||
13331 | typedef std::integral_constant<bool, std::is_same<Fu, lua_CFunction>::value | ||
13332 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
13333 | || std::is_same<Fu, detail::lua_CFunction_noexcept>::value | ||
13334 | #endif | ||
13335 | > is_raw; | ||
13336 | return function_detail::c_call_raw<F, fx>(is_raw(), L); | ||
13337 | } | ||
13338 | |||
13339 | template <typename F, F f> | ||
13340 | struct wrap { | ||
13341 | typedef F type; | ||
13342 | |||
13343 | static int call(lua_State* L) { | ||
13344 | return c_call<type, f>(L); | ||
13345 | } | ||
13346 | }; | ||
13347 | |||
13348 | template <typename... Fxs> | ||
13349 | inline int c_call(lua_State* L) { | ||
13350 | if (sizeof...(Fxs) < 2) { | ||
13351 | return meta::at_in_pack_t<0, Fxs...>::call(L); | ||
13352 | } | ||
13353 | else { | ||
13354 | return call_detail::overload_match_arity<typename Fxs::type...>(function_detail::c_call_matcher<Fxs...>(), L, lua_gettop(L), 1); | ||
13355 | } | ||
13356 | } | ||
13357 | |||
13358 | } // namespace sol | ||
13359 | |||
13360 | // end of sol/function_types_templated.hpp | ||
13361 | |||
13362 | // beginning of sol/function_types_stateless.hpp | ||
13363 | |||
13364 | namespace sol { | ||
13365 | namespace function_detail { | ||
13366 | template <typename Function, bool is_yielding> | ||
13367 | struct upvalue_free_function { | ||
13368 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13369 | typedef meta::bind_traits<function_type> traits_type; | ||
13370 | |||
13371 | static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { | ||
13372 | auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L); | ||
13373 | function_type* fx = udata.first; | ||
13374 | return call_detail::call_wrapped<void, true, false>(L, fx); | ||
13375 | } | ||
13376 | |||
13377 | static int call(lua_State* L) { | ||
13378 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13379 | if (is_yielding) { | ||
13380 | return lua_yield(L, nr); | ||
13381 | } | ||
13382 | else { | ||
13383 | return nr; | ||
13384 | } | ||
13385 | } | ||
13386 | |||
13387 | int operator()(lua_State* L) { | ||
13388 | return call(L); | ||
13389 | } | ||
13390 | }; | ||
13391 | |||
13392 | template <typename T, typename Function, bool is_yielding> | ||
13393 | struct upvalue_member_function { | ||
13394 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13395 | typedef lua_bind_traits<function_type> traits_type; | ||
13396 | |||
13397 | static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { | ||
13398 | // Layout: | ||
13399 | // idx 1...n: verbatim data of member function pointer | ||
13400 | // idx n + 1: is the object's void pointer | ||
13401 | // We don't need to store the size, because the other side is templated | ||
13402 | // with the same member function pointer type | ||
13403 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13404 | auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); | ||
13405 | function_type& memfx = memberdata.first; | ||
13406 | auto& item = *objdata.first; | ||
13407 | return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item); | ||
13408 | } | ||
13409 | |||
13410 | static int call(lua_State* L) { | ||
13411 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13412 | if (is_yielding) { | ||
13413 | return lua_yield(L, nr); | ||
13414 | } | ||
13415 | else { | ||
13416 | return nr; | ||
13417 | } | ||
13418 | } | ||
13419 | |||
13420 | int operator()(lua_State* L) { | ||
13421 | return call(L); | ||
13422 | } | ||
13423 | }; | ||
13424 | |||
13425 | template <typename T, typename Function, bool is_yielding> | ||
13426 | struct upvalue_member_variable { | ||
13427 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13428 | typedef lua_bind_traits<function_type> traits_type; | ||
13429 | |||
13430 | static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { | ||
13431 | // Layout: | ||
13432 | // idx 1...n: verbatim data of member variable pointer | ||
13433 | // idx n + 1: is the object's void pointer | ||
13434 | // We don't need to store the size, because the other side is templated | ||
13435 | // with the same member function pointer type | ||
13436 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13437 | auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); | ||
13438 | auto& mem = *objdata.first; | ||
13439 | function_type& var = memberdata.first; | ||
13440 | switch (lua_gettop(L)) { | ||
13441 | case 0: | ||
13442 | return call_detail::call_wrapped<T, true, false, -1>(L, var, mem); | ||
13443 | case 1: | ||
13444 | return call_detail::call_wrapped<T, false, false, -1>(L, var, mem); | ||
13445 | default: | ||
13446 | return luaL_error(L, "sol: incorrect number of arguments to member variable function"); | ||
13447 | } | ||
13448 | } | ||
13449 | |||
13450 | static int call(lua_State* L) { | ||
13451 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13452 | if (is_yielding) { | ||
13453 | return lua_yield(L, nr); | ||
13454 | } | ||
13455 | else { | ||
13456 | return nr; | ||
13457 | } | ||
13458 | } | ||
13459 | |||
13460 | int operator()(lua_State* L) { | ||
13461 | return call(L); | ||
13462 | } | ||
13463 | }; | ||
13464 | |||
13465 | template <typename T, typename Function, bool is_yielding> | ||
13466 | struct upvalue_member_variable<T, readonly_wrapper<Function>, is_yielding> { | ||
13467 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13468 | typedef lua_bind_traits<function_type> traits_type; | ||
13469 | |||
13470 | static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { | ||
13471 | // Layout: | ||
13472 | // idx 1...n: verbatim data of member variable pointer | ||
13473 | // idx n + 1: is the object's void pointer | ||
13474 | // We don't need to store the size, because the other side is templated | ||
13475 | // with the same member function pointer type | ||
13476 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13477 | auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); | ||
13478 | auto& mem = *objdata.first; | ||
13479 | function_type& var = memberdata.first; | ||
13480 | switch (lua_gettop(L)) { | ||
13481 | case 0: | ||
13482 | return call_detail::call_wrapped<T, true, false, -1>(L, var, mem); | ||
13483 | default: | ||
13484 | return luaL_error(L, "sol: incorrect number of arguments to member variable function"); | ||
13485 | } | ||
13486 | } | ||
13487 | |||
13488 | static int call(lua_State* L) { | ||
13489 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13490 | if (is_yielding) { | ||
13491 | return lua_yield(L, nr); | ||
13492 | } | ||
13493 | else { | ||
13494 | return nr; | ||
13495 | } | ||
13496 | } | ||
13497 | |||
13498 | int operator()(lua_State* L) { | ||
13499 | return call(L); | ||
13500 | } | ||
13501 | }; | ||
13502 | |||
13503 | template <typename T, typename Function, bool is_yielding> | ||
13504 | struct upvalue_this_member_function { | ||
13505 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13506 | typedef lua_bind_traits<function_type> traits_type; | ||
13507 | |||
13508 | static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { | ||
13509 | // Layout: | ||
13510 | // idx 1...n: verbatim data of member variable pointer | ||
13511 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13512 | function_type& memfx = memberdata.first; | ||
13513 | return call_detail::call_wrapped<T, false, false>(L, memfx); | ||
13514 | } | ||
13515 | |||
13516 | static int call(lua_State* L) { | ||
13517 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13518 | if (is_yielding) { | ||
13519 | return lua_yield(L, nr); | ||
13520 | } | ||
13521 | else { | ||
13522 | return nr; | ||
13523 | } | ||
13524 | } | ||
13525 | |||
13526 | int operator()(lua_State* L) { | ||
13527 | return call(L); | ||
13528 | } | ||
13529 | }; | ||
13530 | |||
13531 | template <typename T, typename Function, bool is_yielding> | ||
13532 | struct upvalue_this_member_variable { | ||
13533 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13534 | |||
13535 | static int real_call(lua_State* L) noexcept(false) { | ||
13536 | // Layout: | ||
13537 | // idx 1...n: verbatim data of member variable pointer | ||
13538 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13539 | function_type& var = memberdata.first; | ||
13540 | switch (lua_gettop(L)) { | ||
13541 | case 1: | ||
13542 | return call_detail::call_wrapped<T, true, false>(L, var); | ||
13543 | case 2: | ||
13544 | return call_detail::call_wrapped<T, false, false>(L, var); | ||
13545 | default: | ||
13546 | return luaL_error(L, "sol: incorrect number of arguments to member variable function"); | ||
13547 | } | ||
13548 | } | ||
13549 | |||
13550 | static int call(lua_State* L) { | ||
13551 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13552 | if (is_yielding) { | ||
13553 | return lua_yield(L, nr); | ||
13554 | } | ||
13555 | else { | ||
13556 | return nr; | ||
13557 | } | ||
13558 | } | ||
13559 | |||
13560 | int operator()(lua_State* L) { | ||
13561 | return call(L); | ||
13562 | } | ||
13563 | }; | ||
13564 | |||
13565 | template <typename T, typename Function, bool is_yielding> | ||
13566 | struct upvalue_this_member_variable<T, readonly_wrapper<Function>, is_yielding> { | ||
13567 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13568 | typedef lua_bind_traits<function_type> traits_type; | ||
13569 | |||
13570 | static int real_call(lua_State* L) noexcept(false) { | ||
13571 | // Layout: | ||
13572 | // idx 1...n: verbatim data of member variable pointer | ||
13573 | auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); | ||
13574 | function_type& var = memberdata.first; | ||
13575 | switch (lua_gettop(L)) { | ||
13576 | case 1: | ||
13577 | return call_detail::call_wrapped<T, true, false>(L, var); | ||
13578 | default: | ||
13579 | return luaL_error(L, "sol: incorrect number of arguments to member variable function"); | ||
13580 | } | ||
13581 | } | ||
13582 | |||
13583 | static int call(lua_State* L) { | ||
13584 | int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); | ||
13585 | if (is_yielding) { | ||
13586 | return lua_yield(L, nr); | ||
13587 | } | ||
13588 | else { | ||
13589 | return nr; | ||
13590 | } | ||
13591 | } | ||
13592 | |||
13593 | int operator()(lua_State* L) { | ||
13594 | return call(L); | ||
13595 | } | ||
13596 | }; | ||
13597 | } | ||
13598 | } // namespace sol::function_detail | ||
13599 | |||
13600 | // end of sol/function_types_stateless.hpp | ||
13601 | |||
13602 | // beginning of sol/function_types_stateful.hpp | ||
13603 | |||
13604 | namespace sol { | ||
13605 | namespace function_detail { | ||
13606 | template <typename Func, bool is_yielding> | ||
13607 | struct functor_function { | ||
13608 | typedef std::decay_t<meta::unwrap_unqualified_t<Func>> function_type; | ||
13609 | function_type fx; | ||
13610 | |||
13611 | template <typename... Args> | ||
13612 | functor_function(function_type f, Args&&... args) | ||
13613 | : fx(std::move(f), std::forward<Args>(args)...) { | ||
13614 | } | ||
13615 | |||
13616 | int call(lua_State* L) { | ||
13617 | int nr = call_detail::call_wrapped<void, true, false>(L, fx); | ||
13618 | if (is_yielding) { | ||
13619 | return lua_yield(L, nr); | ||
13620 | } | ||
13621 | else { | ||
13622 | return nr; | ||
13623 | } | ||
13624 | } | ||
13625 | |||
13626 | int operator()(lua_State* L) { | ||
13627 | auto f = [&](lua_State*) -> int { return this->call(L); }; | ||
13628 | return detail::trampoline(L, f); | ||
13629 | } | ||
13630 | }; | ||
13631 | |||
13632 | template <typename T, typename Function, bool is_yielding> | ||
13633 | struct member_function { | ||
13634 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13635 | typedef meta::function_return_t<function_type> return_type; | ||
13636 | typedef meta::function_args_t<function_type> args_lists; | ||
13637 | function_type invocation; | ||
13638 | T member; | ||
13639 | |||
13640 | template <typename... Args> | ||
13641 | member_function(function_type f, Args&&... args) | ||
13642 | : invocation(std::move(f)), member(std::forward<Args>(args)...) { | ||
13643 | } | ||
13644 | |||
13645 | int call(lua_State* L) { | ||
13646 | int nr = call_detail::call_wrapped<T, true, false, -1>(L, invocation, detail::unwrap(detail::deref(member))); | ||
13647 | if (is_yielding) { | ||
13648 | return lua_yield(L, nr); | ||
13649 | } | ||
13650 | else { | ||
13651 | return nr; | ||
13652 | } | ||
13653 | } | ||
13654 | |||
13655 | int operator()(lua_State* L) { | ||
13656 | auto f = [&](lua_State*) -> int { return this->call(L); }; | ||
13657 | return detail::trampoline(L, f); | ||
13658 | } | ||
13659 | }; | ||
13660 | |||
13661 | template <typename T, typename Function, bool is_yielding> | ||
13662 | struct member_variable { | ||
13663 | typedef std::remove_pointer_t<std::decay_t<Function>> function_type; | ||
13664 | typedef typename meta::bind_traits<function_type>::return_type return_type; | ||
13665 | typedef typename meta::bind_traits<function_type>::args_list args_lists; | ||
13666 | function_type var; | ||
13667 | T member; | ||
13668 | typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M; | ||
13669 | |||
13670 | template <typename... Args> | ||
13671 | member_variable(function_type v, Args&&... args) | ||
13672 | : var(std::move(v)), member(std::forward<Args>(args)...) { | ||
13673 | } | ||
13674 | |||
13675 | int call(lua_State* L) { | ||
13676 | int nr; | ||
13677 | { | ||
13678 | M mem = detail::unwrap(detail::deref(member)); | ||
13679 | switch (lua_gettop(L)) { | ||
13680 | case 0: | ||
13681 | nr = call_detail::call_wrapped<T, true, false, -1>(L, var, mem); | ||
13682 | break; | ||
13683 | case 1: | ||
13684 | nr = call_detail::call_wrapped<T, false, false, -1>(L, var, mem); | ||
13685 | break; | ||
13686 | default: | ||
13687 | nr = luaL_error(L, "sol: incorrect number of arguments to member variable function"); | ||
13688 | break; | ||
13689 | } | ||
13690 | } | ||
13691 | if (is_yielding) { | ||
13692 | return lua_yield(L, nr); | ||
13693 | } | ||
13694 | else { | ||
13695 | return nr; | ||
13696 | } | ||
13697 | } | ||
13698 | |||
13699 | int operator()(lua_State* L) { | ||
13700 | auto f = [&](lua_State*) -> int { return this->call(L); }; | ||
13701 | return detail::trampoline(L, f); | ||
13702 | } | ||
13703 | }; | ||
13704 | } | ||
13705 | } // namespace sol::function_detail | ||
13706 | |||
13707 | // end of sol/function_types_stateful.hpp | ||
13708 | |||
13709 | // beginning of sol/function_types_overloaded.hpp | ||
13710 | |||
13711 | namespace sol { | ||
13712 | namespace function_detail { | ||
13713 | template <int start_skew = 0, typename... Functions> | ||
13714 | struct overloaded_function { | ||
13715 | typedef std::tuple<Functions...> overload_list; | ||
13716 | typedef std::make_index_sequence<sizeof...(Functions)> indices; | ||
13717 | overload_list overloads; | ||
13718 | |||
13719 | overloaded_function(overload_list set) | ||
13720 | : overloads(std::move(set)) { | ||
13721 | } | ||
13722 | |||
13723 | overloaded_function(Functions... fxs) | ||
13724 | : overloads(fxs...) { | ||
13725 | } | ||
13726 | |||
13727 | template <typename Fx, std::size_t I, typename... R, typename... Args> | ||
13728 | int call(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) { | ||
13729 | auto& func = std::get<I>(overloads); | ||
13730 | return call_detail::call_wrapped<void, true, false, start_skew>(L, func); | ||
13731 | } | ||
13732 | |||
13733 | int operator()(lua_State* L) { | ||
13734 | auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); }; | ||
13735 | return call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew); | ||
13736 | } | ||
13737 | }; | ||
13738 | } | ||
13739 | } // namespace sol::function_detail | ||
13740 | |||
13741 | // end of sol/function_types_overloaded.hpp | ||
13742 | |||
13743 | // beginning of sol/resolve.hpp | ||
13744 | |||
13745 | namespace sol { | ||
13746 | |||
13747 | #ifndef __clang__ | ||
13748 | // constexpr is fine for not-clang | ||
13749 | |||
13750 | namespace detail { | ||
13751 | template <typename R, typename... Args, typename F, typename = std::result_of_t<meta::unqualified_t<F>(Args...)>> | ||
13752 | inline constexpr auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) { | ||
13753 | using Sig = R(Args...); | ||
13754 | typedef meta::unqualified_t<F> Fu; | ||
13755 | return static_cast<Sig Fu::*>(&Fu::operator()); | ||
13756 | } | ||
13757 | |||
13758 | template <typename F, typename U = meta::unqualified_t<F>> | ||
13759 | inline constexpr auto resolve_f(std::true_type, F&& f) | ||
13760 | -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) { | ||
13761 | return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f)); | ||
13762 | } | ||
13763 | |||
13764 | template <typename F> | ||
13765 | inline constexpr void resolve_f(std::false_type, F&&) { | ||
13766 | static_assert(meta::has_deducible_signature<F>::value, | ||
13767 | "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); | ||
13768 | } | ||
13769 | |||
13770 | template <typename F, typename U = meta::unqualified_t<F>> | ||
13771 | inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) { | ||
13772 | return resolve_f(meta::has_deducible_signature<U>{}, std::forward<F>(f)); | ||
13773 | } | ||
13774 | |||
13775 | template <typename... Args, typename F, typename R = std::result_of_t<F&(Args...)>> | ||
13776 | inline constexpr auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) { | ||
13777 | return resolve_i(types<R(Args...)>(), std::forward<F>(f)); | ||
13778 | } | ||
13779 | |||
13780 | template <typename Sig, typename C> | ||
13781 | inline constexpr Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) { | ||
13782 | return mem_func_ptr; | ||
13783 | } | ||
13784 | |||
13785 | template <typename Sig, typename C> | ||
13786 | inline constexpr Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) { | ||
13787 | return mem_variable_ptr; | ||
13788 | } | ||
13789 | } // namespace detail | ||
13790 | |||
13791 | template <typename... Args, typename R> | ||
13792 | inline constexpr auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) { | ||
13793 | return fun_ptr; | ||
13794 | } | ||
13795 | |||
13796 | template <typename Sig> | ||
13797 | inline constexpr Sig* resolve(Sig* fun_ptr) { | ||
13798 | return fun_ptr; | ||
13799 | } | ||
13800 | |||
13801 | template <typename... Args, typename R, typename C> | ||
13802 | inline constexpr auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) { | ||
13803 | return mem_ptr; | ||
13804 | } | ||
13805 | |||
13806 | template <typename Sig, typename C> | ||
13807 | inline constexpr Sig C::*resolve(Sig C::*mem_ptr) { | ||
13808 | return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr); | ||
13809 | } | ||
13810 | |||
13811 | template <typename... Sig, typename F, meta::disable<std::is_function<meta::unqualified_t<F>>> = meta::enabler> | ||
13812 | inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) { | ||
13813 | return detail::resolve_i(types<Sig...>(), std::forward<F>(f)); | ||
13814 | } | ||
13815 | #else | ||
13816 | |||
13817 | // Clang has distinct problems with constexpr arguments, | ||
13818 | // so don't use the constexpr versions inside of clang. | ||
13819 | |||
13820 | namespace detail { | ||
13821 | template <typename R, typename... Args, typename F, typename = std::result_of_t<meta::unqualified_t<F>(Args...)>> | ||
13822 | inline auto resolve_i(types<R(Args...)>, F &&) -> R (meta::unqualified_t<F>::*)(Args...) { | ||
13823 | using Sig = R(Args...); | ||
13824 | typedef meta::unqualified_t<F> Fu; | ||
13825 | return static_cast<Sig Fu::*>(&Fu::operator()); | ||
13826 | } | ||
13827 | |||
13828 | template <typename F, typename U = meta::unqualified_t<F>> | ||
13829 | inline auto resolve_f(std::true_type, F&& f) | ||
13830 | -> decltype(resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f))) { | ||
13831 | return resolve_i(types<meta::function_signature_t<decltype(&U::operator())>>(), std::forward<F>(f)); | ||
13832 | } | ||
13833 | |||
13834 | template <typename F> | ||
13835 | inline void resolve_f(std::false_type, F&&) { | ||
13836 | static_assert(meta::has_deducible_signature<F>::value, | ||
13837 | "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); | ||
13838 | } | ||
13839 | |||
13840 | template <typename F, typename U = meta::unqualified_t<F>> | ||
13841 | inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature<U>(), std::forward<F>(f))) { | ||
13842 | return resolve_f(meta::has_deducible_signature<U>{}, std::forward<F>(f)); | ||
13843 | } | ||
13844 | |||
13845 | template <typename... Args, typename F, typename R = std::result_of_t<F&(Args...)>> | ||
13846 | inline auto resolve_i(types<Args...>, F&& f) -> decltype(resolve_i(types<R(Args...)>(), std::forward<F>(f))) { | ||
13847 | return resolve_i(types<R(Args...)>(), std::forward<F>(f)); | ||
13848 | } | ||
13849 | |||
13850 | template <typename Sig, typename C> | ||
13851 | inline Sig C::*resolve_v(std::false_type, Sig C::*mem_func_ptr) { | ||
13852 | return mem_func_ptr; | ||
13853 | } | ||
13854 | |||
13855 | template <typename Sig, typename C> | ||
13856 | inline Sig C::*resolve_v(std::true_type, Sig C::*mem_variable_ptr) { | ||
13857 | return mem_variable_ptr; | ||
13858 | } | ||
13859 | } // namespace detail | ||
13860 | |||
13861 | template <typename... Args, typename R> | ||
13862 | inline auto resolve(R fun_ptr(Args...)) -> R (*)(Args...) { | ||
13863 | return fun_ptr; | ||
13864 | } | ||
13865 | |||
13866 | template <typename Sig> | ||
13867 | inline Sig* resolve(Sig* fun_ptr) { | ||
13868 | return fun_ptr; | ||
13869 | } | ||
13870 | |||
13871 | template <typename... Args, typename R, typename C> | ||
13872 | inline auto resolve(R (C::*mem_ptr)(Args...)) -> R (C::*)(Args...) { | ||
13873 | return mem_ptr; | ||
13874 | } | ||
13875 | |||
13876 | template <typename Sig, typename C> | ||
13877 | inline Sig C::*resolve(Sig C::*mem_ptr) { | ||
13878 | return detail::resolve_v(std::is_member_object_pointer<Sig C::*>(), mem_ptr); | ||
13879 | } | ||
13880 | |||
13881 | template <typename... Sig, typename F> | ||
13882 | inline auto resolve(F&& f) -> decltype(detail::resolve_i(types<Sig...>(), std::forward<F>(f))) { | ||
13883 | return detail::resolve_i(types<Sig...>(), std::forward<F>(f)); | ||
13884 | } | ||
13885 | |||
13886 | #endif | ||
13887 | |||
13888 | } // namespace sol | ||
13889 | |||
13890 | // end of sol/resolve.hpp | ||
13891 | |||
13892 | namespace sol { | ||
13893 | namespace function_detail { | ||
13894 | template <typename T> | ||
13895 | struct class_indicator {}; | ||
13896 | |||
13897 | struct call_indicator {}; | ||
13898 | } // namespace function_detail | ||
13899 | |||
13900 | namespace stack { | ||
13901 | template <typename... Sigs> | ||
13902 | struct pusher<function_sig<Sigs...>> { | ||
13903 | template <bool is_yielding, typename... Sig, typename Fx, typename... Args> | ||
13904 | static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) { | ||
13905 | typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; | ||
13906 | typedef function_detail::functor_function<clean_fx, is_yielding> F; | ||
13907 | set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
13908 | } | ||
13909 | |||
13910 | template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> | ||
13911 | static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { | ||
13912 | using fx_ptr_t = R (*)(A...); | ||
13913 | fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); | ||
13914 | select_function<is_yielding>(std::true_type(), L, fxptr, std::forward<Args>(args)...); | ||
13915 | } | ||
13916 | |||
13917 | template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> | ||
13918 | static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) { | ||
13919 | typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t; | ||
13920 | typedef R (*fx_ptr_t)(A...); | ||
13921 | typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible; | ||
13922 | select_convertible<is_yielding>(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
13923 | } | ||
13924 | |||
13925 | template <bool is_yielding, typename Fx, typename... Args> | ||
13926 | static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { | ||
13927 | typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig; | ||
13928 | select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
13929 | } | ||
13930 | |||
13931 | template <bool is_yielding, typename Fx, typename T, typename... Args> | ||
13932 | static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
13933 | typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; | ||
13934 | typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F; | ||
13935 | set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); | ||
13936 | } | ||
13937 | |||
13938 | template <bool is_yielding, typename Fx, typename T, typename... Args> | ||
13939 | static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
13940 | typedef std::decay_t<Fx> dFx; | ||
13941 | dFx memfxptr(std::forward<Fx>(fx)); | ||
13942 | auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); | ||
13943 | lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; | ||
13944 | |||
13945 | int upvalues = 0; | ||
13946 | upvalues += stack::push(L, nullptr); | ||
13947 | upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); | ||
13948 | upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); | ||
13949 | stack::push(L, c_closure(freefunc, upvalues)); | ||
13950 | } | ||
13951 | |||
13952 | template <bool is_yielding, typename Fx, typename... Args> | ||
13953 | static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { | ||
13954 | select_convertible<is_yielding>(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
13955 | } | ||
13956 | |||
13957 | template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler> | ||
13958 | static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
13959 | typedef meta::boolean<meta::is_specialization_of<meta::unqualified_t<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference; | ||
13960 | select_reference_member_variable<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); | ||
13961 | } | ||
13962 | |||
13963 | template <bool is_yielding, typename Fx, typename C> | ||
13964 | static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { | ||
13965 | lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call; | ||
13966 | |||
13967 | int upvalues = 0; | ||
13968 | upvalues += stack::push(L, nullptr); | ||
13969 | upvalues += stack::stack_detail::push_as_upvalues(L, fx); | ||
13970 | stack::push(L, c_closure(freefunc, upvalues)); | ||
13971 | } | ||
13972 | |||
13973 | template <bool is_yielding, typename Fx> | ||
13974 | static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { | ||
13975 | typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; | ||
13976 | lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call; | ||
13977 | |||
13978 | int upvalues = 0; | ||
13979 | upvalues += stack::push(L, nullptr); | ||
13980 | upvalues += stack::stack_detail::push_as_upvalues(L, fx); | ||
13981 | stack::push(L, c_closure(freefunc, upvalues)); | ||
13982 | } | ||
13983 | |||
13984 | template <bool is_yielding, typename Fx, typename T, typename... Args> | ||
13985 | static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
13986 | typedef std::decay_t<Fx> clean_fx; | ||
13987 | typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F; | ||
13988 | set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); | ||
13989 | } | ||
13990 | |||
13991 | template <bool is_yielding, typename Fx, typename T, typename... Args> | ||
13992 | static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
13993 | typedef std::decay_t<Fx> dFx; | ||
13994 | dFx memfxptr(std::forward<Fx>(fx)); | ||
13995 | auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); | ||
13996 | lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; | ||
13997 | |||
13998 | int upvalues = 0; | ||
13999 | upvalues += stack::push(L, nullptr); | ||
14000 | upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); | ||
14001 | upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); | ||
14002 | stack::push(L, c_closure(freefunc, upvalues)); | ||
14003 | } | ||
14004 | |||
14005 | template <bool is_yielding, typename Fx, typename... Args> | ||
14006 | static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { | ||
14007 | select_member_variable<is_yielding>(meta::is_member_object<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
14008 | } | ||
14009 | |||
14010 | template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler> | ||
14011 | static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { | ||
14012 | typedef meta::boolean<meta::is_specialization_of<meta::unqualified_t<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference; | ||
14013 | select_reference_member_function<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); | ||
14014 | } | ||
14015 | |||
14016 | template <bool is_yielding, typename Fx, typename C> | ||
14017 | static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { | ||
14018 | lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call; | ||
14019 | |||
14020 | int upvalues = 0; | ||
14021 | upvalues += stack::push(L, nullptr); | ||
14022 | upvalues += stack::stack_detail::push_as_upvalues(L, fx); | ||
14023 | stack::push(L, c_closure(freefunc, upvalues)); | ||
14024 | } | ||
14025 | |||
14026 | template <bool is_yielding, typename Fx> | ||
14027 | static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { | ||
14028 | typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; | ||
14029 | lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call; | ||
14030 | |||
14031 | int upvalues = 0; | ||
14032 | upvalues += stack::push(L, nullptr); | ||
14033 | upvalues += stack::stack_detail::push_as_upvalues(L, fx); | ||
14034 | stack::push(L, c_closure(freefunc, upvalues)); | ||
14035 | } | ||
14036 | |||
14037 | template <bool is_yielding, typename Fx, typename... Args> | ||
14038 | static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { | ||
14039 | select_member_function<is_yielding>(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
14040 | } | ||
14041 | |||
14042 | template <bool is_yielding, typename Fx, typename... Args> | ||
14043 | static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { | ||
14044 | std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
14045 | lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call; | ||
14046 | |||
14047 | int upvalues = 0; | ||
14048 | upvalues += stack::push(L, nullptr); | ||
14049 | upvalues += stack::stack_detail::push_as_upvalues(L, target); | ||
14050 | stack::push(L, c_closure(freefunc, upvalues)); | ||
14051 | } | ||
14052 | |||
14053 | template <bool is_yielding> | ||
14054 | static void select_function(std::true_type, lua_State* L, lua_CFunction f) { | ||
14055 | // TODO: support yielding | ||
14056 | stack::push(L, f); | ||
14057 | } | ||
14058 | |||
14059 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
14060 | template <bool is_yielding> | ||
14061 | static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { | ||
14062 | // TODO: support yielding | ||
14063 | stack::push(L, f); | ||
14064 | } | ||
14065 | #endif // noexcept function type | ||
14066 | |||
14067 | template <bool is_yielding, typename Fx, typename... Args, meta::disable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler> | ||
14068 | static void select(lua_State* L, Fx&& fx, Args&&... args) { | ||
14069 | select_function<is_yielding>(std::is_function<std::remove_pointer_t<meta::unqualified_t<Fx>>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); | ||
14070 | } | ||
14071 | |||
14072 | template <bool is_yielding, typename Fx, meta::enable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler> | ||
14073 | static void select(lua_State* L, Fx&& fx) { | ||
14074 | // TODO: hoist into lambda in this case?? | ||
14075 | stack::push(L, std::forward<Fx>(fx)); | ||
14076 | } | ||
14077 | |||
14078 | template <bool is_yielding, typename Fx, typename... Args> | ||
14079 | static void set_fx(lua_State* L, Args&&... args) { | ||
14080 | lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>; | ||
14081 | |||
14082 | int upvalues = 0; | ||
14083 | upvalues += stack::push(L, nullptr); | ||
14084 | upvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...); | ||
14085 | stack::push(L, c_closure(freefunc, upvalues)); | ||
14086 | } | ||
14087 | |||
14088 | template <typename Arg0, typename... Args, meta::disable<std::is_same<detail::yield_tag_t, meta::unqualified_t<Arg0>>> = meta::enabler> | ||
14089 | static int push(lua_State* L, Arg0&& arg0, Args&&... args) { | ||
14090 | // Set will always place one thing (function) on the stack | ||
14091 | select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); | ||
14092 | return 1; | ||
14093 | } | ||
14094 | |||
14095 | template <typename... Args> | ||
14096 | static int push(lua_State* L, detail::yield_tag_t, Args&&... args) { | ||
14097 | // Set will always place one thing (function) on the stack | ||
14098 | select<true>(L, std::forward<Args>(args)...); | ||
14099 | return 1; | ||
14100 | } | ||
14101 | }; | ||
14102 | |||
14103 | template <typename T> | ||
14104 | struct pusher<yielding_t<T>> { | ||
14105 | template <typename... Args> | ||
14106 | static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) { | ||
14107 | pusher<function_sig<>> p{}; | ||
14108 | (void)p; | ||
14109 | return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...); | ||
14110 | } | ||
14111 | |||
14112 | template <typename... Args> | ||
14113 | static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) { | ||
14114 | pusher<function_sig<>> p{}; | ||
14115 | (void)p; | ||
14116 | return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...); | ||
14117 | } | ||
14118 | }; | ||
14119 | |||
14120 | template <typename T, typename... Args> | ||
14121 | struct pusher<function_arguments<T, Args...>> { | ||
14122 | template <std::size_t... I, typename FP> | ||
14123 | static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) { | ||
14124 | return stack::push<T>(L, detail::forward_get<I>(fp.arguments)...); | ||
14125 | } | ||
14126 | |||
14127 | static int push(lua_State* L, const function_arguments<T, Args...>& fp) { | ||
14128 | return push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp); | ||
14129 | } | ||
14130 | |||
14131 | static int push(lua_State* L, function_arguments<T, Args...>&& fp) { | ||
14132 | return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp)); | ||
14133 | } | ||
14134 | }; | ||
14135 | |||
14136 | template <typename Signature> | ||
14137 | struct pusher<std::function<Signature>> { | ||
14138 | static int push(lua_State* L, const std::function<Signature>& fx) { | ||
14139 | return pusher<function_sig<Signature>>{}.push(L, fx); | ||
14140 | } | ||
14141 | |||
14142 | static int push(lua_State* L, std::function<Signature>&& fx) { | ||
14143 | return pusher<function_sig<Signature>>{}.push(L, std::move(fx)); | ||
14144 | } | ||
14145 | }; | ||
14146 | |||
14147 | template <typename Signature> | ||
14148 | struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { | ||
14149 | template <typename F, typename... Args> | ||
14150 | static int push(lua_State* L, F&& f, Args&&... args) { | ||
14151 | pusher<function_sig<>> p{}; | ||
14152 | (void)p; | ||
14153 | return p.push(L, std::forward<F>(f), std::forward<Args>(args)...); | ||
14154 | } | ||
14155 | }; | ||
14156 | |||
14157 | template <typename Signature> | ||
14158 | struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>> | ||
14159 | #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE | ||
14160 | , | ||
14161 | meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>> | ||
14162 | #endif // noexcept function types | ||
14163 | >::value>> { | ||
14164 | template <typename F> | ||
14165 | static int push(lua_State* L, F&& f) { | ||
14166 | return pusher<function_sig<>>{}.push(L, std::forward<F>(f)); | ||
14167 | } | ||
14168 | }; | ||
14169 | |||
14170 | template <typename... Functions> | ||
14171 | struct pusher<overload_set<Functions...>> { | ||
14172 | static int push(lua_State* L, overload_set<Functions...>&& set) { | ||
14173 | // TODO: yielding | ||
14174 | typedef function_detail::overloaded_function<0, Functions...> F; | ||
14175 | pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions)); | ||
14176 | return 1; | ||
14177 | } | ||
14178 | |||
14179 | static int push(lua_State* L, const overload_set<Functions...>& set) { | ||
14180 | // TODO: yielding | ||
14181 | typedef function_detail::overloaded_function<0, Functions...> F; | ||
14182 | pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions); | ||
14183 | return 1; | ||
14184 | } | ||
14185 | }; | ||
14186 | |||
14187 | template <typename T> | ||
14188 | struct pusher<protect_t<T>> { | ||
14189 | static int push(lua_State* L, protect_t<T>&& pw) { | ||
14190 | lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>; | ||
14191 | int upvalues = 0; | ||
14192 | upvalues += stack::push(L, nullptr); | ||
14193 | upvalues += stack::push<user<protect_t<T>>>(L, std::move(pw.value)); | ||
14194 | return stack::push(L, c_closure(cf, upvalues)); | ||
14195 | } | ||
14196 | |||
14197 | static int push(lua_State* L, const protect_t<T>& pw) { | ||
14198 | lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>; | ||
14199 | int upvalues = 0; | ||
14200 | upvalues += stack::push(L, nullptr); | ||
14201 | upvalues += stack::push<user<protect_t<T>>>(L, pw.value); | ||
14202 | return stack::push(L, c_closure(cf, upvalues)); | ||
14203 | } | ||
14204 | }; | ||
14205 | |||
14206 | template <typename F, typename G> | ||
14207 | struct pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> { | ||
14208 | static int push(lua_State* L, property_wrapper<F, G>&& pw) { | ||
14209 | return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); | ||
14210 | } | ||
14211 | static int push(lua_State* L, const property_wrapper<F, G>& pw) { | ||
14212 | return stack::push(L, overload(pw.read, pw.write)); | ||
14213 | } | ||
14214 | }; | ||
14215 | |||
14216 | template <typename F> | ||
14217 | struct pusher<property_wrapper<F, void>> { | ||
14218 | static int push(lua_State* L, property_wrapper<F, void>&& pw) { | ||
14219 | return stack::push(L, std::move(pw.read)); | ||
14220 | } | ||
14221 | static int push(lua_State* L, const property_wrapper<F, void>& pw) { | ||
14222 | return stack::push(L, pw.read); | ||
14223 | } | ||
14224 | }; | ||
14225 | |||
14226 | template <typename F> | ||
14227 | struct pusher<property_wrapper<void, F>> { | ||
14228 | static int push(lua_State* L, property_wrapper<void, F>&& pw) { | ||
14229 | return stack::push(L, std::move(pw.write)); | ||
14230 | } | ||
14231 | static int push(lua_State* L, const property_wrapper<void, F>& pw) { | ||
14232 | return stack::push(L, pw.write); | ||
14233 | } | ||
14234 | }; | ||
14235 | |||
14236 | template <typename T> | ||
14237 | struct pusher<var_wrapper<T>> { | ||
14238 | static int push(lua_State* L, var_wrapper<T>&& vw) { | ||
14239 | return stack::push(L, std::move(vw.value)); | ||
14240 | } | ||
14241 | static int push(lua_State* L, const var_wrapper<T>& vw) { | ||
14242 | return stack::push(L, vw.value); | ||
14243 | } | ||
14244 | }; | ||
14245 | |||
14246 | template <typename... Functions> | ||
14247 | struct pusher<factory_wrapper<Functions...>> { | ||
14248 | static int push(lua_State* L, const factory_wrapper<Functions...>& fw) { | ||
14249 | typedef function_detail::overloaded_function<0, Functions...> F; | ||
14250 | pusher<function_sig<>>{}.set_fx<false, F>(L, fw.functions); | ||
14251 | return 1; | ||
14252 | } | ||
14253 | |||
14254 | static int push(lua_State* L, factory_wrapper<Functions...>&& fw) { | ||
14255 | typedef function_detail::overloaded_function<0, Functions...> F; | ||
14256 | pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(fw.functions)); | ||
14257 | return 1; | ||
14258 | } | ||
14259 | |||
14260 | static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) { | ||
14261 | typedef function_detail::overloaded_function<1, Functions...> F; | ||
14262 | pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions); | ||
14263 | return 1; | ||
14264 | } | ||
14265 | |||
14266 | static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) { | ||
14267 | typedef function_detail::overloaded_function<1, Functions...> F; | ||
14268 | pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions)); | ||
14269 | return 1; | ||
14270 | } | ||
14271 | }; | ||
14272 | |||
14273 | template <> | ||
14274 | struct pusher<no_construction> { | ||
14275 | static int push(lua_State* L, no_construction) { | ||
14276 | lua_CFunction cf = &function_detail::no_construction_error; | ||
14277 | return stack::push(L, cf); | ||
14278 | } | ||
14279 | |||
14280 | static int push(lua_State* L, no_construction c, function_detail::call_indicator) { | ||
14281 | return push(L, c); | ||
14282 | } | ||
14283 | }; | ||
14284 | |||
14285 | template <typename T, typename... Lists> | ||
14286 | struct pusher<detail::tagged<T, constructor_list<Lists...>>> { | ||
14287 | static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) { | ||
14288 | lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>; | ||
14289 | return stack::push(L, cf); | ||
14290 | } | ||
14291 | |||
14292 | static int push(lua_State* L, constructor_list<Lists...>) { | ||
14293 | lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>; | ||
14294 | return stack::push(L, cf); | ||
14295 | } | ||
14296 | }; | ||
14297 | |||
14298 | template <typename L0, typename... Lists> | ||
14299 | struct pusher<constructor_list<L0, Lists...>> { | ||
14300 | typedef constructor_list<L0, Lists...> cl_t; | ||
14301 | static int push(lua_State* L, cl_t cl) { | ||
14302 | typedef typename meta::bind_traits<L0>::return_type T; | ||
14303 | return stack::push<detail::tagged<T, cl_t>>(L, cl); | ||
14304 | } | ||
14305 | }; | ||
14306 | |||
14307 | template <typename T, typename... Fxs> | ||
14308 | struct pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> { | ||
14309 | template <typename C> | ||
14310 | static int push(lua_State* L, C&& c) { | ||
14311 | lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>; | ||
14312 | int upvalues = 0; | ||
14313 | upvalues += stack::push(L, nullptr); | ||
14314 | upvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, std::forward<C>(c)); | ||
14315 | return stack::push(L, c_closure(cf, upvalues)); | ||
14316 | } | ||
14317 | }; | ||
14318 | |||
14319 | template <typename F, typename... Fxs> | ||
14320 | struct pusher<constructor_wrapper<F, Fxs...>> { | ||
14321 | template <typename C> | ||
14322 | static int push(lua_State* L, C&& c) { | ||
14323 | typedef typename meta::bind_traits<F>::template arg_at<0> arg0; | ||
14324 | typedef meta::unqualified_t<std::remove_pointer_t<arg0>> T; | ||
14325 | return stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, std::forward<C>(c)); | ||
14326 | } | ||
14327 | }; | ||
14328 | |||
14329 | template <typename T> | ||
14330 | struct pusher<detail::tagged<T, destructor_wrapper<void>>> { | ||
14331 | static int push(lua_State* L, destructor_wrapper<void>) { | ||
14332 | lua_CFunction cf = detail::usertype_alloc_destruct<T>; | ||
14333 | return stack::push(L, cf); | ||
14334 | } | ||
14335 | }; | ||
14336 | |||
14337 | template <typename T, typename Fx> | ||
14338 | struct pusher<detail::tagged<T, destructor_wrapper<Fx>>> { | ||
14339 | static int push(lua_State* L, destructor_wrapper<Fx>&& c) { | ||
14340 | lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>; | ||
14341 | int upvalues = 0; | ||
14342 | upvalues += stack::push(L, nullptr); | ||
14343 | upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c)); | ||
14344 | return stack::push(L, c_closure(cf, upvalues)); | ||
14345 | } | ||
14346 | |||
14347 | static int push(lua_State* L, const destructor_wrapper<Fx>& c) { | ||
14348 | lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>; | ||
14349 | int upvalues = 0; | ||
14350 | upvalues += stack::push(L, nullptr); | ||
14351 | upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c); | ||
14352 | return stack::push(L, c_closure(cf, upvalues)); | ||
14353 | } | ||
14354 | }; | ||
14355 | |||
14356 | template <typename Fx> | ||
14357 | struct pusher<destructor_wrapper<Fx>> { | ||
14358 | static int push(lua_State* L, destructor_wrapper<Fx>&& c) { | ||
14359 | lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>; | ||
14360 | int upvalues = 0; | ||
14361 | upvalues += stack::push(L, nullptr); | ||
14362 | upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c)); | ||
14363 | return stack::push(L, c_closure(cf, upvalues)); | ||
14364 | } | ||
14365 | |||
14366 | static int push(lua_State* L, const destructor_wrapper<Fx>& c) { | ||
14367 | lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>; | ||
14368 | int upvalues = 0; | ||
14369 | upvalues += stack::push(L, nullptr); | ||
14370 | upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c); | ||
14371 | return stack::push(L, c_closure(cf, upvalues)); | ||
14372 | } | ||
14373 | }; | ||
14374 | |||
14375 | template <typename F, typename... Filters> | ||
14376 | struct pusher<filter_wrapper<F, Filters...>> { | ||
14377 | typedef filter_wrapper<F, Filters...> P; | ||
14378 | |||
14379 | static int push(lua_State* L, const P& p) { | ||
14380 | lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>; | ||
14381 | int upvalues = 0; | ||
14382 | upvalues += stack::push(L, nullptr); | ||
14383 | upvalues += stack::push<user<P>>(L, p); | ||
14384 | return stack::push(L, c_closure(cf, upvalues)); | ||
14385 | } | ||
14386 | |||
14387 | static int push(lua_State* L, P&& p) { | ||
14388 | lua_CFunction cf = call_detail::call_user<void, false, false, P, 2>; | ||
14389 | int upvalues = 0; | ||
14390 | upvalues += stack::push(L, nullptr); | ||
14391 | upvalues += stack::push<user<P>>(L, std::move(p)); | ||
14392 | return stack::push(L, c_closure(cf, upvalues)); | ||
14393 | } | ||
14394 | }; | ||
14395 | } // namespace stack | ||
14396 | } // namespace sol | ||
14397 | |||
14398 | // end of sol/function_types.hpp | ||
14399 | |||
14400 | namespace sol { | ||
14401 | template <typename base_t, bool aligned = false> | ||
14402 | class basic_function : public base_t { | ||
14403 | private: | ||
14404 | void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { | ||
14405 | lua_call(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount)); | ||
14406 | } | ||
14407 | |||
14408 | template <std::size_t... I, typename... Ret> | ||
14409 | auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const { | ||
14410 | luacall(n, lua_size<std::tuple<Ret...>>::value); | ||
14411 | return stack::pop<std::tuple<Ret...>>(lua_state()); | ||
14412 | } | ||
14413 | |||
14414 | template <std::size_t I, typename Ret> | ||
14415 | Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const { | ||
14416 | luacall(n, lua_size<Ret>::value); | ||
14417 | return stack::pop<Ret>(lua_state()); | ||
14418 | } | ||
14419 | |||
14420 | template <std::size_t I> | ||
14421 | void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const { | ||
14422 | luacall(n, 0); | ||
14423 | } | ||
14424 | |||
14425 | unsafe_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const { | ||
14426 | int stacksize = lua_gettop(lua_state()); | ||
14427 | int firstreturn = (std::max)(1, stacksize - static_cast<int>(n)); | ||
14428 | luacall(n, LUA_MULTRET); | ||
14429 | int poststacksize = lua_gettop(lua_state()); | ||
14430 | int returncount = poststacksize - (firstreturn - 1); | ||
14431 | return unsafe_function_result(lua_state(), firstreturn, returncount); | ||
14432 | } | ||
14433 | |||
14434 | public: | ||
14435 | using base_t::lua_state; | ||
14436 | |||
14437 | basic_function() = default; | ||
14438 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
14439 | basic_function(T&& r) noexcept | ||
14440 | : base_t(std::forward<T>(r)) { | ||
14441 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14442 | if (!is_function<meta::unqualified_t<T>>::value) { | ||
14443 | auto pp = stack::push_pop(*this); | ||
14444 | constructor_handler handler{}; | ||
14445 | stack::check<basic_function>(lua_state(), -1, handler); | ||
14446 | } | ||
14447 | #endif // Safety | ||
14448 | } | ||
14449 | basic_function(const basic_function&) = default; | ||
14450 | basic_function& operator=(const basic_function&) = default; | ||
14451 | basic_function(basic_function&&) = default; | ||
14452 | basic_function& operator=(basic_function&&) = default; | ||
14453 | basic_function(const stack_reference& r) | ||
14454 | : basic_function(r.lua_state(), r.stack_index()) { | ||
14455 | } | ||
14456 | basic_function(stack_reference&& r) | ||
14457 | : basic_function(r.lua_state(), r.stack_index()) { | ||
14458 | } | ||
14459 | basic_function(lua_nil_t n) | ||
14460 | : base_t(n) { | ||
14461 | } | ||
14462 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
14463 | basic_function(lua_State* L, T&& r) | ||
14464 | : base_t(L, std::forward<T>(r)) { | ||
14465 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14466 | auto pp = stack::push_pop(*this); | ||
14467 | constructor_handler handler{}; | ||
14468 | stack::check<basic_function>(lua_state(), -1, handler); | ||
14469 | #endif // Safety | ||
14470 | } | ||
14471 | basic_function(lua_State* L, int index = -1) | ||
14472 | : base_t(L, index) { | ||
14473 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14474 | constructor_handler handler{}; | ||
14475 | stack::check<basic_function>(L, index, handler); | ||
14476 | #endif // Safety | ||
14477 | } | ||
14478 | basic_function(lua_State* L, ref_index index) | ||
14479 | : base_t(L, index) { | ||
14480 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14481 | auto pp = stack::push_pop(*this); | ||
14482 | constructor_handler handler{}; | ||
14483 | stack::check<basic_function>(lua_state(), -1, handler); | ||
14484 | #endif // Safety | ||
14485 | } | ||
14486 | |||
14487 | template <typename... Args> | ||
14488 | unsafe_function_result operator()(Args&&... args) const { | ||
14489 | return call<>(std::forward<Args>(args)...); | ||
14490 | } | ||
14491 | |||
14492 | template <typename... Ret, typename... Args> | ||
14493 | decltype(auto) operator()(types<Ret...>, Args&&... args) const { | ||
14494 | return call<Ret...>(std::forward<Args>(args)...); | ||
14495 | } | ||
14496 | |||
14497 | template <typename... Ret, typename... Args> | ||
14498 | decltype(auto) call(Args&&... args) const { | ||
14499 | if (!aligned) { | ||
14500 | base_t::push(); | ||
14501 | } | ||
14502 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
14503 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount); | ||
14504 | } | ||
14505 | }; | ||
14506 | } // namespace sol | ||
14507 | |||
14508 | // end of sol/unsafe_function.hpp | ||
14509 | |||
14510 | // beginning of sol/protected_function.hpp | ||
14511 | |||
14512 | // beginning of sol/protected_handler.hpp | ||
14513 | |||
14514 | namespace sol { | ||
14515 | namespace detail { | ||
14516 | inline const char(&default_handler_name())[9]{ | ||
14517 | static const char name[9] = "sol.\xF0\x9F\x94\xA9"; | ||
14518 | return name; | ||
14519 | } | ||
14520 | |||
14521 | template <bool b, typename target_t = reference> | ||
14522 | struct protected_handler { | ||
14523 | typedef is_stack_based<target_t> is_stack; | ||
14524 | const target_t& target; | ||
14525 | int stackindex; | ||
14526 | |||
14527 | protected_handler(std::false_type, const target_t& target) | ||
14528 | : target(target), stackindex(0) { | ||
14529 | if (b) { | ||
14530 | stackindex = lua_gettop(target.lua_state()) + 1; | ||
14531 | target.push(); | ||
14532 | } | ||
14533 | } | ||
14534 | |||
14535 | protected_handler(std::true_type, const target_t& target) | ||
14536 | : target(target), stackindex(0) { | ||
14537 | if (b) { | ||
14538 | stackindex = target.stack_index(); | ||
14539 | } | ||
14540 | } | ||
14541 | |||
14542 | protected_handler(const target_t& target) | ||
14543 | : protected_handler(is_stack(), target) { | ||
14544 | } | ||
14545 | |||
14546 | bool valid() const noexcept { | ||
14547 | return b; | ||
14548 | } | ||
14549 | |||
14550 | ~protected_handler() { | ||
14551 | if (!is_stack::value && stackindex != 0) { | ||
14552 | lua_remove(target.lua_state(), stackindex); | ||
14553 | } | ||
14554 | } | ||
14555 | }; | ||
14556 | |||
14557 | template <typename base_t, typename T> | ||
14558 | basic_function<base_t> force_cast(T& p) { | ||
14559 | return p; | ||
14560 | } | ||
14561 | |||
14562 | template <typename Reference, bool is_main_ref = false> | ||
14563 | static Reference get_default_handler(lua_State* L) { | ||
14564 | if (is_stack_based<Reference>::value || L == nullptr) | ||
14565 | return Reference(L, lua_nil); | ||
14566 | L = is_main_ref ? main_thread(L, L) : L; | ||
14567 | lua_getglobal(L, default_handler_name()); | ||
14568 | auto pp = stack::pop_n(L, 1); | ||
14569 | return Reference(L, -1); | ||
14570 | } | ||
14571 | |||
14572 | template <typename T> | ||
14573 | static void set_default_handler(lua_State* L, const T& ref) { | ||
14574 | if (L == nullptr) { | ||
14575 | return; | ||
14576 | } | ||
14577 | if (!ref.valid()) { | ||
14578 | lua_pushnil(L); | ||
14579 | lua_setglobal(L, default_handler_name()); | ||
14580 | } | ||
14581 | else { | ||
14582 | ref.push(L); | ||
14583 | lua_setglobal(L, default_handler_name()); | ||
14584 | } | ||
14585 | } | ||
14586 | } // namespace detail | ||
14587 | } // namespace sol | ||
14588 | |||
14589 | // end of sol/protected_handler.hpp | ||
14590 | |||
14591 | namespace sol { | ||
14592 | template <typename base_t, bool aligned = false, typename handler_t = reference> | ||
14593 | class basic_protected_function : public base_t { | ||
14594 | public: | ||
14595 | typedef is_stack_based<handler_t> is_stack_handler; | ||
14596 | |||
14597 | static handler_t get_default_handler(lua_State* L) { | ||
14598 | return detail::get_default_handler<handler_t, is_main_threaded<base_t>::value>(L); | ||
14599 | } | ||
14600 | |||
14601 | template <typename T> | ||
14602 | static void set_default_handler(const T& ref) { | ||
14603 | detail::set_default_handler(ref.lua_state(), ref); | ||
14604 | } | ||
14605 | |||
14606 | private: | ||
14607 | template <bool b> | ||
14608 | call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::protected_handler<b, handler_t>& h) const { | ||
14609 | return static_cast<call_status>(lua_pcall(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex)); | ||
14610 | } | ||
14611 | |||
14612 | template <std::size_t... I, bool b, typename... Ret> | ||
14613 | auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { | ||
14614 | luacall(n, sizeof...(Ret), h); | ||
14615 | return stack::pop<std::tuple<Ret...>>(lua_state()); | ||
14616 | } | ||
14617 | |||
14618 | template <std::size_t I, bool b, typename Ret> | ||
14619 | Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { | ||
14620 | luacall(n, 1, h); | ||
14621 | return stack::pop<Ret>(lua_state()); | ||
14622 | } | ||
14623 | |||
14624 | template <std::size_t I, bool b> | ||
14625 | void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { | ||
14626 | luacall(n, 0, h); | ||
14627 | } | ||
14628 | |||
14629 | template <bool b> | ||
14630 | protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const { | ||
14631 | int stacksize = lua_gettop(lua_state()); | ||
14632 | int poststacksize = stacksize; | ||
14633 | int firstreturn = 1; | ||
14634 | int returncount = 0; | ||
14635 | call_status code = call_status::ok; | ||
14636 | #if !defined(SOL_NO_EXCEPTIONS) || !SOL_NO_EXCEPTIONS | ||
14637 | auto onexcept = [&](optional<const std::exception&> maybe_ex, const char* error) { | ||
14638 | h.stackindex = 0; | ||
14639 | if (b) { | ||
14640 | h.target.push(); | ||
14641 | detail::call_exception_handler(lua_state(), maybe_ex, error); | ||
14642 | lua_call(lua_state(), 1, 1); | ||
14643 | } | ||
14644 | else { | ||
14645 | detail::call_exception_handler(lua_state(), maybe_ex, error); | ||
14646 | } | ||
14647 | }; | ||
14648 | (void)onexcept; | ||
14649 | #if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT) | ||
14650 | try { | ||
14651 | #endif // Safe Exception Propagation | ||
14652 | #endif // No Exceptions | ||
14653 | firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid()))); | ||
14654 | code = luacall(n, LUA_MULTRET, h); | ||
14655 | poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid()); | ||
14656 | returncount = poststacksize - (firstreturn - 1); | ||
14657 | #ifndef SOL_NO_EXCEPTIONS | ||
14658 | #if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT) | ||
14659 | } | ||
14660 | // Handle C++ errors thrown from C++ functions bound inside of lua | ||
14661 | catch (const char* error) { | ||
14662 | onexcept(optional<const std::exception&>(nullopt), error); | ||
14663 | firstreturn = lua_gettop(lua_state()); | ||
14664 | return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); | ||
14665 | } | ||
14666 | catch (const std::string& error) { | ||
14667 | onexcept(optional<const std::exception&>(nullopt), error.c_str()); | ||
14668 | firstreturn = lua_gettop(lua_state()); | ||
14669 | return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); | ||
14670 | } | ||
14671 | catch (const std::exception& error) { | ||
14672 | onexcept(optional<const std::exception&>(error), error.what()); | ||
14673 | firstreturn = lua_gettop(lua_state()); | ||
14674 | return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); | ||
14675 | } | ||
14676 | #if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) | ||
14677 | // LuaJIT cannot have the catchall when the safe propagation is on | ||
14678 | // but LuaJIT will swallow all C++ errors | ||
14679 | // if we don't at least catch std::exception ones | ||
14680 | catch (...) { | ||
14681 | onexcept(optional<const std::exception&>(nullopt), "caught (...) unknown error during protected_function call"); | ||
14682 | firstreturn = lua_gettop(lua_state()); | ||
14683 | return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); | ||
14684 | } | ||
14685 | #endif // LuaJIT | ||
14686 | #else | ||
14687 | // do not handle exceptions: they can be propogated into C++ and keep all type information / rich information | ||
14688 | #endif // Safe Exception Propagation | ||
14689 | #endif // Exceptions vs. No Exceptions | ||
14690 | return protected_function_result(lua_state(), firstreturn, returncount, returncount, code); | ||
14691 | } | ||
14692 | |||
14693 | public: | ||
14694 | using base_t::lua_state; | ||
14695 | |||
14696 | handler_t error_handler; | ||
14697 | |||
14698 | basic_protected_function() = default; | ||
14699 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_protected_function>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
14700 | basic_protected_function(T&& r) noexcept | ||
14701 | : base_t(std::forward<T>(r)), error_handler(get_default_handler(r.lua_state())) { | ||
14702 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14703 | if (!is_function<meta::unqualified_t<T>>::value) { | ||
14704 | auto pp = stack::push_pop(*this); | ||
14705 | constructor_handler handler{}; | ||
14706 | stack::check<basic_protected_function>(lua_state(), -1, handler); | ||
14707 | } | ||
14708 | #endif // Safety | ||
14709 | } | ||
14710 | basic_protected_function(const basic_protected_function&) = default; | ||
14711 | basic_protected_function& operator=(const basic_protected_function&) = default; | ||
14712 | basic_protected_function(basic_protected_function&&) = default; | ||
14713 | basic_protected_function& operator=(basic_protected_function&&) = default; | ||
14714 | basic_protected_function(const basic_function<base_t>& b) | ||
14715 | : basic_protected_function(b, get_default_handler(b.lua_state())) { | ||
14716 | } | ||
14717 | basic_protected_function(basic_function<base_t>&& b) | ||
14718 | : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) { | ||
14719 | } | ||
14720 | basic_protected_function(const basic_function<base_t>& b, handler_t eh) | ||
14721 | : base_t(b), error_handler(std::move(eh)) { | ||
14722 | } | ||
14723 | basic_protected_function(basic_function<base_t>&& b, handler_t eh) | ||
14724 | : base_t(std::move(b)), error_handler(std::move(eh)) { | ||
14725 | } | ||
14726 | basic_protected_function(const stack_reference& r) | ||
14727 | : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { | ||
14728 | } | ||
14729 | basic_protected_function(stack_reference&& r) | ||
14730 | : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) { | ||
14731 | } | ||
14732 | basic_protected_function(const stack_reference& r, handler_t eh) | ||
14733 | : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { | ||
14734 | } | ||
14735 | basic_protected_function(stack_reference&& r, handler_t eh) | ||
14736 | : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) { | ||
14737 | } | ||
14738 | |||
14739 | template <typename Super> | ||
14740 | basic_protected_function(const proxy_base<Super>& p) | ||
14741 | : basic_protected_function(p, get_default_handler(p.lua_state())) { | ||
14742 | } | ||
14743 | template <typename Super> | ||
14744 | basic_protected_function(proxy_base<Super>&& p) | ||
14745 | : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) { | ||
14746 | } | ||
14747 | template <typename Proxy, typename Handler, meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler> | ||
14748 | basic_protected_function(Proxy&& p, Handler&& eh) | ||
14749 | : basic_protected_function(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) { | ||
14750 | } | ||
14751 | |||
14752 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
14753 | basic_protected_function(lua_State* L, T&& r) | ||
14754 | : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) { | ||
14755 | } | ||
14756 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
14757 | basic_protected_function(lua_State* L, T&& r, handler_t eh) | ||
14758 | : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) { | ||
14759 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14760 | auto pp = stack::push_pop(*this); | ||
14761 | constructor_handler handler{}; | ||
14762 | stack::check<basic_protected_function>(lua_state(), -1, handler); | ||
14763 | #endif // Safety | ||
14764 | } | ||
14765 | |||
14766 | basic_protected_function(lua_nil_t n) | ||
14767 | : base_t(n), error_handler(n) { | ||
14768 | } | ||
14769 | |||
14770 | basic_protected_function(lua_State* L, int index = -1) | ||
14771 | : basic_protected_function(L, index, get_default_handler(L)) { | ||
14772 | } | ||
14773 | basic_protected_function(lua_State* L, int index, handler_t eh) | ||
14774 | : base_t(L, index), error_handler(std::move(eh)) { | ||
14775 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14776 | constructor_handler handler{}; | ||
14777 | stack::check<basic_protected_function>(L, index, handler); | ||
14778 | #endif // Safety | ||
14779 | } | ||
14780 | basic_protected_function(lua_State* L, absolute_index index) | ||
14781 | : basic_protected_function(L, index, get_default_handler(L)) { | ||
14782 | } | ||
14783 | basic_protected_function(lua_State* L, absolute_index index, handler_t eh) | ||
14784 | : base_t(L, index), error_handler(std::move(eh)) { | ||
14785 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14786 | constructor_handler handler{}; | ||
14787 | stack::check<basic_protected_function>(L, index, handler); | ||
14788 | #endif // Safety | ||
14789 | } | ||
14790 | basic_protected_function(lua_State* L, raw_index index) | ||
14791 | : basic_protected_function(L, index, get_default_handler(L)) { | ||
14792 | } | ||
14793 | basic_protected_function(lua_State* L, raw_index index, handler_t eh) | ||
14794 | : base_t(L, index), error_handler(std::move(eh)) { | ||
14795 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14796 | constructor_handler handler{}; | ||
14797 | stack::check<basic_protected_function>(L, index, handler); | ||
14798 | #endif // Safety | ||
14799 | } | ||
14800 | basic_protected_function(lua_State* L, ref_index index) | ||
14801 | : basic_protected_function(L, index, get_default_handler(L)) { | ||
14802 | } | ||
14803 | basic_protected_function(lua_State* L, ref_index index, handler_t eh) | ||
14804 | : base_t(L, index), error_handler(std::move(eh)) { | ||
14805 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
14806 | auto pp = stack::push_pop(*this); | ||
14807 | constructor_handler handler{}; | ||
14808 | stack::check<basic_protected_function>(lua_state(), -1, handler); | ||
14809 | #endif // Safety | ||
14810 | } | ||
14811 | |||
14812 | template <typename... Args> | ||
14813 | protected_function_result operator()(Args&&... args) const { | ||
14814 | return call<>(std::forward<Args>(args)...); | ||
14815 | } | ||
14816 | |||
14817 | template <typename... Ret, typename... Args> | ||
14818 | decltype(auto) operator()(types<Ret...>, Args&&... args) const { | ||
14819 | return call<Ret...>(std::forward<Args>(args)...); | ||
14820 | } | ||
14821 | |||
14822 | template <typename... Ret, typename... Args> | ||
14823 | decltype(auto) call(Args&&... args) const { | ||
14824 | if (!aligned) { | ||
14825 | // we do not expect the function to already be on the stack: push it | ||
14826 | if (error_handler.valid()) { | ||
14827 | detail::protected_handler<true, handler_t> h(error_handler); | ||
14828 | base_t::push(); | ||
14829 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
14830 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); | ||
14831 | } | ||
14832 | else { | ||
14833 | detail::protected_handler<false, handler_t> h(error_handler); | ||
14834 | base_t::push(); | ||
14835 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
14836 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); | ||
14837 | } | ||
14838 | } | ||
14839 | else { | ||
14840 | // the function is already on the stack at the right location | ||
14841 | if (error_handler.valid()) { | ||
14842 | // the handler will be pushed onto the stack manually, | ||
14843 | // since it's not already on the stack this means we need to push our own | ||
14844 | // function on the stack too and swap things to be in-place | ||
14845 | if (!is_stack_handler::value) { | ||
14846 | // so, we need to remove the function at the top and then dump the handler out ourselves | ||
14847 | base_t::push(); | ||
14848 | } | ||
14849 | detail::protected_handler<true, handler_t> h(error_handler); | ||
14850 | if (!is_stack_handler::value) { | ||
14851 | lua_replace(lua_state(), -3); | ||
14852 | h.stackindex = lua_absindex(lua_state(), -2); | ||
14853 | } | ||
14854 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
14855 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); | ||
14856 | } | ||
14857 | else { | ||
14858 | detail::protected_handler<false, handler_t> h(error_handler); | ||
14859 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
14860 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); | ||
14861 | } | ||
14862 | } | ||
14863 | } | ||
14864 | }; | ||
14865 | } // namespace sol | ||
14866 | |||
14867 | // end of sol/protected_function.hpp | ||
14868 | |||
14869 | namespace sol { | ||
14870 | template <typename... Ret, typename... Args> | ||
14871 | inline decltype(auto) stack_proxy::call(Args&&... args) { | ||
14872 | stack_function sf(this->lua_state(), this->stack_index()); | ||
14873 | return sf.template call<Ret...>(std::forward<Args>(args)...); | ||
14874 | } | ||
14875 | |||
14876 | inline protected_function_result::protected_function_result(unsafe_function_result&& o) noexcept | ||
14877 | : L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()), popcount(o.return_count()), err(o.status()) { | ||
14878 | // Must be manual, otherwise destructor will screw us | ||
14879 | // return count being 0 is enough to keep things clean | ||
14880 | // but we will be thorough | ||
14881 | o.abandon(); | ||
14882 | } | ||
14883 | |||
14884 | inline protected_function_result& protected_function_result::operator=(unsafe_function_result&& o) noexcept { | ||
14885 | L = o.lua_state(); | ||
14886 | index = o.stack_index(); | ||
14887 | returncount = o.return_count(); | ||
14888 | popcount = o.return_count(); | ||
14889 | err = o.status(); | ||
14890 | // Must be manual, otherwise destructor will screw us | ||
14891 | // return count being 0 is enough to keep things clean | ||
14892 | // but we will be thorough | ||
14893 | o.abandon(); | ||
14894 | return *this; | ||
14895 | } | ||
14896 | |||
14897 | inline unsafe_function_result::unsafe_function_result(protected_function_result&& o) noexcept | ||
14898 | : L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()) { | ||
14899 | // Must be manual, otherwise destructor will screw us | ||
14900 | // return count being 0 is enough to keep things clean | ||
14901 | // but we will be thorough | ||
14902 | o.abandon(); | ||
14903 | } | ||
14904 | inline unsafe_function_result& unsafe_function_result::operator=(protected_function_result&& o) noexcept { | ||
14905 | L = o.lua_state(); | ||
14906 | index = o.stack_index(); | ||
14907 | returncount = o.return_count(); | ||
14908 | // Must be manual, otherwise destructor will screw us | ||
14909 | // return count being 0 is enough to keep things clean | ||
14910 | // but we will be thorough | ||
14911 | o.abandon(); | ||
14912 | return *this; | ||
14913 | } | ||
14914 | |||
14915 | namespace stack { | ||
14916 | template <typename Signature> | ||
14917 | struct getter<std::function<Signature>> { | ||
14918 | typedef meta::bind_traits<Signature> fx_t; | ||
14919 | typedef typename fx_t::args_list args_lists; | ||
14920 | typedef meta::tuple_types<typename fx_t::return_type> return_types; | ||
14921 | |||
14922 | template <typename... Args, typename... Ret> | ||
14923 | static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index) { | ||
14924 | unsafe_function f(L, index); | ||
14925 | auto fx = [ f = std::move(f) ](Args && ... args) -> meta::return_type_t<Ret...> { | ||
14926 | return f.call<Ret...>(std::forward<Args>(args)...); | ||
14927 | }; | ||
14928 | return std::move(fx); | ||
14929 | } | ||
14930 | |||
14931 | template <typename... FxArgs> | ||
14932 | static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index) { | ||
14933 | unsafe_function f(L, index); | ||
14934 | auto fx = [f = std::move(f)](FxArgs&&... args) -> void { | ||
14935 | f(std::forward<FxArgs>(args)...); | ||
14936 | }; | ||
14937 | return std::move(fx); | ||
14938 | } | ||
14939 | |||
14940 | template <typename... FxArgs> | ||
14941 | static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index) { | ||
14942 | return get_std_func(types<void>(), t, L, index); | ||
14943 | } | ||
14944 | |||
14945 | static std::function<Signature> get(lua_State* L, int index, record& tracking) { | ||
14946 | tracking.last = 1; | ||
14947 | tracking.used += 1; | ||
14948 | type t = type_of(L, index); | ||
14949 | if (t == type::none || t == type::lua_nil) { | ||
14950 | return nullptr; | ||
14951 | } | ||
14952 | return get_std_func(return_types(), args_lists(), L, index); | ||
14953 | } | ||
14954 | }; | ||
14955 | } // namespace stack | ||
14956 | |||
14957 | } // namespace sol | ||
14958 | |||
14959 | // end of sol/function.hpp | ||
14960 | |||
14961 | namespace sol { | ||
14962 | template <typename Table, typename Key> | ||
14963 | struct proxy : public proxy_base<proxy<Table, Key>> { | ||
14964 | private: | ||
14965 | typedef meta::condition<meta::is_specialization_of<Key, std::tuple>, Key, std::tuple<meta::condition<std::is_array<meta::unqualified_t<Key>>, Key&, meta::unqualified_t<Key>>>> key_type; | ||
14966 | |||
14967 | template <typename T, std::size_t... I> | ||
14968 | decltype(auto) tuple_get(std::index_sequence<I...>) const { | ||
14969 | return tbl.template traverse_get<T>(std::get<I>(key)...); | ||
14970 | } | ||
14971 | |||
14972 | template <std::size_t... I, typename T> | ||
14973 | void tuple_set(std::index_sequence<I...>, T&& value) { | ||
14974 | tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); | ||
14975 | } | ||
14976 | |||
14977 | auto setup_table(std::true_type) { | ||
14978 | auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, tbl.stack_index()); | ||
14979 | lua_pop(lua_state(), p.levels); | ||
14980 | return p; | ||
14981 | } | ||
14982 | |||
14983 | bool is_valid(std::false_type) { | ||
14984 | auto pp = stack::push_pop(tbl); | ||
14985 | auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); | ||
14986 | lua_pop(lua_state(), p.levels); | ||
14987 | return p; | ||
14988 | } | ||
14989 | |||
14990 | public: | ||
14991 | Table tbl; | ||
14992 | key_type key; | ||
14993 | |||
14994 | template <typename T> | ||
14995 | proxy(Table table, T&& k) | ||
14996 | : tbl(table), key(std::forward<T>(k)) { | ||
14997 | } | ||
14998 | |||
14999 | template <typename T> | ||
15000 | proxy& set(T&& item) { | ||
15001 | tuple_set(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>(), std::forward<T>(item)); | ||
15002 | return *this; | ||
15003 | } | ||
15004 | |||
15005 | template <typename... Args> | ||
15006 | proxy& set_function(Args&&... args) { | ||
15007 | tbl.set_function(key, std::forward<Args>(args)...); | ||
15008 | return *this; | ||
15009 | } | ||
15010 | |||
15011 | template <typename U, meta::enable<meta::neg<is_lua_reference_or_proxy<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> | ||
15012 | proxy& operator=(U&& other) { | ||
15013 | return set_function(std::forward<U>(other)); | ||
15014 | } | ||
15015 | |||
15016 | template <typename U, meta::disable<meta::neg<is_lua_reference_or_proxy<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> | ||
15017 | proxy& operator=(U&& other) { | ||
15018 | return set(std::forward<U>(other)); | ||
15019 | } | ||
15020 | |||
15021 | template <typename T> | ||
15022 | proxy& operator=(std::initializer_list<T> other) { | ||
15023 | return set(std::move(other)); | ||
15024 | } | ||
15025 | |||
15026 | template <typename T> | ||
15027 | decltype(auto) get() const { | ||
15028 | return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); | ||
15029 | } | ||
15030 | |||
15031 | template <typename T> | ||
15032 | decltype(auto) get_or(T&& otherwise) const { | ||
15033 | typedef decltype(get<T>()) U; | ||
15034 | optional<U> option = get<optional<U>>(); | ||
15035 | if (option) { | ||
15036 | return static_cast<U>(option.value()); | ||
15037 | } | ||
15038 | return static_cast<U>(std::forward<T>(otherwise)); | ||
15039 | } | ||
15040 | |||
15041 | template <typename T, typename D> | ||
15042 | decltype(auto) get_or(D&& otherwise) const { | ||
15043 | optional<T> option = get<optional<T>>(); | ||
15044 | if (option) { | ||
15045 | return static_cast<T>(option.value()); | ||
15046 | } | ||
15047 | return static_cast<T>(std::forward<D>(otherwise)); | ||
15048 | } | ||
15049 | |||
15050 | template <typename K> | ||
15051 | decltype(auto) operator[](K&& k) const { | ||
15052 | auto keys = meta::tuplefy(key, std::forward<K>(k)); | ||
15053 | return proxy<Table, decltype(keys)>(tbl, std::move(keys)); | ||
15054 | } | ||
15055 | |||
15056 | template <typename... Ret, typename... Args> | ||
15057 | decltype(auto) call(Args&&... args) { | ||
15058 | #if defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 191326131 && _MSC_FULL_VER >= 191200000 | ||
15059 | // MSVC is ass sometimes | ||
15060 | return get<function>().call<Ret...>(std::forward<Args>(args)...); | ||
15061 | #else | ||
15062 | return get<function>().template call<Ret...>(std::forward<Args>(args)...); | ||
15063 | #endif | ||
15064 | } | ||
15065 | |||
15066 | template <typename... Args> | ||
15067 | decltype(auto) operator()(Args&&... args) { | ||
15068 | return call<>(std::forward<Args>(args)...); | ||
15069 | } | ||
15070 | |||
15071 | bool valid() const { | ||
15072 | auto pp = stack::push_pop(tbl); | ||
15073 | auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); | ||
15074 | lua_pop(lua_state(), p.levels); | ||
15075 | return p; | ||
15076 | } | ||
15077 | |||
15078 | int push() const noexcept { | ||
15079 | return push(this->lua_state()); | ||
15080 | } | ||
15081 | |||
15082 | int push(lua_State* L) const noexcept { | ||
15083 | return get<reference>().push(L); | ||
15084 | } | ||
15085 | |||
15086 | type get_type() const { | ||
15087 | type t = type::none; | ||
15088 | auto pp = stack::push_pop(tbl); | ||
15089 | auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); | ||
15090 | if (p) { | ||
15091 | t = type_of(lua_state(), -1); | ||
15092 | } | ||
15093 | lua_pop(lua_state(), p.levels); | ||
15094 | return t; | ||
15095 | } | ||
15096 | |||
15097 | lua_State* lua_state() const { | ||
15098 | return tbl.lua_state(); | ||
15099 | } | ||
15100 | }; | ||
15101 | |||
15102 | template <typename Table, typename Key, typename T> | ||
15103 | inline bool operator==(T&& left, const proxy<Table, Key>& right) { | ||
15104 | typedef decltype(stack::get<T>(nullptr, 0)) U; | ||
15105 | return right.template get<optional<U>>() == left; | ||
15106 | } | ||
15107 | |||
15108 | template <typename Table, typename Key, typename T> | ||
15109 | inline bool operator==(const proxy<Table, Key>& right, T&& left) { | ||
15110 | typedef decltype(stack::get<T>(nullptr, 0)) U; | ||
15111 | return right.template get<optional<U>>() == left; | ||
15112 | } | ||
15113 | |||
15114 | template <typename Table, typename Key, typename T> | ||
15115 | inline bool operator!=(T&& left, const proxy<Table, Key>& right) { | ||
15116 | typedef decltype(stack::get<T>(nullptr, 0)) U; | ||
15117 | return right.template get<optional<U>>() != left; | ||
15118 | } | ||
15119 | |||
15120 | template <typename Table, typename Key, typename T> | ||
15121 | inline bool operator!=(const proxy<Table, Key>& right, T&& left) { | ||
15122 | typedef decltype(stack::get<T>(nullptr, 0)) U; | ||
15123 | return right.template get<optional<U>>() != left; | ||
15124 | } | ||
15125 | |||
15126 | template <typename Table, typename Key> | ||
15127 | inline bool operator==(lua_nil_t, const proxy<Table, Key>& right) { | ||
15128 | return !right.valid(); | ||
15129 | } | ||
15130 | |||
15131 | template <typename Table, typename Key> | ||
15132 | inline bool operator==(const proxy<Table, Key>& right, lua_nil_t) { | ||
15133 | return !right.valid(); | ||
15134 | } | ||
15135 | |||
15136 | template <typename Table, typename Key> | ||
15137 | inline bool operator!=(lua_nil_t, const proxy<Table, Key>& right) { | ||
15138 | return right.valid(); | ||
15139 | } | ||
15140 | |||
15141 | template <typename Table, typename Key> | ||
15142 | inline bool operator!=(const proxy<Table, Key>& right, lua_nil_t) { | ||
15143 | return right.valid(); | ||
15144 | } | ||
15145 | |||
15146 | template <bool b> | ||
15147 | template <typename Super> | ||
15148 | basic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) { | ||
15149 | basic_reference<b> v = r; | ||
15150 | this->operator=(std::move(v)); | ||
15151 | return *this; | ||
15152 | } | ||
15153 | |||
15154 | template <bool b> | ||
15155 | template <typename Super> | ||
15156 | basic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) { | ||
15157 | basic_reference<b> v = r; | ||
15158 | this->operator=(std::move(v)); | ||
15159 | return *this; | ||
15160 | } | ||
15161 | |||
15162 | namespace stack { | ||
15163 | template <typename Table, typename Key> | ||
15164 | struct pusher<proxy<Table, Key>> { | ||
15165 | static int push(lua_State* L, const proxy<Table, Key>& p) { | ||
15166 | reference r = p; | ||
15167 | return r.push(L); | ||
15168 | } | ||
15169 | }; | ||
15170 | } // namespace stack | ||
15171 | } // namespace sol | ||
15172 | |||
15173 | // end of sol/proxy.hpp | ||
15174 | |||
15175 | // beginning of sol/usertype.hpp | ||
15176 | |||
15177 | // beginning of sol/usertype_metatable.hpp | ||
15178 | |||
15179 | // beginning of sol/deprecate.hpp | ||
15180 | |||
15181 | #ifndef SOL_DEPRECATED | ||
15182 | #ifdef _MSC_VER | ||
15183 | #define SOL_DEPRECATED __declspec(deprecated) | ||
15184 | #elif __GNUC__ | ||
15185 | #define SOL_DEPRECATED __attribute__((deprecated)) | ||
15186 | #else | ||
15187 | #define SOL_DEPRECATED [[deprecated]] | ||
15188 | #endif // compilers | ||
15189 | #endif // SOL_DEPRECATED | ||
15190 | |||
15191 | namespace sol { | ||
15192 | namespace detail { | ||
15193 | template <typename T> | ||
15194 | struct SOL_DEPRECATED deprecate_type { | ||
15195 | using type = T; | ||
15196 | }; | ||
15197 | } | ||
15198 | } // namespace sol::detail | ||
15199 | |||
15200 | // end of sol/deprecate.hpp | ||
15201 | |||
15202 | // beginning of sol/object.hpp | ||
15203 | |||
15204 | // beginning of sol/object_base.hpp | ||
15205 | |||
15206 | namespace sol { | ||
15207 | |||
15208 | template <typename base_t> | ||
15209 | class basic_object_base : public base_t { | ||
15210 | private: | ||
15211 | template <typename T> | ||
15212 | decltype(auto) as_stack(std::true_type) const { | ||
15213 | return stack::get<T>(base_t::lua_state(), base_t::stack_index()); | ||
15214 | } | ||
15215 | |||
15216 | template <typename T> | ||
15217 | decltype(auto) as_stack(std::false_type) const { | ||
15218 | base_t::push(); | ||
15219 | return stack::pop<T>(base_t::lua_state()); | ||
15220 | } | ||
15221 | |||
15222 | template <typename T> | ||
15223 | bool is_stack(std::true_type) const { | ||
15224 | return stack::check<T>(base_t::lua_state(), base_t::stack_index(), no_panic); | ||
15225 | } | ||
15226 | |||
15227 | template <typename T> | ||
15228 | bool is_stack(std::false_type) const { | ||
15229 | int r = base_t::registry_index(); | ||
15230 | if (r == LUA_REFNIL) | ||
15231 | return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; | ||
15232 | if (r == LUA_NOREF) | ||
15233 | return false; | ||
15234 | auto pp = stack::push_pop(*this); | ||
15235 | return stack::check<T>(base_t::lua_state(), -1, no_panic); | ||
15236 | } | ||
15237 | |||
15238 | public: | ||
15239 | basic_object_base() noexcept = default; | ||
15240 | basic_object_base(const basic_object_base&) = default; | ||
15241 | basic_object_base(basic_object_base&&) = default; | ||
15242 | basic_object_base& operator=(const basic_object_base&) = default; | ||
15243 | basic_object_base& operator=(basic_object_base&&) = default; | ||
15244 | template <typename T, typename... Args, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object_base>>> = meta::enabler> | ||
15245 | basic_object_base(T&& arg, Args&&... args) | ||
15246 | : base_t(std::forward<T>(arg), std::forward<Args>(args)...) { | ||
15247 | } | ||
15248 | |||
15249 | template <typename T> | ||
15250 | decltype(auto) as() const { | ||
15251 | return as_stack<T>(is_stack_based<base_t>()); | ||
15252 | } | ||
15253 | |||
15254 | template <typename T> | ||
15255 | bool is() const { | ||
15256 | return is_stack<T>(is_stack_based<base_t>()); | ||
15257 | } | ||
15258 | }; | ||
15259 | } // namespace sol | ||
15260 | |||
15261 | // end of sol/object_base.hpp | ||
15262 | |||
15263 | // beginning of sol/userdata.hpp | ||
15264 | |||
15265 | namespace sol { | ||
15266 | template <typename base_type> | ||
15267 | class basic_userdata : public basic_table<base_type> { | ||
15268 | typedef basic_table<base_type> base_t; | ||
15269 | |||
15270 | public: | ||
15271 | using base_t::lua_state; | ||
15272 | |||
15273 | basic_userdata() noexcept = default; | ||
15274 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15275 | basic_userdata(T&& r) noexcept | ||
15276 | : base_t(std::forward<T>(r)) { | ||
15277 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15278 | if (!is_userdata<meta::unqualified_t<T>>::value) { | ||
15279 | auto pp = stack::push_pop(*this); | ||
15280 | type_assert(lua_state(), -1, type::userdata); | ||
15281 | } | ||
15282 | #endif // Safety | ||
15283 | } | ||
15284 | basic_userdata(const basic_userdata&) = default; | ||
15285 | basic_userdata(basic_userdata&&) = default; | ||
15286 | basic_userdata& operator=(const basic_userdata&) = default; | ||
15287 | basic_userdata& operator=(basic_userdata&&) = default; | ||
15288 | basic_userdata(const stack_reference& r) | ||
15289 | : basic_userdata(r.lua_state(), r.stack_index()) { | ||
15290 | } | ||
15291 | basic_userdata(stack_reference&& r) | ||
15292 | : basic_userdata(r.lua_state(), r.stack_index()) { | ||
15293 | } | ||
15294 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15295 | basic_userdata(lua_State* L, T&& r) | ||
15296 | : base_t(L, std::forward<T>(r)) { | ||
15297 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15298 | auto pp = stack::push_pop(*this); | ||
15299 | constructor_handler handler{}; | ||
15300 | stack::check<basic_userdata>(L, -1, handler); | ||
15301 | #endif // Safety | ||
15302 | } | ||
15303 | basic_userdata(lua_State* L, int index = -1) | ||
15304 | : base_t(detail::no_safety, L, index) { | ||
15305 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15306 | constructor_handler handler{}; | ||
15307 | stack::check<basic_userdata>(L, index, handler); | ||
15308 | #endif // Safety | ||
15309 | } | ||
15310 | basic_userdata(lua_State* L, ref_index index) | ||
15311 | : base_t(detail::no_safety, L, index) { | ||
15312 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15313 | auto pp = stack::push_pop(*this); | ||
15314 | constructor_handler handler{}; | ||
15315 | stack::check<basic_userdata>(L, -1, handler); | ||
15316 | #endif // Safety | ||
15317 | } | ||
15318 | }; | ||
15319 | |||
15320 | template <typename base_type> | ||
15321 | class basic_lightuserdata : public basic_object_base<base_type> { | ||
15322 | typedef basic_object_base<base_type> base_t; | ||
15323 | |||
15324 | public: | ||
15325 | using base_t::lua_state; | ||
15326 | |||
15327 | basic_lightuserdata() noexcept = default; | ||
15328 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15329 | basic_lightuserdata(T&& r) noexcept | ||
15330 | : base_t(std::forward<T>(r)) { | ||
15331 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15332 | if (!is_lightuserdata<meta::unqualified_t<T>>::value) { | ||
15333 | auto pp = stack::push_pop(*this); | ||
15334 | type_assert(lua_state(), -1, type::lightuserdata); | ||
15335 | } | ||
15336 | #endif // Safety | ||
15337 | } | ||
15338 | basic_lightuserdata(const basic_lightuserdata&) = default; | ||
15339 | basic_lightuserdata(basic_lightuserdata&&) = default; | ||
15340 | basic_lightuserdata& operator=(const basic_lightuserdata&) = default; | ||
15341 | basic_lightuserdata& operator=(basic_lightuserdata&&) = default; | ||
15342 | basic_lightuserdata(const stack_reference& r) | ||
15343 | : basic_lightuserdata(r.lua_state(), r.stack_index()) { | ||
15344 | } | ||
15345 | basic_lightuserdata(stack_reference&& r) | ||
15346 | : basic_lightuserdata(r.lua_state(), r.stack_index()) { | ||
15347 | } | ||
15348 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15349 | basic_lightuserdata(lua_State* L, T&& r) | ||
15350 | : basic_lightuserdata(L, std::forward<T>(r)) { | ||
15351 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15352 | auto pp = stack::push_pop(*this); | ||
15353 | constructor_handler handler{}; | ||
15354 | stack::check<basic_lightuserdata>(lua_state(), -1, handler); | ||
15355 | #endif // Safety | ||
15356 | } | ||
15357 | basic_lightuserdata(lua_State* L, int index = -1) | ||
15358 | : base_t(L, index) { | ||
15359 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15360 | constructor_handler handler{}; | ||
15361 | stack::check<basic_lightuserdata>(L, index, handler); | ||
15362 | #endif // Safety | ||
15363 | } | ||
15364 | basic_lightuserdata(lua_State* L, ref_index index) | ||
15365 | : base_t(L, index) { | ||
15366 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
15367 | auto pp = stack::push_pop(*this); | ||
15368 | constructor_handler handler{}; | ||
15369 | stack::check<basic_lightuserdata>(lua_state(), index, handler); | ||
15370 | #endif // Safety | ||
15371 | } | ||
15372 | }; | ||
15373 | |||
15374 | } // namespace sol | ||
15375 | |||
15376 | // end of sol/userdata.hpp | ||
15377 | |||
15378 | // beginning of sol/as_args.hpp | ||
15379 | |||
15380 | namespace sol { | ||
15381 | template <typename T> | ||
15382 | struct as_args_t { | ||
15383 | T src; | ||
15384 | }; | ||
15385 | |||
15386 | template <typename Source> | ||
15387 | auto as_args(Source&& source) { | ||
15388 | return as_args_t<Source>{ std::forward<Source>(source) }; | ||
15389 | } | ||
15390 | |||
15391 | namespace stack { | ||
15392 | template <typename T> | ||
15393 | struct pusher<as_args_t<T>> { | ||
15394 | int push(lua_State* L, const as_args_t<T>& e) { | ||
15395 | int p = 0; | ||
15396 | for (const auto& i : e.src) { | ||
15397 | p += stack::push(L, i); | ||
15398 | } | ||
15399 | return p; | ||
15400 | } | ||
15401 | }; | ||
15402 | } // namespace stack | ||
15403 | } // namespace sol | ||
15404 | |||
15405 | // end of sol/as_args.hpp | ||
15406 | |||
15407 | // beginning of sol/variadic_args.hpp | ||
15408 | |||
15409 | namespace sol { | ||
15410 | struct variadic_args { | ||
15411 | private: | ||
15412 | lua_State* L; | ||
15413 | int index; | ||
15414 | int stacktop; | ||
15415 | |||
15416 | public: | ||
15417 | typedef stack_proxy reference_type; | ||
15418 | typedef stack_proxy value_type; | ||
15419 | typedef stack_proxy* pointer; | ||
15420 | typedef std::ptrdiff_t difference_type; | ||
15421 | typedef std::size_t size_type; | ||
15422 | typedef stack_iterator<stack_proxy, false> iterator; | ||
15423 | typedef stack_iterator<stack_proxy, true> const_iterator; | ||
15424 | typedef std::reverse_iterator<iterator> reverse_iterator; | ||
15425 | typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | ||
15426 | |||
15427 | variadic_args() = default; | ||
15428 | variadic_args(lua_State* luastate, int stackindex = -1) | ||
15429 | : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { | ||
15430 | } | ||
15431 | variadic_args(lua_State* luastate, int stackindex, int lastindex) | ||
15432 | : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { | ||
15433 | } | ||
15434 | variadic_args(const variadic_args&) = default; | ||
15435 | variadic_args& operator=(const variadic_args&) = default; | ||
15436 | variadic_args(variadic_args&& o) | ||
15437 | : L(o.L), index(o.index), stacktop(o.stacktop) { | ||
15438 | // Must be manual, otherwise destructor will screw us | ||
15439 | // return count being 0 is enough to keep things clean | ||
15440 | // but will be thorough | ||
15441 | o.L = nullptr; | ||
15442 | o.index = 0; | ||
15443 | o.stacktop = 0; | ||
15444 | } | ||
15445 | variadic_args& operator=(variadic_args&& o) { | ||
15446 | L = o.L; | ||
15447 | index = o.index; | ||
15448 | stacktop = o.stacktop; | ||
15449 | // Must be manual, otherwise destructor will screw us | ||
15450 | // return count being 0 is enough to keep things clean | ||
15451 | // but will be thorough | ||
15452 | o.L = nullptr; | ||
15453 | o.index = 0; | ||
15454 | o.stacktop = 0; | ||
15455 | return *this; | ||
15456 | } | ||
15457 | |||
15458 | iterator begin() { | ||
15459 | return iterator(L, index, stacktop + 1); | ||
15460 | } | ||
15461 | iterator end() { | ||
15462 | return iterator(L, stacktop + 1, stacktop + 1); | ||
15463 | } | ||
15464 | const_iterator begin() const { | ||
15465 | return const_iterator(L, index, stacktop + 1); | ||
15466 | } | ||
15467 | const_iterator end() const { | ||
15468 | return const_iterator(L, stacktop + 1, stacktop + 1); | ||
15469 | } | ||
15470 | const_iterator cbegin() const { | ||
15471 | return begin(); | ||
15472 | } | ||
15473 | const_iterator cend() const { | ||
15474 | return end(); | ||
15475 | } | ||
15476 | |||
15477 | reverse_iterator rbegin() { | ||
15478 | return std::reverse_iterator<iterator>(begin()); | ||
15479 | } | ||
15480 | reverse_iterator rend() { | ||
15481 | return std::reverse_iterator<iterator>(end()); | ||
15482 | } | ||
15483 | const_reverse_iterator rbegin() const { | ||
15484 | return std::reverse_iterator<const_iterator>(begin()); | ||
15485 | } | ||
15486 | const_reverse_iterator rend() const { | ||
15487 | return std::reverse_iterator<const_iterator>(end()); | ||
15488 | } | ||
15489 | const_reverse_iterator crbegin() const { | ||
15490 | return std::reverse_iterator<const_iterator>(cbegin()); | ||
15491 | } | ||
15492 | const_reverse_iterator crend() const { | ||
15493 | return std::reverse_iterator<const_iterator>(cend()); | ||
15494 | } | ||
15495 | |||
15496 | int push() const { | ||
15497 | return push(L); | ||
15498 | } | ||
15499 | |||
15500 | int push(lua_State* target) const { | ||
15501 | int pushcount = 0; | ||
15502 | for (int i = index; i <= stacktop; ++i) { | ||
15503 | lua_pushvalue(L, i); | ||
15504 | pushcount += 1; | ||
15505 | } | ||
15506 | if (target != L) { | ||
15507 | lua_xmove(L, target, pushcount); | ||
15508 | } | ||
15509 | return pushcount; | ||
15510 | } | ||
15511 | |||
15512 | template <typename T> | ||
15513 | decltype(auto) get(difference_type index_offset = 0) const { | ||
15514 | return stack::get<T>(L, index + static_cast<int>(index_offset)); | ||
15515 | } | ||
15516 | |||
15517 | type get_type(difference_type index_offset = 0) const noexcept { | ||
15518 | return type_of(L, index + static_cast<int>(index_offset)); | ||
15519 | } | ||
15520 | |||
15521 | stack_proxy operator[](difference_type index_offset) const { | ||
15522 | return stack_proxy(L, index + static_cast<int>(index_offset)); | ||
15523 | } | ||
15524 | |||
15525 | lua_State* lua_state() const { | ||
15526 | return L; | ||
15527 | }; | ||
15528 | int stack_index() const { | ||
15529 | return index; | ||
15530 | }; | ||
15531 | int leftover_count() const { | ||
15532 | return stacktop - (index - 1); | ||
15533 | } | ||
15534 | std::size_t size() const { | ||
15535 | return static_cast<std::size_t>(leftover_count()); | ||
15536 | } | ||
15537 | int top() const { | ||
15538 | return stacktop; | ||
15539 | } | ||
15540 | }; | ||
15541 | |||
15542 | namespace stack { | ||
15543 | template <> | ||
15544 | struct getter<variadic_args> { | ||
15545 | static variadic_args get(lua_State* L, int index, record& tracking) { | ||
15546 | tracking.last = 0; | ||
15547 | return variadic_args(L, index); | ||
15548 | } | ||
15549 | }; | ||
15550 | |||
15551 | template <> | ||
15552 | struct pusher<variadic_args> { | ||
15553 | static int push(lua_State* L, const variadic_args& ref) { | ||
15554 | return ref.push(L); | ||
15555 | } | ||
15556 | }; | ||
15557 | } // namespace stack | ||
15558 | } // namespace sol | ||
15559 | |||
15560 | // end of sol/variadic_args.hpp | ||
15561 | |||
15562 | namespace sol { | ||
15563 | |||
15564 | template <typename R = reference, bool should_pop = !is_stack_based<R>::value, typename T> | ||
15565 | R make_reference(lua_State* L, T&& value) { | ||
15566 | int backpedal = stack::push(L, std::forward<T>(value)); | ||
15567 | R r = stack::get<R>(L, -backpedal); | ||
15568 | if (should_pop) { | ||
15569 | lua_pop(L, backpedal); | ||
15570 | } | ||
15571 | return r; | ||
15572 | } | ||
15573 | |||
15574 | template <typename T, typename R = reference, bool should_pop = !is_stack_based<R>::value, typename... Args> | ||
15575 | R make_reference(lua_State* L, Args&&... args) { | ||
15576 | int backpedal = stack::push<T>(L, std::forward<Args>(args)...); | ||
15577 | R r = stack::get<R>(L, -backpedal); | ||
15578 | if (should_pop) { | ||
15579 | lua_pop(L, backpedal); | ||
15580 | } | ||
15581 | return r; | ||
15582 | } | ||
15583 | |||
15584 | template <typename base_type> | ||
15585 | class basic_object : public basic_object_base<base_type> { | ||
15586 | private: | ||
15587 | typedef basic_object_base<base_type> base_t; | ||
15588 | |||
15589 | template <bool invert_and_pop = false> | ||
15590 | basic_object(std::integral_constant<bool, invert_and_pop>, lua_State* L, int index = -1) noexcept | ||
15591 | : base_t(L, index) { | ||
15592 | if (invert_and_pop) { | ||
15593 | lua_pop(L, -index); | ||
15594 | } | ||
15595 | } | ||
15596 | |||
15597 | public: | ||
15598 | basic_object() noexcept = default; | ||
15599 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15600 | basic_object(T&& r) | ||
15601 | : base_t(std::forward<T>(r)) { | ||
15602 | } | ||
15603 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
15604 | basic_object(lua_State* L, T&& r) | ||
15605 | : base_t(L, std::forward<T>(r)) { | ||
15606 | } | ||
15607 | basic_object(lua_nil_t r) | ||
15608 | : base_t(r) { | ||
15609 | } | ||
15610 | basic_object(const basic_object&) = default; | ||
15611 | basic_object(basic_object&&) = default; | ||
15612 | basic_object(const stack_reference& r) noexcept | ||
15613 | : basic_object(r.lua_state(), r.stack_index()) { | ||
15614 | } | ||
15615 | basic_object(stack_reference&& r) noexcept | ||
15616 | : basic_object(r.lua_state(), r.stack_index()) { | ||
15617 | } | ||
15618 | template <typename Super> | ||
15619 | basic_object(const proxy_base<Super>& r) noexcept | ||
15620 | : basic_object(r.operator basic_object()) { | ||
15621 | } | ||
15622 | template <typename Super> | ||
15623 | basic_object(proxy_base<Super>&& r) noexcept | ||
15624 | : basic_object(r.operator basic_object()) { | ||
15625 | } | ||
15626 | basic_object(lua_State* L, lua_nil_t r) noexcept | ||
15627 | : base_t(L, r) { | ||
15628 | } | ||
15629 | basic_object(lua_State* L, int index = -1) noexcept | ||
15630 | : base_t(L, index) { | ||
15631 | } | ||
15632 | basic_object(lua_State* L, absolute_index index) noexcept | ||
15633 | : base_t(L, index) { | ||
15634 | } | ||
15635 | basic_object(lua_State* L, raw_index index) noexcept | ||
15636 | : base_t(L, index) { | ||
15637 | } | ||
15638 | basic_object(lua_State* L, ref_index index) noexcept | ||
15639 | : base_t(L, index) { | ||
15640 | } | ||
15641 | template <typename T, typename... Args> | ||
15642 | basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept | ||
15643 | : basic_object(std::integral_constant<bool, !is_stack_based<base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) { | ||
15644 | } | ||
15645 | template <typename T, typename... Args> | ||
15646 | basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept | ||
15647 | : basic_object(L, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) { | ||
15648 | } | ||
15649 | basic_object& operator=(const basic_object&) = default; | ||
15650 | basic_object& operator=(basic_object&&) = default; | ||
15651 | basic_object& operator=(const base_type& b) { | ||
15652 | base_t::operator=(b); | ||
15653 | return *this; | ||
15654 | } | ||
15655 | basic_object& operator=(base_type&& b) { | ||
15656 | base_t::operator=(std::move(b)); | ||
15657 | return *this; | ||
15658 | } | ||
15659 | template <typename Super> | ||
15660 | basic_object& operator=(const proxy_base<Super>& r) { | ||
15661 | this->operator=(r.operator basic_object()); | ||
15662 | return *this; | ||
15663 | } | ||
15664 | template <typename Super> | ||
15665 | basic_object& operator=(proxy_base<Super>&& r) { | ||
15666 | this->operator=(r.operator basic_object()); | ||
15667 | return *this; | ||
15668 | } | ||
15669 | }; | ||
15670 | |||
15671 | template <typename T> | ||
15672 | object make_object(lua_State* L, T&& value) { | ||
15673 | return make_reference<object, true>(L, std::forward<T>(value)); | ||
15674 | } | ||
15675 | |||
15676 | template <typename T, typename... Args> | ||
15677 | object make_object(lua_State* L, Args&&... args) { | ||
15678 | return make_reference<T, object, true>(L, std::forward<Args>(args)...); | ||
15679 | } | ||
15680 | } // namespace sol | ||
15681 | |||
15682 | // end of sol/object.hpp | ||
15683 | |||
15684 | // beginning of sol/container_usertype_metatable.hpp | ||
15685 | |||
15686 | // beginning of sol/container_traits.hpp | ||
15687 | |||
15688 | namespace sol { | ||
15689 | |||
15690 | template <typename T> | ||
15691 | struct container_traits; | ||
15692 | |||
15693 | template <typename T> | ||
15694 | struct as_container_t { | ||
15695 | T source; | ||
15696 | |||
15697 | as_container_t(T value) | ||
15698 | : source(std::move(value)) { | ||
15699 | } | ||
15700 | |||
15701 | operator std::add_rvalue_reference_t<T>() { | ||
15702 | return std::move(source); | ||
15703 | } | ||
15704 | |||
15705 | operator std::add_lvalue_reference_t<std::add_const_t<T>>() const { | ||
15706 | return source; | ||
15707 | } | ||
15708 | }; | ||
15709 | |||
15710 | template <typename T> | ||
15711 | struct as_container_t<T&> { | ||
15712 | std::reference_wrapper<T> source; | ||
15713 | |||
15714 | as_container_t(T& value) | ||
15715 | : source(value) { | ||
15716 | } | ||
15717 | |||
15718 | operator T&() { | ||
15719 | return source; | ||
15720 | } | ||
15721 | }; | ||
15722 | |||
15723 | template <typename T> | ||
15724 | auto as_container(T&& value) { | ||
15725 | return as_container_t<T>(std::forward<T>(value)); | ||
15726 | } | ||
15727 | |||
15728 | namespace container_detail { | ||
15729 | |||
15730 | template <typename T> | ||
15731 | struct has_clear_test { | ||
15732 | private: | ||
15733 | typedef std::array<char, 1> one; | ||
15734 | typedef std::array<char, 2> two; | ||
15735 | |||
15736 | template <typename C> | ||
15737 | static one test(decltype(&C::clear)); | ||
15738 | template <typename C> | ||
15739 | static two test(...); | ||
15740 | |||
15741 | public: | ||
15742 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15743 | }; | ||
15744 | |||
15745 | template <typename T> | ||
15746 | struct has_empty_test { | ||
15747 | private: | ||
15748 | typedef std::array<char, 1> one; | ||
15749 | typedef std::array<char, 2> two; | ||
15750 | |||
15751 | template <typename C> | ||
15752 | static one test(decltype(&C::empty)); | ||
15753 | template <typename C> | ||
15754 | static two test(...); | ||
15755 | |||
15756 | public: | ||
15757 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15758 | }; | ||
15759 | |||
15760 | template <typename T> | ||
15761 | struct has_erase_after_test { | ||
15762 | private: | ||
15763 | typedef std::array<char, 1> one; | ||
15764 | typedef std::array<char, 2> two; | ||
15765 | |||
15766 | template <typename C> | ||
15767 | static one test(decltype(std::declval<C>().erase_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>()))*); | ||
15768 | template <typename C> | ||
15769 | static two test(...); | ||
15770 | |||
15771 | public: | ||
15772 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15773 | }; | ||
15774 | |||
15775 | template <typename T, typename = void> | ||
15776 | struct has_find_test { | ||
15777 | private: | ||
15778 | typedef std::array<char, 1> one; | ||
15779 | typedef std::array<char, 2> two; | ||
15780 | |||
15781 | template <typename C> | ||
15782 | static one test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*); | ||
15783 | template <typename C> | ||
15784 | static two test(...); | ||
15785 | |||
15786 | public: | ||
15787 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15788 | }; | ||
15789 | |||
15790 | template <typename T> | ||
15791 | struct has_find_test<T, std::enable_if_t<meta::is_lookup<T>::value>> { | ||
15792 | private: | ||
15793 | typedef std::array<char, 1> one; | ||
15794 | typedef std::array<char, 2> two; | ||
15795 | |||
15796 | template <typename C> | ||
15797 | static one test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::key_type>>()))*); | ||
15798 | template <typename C> | ||
15799 | static two test(...); | ||
15800 | |||
15801 | public: | ||
15802 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15803 | }; | ||
15804 | |||
15805 | template <typename T> | ||
15806 | struct has_erase_test { | ||
15807 | private: | ||
15808 | typedef std::array<char, 1> one; | ||
15809 | typedef std::array<char, 2> two; | ||
15810 | |||
15811 | template <typename C> | ||
15812 | static one test(decltype(std::declval<C>().erase(std::declval<typename C::iterator>()))*); | ||
15813 | template <typename C> | ||
15814 | static two test(...); | ||
15815 | |||
15816 | public: | ||
15817 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15818 | }; | ||
15819 | |||
15820 | template <typename T> | ||
15821 | struct has_traits_find_test { | ||
15822 | private: | ||
15823 | typedef std::array<char, 1> one; | ||
15824 | typedef std::array<char, 2> two; | ||
15825 | |||
15826 | template <typename C> | ||
15827 | static one test(decltype(&C::find)); | ||
15828 | template <typename C> | ||
15829 | static two test(...); | ||
15830 | |||
15831 | public: | ||
15832 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15833 | }; | ||
15834 | |||
15835 | template <typename T> | ||
15836 | struct has_traits_insert_test { | ||
15837 | private: | ||
15838 | typedef std::array<char, 1> one; | ||
15839 | typedef std::array<char, 2> two; | ||
15840 | |||
15841 | template <typename C> | ||
15842 | static one test(decltype(&C::insert)); | ||
15843 | template <typename C> | ||
15844 | static two test(...); | ||
15845 | |||
15846 | public: | ||
15847 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15848 | }; | ||
15849 | |||
15850 | template <typename T> | ||
15851 | struct has_traits_erase_test { | ||
15852 | private: | ||
15853 | typedef std::array<char, 1> one; | ||
15854 | typedef std::array<char, 2> two; | ||
15855 | |||
15856 | template <typename C> | ||
15857 | static one test(decltype(&C::erase)); | ||
15858 | template <typename C> | ||
15859 | static two test(...); | ||
15860 | |||
15861 | public: | ||
15862 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15863 | }; | ||
15864 | |||
15865 | template <typename T> | ||
15866 | struct has_traits_index_set_test { | ||
15867 | private: | ||
15868 | typedef std::array<char, 1> one; | ||
15869 | typedef std::array<char, 2> two; | ||
15870 | |||
15871 | template <typename C> | ||
15872 | static one test(decltype(&C::index_set)); | ||
15873 | template <typename C> | ||
15874 | static two test(...); | ||
15875 | |||
15876 | public: | ||
15877 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15878 | }; | ||
15879 | |||
15880 | template <typename T> | ||
15881 | struct has_traits_index_get_test { | ||
15882 | private: | ||
15883 | typedef std::array<char, 1> one; | ||
15884 | typedef std::array<char, 2> two; | ||
15885 | |||
15886 | template <typename C> | ||
15887 | static one test(decltype(&C::index_get)); | ||
15888 | template <typename C> | ||
15889 | static two test(...); | ||
15890 | |||
15891 | public: | ||
15892 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15893 | }; | ||
15894 | |||
15895 | template <typename T> | ||
15896 | struct has_traits_set_test { | ||
15897 | private: | ||
15898 | typedef std::array<char, 1> one; | ||
15899 | typedef std::array<char, 2> two; | ||
15900 | |||
15901 | template <typename C> | ||
15902 | static one test(decltype(&C::set)); | ||
15903 | template <typename C> | ||
15904 | static two test(...); | ||
15905 | |||
15906 | public: | ||
15907 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15908 | }; | ||
15909 | |||
15910 | template <typename T> | ||
15911 | struct has_traits_get_test { | ||
15912 | private: | ||
15913 | typedef std::array<char, 1> one; | ||
15914 | typedef std::array<char, 2> two; | ||
15915 | |||
15916 | template <typename C> | ||
15917 | static one test(decltype(&C::get)); | ||
15918 | template <typename C> | ||
15919 | static two test(...); | ||
15920 | |||
15921 | public: | ||
15922 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15923 | }; | ||
15924 | |||
15925 | template <typename T> | ||
15926 | struct has_traits_at_test { | ||
15927 | private: | ||
15928 | typedef std::array<char, 1> one; | ||
15929 | typedef std::array<char, 2> two; | ||
15930 | |||
15931 | template <typename C> | ||
15932 | static one test(decltype(&C::at)); | ||
15933 | template <typename C> | ||
15934 | static two test(...); | ||
15935 | |||
15936 | public: | ||
15937 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15938 | }; | ||
15939 | |||
15940 | template <typename T> | ||
15941 | struct has_traits_pairs_test { | ||
15942 | private: | ||
15943 | typedef std::array<char, 1> one; | ||
15944 | typedef std::array<char, 2> two; | ||
15945 | |||
15946 | template <typename C> | ||
15947 | static one test(decltype(&C::pairs)); | ||
15948 | template <typename C> | ||
15949 | static two test(...); | ||
15950 | |||
15951 | public: | ||
15952 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15953 | }; | ||
15954 | |||
15955 | template <typename T> | ||
15956 | struct has_traits_ipairs_test { | ||
15957 | private: | ||
15958 | typedef std::array<char, 1> one; | ||
15959 | typedef std::array<char, 2> two; | ||
15960 | |||
15961 | template <typename C> | ||
15962 | static one test(decltype(&C::ipairs)); | ||
15963 | template <typename C> | ||
15964 | static two test(...); | ||
15965 | |||
15966 | public: | ||
15967 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15968 | }; | ||
15969 | |||
15970 | template <typename T> | ||
15971 | struct has_traits_next_test { | ||
15972 | private: | ||
15973 | typedef std::array<char, 1> one; | ||
15974 | typedef std::array<char, 2> two; | ||
15975 | |||
15976 | template <typename C> | ||
15977 | static one test(decltype(&C::next)); | ||
15978 | template <typename C> | ||
15979 | static two test(...); | ||
15980 | |||
15981 | public: | ||
15982 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15983 | }; | ||
15984 | |||
15985 | template <typename T> | ||
15986 | struct has_traits_add_test { | ||
15987 | private: | ||
15988 | typedef std::array<char, 1> one; | ||
15989 | typedef std::array<char, 2> two; | ||
15990 | |||
15991 | template <typename C> | ||
15992 | static one test(decltype(&C::add)); | ||
15993 | template <typename C> | ||
15994 | static two test(...); | ||
15995 | |||
15996 | public: | ||
15997 | static const bool value = sizeof(test<T>(0)) == sizeof(char); | ||
15998 | }; | ||
15999 | |||
16000 | template <typename T> | ||
16001 | using has_clear = meta::boolean<has_clear_test<T>::value>; | ||
16002 | |||
16003 | template <typename T> | ||
16004 | using has_empty = meta::boolean<has_empty_test<T>::value>; | ||
16005 | |||
16006 | template <typename T> | ||
16007 | using has_find = meta::boolean<has_find_test<T>::value>; | ||
16008 | |||
16009 | template <typename T> | ||
16010 | using has_erase = meta::boolean<has_erase_test<T>::value>; | ||
16011 | |||
16012 | template <typename T> | ||
16013 | using has_erase_after = meta::boolean<has_erase_after_test<T>::value>; | ||
16014 | |||
16015 | template <typename T> | ||
16016 | using has_traits_get = meta::boolean<has_traits_get_test<T>::value>; | ||
16017 | |||
16018 | template <typename T> | ||
16019 | using has_traits_at = meta::boolean<has_traits_at_test<T>::value>; | ||
16020 | |||
16021 | template <typename T> | ||
16022 | using has_traits_set = meta::boolean<has_traits_set_test<T>::value>; | ||
16023 | |||
16024 | template <typename T> | ||
16025 | using has_traits_index_get = meta::boolean<has_traits_index_get_test<T>::value>; | ||
16026 | |||
16027 | template <typename T> | ||
16028 | using has_traits_index_set = meta::boolean<has_traits_index_set_test<T>::value>; | ||
16029 | |||
16030 | template <typename T> | ||
16031 | using has_traits_pairs = meta::boolean<has_traits_pairs_test<T>::value>; | ||
16032 | |||
16033 | template <typename T> | ||
16034 | using has_traits_ipairs = meta::boolean<has_traits_ipairs_test<T>::value>; | ||
16035 | |||
16036 | template <typename T> | ||
16037 | using has_traits_next = meta::boolean<has_traits_next_test<T>::value>; | ||
16038 | |||
16039 | template <typename T> | ||
16040 | using has_traits_add = meta::boolean<has_traits_add_test<T>::value>; | ||
16041 | |||
16042 | template <typename T> | ||
16043 | using has_traits_size = meta::has_size<T>; | ||
16044 | |||
16045 | template <typename T> | ||
16046 | using has_traits_clear = has_clear<T>; | ||
16047 | |||
16048 | template <typename T> | ||
16049 | using has_traits_empty = has_empty<T>; | ||
16050 | |||
16051 | template <typename T> | ||
16052 | using has_traits_find = meta::boolean<has_traits_find_test<T>::value>; | ||
16053 | |||
16054 | template <typename T> | ||
16055 | using has_traits_insert = meta::boolean<has_traits_insert_test<T>::value>; | ||
16056 | |||
16057 | template <typename T> | ||
16058 | using has_traits_erase = meta::boolean<has_traits_erase_test<T>::value>; | ||
16059 | |||
16060 | template <typename T> | ||
16061 | struct is_forced_container : is_container<T> {}; | ||
16062 | |||
16063 | template <typename T> | ||
16064 | struct is_forced_container<as_container_t<T>> : std::true_type {}; | ||
16065 | |||
16066 | template <typename T> | ||
16067 | struct container_decay { | ||
16068 | typedef T type; | ||
16069 | }; | ||
16070 | |||
16071 | template <typename T> | ||
16072 | struct container_decay<as_container_t<T>> { | ||
16073 | typedef T type; | ||
16074 | }; | ||
16075 | |||
16076 | template <typename T> | ||
16077 | using container_decay_t = typename container_decay<meta::unqualified_t<T>>::type; | ||
16078 | |||
16079 | template <typename T> | ||
16080 | decltype(auto) get_key(std::false_type, T&& t) { | ||
16081 | return std::forward<T>(t); | ||
16082 | } | ||
16083 | |||
16084 | template <typename T> | ||
16085 | decltype(auto) get_key(std::true_type, T&& t) { | ||
16086 | return t.first; | ||
16087 | } | ||
16088 | |||
16089 | template <typename T> | ||
16090 | decltype(auto) get_value(std::false_type, T&& t) { | ||
16091 | return std::forward<T>(t); | ||
16092 | } | ||
16093 | |||
16094 | template <typename T> | ||
16095 | decltype(auto) get_value(std::true_type, T&& t) { | ||
16096 | return t.second; | ||
16097 | } | ||
16098 | |||
16099 | struct error_result { | ||
16100 | int results; | ||
16101 | const char* fmt; | ||
16102 | std::array<const char*, 4> args; | ||
16103 | |||
16104 | error_result() : results(0), fmt(nullptr) { | ||
16105 | } | ||
16106 | |||
16107 | error_result(int results) : results(results), fmt(nullptr) { | ||
16108 | } | ||
16109 | |||
16110 | error_result(const char* fmt, const char* msg) : results(0), fmt(fmt) { | ||
16111 | args[0] = msg; | ||
16112 | } | ||
16113 | }; | ||
16114 | |||
16115 | inline int handle_errors(lua_State* L, const error_result& er) { | ||
16116 | if (er.fmt == nullptr) { | ||
16117 | return er.results; | ||
16118 | } | ||
16119 | return luaL_error(L, er.fmt, er.args[0], er.args[1], er.args[2], er.args[3]); | ||
16120 | } | ||
16121 | |||
16122 | template <typename X, typename = void> | ||
16123 | struct container_traits_default { | ||
16124 | private: | ||
16125 | typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T; | ||
16126 | |||
16127 | public: | ||
16128 | typedef lua_nil_t iterator; | ||
16129 | typedef lua_nil_t value_type; | ||
16130 | |||
16131 | static int at(lua_State* L) { | ||
16132 | return luaL_error(L, "sol: cannot call 'at(index)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16133 | } | ||
16134 | |||
16135 | static int get(lua_State* L) { | ||
16136 | return luaL_error(L, "sol: cannot call 'get(key)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16137 | } | ||
16138 | |||
16139 | static int index_get(lua_State* L) { | ||
16140 | return luaL_error(L, "sol: cannot call 'container[key]' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16141 | } | ||
16142 | |||
16143 | static int set(lua_State* L) { | ||
16144 | return luaL_error(L, "sol: cannot call 'set(key, value)' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16145 | } | ||
16146 | |||
16147 | static int index_set(lua_State* L) { | ||
16148 | return luaL_error(L, "sol: cannot call 'container[key] = value' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16149 | } | ||
16150 | |||
16151 | static int add(lua_State* L) { | ||
16152 | return luaL_error(L, "sol: cannot call 'add' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16153 | } | ||
16154 | |||
16155 | static int insert(lua_State* L) { | ||
16156 | return luaL_error(L, "sol: cannot call 'insert' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16157 | } | ||
16158 | |||
16159 | static int find(lua_State* L) { | ||
16160 | return luaL_error(L, "sol: cannot call 'find' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16161 | } | ||
16162 | |||
16163 | static int size(lua_State* L) { | ||
16164 | return luaL_error(L, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16165 | } | ||
16166 | |||
16167 | static int clear(lua_State* L) { | ||
16168 | return luaL_error(L, "sol: cannot call 'clear' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16169 | } | ||
16170 | |||
16171 | static int empty(lua_State* L) { | ||
16172 | return luaL_error(L, "sol: cannot call 'empty' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16173 | } | ||
16174 | |||
16175 | static int erase(lua_State* L) { | ||
16176 | return luaL_error(L, "sol: cannot call 'erase' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16177 | } | ||
16178 | |||
16179 | static int next(lua_State* L) { | ||
16180 | return luaL_error(L, "sol: cannot call 'next' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16181 | } | ||
16182 | |||
16183 | static int pairs(lua_State* L) { | ||
16184 | return luaL_error(L, "sol: cannot call '__pairs/pairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16185 | } | ||
16186 | |||
16187 | static int ipairs(lua_State* L) { | ||
16188 | return luaL_error(L, "sol: cannot call '__ipairs' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16189 | } | ||
16190 | |||
16191 | static iterator begin(lua_State* L, T&) { | ||
16192 | luaL_error(L, "sol: cannot call 'being' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16193 | return lua_nil; | ||
16194 | } | ||
16195 | |||
16196 | static iterator end(lua_State* L, T&) { | ||
16197 | luaL_error(L, "sol: cannot call 'end' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str()); | ||
16198 | return lua_nil; | ||
16199 | } | ||
16200 | }; | ||
16201 | |||
16202 | template <typename X> | ||
16203 | struct container_traits_default<X, std::enable_if_t<meta::all<is_forced_container<meta::unqualified_t<X>>, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>, meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>>::value>> { | ||
16204 | private: | ||
16205 | typedef std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>> T; | ||
16206 | |||
16207 | private: | ||
16208 | typedef container_traits<X> deferred_traits; | ||
16209 | typedef meta::is_associative<T> is_associative; | ||
16210 | typedef meta::is_lookup<T> is_lookup; | ||
16211 | typedef meta::is_matched_lookup<T> is_matched_lookup; | ||
16212 | typedef typename T::iterator iterator; | ||
16213 | typedef typename T::value_type value_type; | ||
16214 | typedef std::conditional_t<is_matched_lookup::value, | ||
16215 | std::pair<value_type, value_type>, | ||
16216 | std::conditional_t<is_associative::value || is_lookup::value, | ||
16217 | value_type, | ||
16218 | std::pair<std::ptrdiff_t, value_type> | ||
16219 | > | ||
16220 | > KV; | ||
16221 | typedef typename KV::first_type K; | ||
16222 | typedef typename KV::second_type V; | ||
16223 | typedef std::conditional_t<is_matched_lookup::value, std::ptrdiff_t, K> next_K; | ||
16224 | typedef decltype(*std::declval<iterator&>()) iterator_return; | ||
16225 | typedef std::conditional_t<is_associative::value || is_matched_lookup::value, | ||
16226 | std::add_lvalue_reference_t<V>, | ||
16227 | std::conditional_t<is_lookup::value, | ||
16228 | V, | ||
16229 | iterator_return | ||
16230 | > | ||
16231 | > captured_type; | ||
16232 | typedef typename meta::iterator_tag<iterator>::type iterator_category; | ||
16233 | typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator; | ||
16234 | typedef std::conditional_t<is_input_iterator::value, | ||
16235 | V, | ||
16236 | decltype(detail::deref_non_pointer(std::declval<captured_type>())) | ||
16237 | > push_type; | ||
16238 | typedef std::is_copy_assignable<V> is_copyable; | ||
16239 | typedef meta::neg<meta::any< | ||
16240 | std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable> | ||
16241 | >> is_writable; | ||
16242 | typedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type; | ||
16243 | typedef meta::all<std::is_integral<K>, meta::neg<meta::any<is_associative, is_lookup>>> is_linear_integral; | ||
16244 | |||
16245 | struct iter { | ||
16246 | T& source; | ||
16247 | iterator it; | ||
16248 | std::size_t i; | ||
16249 | |||
16250 | iter(T& source, iterator it) | ||
16251 | : source(source), it(std::move(it)), i(0) { | ||
16252 | } | ||
16253 | }; | ||
16254 | |||
16255 | static auto& get_src(lua_State* L) { | ||
16256 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
16257 | auto p = stack::check_get<T*>(L, 1); | ||
16258 | if (!p) { | ||
16259 | luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str()); | ||
16260 | } | ||
16261 | if (p.value() == nullptr) { | ||
16262 | luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); | ||
16263 | } | ||
16264 | return *p.value(); | ||
16265 | #else | ||
16266 | return stack::get<T>(L, 1); | ||
16267 | #endif // Safe getting with error | ||
16268 | } | ||
16269 | |||
16270 | static error_result at_category(std::input_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) { | ||
16271 | pos += deferred_traits::index_adjustment(L, self); | ||
16272 | if (pos < 0) { | ||
16273 | return stack::push(L, lua_nil); | ||
16274 | } | ||
16275 | auto it = deferred_traits::begin(L, self); | ||
16276 | auto e = deferred_traits::end(L, self); | ||
16277 | if (it == e) { | ||
16278 | return stack::push(L, lua_nil); | ||
16279 | } | ||
16280 | while (pos > 0) { | ||
16281 | --pos; | ||
16282 | ++it; | ||
16283 | if (it == e) { | ||
16284 | return stack::push(L, lua_nil); | ||
16285 | } | ||
16286 | } | ||
16287 | return get_associative(is_associative(), L, it); | ||
16288 | } | ||
16289 | |||
16290 | static error_result at_category(std::random_access_iterator_tag, lua_State* L, T& self, std::ptrdiff_t pos) { | ||
16291 | std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); | ||
16292 | pos += deferred_traits::index_adjustment(L, self); | ||
16293 | if (pos < 0 || pos >= len) { | ||
16294 | return stack::push(L, lua_nil); | ||
16295 | } | ||
16296 | auto it = std::next(deferred_traits::begin(L, self), pos); | ||
16297 | return get_associative(is_associative(), L, it); | ||
16298 | } | ||
16299 | |||
16300 | static error_result at_start(lua_State* L, T& self, std::ptrdiff_t pos) { | ||
16301 | return at_category(iterator_category(), L, self, pos); | ||
16302 | } | ||
16303 | |||
16304 | static error_result get_associative(std::true_type, lua_State* L, iterator& it) { | ||
16305 | auto& v = *it; | ||
16306 | return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(v.second)); | ||
16307 | } | ||
16308 | |||
16309 | static error_result get_associative(std::false_type, lua_State* L, iterator& it) { | ||
16310 | return stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it)); | ||
16311 | } | ||
16312 | |||
16313 | static error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { | ||
16314 | key += deferred_traits::index_adjustment(L, self); | ||
16315 | if (key < 0) { | ||
16316 | return stack::push(L, lua_nil); | ||
16317 | } | ||
16318 | auto it = deferred_traits::begin(L, self); | ||
16319 | auto e = deferred_traits::end(L, self); | ||
16320 | if (it == e) { | ||
16321 | return stack::push(L, lua_nil); | ||
16322 | } | ||
16323 | while (key > 0) { | ||
16324 | --key; | ||
16325 | ++it; | ||
16326 | if (it == e) { | ||
16327 | return stack::push(L, lua_nil); | ||
16328 | } | ||
16329 | } | ||
16330 | return get_associative(is_associative(), L, it); | ||
16331 | } | ||
16332 | |||
16333 | static error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { | ||
16334 | std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); | ||
16335 | key += deferred_traits::index_adjustment(L, self); | ||
16336 | if (key < 0 || key >= len) { | ||
16337 | return stack::push(L, lua_nil); | ||
16338 | } | ||
16339 | auto it = std::next(deferred_traits::begin(L, self), key); | ||
16340 | return get_associative(is_associative(), L, it); | ||
16341 | } | ||
16342 | |||
16343 | static error_result get_it(std::true_type, lua_State* L, T& self, K& key) { | ||
16344 | return get_category(iterator_category(), L, self, key); | ||
16345 | } | ||
16346 | |||
16347 | static error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) { | ||
16348 | auto fx = [&](const value_type& r) -> bool { | ||
16349 | return key == get_key(is_associative(), r); | ||
16350 | }; | ||
16351 | auto e = deferred_traits::end(L, self); | ||
16352 | auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); | ||
16353 | if (it == e) { | ||
16354 | return stack::push(L, lua_nil); | ||
16355 | } | ||
16356 | return get_associative(is_associative(), L, it); | ||
16357 | } | ||
16358 | |||
16359 | static error_result get_comparative(std::false_type, lua_State*, T&, K&) { | ||
16360 | return error_result("cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle<T>().data(), detail::demangle<K>().data()); | ||
16361 | } | ||
16362 | |||
16363 | static error_result get_it(std::false_type, lua_State* L, T& self, K& key) { | ||
16364 | return get_comparative(meta::supports_op_equal<K, key_type>(), L, self, key); | ||
16365 | } | ||
16366 | |||
16367 | static error_result set_associative(std::true_type, iterator& it, stack_object value) { | ||
16368 | auto& v = *it; | ||
16369 | v.second = value.as<V>(); | ||
16370 | return {}; | ||
16371 | } | ||
16372 | |||
16373 | static error_result set_associative(std::false_type, iterator& it, stack_object value) { | ||
16374 | auto& v = *it; | ||
16375 | v = value.as<V>(); | ||
16376 | return {}; | ||
16377 | } | ||
16378 | |||
16379 | static error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) { | ||
16380 | return set_associative(is_associative(), it, std::move(value)); | ||
16381 | } | ||
16382 | |||
16383 | static error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) { | ||
16384 | return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); | ||
16385 | } | ||
16386 | |||
16387 | static error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { | ||
16388 | decltype(auto) key = okey.as<K>(); | ||
16389 | key += deferred_traits::index_adjustment(L, self); | ||
16390 | auto e = deferred_traits::end(L, self); | ||
16391 | auto it = deferred_traits::begin(L, self); | ||
16392 | auto backit = it; | ||
16393 | for (; key > 0 && it != e; --key, ++it) { | ||
16394 | backit = it; | ||
16395 | } | ||
16396 | if (it == e) { | ||
16397 | if (key == 0) { | ||
16398 | return add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it); | ||
16399 | } | ||
16400 | return error_result("out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); | ||
16401 | } | ||
16402 | return set_writable(is_writable(), L, self, it, std::move(value)); | ||
16403 | } | ||
16404 | |||
16405 | static error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { | ||
16406 | decltype(auto) key = okey.as<K>(); | ||
16407 | if (key <= 0) { | ||
16408 | return error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); | ||
16409 | } | ||
16410 | key += deferred_traits::index_adjustment(L, self); | ||
16411 | std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self)); | ||
16412 | if (key == len) { | ||
16413 | return add_copyable(is_copyable(), L, self, std::move(value)); | ||
16414 | } | ||
16415 | else if (key > len) { | ||
16416 | return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); | ||
16417 | } | ||
16418 | auto it = std::next(deferred_traits::begin(L, self), key); | ||
16419 | return set_writable(is_writable(), L, self, it, std::move(value)); | ||
16420 | } | ||
16421 | |||
16422 | static error_result set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { | ||
16423 | decltype(auto) key = okey.as<K>(); | ||
16424 | if (!is_writable::value) { | ||
16425 | return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data()); | ||
16426 | } | ||
16427 | auto fx = [&](const value_type& r) -> bool { | ||
16428 | return key == get_key(is_associative(), r); | ||
16429 | }; | ||
16430 | auto e = deferred_traits::end(L, self); | ||
16431 | auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); | ||
16432 | if (it == e) { | ||
16433 | return {}; | ||
16434 | } | ||
16435 | return set_writable(is_writable(), L, self, it, std::move(value)); | ||
16436 | } | ||
16437 | |||
16438 | static error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) { | ||
16439 | return error_result("cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle<T>().data(), detail::demangle<K>().data()); | ||
16440 | } | ||
16441 | |||
16442 | static error_result set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) { | ||
16443 | self.insert(it, value_type(key, value.as<V>())); | ||
16444 | return {}; | ||
16445 | } | ||
16446 | |||
16447 | static error_result set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) { | ||
16448 | self.insert(it, key); | ||
16449 | return {}; | ||
16450 | } | ||
16451 | |||
16452 | static error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) { | ||
16453 | decltype(auto) key = okey.as<K>(); | ||
16454 | auto it = self.find(key); | ||
16455 | if (it == deferred_traits::end(L, self)) { | ||
16456 | return set_associative_insert(is_associative(), L, self, it, key, std::move(value)); | ||
16457 | } | ||
16458 | return set_writable(is_writable(), L, self, it, std::move(value)); | ||
16459 | } | ||
16460 | |||
16461 | static error_result set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { | ||
16462 | return set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value)); | ||
16463 | } | ||
16464 | |||
16465 | static error_result set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { | ||
16466 | return set_category(iterator_category(), L, self, std::move(key), std::move(value)); | ||
16467 | } | ||
16468 | |||
16469 | static error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) { | ||
16470 | return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value)); | ||
16471 | } | ||
16472 | |||
16473 | static error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) { | ||
16474 | decltype(auto) key = stack::get<K>(L, 2); | ||
16475 | auto it = self.find(key); | ||
16476 | if (it == deferred_traits::end(L, self)) { | ||
16477 | return stack::push(L, lua_nil); | ||
16478 | } | ||
16479 | return get_associative(is_associative(), L, it); | ||
16480 | } | ||
16481 | |||
16482 | static error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) { | ||
16483 | decltype(auto) value = stack::get<V>(L, 2); | ||
16484 | auto it = self.find(value); | ||
16485 | if (it == deferred_traits::end(L, self)) { | ||
16486 | return stack::push(L, lua_nil); | ||
16487 | } | ||
16488 | return get_associative(is_associative(), L, it); | ||
16489 | } | ||
16490 | |||
16491 | static error_result find_has(std::true_type, lua_State* L, T& self) { | ||
16492 | return find_has_associative_lookup(meta::any<is_lookup, is_associative>(), L, self); | ||
16493 | } | ||
16494 | |||
16495 | static error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) { | ||
16496 | return get_associative(is_associative(), L, it); | ||
16497 | } | ||
16498 | |||
16499 | static error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) { | ||
16500 | return stack::push(L, index); | ||
16501 | } | ||
16502 | |||
16503 | static error_result find_comparative(std::false_type, lua_State*, T&) { | ||
16504 | return error_result("cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle<T>().c_str()); | ||
16505 | } | ||
16506 | |||
16507 | static error_result find_comparative(std::true_type, lua_State* L, T& self) { | ||
16508 | decltype(auto) value = stack::get<V>(L, 2); | ||
16509 | auto it = deferred_traits::begin(L, self); | ||
16510 | auto e = deferred_traits::end(L, self); | ||
16511 | std::size_t index = 1; | ||
16512 | for (;; ++it, ++index) { | ||
16513 | if (it == e) { | ||
16514 | return stack::push(L, lua_nil); | ||
16515 | } | ||
16516 | if (value == get_value(is_associative(), *it)) { | ||
16517 | break; | ||
16518 | } | ||
16519 | } | ||
16520 | return find_associative_lookup(meta::any<is_lookup, is_associative>(), L, it, index); | ||
16521 | } | ||
16522 | |||
16523 | static error_result find_has(std::false_type, lua_State* L, T& self) { | ||
16524 | return find_comparative(meta::supports_op_equal<V>(), L, self); | ||
16525 | } | ||
16526 | |||
16527 | static error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { | ||
16528 | return add_insert_after(std::false_type(), L, self, value); | ||
16529 | } | ||
16530 | |||
16531 | static error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) { | ||
16532 | return error_result("cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data()); | ||
16533 | } | ||
16534 | |||
16535 | static error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& pos) { | ||
16536 | self.insert_after(pos, value.as<V>()); | ||
16537 | return {}; | ||
16538 | } | ||
16539 | |||
16540 | static error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) { | ||
16541 | auto backit = self.before_begin(); | ||
16542 | { | ||
16543 | auto e = deferred_traits::end(L, self); | ||
16544 | for (auto it = deferred_traits::begin(L, self); it != e; ++backit, ++it) { | ||
16545 | } | ||
16546 | } | ||
16547 | return add_insert_after(std::true_type(), L, self, value, backit); | ||
16548 | } | ||
16549 | |||
16550 | static error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& pos) { | ||
16551 | self.insert(pos, value.as<V>()); | ||
16552 | return {}; | ||
16553 | } | ||
16554 | |||
16555 | static error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) { | ||
16556 | auto pos = deferred_traits::end(L, self); | ||
16557 | return add_insert(std::true_type(), L, self, value, pos); | ||
16558 | } | ||
16559 | |||
16560 | static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& pos) { | ||
16561 | return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value), pos); | ||
16562 | } | ||
16563 | |||
16564 | static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) { | ||
16565 | return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value)); | ||
16566 | } | ||
16567 | |||
16568 | static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) { | ||
16569 | self.push_back(value.as<V>()); | ||
16570 | return {}; | ||
16571 | } | ||
16572 | |||
16573 | static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) { | ||
16574 | self.push_back(value.as<V>()); | ||
16575 | return {}; | ||
16576 | } | ||
16577 | |||
16578 | static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& pos) { | ||
16579 | return add_insert(meta::has_insert<T>(), L, self, value, pos); | ||
16580 | } | ||
16581 | |||
16582 | static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) { | ||
16583 | return add_insert(meta::has_insert<T>(), L, self, value); | ||
16584 | } | ||
16585 | |||
16586 | static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& pos) { | ||
16587 | self.insert(pos, value_type(key.as<K>(), stack::get<V>(L, 3))); | ||
16588 | return {}; | ||
16589 | } | ||
16590 | |||
16591 | static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) { | ||
16592 | auto pos = deferred_traits::end(L, self); | ||
16593 | return add_associative(std::true_type(), L, self, std::move(key), pos); | ||
16594 | } | ||
16595 | |||
16596 | static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& pos) { | ||
16597 | return add_push_back(meta::has_push_back<T>(), L, self, value, pos); | ||
16598 | } | ||
16599 | |||
16600 | static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) { | ||
16601 | return add_push_back(meta::has_push_back<T>(), L, self, value); | ||
16602 | } | ||
16603 | |||
16604 | static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& pos) { | ||
16605 | return add_associative(is_associative(), L, self, std::move(value), pos); | ||
16606 | } | ||
16607 | |||
16608 | static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) { | ||
16609 | return add_associative(is_associative(), L, self, value); | ||
16610 | } | ||
16611 | |||
16612 | static error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) { | ||
16613 | return add_copyable(std::false_type(), L, self, std::move(value)); | ||
16614 | } | ||
16615 | |||
16616 | static error_result add_copyable(std::false_type, lua_State*, T&, stack_object) { | ||
16617 | return error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data()); | ||
16618 | } | ||
16619 | |||
16620 | static error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) { | ||
16621 | // TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity? | ||
16622 | return add_copyable(std::true_type(), L, self, std::move(value)); | ||
16623 | } | ||
16624 | |||
16625 | static error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { | ||
16626 | auto it = deferred_traits::begin(L, self); | ||
16627 | auto key = where.as<K>(); | ||
16628 | key += deferred_traits::index_adjustment(L, self); | ||
16629 | std::advance(it, key); | ||
16630 | self.insert(it, value.as<V>()); | ||
16631 | return {}; | ||
16632 | } | ||
16633 | |||
16634 | static error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) { | ||
16635 | auto key = where.as<K>(); | ||
16636 | auto backit = self.before_begin(); | ||
16637 | { | ||
16638 | key += deferred_traits::index_adjustment(L, self); | ||
16639 | auto e = deferred_traits::end(L, self); | ||
16640 | for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) { | ||
16641 | if (backit == e) { | ||
16642 | return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); | ||
16643 | } | ||
16644 | } | ||
16645 | } | ||
16646 | self.insert_after(backit, value.as<V>()); | ||
16647 | return {}; | ||
16648 | } | ||
16649 | |||
16650 | static error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) { | ||
16651 | return error_result("cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data()); | ||
16652 | } | ||
16653 | |||
16654 | static error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { | ||
16655 | return insert_lookup(meta::any<is_associative, is_lookup>(), L, self, std::move(key), std::move(value)); | ||
16656 | } | ||
16657 | |||
16658 | static error_result insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) { | ||
16659 | return insert_after_has(meta::has_insert_after<T>(), L, self, where, value); | ||
16660 | } | ||
16661 | |||
16662 | static error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) { | ||
16663 | return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value)); | ||
16664 | } | ||
16665 | |||
16666 | static error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) { | ||
16667 | return error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data()); | ||
16668 | } | ||
16669 | |||
16670 | static error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) { | ||
16671 | auto it = deferred_traits::begin(L, self); | ||
16672 | key += deferred_traits::index_adjustment(L, self); | ||
16673 | std::advance(it, key); | ||
16674 | self.erase(it); | ||
16675 | |||
16676 | return {}; | ||
16677 | } | ||
16678 | |||
16679 | static error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) { | ||
16680 | auto fx = [&](const value_type& r) -> bool { | ||
16681 | return key == r; | ||
16682 | }; | ||
16683 | auto e = deferred_traits::end(L, self); | ||
16684 | auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx)); | ||
16685 | if (it == e) { | ||
16686 | return {}; | ||
16687 | } | ||
16688 | self.erase(it); | ||
16689 | |||
16690 | return {}; | ||
16691 | } | ||
16692 | |||
16693 | static error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) { | ||
16694 | self.erase(key); | ||
16695 | return {}; | ||
16696 | } | ||
16697 | |||
16698 | static error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) { | ||
16699 | return erase_integral(std::is_integral<K>(), L, self, key); | ||
16700 | } | ||
16701 | |||
16702 | static error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) { | ||
16703 | auto backit = self.before_begin(); | ||
16704 | { | ||
16705 | key += deferred_traits::index_adjustment(L, self); | ||
16706 | auto e = deferred_traits::end(L, self); | ||
16707 | for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) { | ||
16708 | if (backit == e) { | ||
16709 | return error_result("sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str()); | ||
16710 | } | ||
16711 | } | ||
16712 | } | ||
16713 | self.erase_after(backit); | ||
16714 | return {}; | ||
16715 | } | ||
16716 | |||
16717 | static error_result erase_after_has(std::false_type, lua_State*, T&, const K&) { | ||
16718 | return error_result("sol: cannot call erase on '%s'", detail::demangle<T>().c_str()); | ||
16719 | } | ||
16720 | |||
16721 | static error_result erase_has(std::true_type, lua_State* L, T& self, K& key) { | ||
16722 | return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key); | ||
16723 | } | ||
16724 | |||
16725 | static error_result erase_has(std::false_type, lua_State* L, T& self, K& key) { | ||
16726 | return erase_after_has(has_erase_after<T>(), L, self, key); | ||
16727 | } | ||
16728 | |||
16729 | static auto size_has(std::false_type, lua_State* L, T& self) { | ||
16730 | return std::distance(deferred_traits::begin(L, self), deferred_traits::end(L, self)); | ||
16731 | } | ||
16732 | |||
16733 | static auto size_has(std::true_type, lua_State*, T& self) { | ||
16734 | return self.size(); | ||
16735 | } | ||
16736 | |||
16737 | static void clear_has(std::true_type, lua_State*, T& self) { | ||
16738 | self.clear(); | ||
16739 | } | ||
16740 | |||
16741 | static void clear_has(std::false_type, lua_State* L, T&) { | ||
16742 | luaL_error(L, "sol: cannot call clear on '%s'", detail::demangle<T>().c_str()); | ||
16743 | } | ||
16744 | |||
16745 | static bool empty_has(std::true_type, lua_State*, T& self) { | ||
16746 | return self.empty(); | ||
16747 | } | ||
16748 | |||
16749 | static bool empty_has(std::false_type, lua_State* L, T& self) { | ||
16750 | return deferred_traits::begin(L, self) == deferred_traits::end(L, self); | ||
16751 | } | ||
16752 | |||
16753 | static error_result get_start(lua_State* L, T& self, K& key) { | ||
16754 | return get_it(is_linear_integral(), L, self, key); | ||
16755 | } | ||
16756 | |||
16757 | static error_result set_start(lua_State* L, T& self, stack_object key, stack_object value) { | ||
16758 | return set_it(is_linear_integral(), L, self, std::move(key), std::move(value)); | ||
16759 | } | ||
16760 | |||
16761 | static std::size_t size_start(lua_State* L, T& self) { | ||
16762 | return size_has(meta::has_size<T>(), L, self); | ||
16763 | } | ||
16764 | |||
16765 | static void clear_start(lua_State* L, T& self) { | ||
16766 | clear_has(has_clear<T>(), L, self); | ||
16767 | } | ||
16768 | |||
16769 | static bool empty_start(lua_State* L, T& self) { | ||
16770 | return empty_has(has_empty<T>(), L, self); | ||
16771 | } | ||
16772 | |||
16773 | static error_result erase_start(lua_State* L, T& self, K& key) { | ||
16774 | return erase_has(has_erase<T>(), L, self, key); | ||
16775 | } | ||
16776 | |||
16777 | template <bool ip> | ||
16778 | static int next_associative(std::true_type, lua_State* L) { | ||
16779 | iter& i = stack::get<user<iter>>(L, 1); | ||
16780 | auto& source = i.source; | ||
16781 | auto& it = i.it; | ||
16782 | if (it == deferred_traits::end(L, source)) { | ||
16783 | return 0; | ||
16784 | } | ||
16785 | int p; | ||
16786 | if (ip) { | ||
16787 | ++i.i; | ||
16788 | p = stack::push_reference(L, i.i); | ||
16789 | } | ||
16790 | else { | ||
16791 | p = stack::push_reference(L, it->first); | ||
16792 | } | ||
16793 | p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(it->second)); | ||
16794 | std::advance(it, 1); | ||
16795 | return p; | ||
16796 | } | ||
16797 | |||
16798 | template <bool> | ||
16799 | static int next_associative(std::false_type, lua_State* L) { | ||
16800 | iter& i = stack::get<user<iter>>(L, 1); | ||
16801 | auto& source = i.source; | ||
16802 | auto& it = i.it; | ||
16803 | next_K k = stack::get<next_K>(L, 2); | ||
16804 | if (it == deferred_traits::end(L, source)) { | ||
16805 | return 0; | ||
16806 | } | ||
16807 | int p; | ||
16808 | p = stack::push_reference(L, k + 1); | ||
16809 | p += stack::stack_detail::push_reference<push_type>(L, detail::deref_non_pointer(*it)); | ||
16810 | std::advance(it, 1); | ||
16811 | return p; | ||
16812 | } | ||
16813 | |||
16814 | template <bool ip> | ||
16815 | static int next_iter(lua_State* L) { | ||
16816 | typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; | ||
16817 | return next_associative<ip>(is_assoc(), L); | ||
16818 | } | ||
16819 | |||
16820 | template <bool ip> | ||
16821 | static int pairs_associative(std::true_type, lua_State* L) { | ||
16822 | auto& src = get_src(L); | ||
16823 | stack::push(L, next_iter<ip>); | ||
16824 | stack::push<user<iter>>(L, src, deferred_traits::begin(L, src)); | ||
16825 | stack::push(L, lua_nil); | ||
16826 | return 3; | ||
16827 | } | ||
16828 | |||
16829 | template <bool ip> | ||
16830 | static int pairs_associative(std::false_type, lua_State* L) { | ||
16831 | auto& src = get_src(L); | ||
16832 | stack::push(L, next_iter<ip>); | ||
16833 | stack::push<user<iter>>(L, src, deferred_traits::begin(L, src)); | ||
16834 | stack::push(L, 0); | ||
16835 | return 3; | ||
16836 | } | ||
16837 | |||
16838 | public: | ||
16839 | static int at(lua_State* L) { | ||
16840 | auto& self = get_src(L); | ||
16841 | error_result er; | ||
16842 | { | ||
16843 | std::ptrdiff_t pos = stack::get<std::ptrdiff_t>(L); | ||
16844 | er = at_start(L, self, pos); | ||
16845 | } | ||
16846 | return handle_errors(L, er); | ||
16847 | } | ||
16848 | |||
16849 | static int get(lua_State* L) { | ||
16850 | auto& self = get_src(L); | ||
16851 | error_result er; | ||
16852 | { | ||
16853 | decltype(auto) key = stack::get<K>(L); | ||
16854 | er = get_start(L, self, key); | ||
16855 | } | ||
16856 | return handle_errors(L, er); | ||
16857 | } | ||
16858 | |||
16859 | static int index_get(lua_State* L) { | ||
16860 | return get(L); | ||
16861 | } | ||
16862 | |||
16863 | static int set(lua_State* L) { | ||
16864 | stack_object value = stack_object(L, raw_index(3)); | ||
16865 | if (type_of(L, 3) == type::lua_nil) { | ||
16866 | return erase(L); | ||
16867 | } | ||
16868 | auto& self = get_src(L); | ||
16869 | error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value)); | ||
16870 | return handle_errors(L, er); | ||
16871 | } | ||
16872 | |||
16873 | static int index_set(lua_State* L) { | ||
16874 | return set(L); | ||
16875 | } | ||
16876 | |||
16877 | static int add(lua_State* L) { | ||
16878 | auto& self = get_src(L); | ||
16879 | error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2))); | ||
16880 | return handle_errors(L, er); | ||
16881 | } | ||
16882 | |||
16883 | static int insert(lua_State* L) { | ||
16884 | auto& self = get_src(L); | ||
16885 | error_result er = insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3))); | ||
16886 | return handle_errors(L, er); | ||
16887 | } | ||
16888 | |||
16889 | static int find(lua_State* L) { | ||
16890 | auto& self = get_src(L); | ||
16891 | error_result er = find_has(has_find<T>(), L, self); | ||
16892 | return handle_errors(L, er); | ||
16893 | } | ||
16894 | |||
16895 | static iterator begin(lua_State*, T& self) { | ||
16896 | using std::begin; | ||
16897 | return begin(self); | ||
16898 | } | ||
16899 | |||
16900 | static iterator end(lua_State*, T& self) { | ||
16901 | using std::end; | ||
16902 | return end(self); | ||
16903 | } | ||
16904 | |||
16905 | static int size(lua_State* L) { | ||
16906 | auto& self = get_src(L); | ||
16907 | std::size_t r = size_start(L, self); | ||
16908 | return stack::push(L, r); | ||
16909 | } | ||
16910 | |||
16911 | static int clear(lua_State* L) { | ||
16912 | auto& self = get_src(L); | ||
16913 | clear_start(L, self); | ||
16914 | return 0; | ||
16915 | } | ||
16916 | |||
16917 | static int erase(lua_State* L) { | ||
16918 | auto& self = get_src(L); | ||
16919 | error_result er; | ||
16920 | { | ||
16921 | decltype(auto) key = stack::get<K>(L, 2); | ||
16922 | er = erase_start(L, self, key); | ||
16923 | } | ||
16924 | return handle_errors(L, er); | ||
16925 | } | ||
16926 | |||
16927 | static int empty(lua_State* L) { | ||
16928 | auto& self = get_src(L); | ||
16929 | return stack::push(L, empty_start(L, self)); | ||
16930 | } | ||
16931 | |||
16932 | static std::ptrdiff_t index_adjustment(lua_State*, T&) { | ||
16933 | return static_cast<std::ptrdiff_t>(-1); | ||
16934 | } | ||
16935 | |||
16936 | static int pairs(lua_State* L) { | ||
16937 | typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; | ||
16938 | return pairs_associative<false>(is_assoc(), L); | ||
16939 | } | ||
16940 | |||
16941 | static int ipairs(lua_State* L) { | ||
16942 | typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc; | ||
16943 | return pairs_associative<true>(is_assoc(), L); | ||
16944 | } | ||
16945 | |||
16946 | static int next(lua_State* L) { | ||
16947 | return stack::push(L, next_iter<false>); | ||
16948 | } | ||
16949 | }; | ||
16950 | |||
16951 | template <typename X> | ||
16952 | struct container_traits_default<X, std::enable_if_t<std::is_array<std::remove_pointer_t<meta::unwrap_unqualified_t<X>>>::value>> { | ||
16953 | private: | ||
16954 | typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T; | ||
16955 | typedef container_traits<X> deferred_traits; | ||
16956 | |||
16957 | public: | ||
16958 | typedef std::remove_extent_t<T> value_type; | ||
16959 | typedef value_type* iterator; | ||
16960 | |||
16961 | private: | ||
16962 | struct iter { | ||
16963 | T& source; | ||
16964 | iterator it; | ||
16965 | |||
16966 | iter(T& source, iterator it) | ||
16967 | : source(source), it(std::move(it)) { | ||
16968 | } | ||
16969 | }; | ||
16970 | |||
16971 | static auto& get_src(lua_State* L) { | ||
16972 | auto p = stack::check_get<T*>(L, 1); | ||
16973 | #if defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
16974 | if (!p) { | ||
16975 | luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str()); | ||
16976 | } | ||
16977 | if (p.value() == nullptr) { | ||
16978 | luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str()); | ||
16979 | } | ||
16980 | #endif // Safe getting with error | ||
16981 | return *p.value(); | ||
16982 | } | ||
16983 | |||
16984 | static int find(std::true_type, lua_State* L) { | ||
16985 | T& self = get_src(L); | ||
16986 | decltype(auto) value = stack::get<value_type>(L, 2); | ||
16987 | std::size_t N = std::extent<T>::value; | ||
16988 | for (std::size_t idx = 0; idx < N; ++idx) { | ||
16989 | const auto& v = self[idx]; | ||
16990 | if (v == value) { | ||
16991 | return stack::push(L, idx + 1); | ||
16992 | } | ||
16993 | } | ||
16994 | return stack::push(L, lua_nil); | ||
16995 | } | ||
16996 | |||
16997 | static int find(std::false_type, lua_State* L) { | ||
16998 | return luaL_error(L, "sol: cannot call 'find' on '%s': no supported comparison operator for the value type", detail::demangle<T>().c_str()); | ||
16999 | } | ||
17000 | |||
17001 | static int next_iter(lua_State* L) { | ||
17002 | iter& i = stack::get<user<iter>>(L, 1); | ||
17003 | auto& source = i.source; | ||
17004 | auto& it = i.it; | ||
17005 | std::size_t k = stack::get<std::size_t>(L, 2); | ||
17006 | if (it == deferred_traits::end(L, source)) { | ||
17007 | return 0; | ||
17008 | } | ||
17009 | int p; | ||
17010 | p = stack::push_reference(L, k + 1); | ||
17011 | p += stack::push_reference(L, detail::deref_non_pointer(*it)); | ||
17012 | std::advance(it, 1); | ||
17013 | return p; | ||
17014 | } | ||
17015 | |||
17016 | public: | ||
17017 | static int clear(lua_State* L) { | ||
17018 | return luaL_error(L, "sol: cannot call 'clear' on type '%s': cannot remove all items from a fixed array", detail::demangle<T>().c_str()); | ||
17019 | } | ||
17020 | |||
17021 | static int erase(lua_State* L) { | ||
17022 | return luaL_error(L, "sol: cannot call 'erase' on type '%s': cannot remove an item from fixed arrays", detail::demangle<T>().c_str()); | ||
17023 | } | ||
17024 | |||
17025 | static int add(lua_State* L) { | ||
17026 | return luaL_error(L, "sol: cannot call 'add' on type '%s': cannot add to fixed arrays", detail::demangle<T>().c_str()); | ||
17027 | } | ||
17028 | |||
17029 | static int insert(lua_State* L) { | ||
17030 | return luaL_error(L, "sol: cannot call 'insert' on type '%s': cannot insert new entries into fixed arrays", detail::demangle<T>().c_str()); | ||
17031 | } | ||
17032 | |||
17033 | static int at(lua_State* L) { | ||
17034 | return get(L); | ||
17035 | } | ||
17036 | |||
17037 | static int get(lua_State* L) { | ||
17038 | T& self = get_src(L); | ||
17039 | std::ptrdiff_t idx = stack::get<std::ptrdiff_t>(L, 2); | ||
17040 | idx += deferred_traits::index_adjustment(L, self); | ||
17041 | if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value) || idx < 0) { | ||
17042 | return stack::push(L, lua_nil); | ||
17043 | } | ||
17044 | return stack::push_reference(L, detail::deref_non_pointer(self[idx])); | ||
17045 | } | ||
17046 | |||
17047 | static int index_get(lua_State* L) { | ||
17048 | return get(L); | ||
17049 | } | ||
17050 | |||
17051 | static int set(lua_State* L) { | ||
17052 | T& self = get_src(L); | ||
17053 | std::ptrdiff_t idx = stack::get<std::ptrdiff_t>(L, 2); | ||
17054 | idx += deferred_traits::index_adjustment(L, self); | ||
17055 | if (idx >= static_cast<std::ptrdiff_t>(std::extent<T>::value)) { | ||
17056 | return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str()); | ||
17057 | } | ||
17058 | if (idx < 0) { | ||
17059 | return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str()); | ||
17060 | } | ||
17061 | self[idx] = stack::get<value_type>(L, 3); | ||
17062 | return 0; | ||
17063 | } | ||
17064 | |||
17065 | static int index_set(lua_State* L) { | ||
17066 | return set(L); | ||
17067 | } | ||
17068 | |||
17069 | static int find(lua_State* L) { | ||
17070 | return find(meta::supports_op_equal<value_type, value_type>(), L); | ||
17071 | } | ||
17072 | |||
17073 | static int size(lua_State* L) { | ||
17074 | return stack::push(L, std::extent<T>::value); | ||
17075 | } | ||
17076 | |||
17077 | static int empty(lua_State* L) { | ||
17078 | return stack::push(L, std::extent<T>::value > 0); | ||
17079 | } | ||
17080 | |||
17081 | static int pairs(lua_State* L) { | ||
17082 | auto& src = get_src(L); | ||
17083 | stack::push(L, next_iter); | ||
17084 | stack::push<user<iter>>(L, src, deferred_traits::begin(L, src)); | ||
17085 | stack::push(L, 0); | ||
17086 | return 3; | ||
17087 | } | ||
17088 | |||
17089 | static int ipairs(lua_State* L) { | ||
17090 | return pairs(L); | ||
17091 | } | ||
17092 | |||
17093 | static int next(lua_State* L) { | ||
17094 | return stack::push(L, next_iter); | ||
17095 | } | ||
17096 | |||
17097 | static std::ptrdiff_t index_adjustment(lua_State*, T&) { | ||
17098 | #if defined(SOL_CONTAINERS_START_INDEX) | ||
17099 | return (SOL_CONTAINERS_START) == 0 ? 0 : -(SOL_CONTAINERS_START); | ||
17100 | #else | ||
17101 | return -1; | ||
17102 | #endif | ||
17103 | } | ||
17104 | |||
17105 | static iterator begin(lua_State*, T& self) { | ||
17106 | return std::addressof(self[0]); | ||
17107 | } | ||
17108 | |||
17109 | static iterator end(lua_State*, T& self) { | ||
17110 | return std::addressof(self[0]) + std::extent<T>::value; | ||
17111 | } | ||
17112 | }; | ||
17113 | |||
17114 | template <typename X> | ||
17115 | struct container_traits_default<container_traits<X>> : container_traits_default<X> {}; | ||
17116 | } // namespace container_detail | ||
17117 | |||
17118 | template <typename T> | ||
17119 | struct container_traits : container_detail::container_traits_default<T> {}; | ||
17120 | |||
17121 | } // namespace sol | ||
17122 | |||
17123 | // end of sol/container_traits.hpp | ||
17124 | |||
17125 | namespace sol { | ||
17126 | |||
17127 | template <typename X> | ||
17128 | struct container_usertype_metatable { | ||
17129 | typedef std::remove_pointer_t<meta::unqualified_t<X>> T; | ||
17130 | typedef container_traits<T> traits; | ||
17131 | typedef container_detail::container_traits_default<T> default_traits; | ||
17132 | |||
17133 | static int real_index_get_traits(std::true_type, lua_State* L) { | ||
17134 | return traits::index_get(L); | ||
17135 | } | ||
17136 | |||
17137 | static int real_index_get_traits(std::false_type, lua_State* L) { | ||
17138 | return default_traits::index_get(L); | ||
17139 | } | ||
17140 | |||
17141 | static int real_index_call(lua_State* L) { | ||
17142 | typedef usertype_detail::map_t<std::string, lua_CFunction> call_map; | ||
17143 | static const call_map calls{ | ||
17144 | { "at", &at_call }, | ||
17145 | { "get", &real_get_call }, | ||
17146 | { "set", &real_set_call }, | ||
17147 | { "size", &real_length_call }, | ||
17148 | { "add", &real_add_call }, | ||
17149 | { "empty", &real_empty_call }, | ||
17150 | { "insert", &real_insert_call }, | ||
17151 | { "clear", &real_clear_call }, | ||
17152 | { "find", &real_find_call }, | ||
17153 | { "erase", &real_erase_call }, | ||
17154 | { "pairs", &pairs_call }, | ||
17155 | { "next", &next_call }, | ||
17156 | }; | ||
17157 | auto maybenameview = stack::check_get<string_view>(L, 2); | ||
17158 | if (maybenameview) { | ||
17159 | const string_view& nameview = *maybenameview; | ||
17160 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
17161 | auto it = calls.find(nameview, string_view_hash(), std::equal_to<string_view>()); | ||
17162 | #else | ||
17163 | std::string name(nameview.data(), nameview.size()); | ||
17164 | auto it = calls.find(name); | ||
17165 | #endif | ||
17166 | if (it != calls.cend()) { | ||
17167 | return stack::push(L, it->second); | ||
17168 | } | ||
17169 | } | ||
17170 | return real_index_get_traits(container_detail::has_traits_index_get<traits>(), L); | ||
17171 | } | ||
17172 | |||
17173 | static int real_at_traits(std::true_type, lua_State* L) { | ||
17174 | return traits::at(L); | ||
17175 | } | ||
17176 | |||
17177 | static int real_at_traits(std::false_type, lua_State* L) { | ||
17178 | return default_traits::at(L); | ||
17179 | } | ||
17180 | |||
17181 | static int real_at_call(lua_State* L) { | ||
17182 | return real_at_traits(container_detail::has_traits_at<traits>(), L); | ||
17183 | } | ||
17184 | |||
17185 | static int real_get_traits(std::true_type, lua_State* L) { | ||
17186 | return traits::get(L); | ||
17187 | } | ||
17188 | |||
17189 | static int real_get_traits(std::false_type, lua_State* L) { | ||
17190 | return default_traits::get(L); | ||
17191 | } | ||
17192 | |||
17193 | static int real_get_call(lua_State* L) { | ||
17194 | return real_get_traits(container_detail::has_traits_get<traits>(), L); | ||
17195 | } | ||
17196 | |||
17197 | static int real_set_traits(std::true_type, lua_State* L) { | ||
17198 | return traits::set(L); | ||
17199 | } | ||
17200 | |||
17201 | static int real_set_traits(std::false_type, lua_State* L) { | ||
17202 | return default_traits::set(L); | ||
17203 | } | ||
17204 | |||
17205 | static int real_set_call(lua_State* L) { | ||
17206 | return real_set_traits(container_detail::has_traits_set<traits>(), L); | ||
17207 | } | ||
17208 | |||
17209 | static int real_index_set_traits(std::true_type, lua_State* L) { | ||
17210 | return traits::index_set(L); | ||
17211 | } | ||
17212 | |||
17213 | static int real_index_set_traits(std::false_type, lua_State* L) { | ||
17214 | return default_traits::index_set(L); | ||
17215 | } | ||
17216 | |||
17217 | static int real_new_index_call(lua_State* L) { | ||
17218 | return real_index_set_traits(container_detail::has_traits_index_set<traits>(), L); | ||
17219 | } | ||
17220 | |||
17221 | static int real_pairs_traits(std::true_type, lua_State* L) { | ||
17222 | return traits::pairs(L); | ||
17223 | } | ||
17224 | |||
17225 | static int real_pairs_traits(std::false_type, lua_State* L) { | ||
17226 | return default_traits::pairs(L); | ||
17227 | } | ||
17228 | |||
17229 | static int real_pairs_call(lua_State* L) { | ||
17230 | return real_pairs_traits(container_detail::has_traits_pairs<traits>(), L); | ||
17231 | } | ||
17232 | |||
17233 | static int real_ipairs_traits(std::true_type, lua_State* L) { | ||
17234 | return traits::ipairs(L); | ||
17235 | } | ||
17236 | |||
17237 | static int real_ipairs_traits(std::false_type, lua_State* L) { | ||
17238 | return default_traits::ipairs(L); | ||
17239 | } | ||
17240 | |||
17241 | static int real_ipairs_call(lua_State* L) { | ||
17242 | return real_ipairs_traits(container_detail::has_traits_ipairs<traits>(), L); | ||
17243 | } | ||
17244 | |||
17245 | static int real_next_traits(std::true_type, lua_State* L) { | ||
17246 | return traits::next(L); | ||
17247 | } | ||
17248 | |||
17249 | static int real_next_traits(std::false_type, lua_State* L) { | ||
17250 | return default_traits::next(L); | ||
17251 | } | ||
17252 | |||
17253 | static int real_next_call(lua_State* L) { | ||
17254 | return real_next_traits(container_detail::has_traits_next<traits>(), L); | ||
17255 | } | ||
17256 | |||
17257 | static int real_size_traits(std::true_type, lua_State* L) { | ||
17258 | return traits::size(L); | ||
17259 | } | ||
17260 | |||
17261 | static int real_size_traits(std::false_type, lua_State* L) { | ||
17262 | return default_traits::size(L); | ||
17263 | } | ||
17264 | |||
17265 | static int real_length_call(lua_State* L) { | ||
17266 | return real_size_traits(container_detail::has_traits_size<traits>(), L); | ||
17267 | } | ||
17268 | |||
17269 | static int real_add_traits(std::true_type, lua_State* L) { | ||
17270 | return traits::add(L); | ||
17271 | } | ||
17272 | |||
17273 | static int real_add_traits(std::false_type, lua_State* L) { | ||
17274 | return default_traits::add(L); | ||
17275 | } | ||
17276 | |||
17277 | static int real_add_call(lua_State* L) { | ||
17278 | return real_add_traits(container_detail::has_traits_add<traits>(), L); | ||
17279 | } | ||
17280 | |||
17281 | static int real_insert_traits(std::true_type, lua_State* L) { | ||
17282 | return traits::insert(L); | ||
17283 | } | ||
17284 | |||
17285 | static int real_insert_traits(std::false_type, lua_State* L) { | ||
17286 | return default_traits::insert(L); | ||
17287 | } | ||
17288 | |||
17289 | static int real_insert_call(lua_State* L) { | ||
17290 | return real_insert_traits(container_detail::has_traits_insert<traits>(), L); | ||
17291 | } | ||
17292 | |||
17293 | static int real_clear_traits(std::true_type, lua_State* L) { | ||
17294 | return traits::clear(L); | ||
17295 | } | ||
17296 | |||
17297 | static int real_clear_traits(std::false_type, lua_State* L) { | ||
17298 | return default_traits::clear(L); | ||
17299 | } | ||
17300 | |||
17301 | static int real_clear_call(lua_State* L) { | ||
17302 | return real_clear_traits(container_detail::has_traits_clear<traits>(), L); | ||
17303 | } | ||
17304 | |||
17305 | static int real_empty_traits(std::true_type, lua_State* L) { | ||
17306 | return traits::empty(L); | ||
17307 | } | ||
17308 | |||
17309 | static int real_empty_traits(std::false_type, lua_State* L) { | ||
17310 | return default_traits::empty(L); | ||
17311 | } | ||
17312 | |||
17313 | static int real_empty_call(lua_State* L) { | ||
17314 | return real_empty_traits(container_detail::has_traits_empty<traits>(), L); | ||
17315 | } | ||
17316 | |||
17317 | static int real_erase_traits(std::true_type, lua_State* L) { | ||
17318 | return traits::erase(L); | ||
17319 | } | ||
17320 | |||
17321 | static int real_erase_traits(std::false_type, lua_State* L) { | ||
17322 | return default_traits::erase(L); | ||
17323 | } | ||
17324 | |||
17325 | static int real_erase_call(lua_State* L) { | ||
17326 | return real_erase_traits(container_detail::has_traits_erase<traits>(), L); | ||
17327 | } | ||
17328 | |||
17329 | static int real_find_traits(std::true_type, lua_State* L) { | ||
17330 | return traits::find(L); | ||
17331 | } | ||
17332 | |||
17333 | static int real_find_traits(std::false_type, lua_State* L) { | ||
17334 | return default_traits::find(L); | ||
17335 | } | ||
17336 | |||
17337 | static int real_find_call(lua_State* L) { | ||
17338 | return real_find_traits(container_detail::has_traits_find<traits>(), L); | ||
17339 | } | ||
17340 | |||
17341 | static int add_call(lua_State* L) { | ||
17342 | return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L); | ||
17343 | } | ||
17344 | |||
17345 | static int erase_call(lua_State* L) { | ||
17346 | return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L); | ||
17347 | } | ||
17348 | |||
17349 | static int insert_call(lua_State* L) { | ||
17350 | return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L); | ||
17351 | } | ||
17352 | |||
17353 | static int clear_call(lua_State* L) { | ||
17354 | return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L); | ||
17355 | } | ||
17356 | |||
17357 | static int empty_call(lua_State* L) { | ||
17358 | return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L); | ||
17359 | } | ||
17360 | |||
17361 | static int find_call(lua_State* L) { | ||
17362 | return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L); | ||
17363 | } | ||
17364 | |||
17365 | static int length_call(lua_State* L) { | ||
17366 | return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L); | ||
17367 | } | ||
17368 | |||
17369 | static int pairs_call(lua_State* L) { | ||
17370 | return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L); | ||
17371 | } | ||
17372 | |||
17373 | static int ipairs_call(lua_State* L) { | ||
17374 | return detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L); | ||
17375 | } | ||
17376 | |||
17377 | static int next_call(lua_State* L) { | ||
17378 | return detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L); | ||
17379 | } | ||
17380 | |||
17381 | static int at_call(lua_State* L) { | ||
17382 | return detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L); | ||
17383 | } | ||
17384 | |||
17385 | static int get_call(lua_State* L) { | ||
17386 | return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L); | ||
17387 | } | ||
17388 | |||
17389 | static int set_call(lua_State* L) { | ||
17390 | return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L); | ||
17391 | } | ||
17392 | |||
17393 | static int index_call(lua_State* L) { | ||
17394 | return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L); | ||
17395 | } | ||
17396 | |||
17397 | static int new_index_call(lua_State* L) { | ||
17398 | return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L); | ||
17399 | } | ||
17400 | }; | ||
17401 | |||
17402 | namespace stack { | ||
17403 | namespace stack_detail { | ||
17404 | template <typename T, bool is_shim = false> | ||
17405 | struct metatable_setup { | ||
17406 | lua_State* L; | ||
17407 | |||
17408 | metatable_setup(lua_State* L) | ||
17409 | : L(L) { | ||
17410 | } | ||
17411 | |||
17412 | void operator()() { | ||
17413 | typedef container_usertype_metatable<std::conditional_t<is_shim, | ||
17414 | as_container_t<std::remove_pointer_t<T>>, | ||
17415 | std::remove_pointer_t<T>>> | ||
17416 | meta_cumt; | ||
17417 | static const char* metakey = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0]; | ||
17418 | static const std::array<luaL_Reg, 19> reg = { { | ||
17419 | { "__pairs", &meta_cumt::pairs_call }, | ||
17420 | { "__ipairs", &meta_cumt::ipairs_call }, | ||
17421 | { "__len", &meta_cumt::length_call }, | ||
17422 | { "__index", &meta_cumt::index_call }, | ||
17423 | { "__newindex", &meta_cumt::new_index_call }, | ||
17424 | { "pairs", &meta_cumt::pairs_call }, | ||
17425 | { "next", &meta_cumt::next_call }, | ||
17426 | { "at", &meta_cumt::at_call }, | ||
17427 | { "get", &meta_cumt::get_call }, | ||
17428 | { "set", &meta_cumt::set_call }, | ||
17429 | { "size", &meta_cumt::length_call }, | ||
17430 | { "empty", &meta_cumt::empty_call }, | ||
17431 | { "clear", &meta_cumt::clear_call }, | ||
17432 | { "insert", &meta_cumt::insert_call }, | ||
17433 | { "add", &meta_cumt::add_call }, | ||
17434 | { "find", &meta_cumt::find_call }, | ||
17435 | { "erase", &meta_cumt::erase_call }, | ||
17436 | std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> }, | ||
17437 | { nullptr, nullptr } | ||
17438 | } }; | ||
17439 | |||
17440 | if (luaL_newmetatable(L, metakey) == 1) { | ||
17441 | luaL_setfuncs(L, reg.data(), 0); | ||
17442 | } | ||
17443 | lua_setmetatable(L, -2); | ||
17444 | } | ||
17445 | }; | ||
17446 | } // namespace stack_detail | ||
17447 | |||
17448 | template <typename T> | ||
17449 | struct pusher<as_container_t<T>> { | ||
17450 | typedef meta::unqualified_t<T> C; | ||
17451 | |||
17452 | static int push_lvalue(std::true_type, lua_State* L, const C& cont) { | ||
17453 | stack_detail::metatable_setup<C*, true> fx(L); | ||
17454 | return pusher<detail::as_pointer_tag<const C>>{}.push_fx(L, fx, detail::ptr(cont)); | ||
17455 | } | ||
17456 | |||
17457 | static int push_lvalue(std::false_type, lua_State* L, const C& cont) { | ||
17458 | stack_detail::metatable_setup<C, true> fx(L); | ||
17459 | return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, cont); | ||
17460 | } | ||
17461 | |||
17462 | static int push_rvalue(std::true_type, lua_State* L, C&& cont) { | ||
17463 | stack_detail::metatable_setup<C, true> fx(L); | ||
17464 | return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, std::move(cont)); | ||
17465 | } | ||
17466 | |||
17467 | static int push_rvalue(std::false_type, lua_State* L, const C& cont) { | ||
17468 | return push_lvalue(std::is_lvalue_reference<T>(), L, cont); | ||
17469 | } | ||
17470 | |||
17471 | static int push(lua_State* L, const as_container_t<T>& as_cont) { | ||
17472 | return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.source); | ||
17473 | } | ||
17474 | |||
17475 | static int push(lua_State* L, as_container_t<T>&& as_cont) { | ||
17476 | return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.source)); | ||
17477 | } | ||
17478 | }; | ||
17479 | |||
17480 | template <typename T> | ||
17481 | struct pusher<as_container_t<T*>> { | ||
17482 | typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; | ||
17483 | |||
17484 | static int push(lua_State* L, T* cont) { | ||
17485 | stack_detail::metatable_setup<C> fx(L); | ||
17486 | return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont); | ||
17487 | } | ||
17488 | }; | ||
17489 | |||
17490 | template <typename T> | ||
17491 | struct pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { | ||
17492 | typedef meta::unqualified_t<T> C; | ||
17493 | |||
17494 | static int push(lua_State* L, const T& cont) { | ||
17495 | stack_detail::metatable_setup<C> fx(L); | ||
17496 | return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, cont); | ||
17497 | } | ||
17498 | |||
17499 | static int push(lua_State* L, T&& cont) { | ||
17500 | stack_detail::metatable_setup<C> fx(L); | ||
17501 | return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, std::move(cont)); | ||
17502 | } | ||
17503 | }; | ||
17504 | |||
17505 | template <typename T> | ||
17506 | struct pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> { | ||
17507 | typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C; | ||
17508 | |||
17509 | static int push(lua_State* L, T* cont) { | ||
17510 | stack_detail::metatable_setup<C> fx(L); | ||
17511 | return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont); | ||
17512 | } | ||
17513 | }; | ||
17514 | |||
17515 | template <typename T, typename C> | ||
17516 | struct checker<as_container_t<T>, type::userdata, C> { | ||
17517 | template <typename Handler> | ||
17518 | static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
17519 | return stack::check<T>(L, index, std::forward<Handler>(handler), tracking); | ||
17520 | } | ||
17521 | }; | ||
17522 | |||
17523 | template <typename T> | ||
17524 | struct getter<as_container_t<T>> { | ||
17525 | static decltype(auto) get(lua_State* L, int index, record& tracking) { | ||
17526 | return stack::get<T>(L, index, tracking); | ||
17527 | } | ||
17528 | }; | ||
17529 | |||
17530 | template <typename T> | ||
17531 | struct getter<as_container_t<T>*> { | ||
17532 | static decltype(auto) get(lua_State* L, int index, record& tracking) { | ||
17533 | return stack::get<T*>(L, index, tracking); | ||
17534 | } | ||
17535 | }; | ||
17536 | } // namespace stack | ||
17537 | |||
17538 | } // namespace sol | ||
17539 | |||
17540 | // end of sol/container_usertype_metatable.hpp | ||
17541 | |||
17542 | // beginning of sol/usertype_core.hpp | ||
17543 | |||
17544 | #include <sstream> | ||
17545 | |||
17546 | namespace sol { | ||
17547 | namespace usertype_detail { | ||
17548 | struct no_comp { | ||
17549 | template <typename A, typename B> | ||
17550 | bool operator()(A&&, B&&) const { | ||
17551 | return false; | ||
17552 | } | ||
17553 | }; | ||
17554 | |||
17555 | template <typename T> | ||
17556 | int is_check(lua_State* L) { | ||
17557 | return stack::push(L, stack::check<T>(L, 1, &no_panic)); | ||
17558 | } | ||
17559 | |||
17560 | template <typename T> | ||
17561 | inline int member_default_to_string(std::true_type, lua_State* L) { | ||
17562 | decltype(auto) ts = stack::get<T>(L, 1).to_string(); | ||
17563 | return stack::push(L, std::forward<decltype(ts)>(ts)); | ||
17564 | } | ||
17565 | |||
17566 | template <typename T> | ||
17567 | inline int member_default_to_string(std::false_type, lua_State* L) { | ||
17568 | return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member function, or operator<<(ostream&, ...) present", detail::demangle<T>().data()); | ||
17569 | } | ||
17570 | |||
17571 | template <typename T> | ||
17572 | inline int adl_default_to_string(std::true_type, lua_State* L) { | ||
17573 | using namespace std; | ||
17574 | decltype(auto) ts = to_string(stack::get<T>(L, 1)); | ||
17575 | return stack::push(L, std::forward<decltype(ts)>(ts)); | ||
17576 | } | ||
17577 | |||
17578 | template <typename T> | ||
17579 | inline int adl_default_to_string(std::false_type, lua_State* L) { | ||
17580 | return member_default_to_string<T>(meta::supports_to_string_member<T>(), L); | ||
17581 | } | ||
17582 | |||
17583 | template <typename T> | ||
17584 | inline int oss_default_to_string(std::true_type, lua_State* L) { | ||
17585 | std::ostringstream oss; | ||
17586 | oss << stack::get<T>(L, 1); | ||
17587 | return stack::push(L, oss.str()); | ||
17588 | } | ||
17589 | |||
17590 | template <typename T> | ||
17591 | inline int oss_default_to_string(std::false_type, lua_State* L) { | ||
17592 | return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L); | ||
17593 | } | ||
17594 | |||
17595 | template <typename T> | ||
17596 | inline int default_to_string(lua_State* L) { | ||
17597 | return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L); | ||
17598 | } | ||
17599 | |||
17600 | template <typename T, typename Op> | ||
17601 | int comparsion_operator_wrap(lua_State* L) { | ||
17602 | auto maybel = stack::check_get<T>(L, 1); | ||
17603 | if (maybel) { | ||
17604 | auto mayber = stack::check_get<T>(L, 2); | ||
17605 | if (mayber) { | ||
17606 | auto& l = *maybel; | ||
17607 | auto& r = *mayber; | ||
17608 | if (std::is_same<no_comp, Op>::value) { | ||
17609 | return stack::push(L, detail::ptr(l) == detail::ptr(r)); | ||
17610 | } | ||
17611 | else { | ||
17612 | Op op; | ||
17613 | return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r))); | ||
17614 | } | ||
17615 | } | ||
17616 | } | ||
17617 | return stack::push(L, false); | ||
17618 | } | ||
17619 | |||
17620 | template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler> | ||
17621 | inline void make_reg_op(Regs& l, int& index, const char* name) { | ||
17622 | lua_CFunction f = &comparsion_operator_wrap<T, Op>; | ||
17623 | l[index] = luaL_Reg{ name, f }; | ||
17624 | ++index; | ||
17625 | } | ||
17626 | |||
17627 | template <typename T, typename Op, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler> | ||
17628 | inline void make_reg_op(Regs&, int&, const char*) { | ||
17629 | // Do nothing if there's no support | ||
17630 | } | ||
17631 | |||
17632 | template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler> | ||
17633 | inline void make_to_string_op(Regs& l, int& index) { | ||
17634 | const char* name = to_string(meta_function::to_string).c_str(); | ||
17635 | lua_CFunction f = &detail::static_trampoline<&default_to_string<T>>; | ||
17636 | l[index] = luaL_Reg{ name, f }; | ||
17637 | ++index; | ||
17638 | } | ||
17639 | |||
17640 | template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler> | ||
17641 | inline void make_to_string_op(Regs&, int&) { | ||
17642 | // Do nothing if there's no support | ||
17643 | } | ||
17644 | |||
17645 | template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler> | ||
17646 | inline void make_call_op(Regs& l, int& index) { | ||
17647 | const char* name = to_string(meta_function::call).c_str(); | ||
17648 | lua_CFunction f = &c_call<decltype(&T::operator()), &T::operator()>; | ||
17649 | l[index] = luaL_Reg{ name, f }; | ||
17650 | ++index; | ||
17651 | } | ||
17652 | |||
17653 | template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler> | ||
17654 | inline void make_call_op(Regs&, int&) { | ||
17655 | // Do nothing if there's no support | ||
17656 | } | ||
17657 | |||
17658 | template <typename T, typename Regs> | ||
17659 | inline void make_length_op_const(std::true_type, Regs& l, int& index) { | ||
17660 | const char* name = to_string(meta_function::length).c_str(); | ||
17661 | #if defined(__clang__) | ||
17662 | l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> }; | ||
17663 | #else | ||
17664 | typedef decltype(std::declval<T>().size()) R; | ||
17665 | using sz_func = R(T::*)()const; | ||
17666 | l[index] = luaL_Reg{ name, &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)> }; | ||
17667 | #endif | ||
17668 | ++index; | ||
17669 | } | ||
17670 | |||
17671 | template <typename T, typename Regs> | ||
17672 | inline void make_length_op_const(std::false_type, Regs& l, int& index) { | ||
17673 | const char* name = to_string(meta_function::length).c_str(); | ||
17674 | #if defined(__clang__) | ||
17675 | l[index] = luaL_Reg{ name, &c_call<decltype(&T::size), &T::size> }; | ||
17676 | #else | ||
17677 | typedef decltype(std::declval<T>().size()) R; | ||
17678 | using sz_func = R(T::*)(); | ||
17679 | l[index] = luaL_Reg{ name, &c_call<decltype(static_cast<sz_func>(&T::size)), static_cast<sz_func>(&T::size)> }; | ||
17680 | #endif | ||
17681 | ++index; | ||
17682 | } | ||
17683 | |||
17684 | template <typename T, typename Regs, meta::enable<meta::has_size<T>, meta::has_size<const T>> = meta::enabler> | ||
17685 | inline void make_length_op(Regs& l, int& index) { | ||
17686 | make_length_op_const<T>(meta::has_size<const T>(), l, index); | ||
17687 | } | ||
17688 | |||
17689 | template <typename T, typename Regs, meta::disable<meta::has_size<T>, meta::has_size<const T>> = meta::enabler> | ||
17690 | inline void make_length_op(Regs&, int&) { | ||
17691 | // Do nothing if there's no support | ||
17692 | } | ||
17693 | |||
17694 | template <typename T, typename Regs, meta::enable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>> | ||
17695 | void make_destructor(Regs& l, int& index) { | ||
17696 | const char* name = to_string(meta_function::garbage_collect).c_str(); | ||
17697 | l[index] = luaL_Reg{ name, is_unique_usertype<T>::value ? &detail::unique_destruct<T> : &detail::usertype_alloc_destruct<T> }; | ||
17698 | ++index; | ||
17699 | } | ||
17700 | |||
17701 | template <typename T, typename Regs, meta::disable<meta::neg<std::is_pointer<T>>, std::is_destructible<T>>> | ||
17702 | void make_destructor(Regs& l, int& index) { | ||
17703 | if (!std::is_destructible<T>::value) { | ||
17704 | // if the value is not destructible, plant an erroring __gc method | ||
17705 | // to warn the user of a problem when it comes around | ||
17706 | // this won't trigger if the user performs `new_usertype` / `new_simple_usertype` and | ||
17707 | // rigs the class up properly | ||
17708 | const char* name = to_string(meta_function::garbage_collect).c_str(); | ||
17709 | l[index] = luaL_Reg{ name, &detail::cannot_destruct<T> }; | ||
17710 | ++index; | ||
17711 | } | ||
17712 | } | ||
17713 | |||
17714 | template <typename T, typename Regs, typename Fx> | ||
17715 | void insert_default_registrations(std::false_type, Regs&, int&, Fx&&) { | ||
17716 | // no-op | ||
17717 | } | ||
17718 | |||
17719 | template <typename T, typename Regs, typename Fx> | ||
17720 | void insert_default_registrations(std::true_type, Regs& l, int& index, Fx&& fx) { | ||
17721 | if (fx(meta_function::less_than)) { | ||
17722 | const char* name = to_string(meta_function::less_than).c_str(); | ||
17723 | usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name); | ||
17724 | } | ||
17725 | if (fx(meta_function::less_than_or_equal_to)) { | ||
17726 | const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); | ||
17727 | usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name); | ||
17728 | } | ||
17729 | if (fx(meta_function::equal_to)) { | ||
17730 | const char* name = to_string(meta_function::equal_to).c_str(); | ||
17731 | usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); | ||
17732 | } | ||
17733 | if (fx(meta_function::pairs)) { | ||
17734 | const char* name = to_string(meta_function::pairs).c_str(); | ||
17735 | l[index] = luaL_Reg{ name, container_usertype_metatable<as_container_t<T>>::pairs_call }; | ||
17736 | ++index; | ||
17737 | } | ||
17738 | if (fx(meta_function::length)) { | ||
17739 | usertype_detail::make_length_op<T>(l, index); | ||
17740 | } | ||
17741 | if (fx(meta_function::to_string)) { | ||
17742 | usertype_detail::make_to_string_op<T, is_to_stringable<T>>(l, index); | ||
17743 | } | ||
17744 | if (fx(meta_function::call_function)) { | ||
17745 | usertype_detail::make_call_op<T>(l, index); | ||
17746 | } | ||
17747 | } | ||
17748 | |||
17749 | template <typename T, typename Regs, typename Fx> | ||
17750 | void insert_default_registrations(Regs& l, int& index, Fx&& fx) { | ||
17751 | insert_default_registrations<T>(is_automagical<T>(), l, index, std::forward<Fx>(fx)); | ||
17752 | } | ||
17753 | } // namespace usertype_detail | ||
17754 | |||
17755 | namespace stack { namespace stack_detail { | ||
17756 | template <typename T> | ||
17757 | struct undefined_metatable { | ||
17758 | typedef meta::all<meta::neg<std::is_pointer<T>>, std::is_destructible<T>> is_destructible; | ||
17759 | typedef std::remove_pointer_t<T> P; | ||
17760 | lua_State* L; | ||
17761 | const char* key; | ||
17762 | |||
17763 | undefined_metatable(lua_State* l, const char* k) | ||
17764 | : L(l), key(k) { | ||
17765 | } | ||
17766 | |||
17767 | void operator()() const { | ||
17768 | if (luaL_newmetatable(L, key) == 1) { | ||
17769 | luaL_Reg l[32]{}; | ||
17770 | int index = 0; | ||
17771 | auto fx = [](meta_function) { return true; }; | ||
17772 | usertype_detail::insert_default_registrations<P>(l, index, fx); | ||
17773 | usertype_detail::make_destructor<T>(l, index); | ||
17774 | luaL_setfuncs(L, l, 0); | ||
17775 | |||
17776 | // __type table | ||
17777 | lua_createtable(L, 0, 2); | ||
17778 | const std::string& name = detail::demangle<T>(); | ||
17779 | lua_pushlstring(L, name.c_str(), name.size()); | ||
17780 | lua_setfield(L, -2, "name"); | ||
17781 | lua_CFunction is_func = &usertype_detail::is_check<T>; | ||
17782 | lua_pushcclosure(L, is_func, 0); | ||
17783 | lua_setfield(L, -2, "is"); | ||
17784 | lua_setfield(L, -2, to_string(meta_function::type).c_str()); | ||
17785 | } | ||
17786 | lua_setmetatable(L, -2); | ||
17787 | } | ||
17788 | }; | ||
17789 | } | ||
17790 | } // namespace stack::stack_detail | ||
17791 | } // namespace sol | ||
17792 | |||
17793 | // end of sol/usertype_core.hpp | ||
17794 | |||
17795 | #include <cstdio> | ||
17796 | #include <bitset> | ||
17797 | |||
17798 | namespace sol { | ||
17799 | namespace usertype_detail { | ||
17800 | const int metatable_index = 2; | ||
17801 | const int metatable_core_index = 3; | ||
17802 | const int filler_index = 4; | ||
17803 | const int magic_index = 5; | ||
17804 | |||
17805 | const int simple_metatable_index = 2; | ||
17806 | const int index_function_index = 3; | ||
17807 | const int newindex_function_index = 4; | ||
17808 | |||
17809 | typedef void (*base_walk)(lua_State*, bool&, int&, string_view&); | ||
17810 | typedef int (*member_search)(lua_State*, void*, int); | ||
17811 | |||
17812 | struct call_information { | ||
17813 | member_search index; | ||
17814 | member_search new_index; | ||
17815 | int runtime_target; | ||
17816 | |||
17817 | call_information(member_search index, member_search newindex) | ||
17818 | : call_information(index, newindex, -1) { | ||
17819 | } | ||
17820 | call_information(member_search index, member_search newindex, int runtimetarget) | ||
17821 | : index(index), new_index(newindex), runtime_target(runtimetarget) { | ||
17822 | } | ||
17823 | }; | ||
17824 | |||
17825 | typedef map_t<std::string, call_information> mapping_t; | ||
17826 | |||
17827 | struct variable_wrapper { | ||
17828 | virtual int index(lua_State* L) = 0; | ||
17829 | virtual int new_index(lua_State* L) = 0; | ||
17830 | virtual ~variable_wrapper(){}; | ||
17831 | }; | ||
17832 | |||
17833 | template <typename T, typename F> | ||
17834 | struct callable_binding : variable_wrapper { | ||
17835 | F fx; | ||
17836 | |||
17837 | template <typename Arg> | ||
17838 | callable_binding(Arg&& arg) | ||
17839 | : fx(std::forward<Arg>(arg)) { | ||
17840 | } | ||
17841 | |||
17842 | virtual int index(lua_State* L) override { | ||
17843 | return call_detail::call_wrapped<T, true, true>(L, fx); | ||
17844 | } | ||
17845 | |||
17846 | virtual int new_index(lua_State* L) override { | ||
17847 | return call_detail::call_wrapped<T, false, true>(L, fx); | ||
17848 | } | ||
17849 | }; | ||
17850 | |||
17851 | typedef map_t<std::string, std::unique_ptr<variable_wrapper>> variable_map; | ||
17852 | typedef map_t<std::string, object> function_map; | ||
17853 | |||
17854 | struct simple_map { | ||
17855 | const char* metakey; | ||
17856 | variable_map variables; | ||
17857 | function_map functions; | ||
17858 | object index; | ||
17859 | object newindex; | ||
17860 | base_walk indexbaseclasspropogation; | ||
17861 | base_walk newindexbaseclasspropogation; | ||
17862 | |||
17863 | simple_map(const char* mkey, base_walk index, base_walk newindex, object i, object ni, variable_map&& vars, function_map&& funcs) | ||
17864 | : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), index(std::move(i)), newindex(std::move(ni)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) { | ||
17865 | } | ||
17866 | }; | ||
17867 | } // namespace usertype_detail | ||
17868 | |||
17869 | struct usertype_metatable_core { | ||
17870 | usertype_detail::mapping_t mapping; | ||
17871 | lua_CFunction indexfunc; | ||
17872 | lua_CFunction newindexfunc; | ||
17873 | std::vector<object> runtime; | ||
17874 | bool mustindex; | ||
17875 | |||
17876 | usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) | ||
17877 | : mapping(), indexfunc(ifx), newindexfunc(nifx), runtime(), mustindex(false) { | ||
17878 | } | ||
17879 | |||
17880 | usertype_metatable_core(const usertype_metatable_core&) = default; | ||
17881 | usertype_metatable_core(usertype_metatable_core&&) = default; | ||
17882 | usertype_metatable_core& operator=(const usertype_metatable_core&) = default; | ||
17883 | usertype_metatable_core& operator=(usertype_metatable_core&&) = default; | ||
17884 | }; | ||
17885 | |||
17886 | namespace usertype_detail { | ||
17887 | const lua_Integer toplevel_magic = static_cast<lua_Integer>(0xCCC2CCC1); | ||
17888 | |||
17889 | inline int is_indexer(string_view s) { | ||
17890 | if (s == to_string(meta_function::index)) { | ||
17891 | return 1; | ||
17892 | } | ||
17893 | else if (s == to_string(meta_function::new_index)) { | ||
17894 | return 2; | ||
17895 | } | ||
17896 | return 0; | ||
17897 | } | ||
17898 | |||
17899 | inline int is_indexer(meta_function mf) { | ||
17900 | if (mf == meta_function::index) { | ||
17901 | return 1; | ||
17902 | } | ||
17903 | else if (mf == meta_function::new_index) { | ||
17904 | return 2; | ||
17905 | } | ||
17906 | return 0; | ||
17907 | } | ||
17908 | |||
17909 | inline int is_indexer(call_construction) { | ||
17910 | return 0; | ||
17911 | } | ||
17912 | |||
17913 | inline int is_indexer(base_classes_tag) { | ||
17914 | return 0; | ||
17915 | } | ||
17916 | |||
17917 | inline auto make_string_view(string_view s) { | ||
17918 | return s; | ||
17919 | } | ||
17920 | |||
17921 | inline auto make_string_view(call_construction) { | ||
17922 | return string_view(to_string(meta_function::call_function)); | ||
17923 | } | ||
17924 | |||
17925 | inline auto make_string_view(meta_function mf) { | ||
17926 | return string_view(to_string(mf)); | ||
17927 | } | ||
17928 | |||
17929 | inline auto make_string_view(base_classes_tag) { | ||
17930 | return string_view(detail::base_class_cast_key()); | ||
17931 | } | ||
17932 | |||
17933 | template <typename Arg> | ||
17934 | inline std::string make_string(Arg&& arg) { | ||
17935 | string_view s = make_string_view(arg); | ||
17936 | return std::string(s.data(), s.size()); | ||
17937 | } | ||
17938 | |||
17939 | template <typename N> | ||
17940 | inline luaL_Reg make_reg(N&& n, lua_CFunction f) { | ||
17941 | luaL_Reg l{make_string_view(std::forward<N>(n)).data(), f}; | ||
17942 | return l; | ||
17943 | } | ||
17944 | |||
17945 | struct registrar { | ||
17946 | registrar() = default; | ||
17947 | registrar(const registrar&) = default; | ||
17948 | registrar(registrar&&) = default; | ||
17949 | registrar& operator=(const registrar&) = default; | ||
17950 | registrar& operator=(registrar&&) = default; | ||
17951 | virtual int push_um(lua_State* L) = 0; | ||
17952 | virtual ~registrar() { | ||
17953 | } | ||
17954 | }; | ||
17955 | |||
17956 | inline bool is_toplevel(lua_State* L, int index = magic_index) { | ||
17957 | int isnum = 0; | ||
17958 | lua_Integer magic = lua_tointegerx(L, upvalue_index(index), &isnum); | ||
17959 | return isnum != 0 && magic == toplevel_magic; | ||
17960 | } | ||
17961 | |||
17962 | inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { | ||
17963 | usertype_metatable_core& umc = stack::get<light<usertype_metatable_core>>(L, upvalue_index(metatable_core_index)); | ||
17964 | std::vector<object>& runtime = umc.runtime; | ||
17965 | object& runtimeobj = runtime[runtimetarget]; | ||
17966 | return stack::push(L, runtimeobj); | ||
17967 | } | ||
17968 | |||
17969 | template <typename T, bool is_index> | ||
17970 | inline int indexing_fail(lua_State* L) { | ||
17971 | if (is_index) { | ||
17972 | #if 0 //defined(SOL_SAFE_USERTYPE) && SOL_SAFE_USERTYPE | ||
17973 | auto maybeaccessor = stack::get<optional<string_view>>(L, is_index ? -1 : -2); | ||
17974 | string_view accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); | ||
17975 | return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); | ||
17976 | #else | ||
17977 | if (is_toplevel(L)) { | ||
17978 | if (lua_getmetatable(L, 1) == 1) { | ||
17979 | int metatarget = lua_gettop(L); | ||
17980 | stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); | ||
17981 | return 1; | ||
17982 | } | ||
17983 | } | ||
17984 | // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... | ||
17985 | return stack::push(L, lua_nil); | ||
17986 | #endif | ||
17987 | } | ||
17988 | else { | ||
17989 | auto maybeaccessor = stack::get<optional<string_view>>(L, is_index ? -1 : -2); | ||
17990 | string_view accessor = maybeaccessor.value_or(string_view("(unknown)")); | ||
17991 | return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); | ||
17992 | } | ||
17993 | } | ||
17994 | |||
17995 | int runtime_new_index(lua_State* L, void*, int runtimetarget); | ||
17996 | |||
17997 | template <typename T, bool is_simple> | ||
17998 | inline int metatable_newindex(lua_State* L) { | ||
17999 | if (is_toplevel(L)) { | ||
18000 | auto non_indexable = [&L]() { | ||
18001 | if (is_simple) { | ||
18002 | simple_map& sm = stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index)); | ||
18003 | function_map& functions = sm.functions; | ||
18004 | optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2); | ||
18005 | if (!maybeaccessor) { | ||
18006 | return; | ||
18007 | } | ||
18008 | string_view& accessor_view = maybeaccessor.value(); | ||
18009 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18010 | auto preexistingit = functions.find(accessor_view, string_view_hash(), std::equal_to<string_view>()); | ||
18011 | #else | ||
18012 | std::string accessor(accessor_view.data(), accessor_view.size()); | ||
18013 | auto preexistingit = functions.find(accessor); | ||
18014 | #endif | ||
18015 | if (preexistingit == functions.cend()) { | ||
18016 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18017 | std::string accessor(accessor_view.data(), accessor_view.size()); | ||
18018 | #endif | ||
18019 | functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); | ||
18020 | } | ||
18021 | else { | ||
18022 | preexistingit->second = object(L, 3); | ||
18023 | } | ||
18024 | return; | ||
18025 | } | ||
18026 | usertype_metatable_core& umc = stack::get<light<usertype_metatable_core>>(L, upvalue_index(metatable_core_index)); | ||
18027 | bool mustindex = umc.mustindex; | ||
18028 | if (!mustindex) | ||
18029 | return; | ||
18030 | optional<string_view> maybeaccessor = stack::get<optional<string_view>>(L, 2); | ||
18031 | if (!maybeaccessor) { | ||
18032 | return; | ||
18033 | } | ||
18034 | string_view& accessor_view = maybeaccessor.value(); | ||
18035 | mapping_t& mapping = umc.mapping; | ||
18036 | std::vector<object>& runtime = umc.runtime; | ||
18037 | int target = static_cast<int>(runtime.size()); | ||
18038 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18039 | auto preexistingit = mapping.find(accessor_view, string_view_hash(), std::equal_to<string_view>()); | ||
18040 | #else | ||
18041 | std::string accessor(accessor_view.data(), accessor_view.size()); | ||
18042 | auto preexistingit = mapping.find(accessor); | ||
18043 | #endif | ||
18044 | if (preexistingit == mapping.cend()) { | ||
18045 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18046 | std::string accessor(accessor_view.data(), accessor_view.size()); | ||
18047 | #endif | ||
18048 | runtime.emplace_back(L, 3); | ||
18049 | mapping.emplace_hint(mapping.cend(), std::move(accessor), call_information(&runtime_object_call, &runtime_new_index, target)); | ||
18050 | } | ||
18051 | else { | ||
18052 | target = preexistingit->second.runtime_target; | ||
18053 | runtime[target] = object(L, 3); | ||
18054 | preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); | ||
18055 | } | ||
18056 | }; | ||
18057 | non_indexable(); | ||
18058 | for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { | ||
18059 | const char* metakey = nullptr; | ||
18060 | switch (i) { | ||
18061 | case 0: | ||
18062 | metakey = &usertype_traits<T*>::metatable()[0]; | ||
18063 | luaL_getmetatable(L, metakey); | ||
18064 | break; | ||
18065 | case 1: | ||
18066 | metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0]; | ||
18067 | luaL_getmetatable(L, metakey); | ||
18068 | break; | ||
18069 | case 2: | ||
18070 | metakey = &usertype_traits<T>::metatable()[0]; | ||
18071 | luaL_getmetatable(L, metakey); | ||
18072 | break; | ||
18073 | case 3: | ||
18074 | default: | ||
18075 | metakey = &usertype_traits<T>::user_metatable()[0]; | ||
18076 | { | ||
18077 | luaL_getmetatable(L, metakey); | ||
18078 | lua_getmetatable(L, -1); | ||
18079 | } | ||
18080 | break; | ||
18081 | } | ||
18082 | int tableindex = lua_gettop(L); | ||
18083 | if (type_of(L, tableindex) == type::lua_nil) { | ||
18084 | continue; | ||
18085 | } | ||
18086 | stack::set_field<false, true>(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); | ||
18087 | } | ||
18088 | lua_settop(L, 0); | ||
18089 | return 0; | ||
18090 | } | ||
18091 | return indexing_fail<T, false>(L); | ||
18092 | } | ||
18093 | |||
18094 | inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { | ||
18095 | usertype_metatable_core& umc = stack::get<light<usertype_metatable_core>>(L, upvalue_index(metatable_core_index)); | ||
18096 | std::vector<object>& runtime = umc.runtime; | ||
18097 | object& runtimeobj = runtime[runtimetarget]; | ||
18098 | runtimeobj = object(L, 3); | ||
18099 | return 0; | ||
18100 | } | ||
18101 | |||
18102 | template <bool is_index, typename Base> | ||
18103 | static void walk_single_base(lua_State* L, bool& found, int& ret, string_view&) { | ||
18104 | if (found) | ||
18105 | return; | ||
18106 | const char* metakey = &usertype_traits<Base>::metatable()[0]; | ||
18107 | const char* gcmetakey = &usertype_traits<Base>::gc_table()[0]; | ||
18108 | const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key(); | ||
18109 | |||
18110 | luaL_getmetatable(L, metakey); | ||
18111 | if (type_of(L, -1) == type::lua_nil) { | ||
18112 | lua_pop(L, 1); | ||
18113 | return; | ||
18114 | } | ||
18115 | |||
18116 | stack::get_field(L, basewalkkey); | ||
18117 | if (type_of(L, -1) == type::lua_nil) { | ||
18118 | lua_pop(L, 2); | ||
18119 | return; | ||
18120 | } | ||
18121 | lua_CFunction basewalkfunc = stack::pop<lua_CFunction>(L); | ||
18122 | lua_pop(L, 1); | ||
18123 | |||
18124 | stack::get_field<true>(L, gcmetakey); | ||
18125 | int value = basewalkfunc(L); | ||
18126 | if (value > -1) { | ||
18127 | found = true; | ||
18128 | ret = value; | ||
18129 | } | ||
18130 | } | ||
18131 | |||
18132 | template <bool is_index, typename... Bases> | ||
18133 | static void walk_all_bases(lua_State* L, bool& found, int& ret, string_view& accessor) { | ||
18134 | (void)L; | ||
18135 | (void)found; | ||
18136 | (void)ret; | ||
18137 | (void)accessor; | ||
18138 | (void)detail::swallow{0, (walk_single_base<is_index, Bases>(L, found, ret, accessor), 0)...}; | ||
18139 | } | ||
18140 | } // namespace usertype_detail | ||
18141 | |||
18142 | template <typename T> | ||
18143 | struct clean_type { | ||
18144 | typedef std::conditional_t<std::is_array<meta::unqualified_t<T>>::value, T&, std::decay_t<T>> type; | ||
18145 | }; | ||
18146 | |||
18147 | template <typename T> | ||
18148 | using clean_type_t = typename clean_type<T>::type; | ||
18149 | |||
18150 | template <typename T, typename IndexSequence, typename... Tn> | ||
18151 | struct usertype_metatable : usertype_detail::registrar {}; | ||
18152 | |||
18153 | template <typename T, std::size_t... I, typename... Tn> | ||
18154 | struct usertype_metatable<T, std::index_sequence<I...>, Tn...> : usertype_metatable_core, usertype_detail::registrar { | ||
18155 | typedef std::make_index_sequence<sizeof...(I) * 2> indices; | ||
18156 | typedef std::index_sequence<I...> half_indices; | ||
18157 | typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 31> regs_t; | ||
18158 | typedef std::tuple<Tn...> RawTuple; | ||
18159 | typedef std::tuple<clean_type_t<Tn>...> Tuple; | ||
18160 | template <std::size_t Idx> | ||
18161 | struct check_binding : is_variable_binding<meta::unqualified_tuple_element_t<Idx, Tuple>> {}; | ||
18162 | Tuple functions; | ||
18163 | lua_CFunction destructfunc; | ||
18164 | lua_CFunction callconstructfunc; | ||
18165 | lua_CFunction indexbase; | ||
18166 | lua_CFunction newindexbase; | ||
18167 | usertype_detail::base_walk indexbaseclasspropogation; | ||
18168 | usertype_detail::base_walk newindexbaseclasspropogation; | ||
18169 | void* baseclasscheck; | ||
18170 | void* baseclasscast; | ||
18171 | bool secondarymeta; | ||
18172 | std::bitset<32> properties; | ||
18173 | |||
18174 | template <std::size_t Idx, meta::enable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler> | ||
18175 | lua_CFunction make_func() const { | ||
18176 | return std::get<Idx + 1>(functions); | ||
18177 | } | ||
18178 | |||
18179 | template <std::size_t Idx, meta::disable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler> | ||
18180 | lua_CFunction make_func() const { | ||
18181 | const auto& name = std::get<Idx>(functions); | ||
18182 | return (usertype_detail::make_string_view(name) == "__newindex") ? &call<Idx + 1, false> : &call<Idx + 1, true>; | ||
18183 | } | ||
18184 | |||
18185 | static bool contains_variable() { | ||
18186 | typedef meta::any<check_binding<(I * 2 + 1)>...> has_variables; | ||
18187 | return has_variables::value; | ||
18188 | } | ||
18189 | |||
18190 | bool contains_index() const { | ||
18191 | bool idx = false; | ||
18192 | (void)detail::swallow{0, ((idx |= (usertype_detail::is_indexer(std::get<I * 2>(functions)) != 0)), 0)...}; | ||
18193 | return idx; | ||
18194 | } | ||
18195 | |||
18196 | int finish_regs(regs_t& l, int& index) { | ||
18197 | auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; }; | ||
18198 | usertype_detail::insert_default_registrations<T>(l, index, prop_fx); | ||
18199 | if (destructfunc != nullptr) { | ||
18200 | l[index] = luaL_Reg{to_string(meta_function::garbage_collect).c_str(), destructfunc}; | ||
18201 | ++index; | ||
18202 | } | ||
18203 | return index; | ||
18204 | } | ||
18205 | |||
18206 | template <std::size_t Idx, typename F> | ||
18207 | void make_regs(regs_t&, int&, call_construction, F&&) { | ||
18208 | callconstructfunc = call<Idx + 1>; | ||
18209 | secondarymeta = true; | ||
18210 | } | ||
18211 | |||
18212 | template <std::size_t, typename... Bases> | ||
18213 | void make_regs(regs_t&, int&, base_classes_tag, bases<Bases...>) { | ||
18214 | static_assert(!meta::any_same<T, Bases...>::value, "base classes cannot list the original class as part of the bases"); | ||
18215 | if (sizeof...(Bases) < 1) { | ||
18216 | return; | ||
18217 | } | ||
18218 | mustindex = true; | ||
18219 | (void)detail::swallow{0, ((detail::has_derived<Bases>::value = true), 0)...}; | ||
18220 | |||
18221 | static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); | ||
18222 | static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); | ||
18223 | baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check; | ||
18224 | baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast; | ||
18225 | indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>; | ||
18226 | newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>; | ||
18227 | } | ||
18228 | |||
18229 | template <std::size_t Idx, typename N, typename F, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, base_classes_tag, call_construction>::value>> | ||
18230 | void make_regs(regs_t& l, int& index, N&& n, F&&) { | ||
18231 | if (is_variable_binding<meta::unqualified_t<F>>::value) { | ||
18232 | return; | ||
18233 | } | ||
18234 | luaL_Reg reg = usertype_detail::make_reg(std::forward<N>(n), make_func<Idx>()); | ||
18235 | for (std::size_t i = 0; i < properties.size(); ++i) { | ||
18236 | meta_function mf = static_cast<meta_function>(i); | ||
18237 | const std::string& mfname = to_string(mf); | ||
18238 | if (mfname == reg.name) { | ||
18239 | switch (mf) { | ||
18240 | case meta_function::construct: | ||
18241 | if (properties[i]) { | ||
18242 | #if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) | ||
18243 | throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
18244 | #else | ||
18245 | assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
18246 | #endif | ||
18247 | } | ||
18248 | break; | ||
18249 | case meta_function::garbage_collect: | ||
18250 | if (destructfunc != nullptr) { | ||
18251 | #if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) | ||
18252 | throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
18253 | #else | ||
18254 | assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
18255 | #endif | ||
18256 | } | ||
18257 | destructfunc = reg.func; | ||
18258 | return; | ||
18259 | case meta_function::index: | ||
18260 | indexfunc = reg.func; | ||
18261 | mustindex = true; | ||
18262 | properties.set(i); | ||
18263 | return; | ||
18264 | case meta_function::new_index: | ||
18265 | newindexfunc = reg.func; | ||
18266 | mustindex = true; | ||
18267 | properties.set(i); | ||
18268 | return; | ||
18269 | default: | ||
18270 | break; | ||
18271 | } | ||
18272 | properties.set(i); | ||
18273 | break; | ||
18274 | } | ||
18275 | } | ||
18276 | l[index] = reg; | ||
18277 | ++index; | ||
18278 | } | ||
18279 | |||
18280 | template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>> | ||
18281 | usertype_metatable(Args&&... args) | ||
18282 | : usertype_metatable_core(&usertype_detail::indexing_fail<T, true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(), functions(std::forward<Args>(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>), indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(usertype_detail::walk_all_bases<false>), baseclasscheck(nullptr), baseclasscast(nullptr), secondarymeta(contains_variable()), properties() { | ||
18283 | properties.reset(); | ||
18284 | std::initializer_list<typename usertype_detail::mapping_t::value_type> ilist{{std::pair<std::string, usertype_detail::call_information>(usertype_detail::make_string(std::get<I * 2>(functions)), | ||
18285 | usertype_detail::call_information(&usertype_metatable::real_find_call<I * 2, I * 2 + 1, true>, | ||
18286 | &usertype_metatable::real_find_call<I * 2, I * 2 + 1, false>))}...}; | ||
18287 | this->mapping.insert(ilist); | ||
18288 | for (const auto& n : meta_function_names()) { | ||
18289 | this->mapping.erase(n); | ||
18290 | } | ||
18291 | this->mustindex = contains_variable() || contains_index(); | ||
18292 | } | ||
18293 | |||
18294 | usertype_metatable(const usertype_metatable&) = default; | ||
18295 | usertype_metatable(usertype_metatable&&) = default; | ||
18296 | usertype_metatable& operator=(const usertype_metatable&) = default; | ||
18297 | usertype_metatable& operator=(usertype_metatable&&) = default; | ||
18298 | |||
18299 | template <std::size_t I0, std::size_t I1, bool is_index> | ||
18300 | static int real_find_call(lua_State* L, void* um, int) { | ||
18301 | auto& f = *static_cast<usertype_metatable*>(um); | ||
18302 | if (is_variable_binding<decltype(std::get<I1>(f.functions))>::value) { | ||
18303 | return real_call_with<I1, is_index, true>(L, f); | ||
18304 | } | ||
18305 | // set up upvalues | ||
18306 | // for a chained call | ||
18307 | int upvalues = 0; | ||
18308 | upvalues += stack::push(L, nullptr); | ||
18309 | upvalues += stack::push(L, light<usertype_metatable>(f)); | ||
18310 | auto cfunc = &call<I1, is_index>; | ||
18311 | return stack::push(L, c_closure(cfunc, upvalues)); | ||
18312 | } | ||
18313 | |||
18314 | template <bool is_index> | ||
18315 | static int real_meta_call(lua_State* L, void* um, int) { | ||
18316 | auto& f = *static_cast<usertype_metatable*>(um); | ||
18317 | return is_index ? f.indexfunc(L) : f.newindexfunc(L); | ||
18318 | } | ||
18319 | |||
18320 | template <bool is_index, bool toplevel = false> | ||
18321 | static int core_indexing_call(lua_State* L) { | ||
18322 | usertype_metatable& f = toplevel | ||
18323 | ? stack::get<light<usertype_metatable>>(L, upvalue_index(usertype_detail::metatable_index)) | ||
18324 | : stack::pop<light<usertype_metatable>>(L); | ||
18325 | static const int keyidx = -2 + static_cast<int>(is_index); | ||
18326 | if (toplevel && stack::get<type>(L, keyidx) != type::string) { | ||
18327 | return is_index ? f.indexfunc(L) : f.newindexfunc(L); | ||
18328 | } | ||
18329 | int runtime_target = 0; | ||
18330 | usertype_detail::member_search member = nullptr; | ||
18331 | { | ||
18332 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18333 | string_view name = stack::get<string_view>(L, keyidx); | ||
18334 | auto memberit = f.mapping.find(name, string_view_hash(), std::equal_to<string_view>()); | ||
18335 | #else | ||
18336 | std::string name = stack::get<std::string>(L, keyidx); | ||
18337 | auto memberit = f.mapping.find(name); | ||
18338 | #endif | ||
18339 | if (memberit != f.mapping.cend()) { | ||
18340 | const usertype_detail::call_information& ci = memberit->second; | ||
18341 | member = is_index ? ci.index : ci.new_index; | ||
18342 | runtime_target = ci.runtime_target; | ||
18343 | } | ||
18344 | } | ||
18345 | if (member != nullptr) { | ||
18346 | return (member)(L, static_cast<void*>(&f), runtime_target); | ||
18347 | } | ||
18348 | string_view accessor = stack::get<string_view>(L, keyidx); | ||
18349 | int ret = 0; | ||
18350 | bool found = false; | ||
18351 | // Otherwise, we need to do propagating calls through the bases | ||
18352 | if (is_index) | ||
18353 | f.indexbaseclasspropogation(L, found, ret, accessor); | ||
18354 | else | ||
18355 | f.newindexbaseclasspropogation(L, found, ret, accessor); | ||
18356 | if (found) { | ||
18357 | return ret; | ||
18358 | } | ||
18359 | return toplevel ? (is_index ? f.indexfunc(L) : f.newindexfunc(L)) : -1; | ||
18360 | } | ||
18361 | |||
18362 | static int real_index_call(lua_State* L) { | ||
18363 | return core_indexing_call<true, true>(L); | ||
18364 | } | ||
18365 | |||
18366 | static int real_new_index_call(lua_State* L) { | ||
18367 | return core_indexing_call<false, true>(L); | ||
18368 | } | ||
18369 | |||
18370 | template <std::size_t Idx, bool is_index = true, bool is_variable = false> | ||
18371 | static int real_call(lua_State* L) { | ||
18372 | usertype_metatable& f = stack::get<light<usertype_metatable>>(L, upvalue_index(usertype_detail::metatable_index)); | ||
18373 | return real_call_with<Idx, is_index, is_variable>(L, f); | ||
18374 | } | ||
18375 | |||
18376 | template <std::size_t Idx, bool is_index = true, bool is_variable = false> | ||
18377 | static int real_call_with(lua_State* L, usertype_metatable& um) { | ||
18378 | typedef meta::unqualified_tuple_element_t<Idx - 1, Tuple> K; | ||
18379 | typedef meta::unqualified_tuple_element_t<Idx, Tuple> F; | ||
18380 | static const int boost = !detail::is_non_factory_constructor<F>::value | ||
18381 | && std::is_same<K, call_construction>::value | ||
18382 | ? 1 | ||
18383 | : 0; | ||
18384 | auto& f = std::get<Idx>(um.functions); | ||
18385 | return call_detail::call_wrapped<T, is_index, is_variable, boost>(L, f); | ||
18386 | } | ||
18387 | |||
18388 | template <std::size_t Idx, bool is_index = true, bool is_variable = false> | ||
18389 | static int call(lua_State* L) { | ||
18390 | return detail::typed_static_trampoline<decltype(&real_call<Idx, is_index, is_variable>), (&real_call<Idx, is_index, is_variable>)>(L); | ||
18391 | } | ||
18392 | |||
18393 | template <std::size_t Idx, bool is_index = true, bool is_variable = false> | ||
18394 | static int call_with(lua_State* L) { | ||
18395 | return detail::typed_static_trampoline<decltype(&real_call_with<Idx, is_index, is_variable>), (&real_call_with<Idx, is_index, is_variable>)>(L); | ||
18396 | } | ||
18397 | |||
18398 | static int index_call(lua_State* L) { | ||
18399 | return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L); | ||
18400 | } | ||
18401 | |||
18402 | static int new_index_call(lua_State* L) { | ||
18403 | return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L); | ||
18404 | } | ||
18405 | |||
18406 | virtual int push_um(lua_State* L) override { | ||
18407 | return stack::push(L, std::move(*this)); | ||
18408 | } | ||
18409 | |||
18410 | ~usertype_metatable() override { | ||
18411 | } | ||
18412 | }; | ||
18413 | |||
18414 | namespace stack { | ||
18415 | |||
18416 | template <typename T, std::size_t... I, typename... Args> | ||
18417 | struct pusher<usertype_metatable<T, std::index_sequence<I...>, Args...>> { | ||
18418 | typedef usertype_metatable<T, std::index_sequence<I...>, Args...> umt_t; | ||
18419 | typedef typename umt_t::regs_t regs_t; | ||
18420 | |||
18421 | static umt_t& make_cleanup(lua_State* L, umt_t&& umx) { | ||
18422 | // ensure some sort of uniqueness | ||
18423 | static int uniqueness = 0; | ||
18424 | std::string uniquegcmetakey = usertype_traits<T>::user_gc_metatable(); | ||
18425 | // std::to_string doesn't exist in android still, with NDK, so this bullshit | ||
18426 | // is necessary | ||
18427 | // thanks, Android :v | ||
18428 | int appended = snprintf(nullptr, 0, "%d", uniqueness); | ||
18429 | std::size_t insertionpoint = uniquegcmetakey.length() - 1; | ||
18430 | uniquegcmetakey.append(appended, '\0'); | ||
18431 | char* uniquetarget = &uniquegcmetakey[insertionpoint]; | ||
18432 | snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); | ||
18433 | ++uniqueness; | ||
18434 | |||
18435 | const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; | ||
18436 | // Make sure userdata's memory is properly in lua first, | ||
18437 | // otherwise all the light userdata we make later will become invalid | ||
18438 | stack::push<user<umt_t>>(L, metatable_key, uniquegcmetakey, std::move(umx)); | ||
18439 | // Create the top level thing that will act as our deleter later on | ||
18440 | stack_reference umt(L, -1); | ||
18441 | stack::set_field<true>(L, gcmetakey, umt); | ||
18442 | umt.pop(); | ||
18443 | |||
18444 | stack::get_field<true>(L, gcmetakey); | ||
18445 | umt_t& target_umt = stack::pop<user<umt_t>>(L); | ||
18446 | return target_umt; | ||
18447 | } | ||
18448 | |||
18449 | static int push(lua_State* L, umt_t&& umx) { | ||
18450 | |||
18451 | umt_t& um = make_cleanup(L, std::move(umx)); | ||
18452 | usertype_metatable_core& umc = um; | ||
18453 | regs_t value_table{{}}; | ||
18454 | int lastreg = 0; | ||
18455 | (void)detail::swallow{0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)...}; | ||
18456 | um.finish_regs(value_table, lastreg); | ||
18457 | value_table[lastreg] = {nullptr, nullptr}; | ||
18458 | regs_t ref_table = value_table; | ||
18459 | regs_t unique_table = value_table; | ||
18460 | bool hasdestructor = !value_table.empty() && to_string(meta_function::garbage_collect) == value_table[lastreg - 1].name; | ||
18461 | if (hasdestructor) { | ||
18462 | ref_table[lastreg - 1] = {nullptr, nullptr}; | ||
18463 | } | ||
18464 | unique_table[lastreg - 1] = {value_table[lastreg - 1].name, detail::unique_destruct<T>}; | ||
18465 | |||
18466 | lua_createtable(L, 0, 2); | ||
18467 | stack_reference type_table(L, -1); | ||
18468 | |||
18469 | stack::set_field(L, "name", detail::demangle<T>(), type_table.stack_index()); | ||
18470 | stack::set_field(L, "is", &usertype_detail::is_check<T>, type_table.stack_index()); | ||
18471 | |||
18472 | // Now use um | ||
18473 | const bool& mustindex = umc.mustindex; | ||
18474 | for (std::size_t i = 0; i < 3; ++i) { | ||
18475 | // Pointer types, AKA "references" from C++ | ||
18476 | const char* metakey = nullptr; | ||
18477 | luaL_Reg* metaregs = nullptr; | ||
18478 | switch (i) { | ||
18479 | case 0: | ||
18480 | metakey = &usertype_traits<T*>::metatable()[0]; | ||
18481 | metaregs = ref_table.data(); | ||
18482 | break; | ||
18483 | case 1: | ||
18484 | metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0]; | ||
18485 | metaregs = unique_table.data(); | ||
18486 | break; | ||
18487 | case 2: | ||
18488 | default: | ||
18489 | metakey = &usertype_traits<T>::metatable()[0]; | ||
18490 | metaregs = value_table.data(); | ||
18491 | break; | ||
18492 | } | ||
18493 | luaL_newmetatable(L, metakey); | ||
18494 | stack_reference t(L, -1); | ||
18495 | stack::set_field(L, meta_function::type, type_table, t.stack_index()); | ||
18496 | int upvalues = 0; | ||
18497 | upvalues += stack::push(L, nullptr); | ||
18498 | upvalues += stack::push(L, make_light(um)); | ||
18499 | luaL_setfuncs(L, metaregs, upvalues); | ||
18500 | |||
18501 | if (um.baseclasscheck != nullptr) { | ||
18502 | stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index()); | ||
18503 | } | ||
18504 | if (um.baseclasscast != nullptr) { | ||
18505 | stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index()); | ||
18506 | } | ||
18507 | |||
18508 | stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); | ||
18509 | stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); | ||
18510 | |||
18511 | if (mustindex) { | ||
18512 | // Basic index pushing: specialize | ||
18513 | // index and newindex to give variables and stuff | ||
18514 | stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); | ||
18515 | stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); | ||
18516 | } | ||
18517 | else { | ||
18518 | // If there's only functions, we can use the fast index version | ||
18519 | stack::set_field(L, meta_function::index, t, t.stack_index()); | ||
18520 | } | ||
18521 | // metatable on the metatable | ||
18522 | // for call constructor purposes and such | ||
18523 | lua_createtable(L, 0, 3); | ||
18524 | stack_reference metabehind(L, -1); | ||
18525 | stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); | ||
18526 | if (um.callconstructfunc != nullptr) { | ||
18527 | stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); | ||
18528 | } | ||
18529 | if (um.secondarymeta) { | ||
18530 | stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); | ||
18531 | stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); | ||
18532 | } | ||
18533 | // type information needs to be present on the behind-tables too | ||
18534 | |||
18535 | stack::set_field(L, metatable_key, metabehind, t.stack_index()); | ||
18536 | metabehind.pop(); | ||
18537 | // We want to just leave the table | ||
18538 | // in the registry only, otherwise we return it | ||
18539 | t.pop(); | ||
18540 | } | ||
18541 | |||
18542 | // Now for the shim-table that actually gets assigned to the name | ||
18543 | luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]); | ||
18544 | stack_reference t(L, -1); | ||
18545 | stack::set_field(L, meta_function::type, type_table, t.stack_index()); | ||
18546 | int upvalues = 0; | ||
18547 | upvalues += stack::push(L, nullptr); | ||
18548 | upvalues += stack::push(L, make_light(um)); | ||
18549 | luaL_setfuncs(L, value_table.data(), upvalues); | ||
18550 | { | ||
18551 | lua_createtable(L, 0, 3); | ||
18552 | stack_reference metabehind(L, -1); | ||
18553 | // type information needs to be present on the behind-tables too | ||
18554 | stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); | ||
18555 | if (um.callconstructfunc != nullptr) { | ||
18556 | stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); | ||
18557 | } | ||
18558 | |||
18559 | stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); | ||
18560 | stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); | ||
18561 | stack::set_field(L, metatable_key, metabehind, t.stack_index()); | ||
18562 | metabehind.pop(); | ||
18563 | } | ||
18564 | |||
18565 | lua_remove(L, type_table.stack_index()); | ||
18566 | |||
18567 | return 1; | ||
18568 | } | ||
18569 | }; | ||
18570 | |||
18571 | } // namespace stack | ||
18572 | |||
18573 | } // namespace sol | ||
18574 | |||
18575 | // end of sol/usertype_metatable.hpp | ||
18576 | |||
18577 | // beginning of sol/simple_usertype_metatable.hpp | ||
18578 | |||
18579 | namespace sol { | ||
18580 | |||
18581 | namespace usertype_detail { | ||
18582 | inline int call_indexing_object(lua_State* L, object& f) { | ||
18583 | int before = lua_gettop(L); | ||
18584 | f.push(); | ||
18585 | for (int i = 1; i <= before; ++i) { | ||
18586 | lua_pushvalue(L, i); | ||
18587 | } | ||
18588 | lua_call(L, before, LUA_MULTRET); | ||
18589 | int after = lua_gettop(L); | ||
18590 | return after - before; | ||
18591 | } | ||
18592 | |||
18593 | template <typename T, bool is_index, bool toplevel = false, bool has_indexing = false> | ||
18594 | inline int simple_core_indexing_call(lua_State* L) { | ||
18595 | simple_map& sm = toplevel | ||
18596 | ? stack::get<user<simple_map>>(L, upvalue_index(simple_metatable_index)) | ||
18597 | : stack::pop<user<simple_map>>(L); | ||
18598 | variable_map& variables = sm.variables; | ||
18599 | function_map& functions = sm.functions; | ||
18600 | static const int keyidx = -2 + static_cast<int>(is_index); | ||
18601 | if (toplevel) { | ||
18602 | if (type_of(L, keyidx) != type::string) { | ||
18603 | if (has_indexing) { | ||
18604 | object& indexingfunc = is_index | ||
18605 | ? sm.index | ||
18606 | : sm.newindex; | ||
18607 | return call_indexing_object(L, indexingfunc); | ||
18608 | } | ||
18609 | else { | ||
18610 | return is_index | ||
18611 | ? indexing_fail<T, is_index>(L) | ||
18612 | : metatable_newindex<T, true>(L); | ||
18613 | } | ||
18614 | } | ||
18615 | } | ||
18616 | string_view accessor = stack::get<string_view>(L, keyidx); | ||
18617 | variable_wrapper* varwrap = nullptr; | ||
18618 | { | ||
18619 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18620 | string_view& accessorkey = accessor; | ||
18621 | auto vit = variables.find(accessorkey, string_view_hash(), std::equal_to<string_view>()); | ||
18622 | #else | ||
18623 | std::string accessorkey(accessor.data(), accessor.size()); | ||
18624 | auto vit = variables.find(accessorkey); | ||
18625 | #endif // Compatible Hash | ||
18626 | if (vit != variables.cend()) { | ||
18627 | varwrap = vit->second.get(); | ||
18628 | } | ||
18629 | } | ||
18630 | if (varwrap != nullptr) { | ||
18631 | return is_index ? varwrap->index(L) : varwrap->new_index(L); | ||
18632 | } | ||
18633 | bool function_failed = false; | ||
18634 | { | ||
18635 | #if defined(SOL_UNORDERED_MAP_COMPATIBLE_HASH) && SOL_UNORDERED_MAP_COMPATIBLE_HASH | ||
18636 | string_view& accessorkey = accessor; | ||
18637 | auto fit = functions.find(accessorkey, string_view_hash(), std::equal_to<string_view>()); | ||
18638 | #else | ||
18639 | std::string accessorkey(accessor.data(), accessor.size()); | ||
18640 | auto fit = functions.find(accessorkey); | ||
18641 | #endif // Compatible Hash | ||
18642 | if (fit != functions.cend()) { | ||
18643 | object& func = fit->second; | ||
18644 | if (is_index) { | ||
18645 | return stack::push(L, func); | ||
18646 | } | ||
18647 | else { | ||
18648 | function_failed = true; | ||
18649 | } | ||
18650 | } | ||
18651 | } | ||
18652 | if (function_failed) { | ||
18653 | if (has_indexing && !is_toplevel(L)) { | ||
18654 | object& indexingfunc = is_index | ||
18655 | ? sm.index | ||
18656 | : sm.newindex; | ||
18657 | return call_indexing_object(L, indexingfunc); | ||
18658 | } | ||
18659 | else { | ||
18660 | return is_index | ||
18661 | ? indexing_fail<T, is_index>(L) | ||
18662 | : metatable_newindex<T, true>(L); | ||
18663 | } | ||
18664 | } | ||
18665 | /* Check table storage first for a method that works | ||
18666 | luaL_getmetatable(L, sm.metakey); | ||
18667 | if (type_of(L, -1) != type::lua_nil) { | ||
18668 | stack::get_field<false, true>(L, accessor.c_str(), lua_gettop(L)); | ||
18669 | if (type_of(L, -1) != type::lua_nil) { | ||
18670 | // Woo, we found it? | ||
18671 | lua_remove(L, -2); | ||
18672 | return 1; | ||
18673 | } | ||
18674 | lua_pop(L, 1); | ||
18675 | } | ||
18676 | lua_pop(L, 1); | ||
18677 | */ | ||
18678 | |||
18679 | int ret = 0; | ||
18680 | bool found = false; | ||
18681 | // Otherwise, we need to do propagating calls through the bases | ||
18682 | if (is_index) { | ||
18683 | sm.indexbaseclasspropogation(L, found, ret, accessor); | ||
18684 | } | ||
18685 | else { | ||
18686 | sm.newindexbaseclasspropogation(L, found, ret, accessor); | ||
18687 | } | ||
18688 | if (found) { | ||
18689 | return ret; | ||
18690 | } | ||
18691 | if (toplevel) { | ||
18692 | if (has_indexing && !is_toplevel(L)) { | ||
18693 | object& indexingfunc = is_index | ||
18694 | ? sm.index | ||
18695 | : sm.newindex; | ||
18696 | return call_indexing_object(L, indexingfunc); | ||
18697 | } | ||
18698 | else { | ||
18699 | return is_index | ||
18700 | ? indexing_fail<T, is_index>(L) | ||
18701 | : metatable_newindex<T, true>(L); | ||
18702 | } | ||
18703 | } | ||
18704 | return -1; | ||
18705 | } | ||
18706 | |||
18707 | template <typename T, bool has_indexing = false> | ||
18708 | inline int simple_real_index_call(lua_State* L) { | ||
18709 | return simple_core_indexing_call<T, true, true, has_indexing>(L); | ||
18710 | } | ||
18711 | |||
18712 | template <typename T, bool has_indexing = false> | ||
18713 | inline int simple_real_new_index_call(lua_State* L) { | ||
18714 | return simple_core_indexing_call<T, false, true, has_indexing>(L); | ||
18715 | } | ||
18716 | |||
18717 | template <typename T, bool has_indexing = false> | ||
18718 | inline int simple_index_call(lua_State* L) { | ||
18719 | #if defined(__clang__) | ||
18720 | return detail::trampoline(L, &simple_real_index_call<T, has_indexing>); | ||
18721 | #else | ||
18722 | return detail::typed_static_trampoline<decltype(&simple_real_index_call<T, has_indexing>), (&simple_real_index_call<T, has_indexing>)>(L); | ||
18723 | #endif | ||
18724 | } | ||
18725 | |||
18726 | template <typename T, bool has_indexing = false> | ||
18727 | inline int simple_new_index_call(lua_State* L) { | ||
18728 | #if defined(__clang__) | ||
18729 | return detail::trampoline(L, &simple_real_new_index_call<T, has_indexing>); | ||
18730 | #else | ||
18731 | return detail::typed_static_trampoline<decltype(&simple_real_new_index_call<T, has_indexing>), (&simple_real_new_index_call<T, has_indexing>)>(L); | ||
18732 | #endif | ||
18733 | } | ||
18734 | } // namespace usertype_detail | ||
18735 | |||
18736 | struct simple_tag { | ||
18737 | } const simple{}; | ||
18738 | |||
18739 | template <typename T> | ||
18740 | struct simple_usertype_metatable : usertype_detail::registrar { | ||
18741 | public: | ||
18742 | usertype_detail::function_map registrations; | ||
18743 | usertype_detail::variable_map varmap; | ||
18744 | object callconstructfunc; | ||
18745 | object indexfunc; | ||
18746 | object newindexfunc; | ||
18747 | lua_CFunction indexbase; | ||
18748 | lua_CFunction newindexbase; | ||
18749 | usertype_detail::base_walk indexbaseclasspropogation; | ||
18750 | usertype_detail::base_walk newindexbaseclasspropogation; | ||
18751 | void* baseclasscheck; | ||
18752 | void* baseclasscast; | ||
18753 | bool mustindex; | ||
18754 | bool secondarymeta; | ||
18755 | std::array<bool, 32> properties; | ||
18756 | |||
18757 | template <typename N> | ||
18758 | void insert(N&& n, object&& o) { | ||
18759 | std::string key = usertype_detail::make_string(std::forward<N>(n)); | ||
18760 | int is_indexer = static_cast<int>(usertype_detail::is_indexer(n)); | ||
18761 | if (is_indexer == 1) { | ||
18762 | indexfunc = o; | ||
18763 | mustindex = true; | ||
18764 | } | ||
18765 | else if (is_indexer == 2) { | ||
18766 | newindexfunc = o; | ||
18767 | mustindex = true; | ||
18768 | } | ||
18769 | auto hint = registrations.find(key); | ||
18770 | if (hint == registrations.cend()) { | ||
18771 | registrations.emplace_hint(hint, std::move(key), std::move(o)); | ||
18772 | return; | ||
18773 | } | ||
18774 | hint->second = std::move(o); | ||
18775 | } | ||
18776 | |||
18777 | template <typename N, typename F, typename... Args> | ||
18778 | void insert_prepare(std::true_type, lua_State* L, N&&, F&& f, Args&&... args) { | ||
18779 | object o = make_object<F>(L, std::forward<F>(f), function_detail::call_indicator(), std::forward<Args>(args)...); | ||
18780 | callconstructfunc = std::move(o); | ||
18781 | } | ||
18782 | |||
18783 | template <typename N, typename F, typename... Args> | ||
18784 | void insert_prepare(std::false_type, lua_State* L, N&& n, F&& f, Args&&... args) { | ||
18785 | object o = make_object<F>(L, std::forward<F>(f), std::forward<Args>(args)...); | ||
18786 | insert(std::forward<N>(n), std::move(o)); | ||
18787 | } | ||
18788 | |||
18789 | template <typename N, typename F> | ||
18790 | void add_member_function(std::true_type, lua_State* L, N&& n, F&& f) { | ||
18791 | insert_prepare(std::is_same<meta::unqualified_t<N>, call_construction>(), L, std::forward<N>(n), std::forward<F>(f), function_detail::class_indicator<T>()); | ||
18792 | } | ||
18793 | |||
18794 | template <typename N, typename F> | ||
18795 | void add_member_function(std::false_type, lua_State* L, N&& n, F&& f) { | ||
18796 | insert_prepare(std::is_same<meta::unqualified_t<N>, call_construction>(), L, std::forward<N>(n), std::forward<F>(f)); | ||
18797 | } | ||
18798 | |||
18799 | template <typename N, typename F, meta::enable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler> | ||
18800 | void add_function(lua_State* L, N&& n, F&& f) { | ||
18801 | object o = make_object(L, as_function_reference(std::forward<F>(f))); | ||
18802 | if (std::is_same<meta::unqualified_t<N>, call_construction>::value) { | ||
18803 | callconstructfunc = std::move(o); | ||
18804 | return; | ||
18805 | } | ||
18806 | insert(std::forward<N>(n), std::move(o)); | ||
18807 | } | ||
18808 | |||
18809 | template <typename N, typename F, meta::disable<meta::is_callable<meta::unwrap_unqualified_t<F>>> = meta::enabler> | ||
18810 | void add_function(lua_State* L, N&& n, F&& f) { | ||
18811 | add_member_function(std::is_member_pointer<meta::unwrap_unqualified_t<F>>(), L, std::forward<N>(n), std::forward<F>(f)); | ||
18812 | } | ||
18813 | |||
18814 | template <typename N, typename F, meta::disable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler> | ||
18815 | void add(lua_State* L, N&& n, F&& f) { | ||
18816 | add_function(L, std::forward<N>(n), std::forward<F>(f)); | ||
18817 | } | ||
18818 | |||
18819 | template <typename N, typename F, meta::enable<is_variable_binding<meta::unqualified_t<F>>> = meta::enabler> | ||
18820 | void add(lua_State*, N&& n, F&& f) { | ||
18821 | mustindex = true; | ||
18822 | secondarymeta = true; | ||
18823 | std::string key = usertype_detail::make_string(std::forward<N>(n)); | ||
18824 | auto o = std::make_unique<usertype_detail::callable_binding<T, std::decay_t<F>>>(std::forward<F>(f)); | ||
18825 | auto hint = varmap.find(key); | ||
18826 | if (hint == varmap.cend()) { | ||
18827 | varmap.emplace_hint(hint, std::move(key), std::move(o)); | ||
18828 | return; | ||
18829 | } | ||
18830 | hint->second = std::move(o); | ||
18831 | } | ||
18832 | |||
18833 | template <typename N, typename... Fxs> | ||
18834 | void add(lua_State* L, N&& n, constructor_wrapper<Fxs...> c) { | ||
18835 | object o(L, in_place_type<detail::tagged<T, constructor_wrapper<Fxs...>>>, std::move(c)); | ||
18836 | if (std::is_same<meta::unqualified_t<N>, call_construction>::value) { | ||
18837 | callconstructfunc = std::move(o); | ||
18838 | return; | ||
18839 | } | ||
18840 | insert(std::forward<N>(n), std::move(o)); | ||
18841 | } | ||
18842 | |||
18843 | template <typename N, typename... Lists> | ||
18844 | void add(lua_State* L, N&& n, constructor_list<Lists...> c) { | ||
18845 | object o(L, in_place_type<detail::tagged<T, constructor_list<Lists...>>>, std::move(c)); | ||
18846 | if (std::is_same<meta::unqualified_t<N>, call_construction>::value) { | ||
18847 | callconstructfunc = std::move(o); | ||
18848 | return; | ||
18849 | } | ||
18850 | insert(std::forward<N>(n), std::move(o)); | ||
18851 | } | ||
18852 | |||
18853 | template <typename N> | ||
18854 | void add(lua_State* L, N&& n, destructor_wrapper<void> c) { | ||
18855 | object o(L, in_place_type<detail::tagged<T, destructor_wrapper<void>>>, std::move(c)); | ||
18856 | if (std::is_same<meta::unqualified_t<N>, call_construction>::value) { | ||
18857 | callconstructfunc = std::move(o); | ||
18858 | return; | ||
18859 | } | ||
18860 | insert(std::forward<N>(n), std::move(o)); | ||
18861 | } | ||
18862 | |||
18863 | template <typename N, typename Fx> | ||
18864 | void add(lua_State* L, N&& n, destructor_wrapper<Fx> c) { | ||
18865 | object o(L, in_place_type<detail::tagged<T, destructor_wrapper<Fx>>>, std::move(c)); | ||
18866 | if (std::is_same<meta::unqualified_t<N>, call_construction>::value) { | ||
18867 | callconstructfunc = std::move(o); | ||
18868 | return; | ||
18869 | } | ||
18870 | insert(std::forward<N>(n), std::move(o)); | ||
18871 | } | ||
18872 | |||
18873 | template <typename... Bases> | ||
18874 | void add(lua_State*, base_classes_tag, bases<Bases...>) { | ||
18875 | static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform. Please file a bug report."); | ||
18876 | static_assert(!meta::any_same<T, Bases...>::value, "base classes cannot list the original class as part of the bases"); | ||
18877 | if (sizeof...(Bases) < 1) { | ||
18878 | return; | ||
18879 | } | ||
18880 | mustindex = true; | ||
18881 | (void)detail::swallow{0, ((detail::has_derived<Bases>::value = true), 0)...}; | ||
18882 | |||
18883 | static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); | ||
18884 | static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); | ||
18885 | baseclasscheck = reinterpret_cast<void*>(&detail::inheritance<T, Bases...>::type_check); | ||
18886 | baseclasscast = reinterpret_cast<void*>(&detail::inheritance<T, Bases...>::type_cast); | ||
18887 | indexbaseclasspropogation = usertype_detail::walk_all_bases<true, Bases...>; | ||
18888 | newindexbaseclasspropogation = usertype_detail::walk_all_bases<false, Bases...>; | ||
18889 | } | ||
18890 | |||
18891 | private: | ||
18892 | template <std::size_t... I, typename Tuple> | ||
18893 | simple_usertype_metatable(detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args) | ||
18894 | : callconstructfunc(lua_nil), indexfunc(lua_nil), newindexfunc(lua_nil), indexbase(&usertype_detail::simple_core_indexing_call<T, true>), newindexbase(&usertype_detail::simple_core_indexing_call<T, false>), indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>), baseclasscheck(nullptr), baseclasscast(nullptr), mustindex(false), secondarymeta(false), properties() { | ||
18895 | properties.fill(false); | ||
18896 | |||
18897 | (void)detail::swallow{0, | ||
18898 | (add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)), 0)...}; | ||
18899 | } | ||
18900 | |||
18901 | template <typename... Args> | ||
18902 | simple_usertype_metatable(lua_State* L, detail::verified_tag v, Args&&... args) | ||
18903 | : simple_usertype_metatable(v, std::make_index_sequence<sizeof...(Args) / 2>(), L, std::forward_as_tuple(std::forward<Args>(args)...)) { | ||
18904 | } | ||
18905 | |||
18906 | template <typename... Args> | ||
18907 | simple_usertype_metatable(lua_State* L, detail::add_destructor_tag, Args&&... args) | ||
18908 | : simple_usertype_metatable(L, detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) { | ||
18909 | } | ||
18910 | |||
18911 | template <typename... Args> | ||
18912 | simple_usertype_metatable(lua_State* L, detail::check_destructor_tag, Args&&... args) | ||
18913 | : simple_usertype_metatable(L, meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) { | ||
18914 | } | ||
18915 | |||
18916 | public: | ||
18917 | simple_usertype_metatable(lua_State* L) | ||
18918 | : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>>, decltype(default_constructor), detail::check_destructor_tag>()) { | ||
18919 | } | ||
18920 | |||
18921 | template <typename Arg, typename... Args, meta::disable_any<meta::any_same<meta::unqualified_t<Arg>, detail::verified_tag, detail::add_destructor_tag, detail::check_destructor_tag>, meta::is_specialization_of<meta::unqualified_t<Arg>, constructors>, meta::is_specialization_of<meta::unqualified_t<Arg>, constructor_wrapper>> = meta::enabler> | ||
18922 | simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) | ||
18923 | : simple_usertype_metatable(L, meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Arg>(arg), std::forward<Args>(args)...) { | ||
18924 | } | ||
18925 | |||
18926 | template <typename... Args, typename... CArgs> | ||
18927 | simple_usertype_metatable(lua_State* L, constructors<CArgs...> constructorlist, Args&&... args) | ||
18928 | : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) { | ||
18929 | } | ||
18930 | |||
18931 | template <typename... Args, typename... Fxs> | ||
18932 | simple_usertype_metatable(lua_State* L, constructor_wrapper<Fxs...> constructorlist, Args&&... args) | ||
18933 | : simple_usertype_metatable(L, detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) { | ||
18934 | } | ||
18935 | |||
18936 | simple_usertype_metatable(const simple_usertype_metatable&) = default; | ||
18937 | simple_usertype_metatable(simple_usertype_metatable&&) = default; | ||
18938 | simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default; | ||
18939 | simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default; | ||
18940 | |||
18941 | virtual int push_um(lua_State* L) override { | ||
18942 | return stack::push(L, std::move(*this)); | ||
18943 | } | ||
18944 | }; | ||
18945 | |||
18946 | namespace stack { | ||
18947 | template <typename T> | ||
18948 | struct pusher<simple_usertype_metatable<T>> { | ||
18949 | typedef simple_usertype_metatable<T> umt_t; | ||
18950 | |||
18951 | static usertype_detail::simple_map& make_cleanup(lua_State* L, umt_t& umx) { | ||
18952 | static int uniqueness = 0; | ||
18953 | std::string uniquegcmetakey = usertype_traits<T>::user_gc_metatable(); | ||
18954 | // std::to_string doesn't exist in android still, with NDK, so this bullshit | ||
18955 | // is necessary | ||
18956 | // thanks, Android :v | ||
18957 | int appended = snprintf(nullptr, 0, "%d", uniqueness); | ||
18958 | std::size_t insertionpoint = uniquegcmetakey.length() - 1; | ||
18959 | uniquegcmetakey.append(appended, '\0'); | ||
18960 | char* uniquetarget = &uniquegcmetakey[insertionpoint]; | ||
18961 | snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); | ||
18962 | ++uniqueness; | ||
18963 | |||
18964 | const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; | ||
18965 | stack::push<user<usertype_detail::simple_map>>(L, metatable_key, uniquegcmetakey, &usertype_traits<T>::metatable()[0], | ||
18966 | umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation, | ||
18967 | std::move(umx.indexfunc), std::move(umx.newindexfunc), | ||
18968 | std::move(umx.varmap), std::move(umx.registrations)); | ||
18969 | stack_reference stackvarmap(L, -1); | ||
18970 | stack::set_field<true>(L, gcmetakey, stackvarmap); | ||
18971 | stackvarmap.pop(); | ||
18972 | |||
18973 | stack::get_field<true>(L, gcmetakey); | ||
18974 | usertype_detail::simple_map& varmap = stack::pop<user<usertype_detail::simple_map>>(L); | ||
18975 | return varmap; | ||
18976 | } | ||
18977 | |||
18978 | static int push(lua_State* L, umt_t&& umx) { | ||
18979 | bool hasindex = umx.indexfunc.valid(); | ||
18980 | bool hasnewindex = umx.newindexfunc.valid(); | ||
18981 | auto& varmap = make_cleanup(L, umx); | ||
18982 | auto& properties = umx.properties; | ||
18983 | auto sic = hasindex ? &usertype_detail::simple_index_call<T, true> : &usertype_detail::simple_index_call<T, false>; | ||
18984 | auto snic = hasnewindex ? &usertype_detail::simple_new_index_call<T, true> : &usertype_detail::simple_new_index_call<T, false>; | ||
18985 | |||
18986 | lua_createtable(L, 0, 2); | ||
18987 | stack_reference type_table(L, -1); | ||
18988 | |||
18989 | stack::set_field(L, "name", detail::demangle<T>(), type_table.stack_index()); | ||
18990 | stack::set_field(L, "is", &usertype_detail::is_check<T>, type_table.stack_index()); | ||
18991 | |||
18992 | auto safety_check = [&](const std::string& first) { | ||
18993 | for (std::size_t j = 0; j < properties.size(); ++j) { | ||
18994 | meta_function mf = static_cast<meta_function>(j); | ||
18995 | const std::string& mfname = to_string(mf); | ||
18996 | bool& prop = properties[j]; | ||
18997 | if (mfname != first) | ||
18998 | continue; | ||
18999 | switch (mf) { | ||
19000 | case meta_function::construct: | ||
19001 | if (prop) { | ||
19002 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
19003 | assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
19004 | #else | ||
19005 | throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
19006 | #endif | ||
19007 | } | ||
19008 | break; | ||
19009 | case meta_function::garbage_collect: | ||
19010 | if (prop) { | ||
19011 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
19012 | assert(false && "sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
19013 | #else | ||
19014 | throw error("sol: 2 separate constructor (new) functions were set on this type. Please specify only 1 sol::meta_function::construct/'new' type AND wrap the function in a sol::factories/initializers call, as shown by the documentation and examples, otherwise you may create problems"); | ||
19015 | #endif | ||
19016 | } | ||
19017 | return; | ||
19018 | default: | ||
19019 | break; | ||
19020 | } | ||
19021 | prop = true; | ||
19022 | break; | ||
19023 | } | ||
19024 | }; | ||
19025 | |||
19026 | for (auto& kvp : varmap.functions) { | ||
19027 | auto& first = std::get<0>(kvp); | ||
19028 | safety_check(first); | ||
19029 | } | ||
19030 | |||
19031 | auto register_kvp = [&](std::size_t meta_index, stack_reference& t, const std::string& first, object& second) { | ||
19032 | meta_function mf = meta_function::construct; | ||
19033 | for (std::size_t j = 0; j < properties.size(); ++j) { | ||
19034 | mf = static_cast<meta_function>(j); | ||
19035 | const std::string& mfname = to_string(mf); | ||
19036 | bool& prop = properties[j]; | ||
19037 | if (mfname != first) | ||
19038 | continue; | ||
19039 | switch (mf) { | ||
19040 | case meta_function::index: | ||
19041 | umx.indexfunc = second; | ||
19042 | break; | ||
19043 | case meta_function::new_index: | ||
19044 | umx.newindexfunc = second; | ||
19045 | break; | ||
19046 | default: | ||
19047 | break; | ||
19048 | } | ||
19049 | prop = true; | ||
19050 | break; | ||
19051 | } | ||
19052 | switch (meta_index) { | ||
19053 | case 0: | ||
19054 | if (mf == meta_function::garbage_collect) { | ||
19055 | return; | ||
19056 | } | ||
19057 | break; | ||
19058 | case 1: | ||
19059 | if (mf == meta_function::garbage_collect) { | ||
19060 | stack::set_field(L, first, detail::unique_destruct<T>, t.stack_index()); | ||
19061 | return; | ||
19062 | } | ||
19063 | break; | ||
19064 | case 2: | ||
19065 | default: | ||
19066 | break; | ||
19067 | } | ||
19068 | stack::set_field(L, first, second, t.stack_index()); | ||
19069 | }; | ||
19070 | for (std::size_t i = 0; i < 3; ++i) { | ||
19071 | const char* metakey = nullptr; | ||
19072 | switch (i) { | ||
19073 | case 0: | ||
19074 | metakey = &usertype_traits<T*>::metatable()[0]; | ||
19075 | break; | ||
19076 | case 1: | ||
19077 | metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0]; | ||
19078 | break; | ||
19079 | case 2: | ||
19080 | default: | ||
19081 | metakey = &usertype_traits<T>::metatable()[0]; | ||
19082 | break; | ||
19083 | } | ||
19084 | luaL_newmetatable(L, metakey); | ||
19085 | stack_reference t(L, -1); | ||
19086 | stack::set_field(L, meta_function::type, type_table, t.stack_index()); | ||
19087 | |||
19088 | for (auto& kvp : varmap.functions) { | ||
19089 | auto& first = std::get<0>(kvp); | ||
19090 | auto& second = std::get<1>(kvp); | ||
19091 | register_kvp(i, t, first, second); | ||
19092 | } | ||
19093 | luaL_Reg opregs[34]{}; | ||
19094 | int opregsindex = 0; | ||
19095 | auto prop_fx = [&](meta_function mf) { return !properties[static_cast<int>(mf)]; }; | ||
19096 | usertype_detail::insert_default_registrations<T>(opregs, opregsindex, prop_fx); | ||
19097 | t.push(); | ||
19098 | luaL_setfuncs(L, opregs, 0); | ||
19099 | t.pop(); | ||
19100 | |||
19101 | if (umx.baseclasscheck != nullptr) { | ||
19102 | stack::set_field(L, detail::base_class_check_key(), umx.baseclasscheck, t.stack_index()); | ||
19103 | } | ||
19104 | if (umx.baseclasscast != nullptr) { | ||
19105 | stack::set_field(L, detail::base_class_cast_key(), umx.baseclasscast, t.stack_index()); | ||
19106 | } | ||
19107 | |||
19108 | // Base class propagation features | ||
19109 | stack::set_field(L, detail::base_class_index_propogation_key(), umx.indexbase, t.stack_index()); | ||
19110 | stack::set_field(L, detail::base_class_new_index_propogation_key(), umx.newindexbase, t.stack_index()); | ||
19111 | |||
19112 | if (umx.mustindex) { | ||
19113 | // use indexing function | ||
19114 | stack::set_field(L, meta_function::index, | ||
19115 | make_closure(sic, | ||
19116 | nullptr, | ||
19117 | make_light(varmap)), | ||
19118 | t.stack_index()); | ||
19119 | stack::set_field(L, meta_function::new_index, | ||
19120 | make_closure(snic, | ||
19121 | nullptr, | ||
19122 | make_light(varmap)), | ||
19123 | t.stack_index()); | ||
19124 | } | ||
19125 | else { | ||
19126 | // Metatable indexes itself | ||
19127 | stack::set_field(L, meta_function::index, t, t.stack_index()); | ||
19128 | } | ||
19129 | // metatable on the metatable | ||
19130 | // for call constructor purposes and such | ||
19131 | lua_createtable(L, 0, 2 * static_cast<int>(umx.secondarymeta) + static_cast<int>(umx.callconstructfunc.valid())); | ||
19132 | stack_reference metabehind(L, -1); | ||
19133 | stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); | ||
19134 | if (umx.callconstructfunc.valid()) { | ||
19135 | stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); | ||
19136 | } | ||
19137 | if (umx.secondarymeta) { | ||
19138 | stack::set_field(L, meta_function::index, | ||
19139 | make_closure(sic, | ||
19140 | nullptr, | ||
19141 | make_light(varmap)), | ||
19142 | metabehind.stack_index()); | ||
19143 | stack::set_field(L, meta_function::new_index, | ||
19144 | make_closure(snic, | ||
19145 | nullptr, | ||
19146 | make_light(varmap)), | ||
19147 | metabehind.stack_index()); | ||
19148 | } | ||
19149 | stack::set_field(L, metatable_key, metabehind, t.stack_index()); | ||
19150 | metabehind.pop(); | ||
19151 | |||
19152 | t.pop(); | ||
19153 | } | ||
19154 | |||
19155 | // Now for the shim-table that actually gets pushed | ||
19156 | luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]); | ||
19157 | stack_reference t(L, -1); | ||
19158 | stack::set_field(L, meta_function::type, type_table, t.stack_index()); | ||
19159 | |||
19160 | for (auto& kvp : varmap.functions) { | ||
19161 | auto& first = std::get<0>(kvp); | ||
19162 | auto& second = std::get<1>(kvp); | ||
19163 | register_kvp(2, t, first, second); | ||
19164 | } | ||
19165 | { | ||
19166 | lua_createtable(L, 0, 2 + static_cast<int>(umx.callconstructfunc.valid())); | ||
19167 | stack_reference metabehind(L, -1); | ||
19168 | stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); | ||
19169 | if (umx.callconstructfunc.valid()) { | ||
19170 | stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); | ||
19171 | } | ||
19172 | // use indexing function | ||
19173 | stack::set_field(L, meta_function::index, | ||
19174 | make_closure(sic, | ||
19175 | nullptr, | ||
19176 | make_light(varmap), | ||
19177 | nullptr, | ||
19178 | nullptr, | ||
19179 | usertype_detail::toplevel_magic), | ||
19180 | metabehind.stack_index()); | ||
19181 | stack::set_field(L, meta_function::new_index, | ||
19182 | make_closure(snic, | ||
19183 | nullptr, | ||
19184 | make_light(varmap), | ||
19185 | nullptr, | ||
19186 | nullptr, | ||
19187 | usertype_detail::toplevel_magic), | ||
19188 | metabehind.stack_index()); | ||
19189 | stack::set_field(L, metatable_key, metabehind, t.stack_index()); | ||
19190 | metabehind.pop(); | ||
19191 | } | ||
19192 | |||
19193 | lua_remove(L, type_table.stack_index()); | ||
19194 | |||
19195 | // Don't pop the table when we're done; | ||
19196 | // return it | ||
19197 | return 1; | ||
19198 | } | ||
19199 | }; | ||
19200 | } // namespace stack | ||
19201 | } // namespace sol | ||
19202 | |||
19203 | // end of sol/simple_usertype_metatable.hpp | ||
19204 | |||
19205 | namespace sol { | ||
19206 | |||
19207 | template <typename T> | ||
19208 | class usertype { | ||
19209 | private: | ||
19210 | std::unique_ptr<usertype_detail::registrar, detail::deleter> metatableregister; | ||
19211 | |||
19212 | template <typename... Args> | ||
19213 | usertype(detail::verified_tag, Args&&... args) | ||
19214 | : metatableregister(detail::make_unique_deleter<usertype_metatable<T, std::make_index_sequence<sizeof...(Args) / 2>, Args...>, detail::deleter>(std::forward<Args>(args)...)) { | ||
19215 | static_assert(detail::has_destructor<Args...>::value, "this type does not have an explicit destructor declared; please pass a custom destructor function wrapped in sol::destruct, especially if the type does not have an accessible (private) destructor"); | ||
19216 | } | ||
19217 | |||
19218 | template <typename... Args> | ||
19219 | usertype(detail::add_destructor_tag, Args&&... args) | ||
19220 | : usertype(detail::verified, std::forward<Args>(args)..., "__gc", default_destructor) { | ||
19221 | } | ||
19222 | |||
19223 | template <typename... Args> | ||
19224 | usertype(detail::check_destructor_tag, Args&&... args) | ||
19225 | : usertype(meta::condition<meta::all<std::is_destructible<T>, meta::neg<detail::has_destructor<Args...>>>, detail::add_destructor_tag, detail::verified_tag>(), std::forward<Args>(args)...) { | ||
19226 | } | ||
19227 | |||
19228 | public: | ||
19229 | template <typename... Args> | ||
19230 | usertype(Args&&... args) | ||
19231 | : usertype(meta::condition<meta::all<std::is_default_constructible<T>, meta::neg<detail::has_constructor<Args...>>>, decltype(default_constructor), detail::check_destructor_tag>(), std::forward<Args>(args)...) { | ||
19232 | } | ||
19233 | |||
19234 | template <typename... Args, typename... CArgs> | ||
19235 | usertype(constructors<CArgs...> constructorlist, Args&&... args) | ||
19236 | : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) { | ||
19237 | } | ||
19238 | |||
19239 | template <typename... Args, typename... Fxs> | ||
19240 | usertype(constructor_wrapper<Fxs...> constructorlist, Args&&... args) | ||
19241 | : usertype(detail::check_destructor_tag(), std::forward<Args>(args)..., "new", constructorlist) { | ||
19242 | } | ||
19243 | |||
19244 | template <typename... Args> | ||
19245 | usertype(simple_tag, lua_State* L, Args&&... args) | ||
19246 | : metatableregister(detail::make_unique_deleter<simple_usertype_metatable<T>, detail::deleter>(L, std::forward<Args>(args)...)) { | ||
19247 | } | ||
19248 | |||
19249 | usertype_detail::registrar* registrar_data() { | ||
19250 | return metatableregister.get(); | ||
19251 | } | ||
19252 | |||
19253 | int push(lua_State* L) { | ||
19254 | int r = metatableregister->push_um(L); | ||
19255 | metatableregister = nullptr; | ||
19256 | return r; | ||
19257 | } | ||
19258 | }; | ||
19259 | |||
19260 | template <typename T> | ||
19261 | class simple_usertype : public usertype<T> { | ||
19262 | private: | ||
19263 | typedef usertype<T> base_t; | ||
19264 | lua_State* state; | ||
19265 | |||
19266 | public: | ||
19267 | template <typename... Args> | ||
19268 | simple_usertype(lua_State* L, Args&&... args) | ||
19269 | : base_t(simple, L, std::forward<Args>(args)...), state(L) { | ||
19270 | } | ||
19271 | |||
19272 | template <typename N, typename F> | ||
19273 | void set(N&& n, F&& f) { | ||
19274 | auto meta = static_cast<simple_usertype_metatable<T>*>(base_t::registrar_data()); | ||
19275 | meta->add(state, std::forward<N>(n), std::forward<F>(f)); | ||
19276 | } | ||
19277 | }; | ||
19278 | |||
19279 | namespace stack { | ||
19280 | template <typename T> | ||
19281 | struct pusher<usertype<T>> { | ||
19282 | static int push(lua_State* L, usertype<T>& user) { | ||
19283 | return user.push(L); | ||
19284 | } | ||
19285 | }; | ||
19286 | } // namespace stack | ||
19287 | } // namespace sol | ||
19288 | |||
19289 | // end of sol/usertype.hpp | ||
19290 | |||
19291 | // beginning of sol/table_iterator.hpp | ||
19292 | |||
19293 | namespace sol { | ||
19294 | |||
19295 | template <typename reference_type> | ||
19296 | class basic_table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> { | ||
19297 | public: | ||
19298 | typedef object key_type; | ||
19299 | typedef object mapped_type; | ||
19300 | typedef std::pair<object, object> value_type; | ||
19301 | typedef std::input_iterator_tag iterator_category; | ||
19302 | typedef std::ptrdiff_t difference_type; | ||
19303 | typedef value_type* pointer; | ||
19304 | typedef value_type& reference; | ||
19305 | typedef const value_type& const_reference; | ||
19306 | |||
19307 | private: | ||
19308 | std::pair<object, object> kvp; | ||
19309 | reference_type ref; | ||
19310 | int tableidx = 0; | ||
19311 | int keyidx = 0; | ||
19312 | std::ptrdiff_t idx = 0; | ||
19313 | |||
19314 | public: | ||
19315 | basic_table_iterator() | ||
19316 | : keyidx(-1), idx(-1) { | ||
19317 | } | ||
19318 | |||
19319 | basic_table_iterator(reference_type x) | ||
19320 | : ref(std::move(x)) { | ||
19321 | ref.push(); | ||
19322 | tableidx = lua_gettop(ref.lua_state()); | ||
19323 | stack::push(ref.lua_state(), lua_nil); | ||
19324 | this->operator++(); | ||
19325 | if (idx == -1) { | ||
19326 | return; | ||
19327 | } | ||
19328 | --idx; | ||
19329 | } | ||
19330 | |||
19331 | basic_table_iterator& operator++() { | ||
19332 | if (idx == -1) | ||
19333 | return *this; | ||
19334 | |||
19335 | if (lua_next(ref.lua_state(), tableidx) == 0) { | ||
19336 | idx = -1; | ||
19337 | keyidx = -1; | ||
19338 | return *this; | ||
19339 | } | ||
19340 | ++idx; | ||
19341 | kvp.first = object(ref.lua_state(), -2); | ||
19342 | kvp.second = object(ref.lua_state(), -1); | ||
19343 | lua_pop(ref.lua_state(), 1); | ||
19344 | // leave key on the stack | ||
19345 | keyidx = lua_gettop(ref.lua_state()); | ||
19346 | return *this; | ||
19347 | } | ||
19348 | |||
19349 | basic_table_iterator operator++(int) { | ||
19350 | auto saved = *this; | ||
19351 | this->operator++(); | ||
19352 | return saved; | ||
19353 | } | ||
19354 | |||
19355 | reference operator*() { | ||
19356 | return kvp; | ||
19357 | } | ||
19358 | |||
19359 | const_reference operator*() const { | ||
19360 | return kvp; | ||
19361 | } | ||
19362 | |||
19363 | bool operator==(const basic_table_iterator& right) const { | ||
19364 | return idx == right.idx; | ||
19365 | } | ||
19366 | |||
19367 | bool operator!=(const basic_table_iterator& right) const { | ||
19368 | return idx != right.idx; | ||
19369 | } | ||
19370 | |||
19371 | ~basic_table_iterator() { | ||
19372 | if (keyidx != -1) { | ||
19373 | stack::remove(ref.lua_state(), keyidx, 1); | ||
19374 | } | ||
19375 | if (ref.valid()) { | ||
19376 | stack::remove(ref.lua_state(), tableidx, 1); | ||
19377 | } | ||
19378 | } | ||
19379 | }; | ||
19380 | |||
19381 | } // namespace sol | ||
19382 | |||
19383 | // end of sol/table_iterator.hpp | ||
19384 | |||
19385 | namespace sol { | ||
19386 | namespace detail { | ||
19387 | template <std::size_t n> | ||
19388 | struct clean { | ||
19389 | lua_State* L; | ||
19390 | clean(lua_State* luastate) | ||
19391 | : L(luastate) { | ||
19392 | } | ||
19393 | ~clean() { | ||
19394 | lua_pop(L, static_cast<int>(n)); | ||
19395 | } | ||
19396 | }; | ||
19397 | struct ref_clean { | ||
19398 | lua_State* L; | ||
19399 | int& n; | ||
19400 | ref_clean(lua_State* luastate, int& n) | ||
19401 | : L(luastate), n(n) { | ||
19402 | } | ||
19403 | ~ref_clean() { | ||
19404 | lua_pop(L, static_cast<int>(n)); | ||
19405 | } | ||
19406 | }; | ||
19407 | inline int fail_on_newindex(lua_State* L) { | ||
19408 | return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); | ||
19409 | } | ||
19410 | } // namespace detail | ||
19411 | |||
19412 | const new_table create = new_table{}; | ||
19413 | |||
19414 | template <bool top_level, typename base_type> | ||
19415 | class basic_table_core : public basic_object_base<base_type> { | ||
19416 | typedef basic_object_base<base_type> base_t; | ||
19417 | friend class state; | ||
19418 | friend class state_view; | ||
19419 | |||
19420 | template <typename... Args> | ||
19421 | using is_global = meta::all<meta::boolean<top_level>, meta::is_c_str<Args>...>; | ||
19422 | |||
19423 | template <typename Fx> | ||
19424 | void for_each(std::true_type, Fx&& fx) const { | ||
19425 | auto pp = stack::push_pop(*this); | ||
19426 | stack::push(base_t::lua_state(), lua_nil); | ||
19427 | while (lua_next(base_t::lua_state(), -2)) { | ||
19428 | object key(base_t::lua_state(), -2); | ||
19429 | object value(base_t::lua_state(), -1); | ||
19430 | std::pair<object&, object&> keyvalue(key, value); | ||
19431 | auto pn = stack::pop_n(base_t::lua_state(), 1); | ||
19432 | fx(keyvalue); | ||
19433 | } | ||
19434 | } | ||
19435 | |||
19436 | template <typename Fx> | ||
19437 | void for_each(std::false_type, Fx&& fx) const { | ||
19438 | auto pp = stack::push_pop(*this); | ||
19439 | stack::push(base_t::lua_state(), lua_nil); | ||
19440 | while (lua_next(base_t::lua_state(), -2)) { | ||
19441 | object key(base_t::lua_state(), -2); | ||
19442 | object value(base_t::lua_state(), -1); | ||
19443 | auto pn = stack::pop_n(base_t::lua_state(), 1); | ||
19444 | fx(key, value); | ||
19445 | } | ||
19446 | } | ||
19447 | |||
19448 | template <bool raw, typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys> | ||
19449 | auto tuple_get(types<Ret0, Ret1, Ret...>, std::index_sequence<0, 1, I...>, Keys&& keys) const | ||
19450 | -> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) { | ||
19451 | typedef decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) Tup; | ||
19452 | return Tup( | ||
19453 | traverse_get_optional<top_level, raw, Ret0>(meta::is_optional<meta::unqualified_t<Ret0>>(), detail::forward_get<0>(keys)), | ||
19454 | traverse_get_optional<top_level, raw, Ret1>(meta::is_optional<meta::unqualified_t<Ret1>>(), detail::forward_get<1>(keys)), | ||
19455 | traverse_get_optional<top_level, raw, Ret>(meta::is_optional<meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys))...); | ||
19456 | } | ||
19457 | |||
19458 | template <bool raw, typename Ret, std::size_t I, typename Keys> | ||
19459 | decltype(auto) tuple_get(types<Ret>, std::index_sequence<I>, Keys&& keys) const { | ||
19460 | return traverse_get_optional<top_level, raw, Ret>(meta::is_optional<meta::unqualified_t<Ret>>(), detail::forward_get<I>(keys)); | ||
19461 | } | ||
19462 | |||
19463 | template <bool raw, typename Pairs, std::size_t... I> | ||
19464 | void tuple_set(std::index_sequence<I...>, Pairs&& pairs) { | ||
19465 | auto pp = stack::push_pop < top_level && (is_global<decltype(detail::forward_get<I * 2>(pairs))...>::value) > (*this); | ||
19466 | void(detail::swallow{ (stack::set_field<top_level, raw>(base_t::lua_state(), | ||
19467 | detail::forward_get<I * 2>(pairs), | ||
19468 | detail::forward_get<I * 2 + 1>(pairs), | ||
19469 | lua_gettop(base_t::lua_state())), | ||
19470 | 0)... }); | ||
19471 | } | ||
19472 | |||
19473 | template <bool global, bool raw, typename T, typename Key> | ||
19474 | decltype(auto) traverse_get_deep(Key&& key) const { | ||
19475 | stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); | ||
19476 | return stack::get<T>(base_t::lua_state()); | ||
19477 | } | ||
19478 | |||
19479 | template <bool global, bool raw, typename T, typename Key, typename... Keys> | ||
19480 | decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const { | ||
19481 | stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); | ||
19482 | return traverse_get_deep<false, raw, T>(std::forward<Keys>(keys)...); | ||
19483 | } | ||
19484 | |||
19485 | template <bool global, bool raw, typename T, std::size_t I, typename Key> | ||
19486 | decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const { | ||
19487 | typedef decltype(stack::get<T>(base_t::lua_state())) R; | ||
19488 | auto p = stack::probe_get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state())); | ||
19489 | popcount += p.levels; | ||
19490 | if (!p.success) | ||
19491 | return R(nullopt); | ||
19492 | return stack::get<T>(base_t::lua_state()); | ||
19493 | } | ||
19494 | |||
19495 | template <bool global, bool raw, typename T, std::size_t I, typename Key, typename... Keys> | ||
19496 | decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const { | ||
19497 | auto p = I > 0 ? stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), -1) : stack::probe_get_field<global>(base_t::lua_state(), std::forward<Key>(key), lua_gettop(base_t::lua_state())); | ||
19498 | popcount += p.levels; | ||
19499 | if (!p.success) | ||
19500 | return T(nullopt); | ||
19501 | return traverse_get_deep_optional<false, raw, T, I + 1>(popcount, std::forward<Keys>(keys)...); | ||
19502 | } | ||
19503 | |||
19504 | template <bool global, bool raw, typename T, typename... Keys> | ||
19505 | decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const { | ||
19506 | detail::clean<sizeof...(Keys)> c(base_t::lua_state()); | ||
19507 | return traverse_get_deep<global, raw, T>(std::forward<Keys>(keys)...); | ||
19508 | } | ||
19509 | |||
19510 | template <bool global, bool raw, typename T, typename... Keys> | ||
19511 | decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const { | ||
19512 | int popcount = 0; | ||
19513 | detail::ref_clean c(base_t::lua_state(), popcount); | ||
19514 | return traverse_get_deep_optional<global, raw, T, 0>(popcount, std::forward<Keys>(keys)...); | ||
19515 | } | ||
19516 | |||
19517 | template <bool global, bool raw, typename Key, typename Value> | ||
19518 | void traverse_set_deep(Key&& key, Value&& value) const { | ||
19519 | stack::set_field<global, raw>(base_t::lua_state(), std::forward<Key>(key), std::forward<Value>(value)); | ||
19520 | } | ||
19521 | |||
19522 | template <bool global, bool raw, typename Key, typename... Keys> | ||
19523 | void traverse_set_deep(Key&& key, Keys&&... keys) const { | ||
19524 | stack::get_field<global, raw>(base_t::lua_state(), std::forward<Key>(key)); | ||
19525 | traverse_set_deep<false, raw>(std::forward<Keys>(keys)...); | ||
19526 | } | ||
19527 | |||
19528 | basic_table_core(lua_State* L, detail::global_tag t) noexcept | ||
19529 | : base_t(L, t) { | ||
19530 | } | ||
19531 | |||
19532 | protected: | ||
19533 | basic_table_core(detail::no_safety_tag, lua_nil_t n) | ||
19534 | : base_t(n) { | ||
19535 | } | ||
19536 | basic_table_core(detail::no_safety_tag, lua_State* L, int index) | ||
19537 | : base_t(L, index) { | ||
19538 | } | ||
19539 | basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) | ||
19540 | : base_t(L, index) { | ||
19541 | } | ||
19542 | template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
19543 | basic_table_core(detail::no_safety_tag, T&& r) noexcept | ||
19544 | : base_t(std::forward<T>(r)) { | ||
19545 | } | ||
19546 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
19547 | basic_table_core(detail::no_safety_tag, lua_State*L, T&& r) noexcept | ||
19548 | : base_t(L, std::forward<T>(r)) { | ||
19549 | } | ||
19550 | |||
19551 | public: | ||
19552 | typedef basic_table_iterator<base_type> iterator; | ||
19553 | typedef iterator const_iterator; | ||
19554 | |||
19555 | using base_t::lua_state; | ||
19556 | |||
19557 | basic_table_core() noexcept = default; | ||
19558 | basic_table_core(const basic_table_core&) = default; | ||
19559 | basic_table_core(basic_table_core&&) = default; | ||
19560 | basic_table_core& operator=(const basic_table_core&) = default; | ||
19561 | basic_table_core& operator=(basic_table_core&&) = default; | ||
19562 | basic_table_core(const stack_reference& r) | ||
19563 | : basic_table_core(r.lua_state(), r.stack_index()) { | ||
19564 | } | ||
19565 | basic_table_core(stack_reference&& r) | ||
19566 | : basic_table_core(r.lua_state(), r.stack_index()) { | ||
19567 | } | ||
19568 | template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
19569 | basic_table_core(lua_State* L, T&& r) | ||
19570 | : base_t(L, std::forward<T>(r)) { | ||
19571 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
19572 | auto pp = stack::push_pop(*this); | ||
19573 | constructor_handler handler{}; | ||
19574 | stack::check<basic_table_core>(lua_state(), -1, handler); | ||
19575 | #endif // Safety | ||
19576 | } | ||
19577 | basic_table_core(lua_State* L, const new_table& nt) | ||
19578 | : base_t(L, -stack::push(L, nt)) { | ||
19579 | if (!is_stack_based<meta::unqualified_t<base_type>>::value) { | ||
19580 | lua_pop(L, 1); | ||
19581 | } | ||
19582 | } | ||
19583 | basic_table_core(lua_State* L, int index = -1) | ||
19584 | : basic_table_core(detail::no_safety, L, index) { | ||
19585 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
19586 | constructor_handler handler{}; | ||
19587 | stack::check<basic_table_core>(L, index, handler); | ||
19588 | #endif // Safety | ||
19589 | } | ||
19590 | basic_table_core(lua_State* L, ref_index index) | ||
19591 | : basic_table_core(detail::no_safety, L, index) { | ||
19592 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
19593 | auto pp = stack::push_pop(*this); | ||
19594 | constructor_handler handler{}; | ||
19595 | stack::check<basic_table_core>(lua_state(), -1, handler); | ||
19596 | #endif // Safety | ||
19597 | } | ||
19598 | template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
19599 | basic_table_core(T&& r) noexcept | ||
19600 | : basic_table_core(detail::no_safety, std::forward<T>(r)) { | ||
19601 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
19602 | if (!is_table<meta::unqualified_t<T>>::value) { | ||
19603 | auto pp = stack::push_pop(*this); | ||
19604 | constructor_handler handler{}; | ||
19605 | stack::check<basic_table_core>(base_t::lua_state(), -1, handler); | ||
19606 | } | ||
19607 | #endif // Safety | ||
19608 | } | ||
19609 | basic_table_core(lua_nil_t r) noexcept | ||
19610 | : basic_table_core(detail::no_safety, r) { | ||
19611 | } | ||
19612 | |||
19613 | iterator begin() const { | ||
19614 | return iterator(*this); | ||
19615 | } | ||
19616 | |||
19617 | iterator end() const { | ||
19618 | return iterator(); | ||
19619 | } | ||
19620 | |||
19621 | const_iterator cbegin() const { | ||
19622 | return begin(); | ||
19623 | } | ||
19624 | |||
19625 | const_iterator cend() const { | ||
19626 | return end(); | ||
19627 | } | ||
19628 | |||
19629 | template <typename... Ret, typename... Keys> | ||
19630 | decltype(auto) get(Keys&&... keys) const { | ||
19631 | static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); | ||
19632 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19633 | return tuple_get<false>(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), std::forward_as_tuple(std::forward<Keys>(keys)...)); | ||
19634 | } | ||
19635 | |||
19636 | template <typename T, typename Key> | ||
19637 | decltype(auto) get_or(Key&& key, T&& otherwise) const { | ||
19638 | typedef decltype(get<T>("")) U; | ||
19639 | optional<U> option = get<optional<U>>(std::forward<Key>(key)); | ||
19640 | if (option) { | ||
19641 | return static_cast<U>(option.value()); | ||
19642 | } | ||
19643 | return static_cast<U>(std::forward<T>(otherwise)); | ||
19644 | } | ||
19645 | |||
19646 | template <typename T, typename Key, typename D> | ||
19647 | decltype(auto) get_or(Key&& key, D&& otherwise) const { | ||
19648 | optional<T> option = get<optional<T>>(std::forward<Key>(key)); | ||
19649 | if (option) { | ||
19650 | return static_cast<T>(option.value()); | ||
19651 | } | ||
19652 | return static_cast<T>(std::forward<D>(otherwise)); | ||
19653 | } | ||
19654 | |||
19655 | template <typename T, typename... Keys> | ||
19656 | decltype(auto) traverse_get(Keys&&... keys) const { | ||
19657 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19658 | return traverse_get_optional<top_level, false, T>(meta::is_optional<meta::unqualified_t<T>>(), std::forward<Keys>(keys)...); | ||
19659 | } | ||
19660 | |||
19661 | template <typename... Keys> | ||
19662 | basic_table_core& traverse_set(Keys&&... keys) { | ||
19663 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19664 | auto pn = stack::pop_n(base_t::lua_state(), static_cast<int>(sizeof...(Keys) - 2)); | ||
19665 | traverse_set_deep<top_level, false>(std::forward<Keys>(keys)...); | ||
19666 | return *this; | ||
19667 | } | ||
19668 | |||
19669 | template <typename... Args> | ||
19670 | basic_table_core& set(Args&&... args) { | ||
19671 | tuple_set<false>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); | ||
19672 | return *this; | ||
19673 | } | ||
19674 | |||
19675 | template <typename... Ret, typename... Keys> | ||
19676 | decltype(auto) raw_get(Keys&&... keys) const { | ||
19677 | static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); | ||
19678 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19679 | return tuple_get<true>(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), std::forward_as_tuple(std::forward<Keys>(keys)...)); | ||
19680 | } | ||
19681 | |||
19682 | template <typename T, typename Key> | ||
19683 | decltype(auto) raw_get_or(Key&& key, T&& otherwise) const { | ||
19684 | typedef decltype(raw_get<T>("")) U; | ||
19685 | optional<U> option = raw_get<optional<U>>(std::forward<Key>(key)); | ||
19686 | if (option) { | ||
19687 | return static_cast<U>(option.value()); | ||
19688 | } | ||
19689 | return static_cast<U>(std::forward<T>(otherwise)); | ||
19690 | } | ||
19691 | |||
19692 | template <typename T, typename Key, typename D> | ||
19693 | decltype(auto) raw_get_or(Key&& key, D&& otherwise) const { | ||
19694 | optional<T> option = raw_get<optional<T>>(std::forward<Key>(key)); | ||
19695 | if (option) { | ||
19696 | return static_cast<T>(option.value()); | ||
19697 | } | ||
19698 | return static_cast<T>(std::forward<D>(otherwise)); | ||
19699 | } | ||
19700 | |||
19701 | template <typename T, typename... Keys> | ||
19702 | decltype(auto) traverse_raw_get(Keys&&... keys) const { | ||
19703 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19704 | return traverse_get_optional<top_level, true, T>(meta::is_optional<meta::unqualified_t<T>>(), std::forward<Keys>(keys)...); | ||
19705 | } | ||
19706 | |||
19707 | template <typename... Keys> | ||
19708 | basic_table_core& traverse_raw_set(Keys&&... keys) { | ||
19709 | auto pp = stack::push_pop<is_global<Keys...>::value>(*this); | ||
19710 | auto pn = stack::pop_n(base_t::lua_state(), static_cast<int>(sizeof...(Keys) - 2)); | ||
19711 | traverse_set_deep<top_level, true>(std::forward<Keys>(keys)...); | ||
19712 | return *this; | ||
19713 | } | ||
19714 | |||
19715 | template <typename... Args> | ||
19716 | basic_table_core& raw_set(Args&&... args) { | ||
19717 | tuple_set<true>(std::make_index_sequence<sizeof...(Args) / 2>(), std::forward_as_tuple(std::forward<Args>(args)...)); | ||
19718 | return *this; | ||
19719 | } | ||
19720 | |||
19721 | template <typename T> | ||
19722 | basic_table_core& set_usertype(usertype<T>& user) { | ||
19723 | return set_usertype(usertype_traits<T>::name(), user); | ||
19724 | } | ||
19725 | |||
19726 | template <typename Key, typename T> | ||
19727 | basic_table_core& set_usertype(Key&& key, usertype<T>& user) { | ||
19728 | return set(std::forward<Key>(key), user); | ||
19729 | } | ||
19730 | |||
19731 | template <typename Class, typename... Args> | ||
19732 | basic_table_core& new_usertype(const std::string& name, Args&&... args) { | ||
19733 | usertype<Class> utype(std::forward<Args>(args)...); | ||
19734 | set_usertype(name, utype); | ||
19735 | return *this; | ||
19736 | } | ||
19737 | |||
19738 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
19739 | basic_table_core& new_usertype(const std::string& name, Args&&... args) { | ||
19740 | constructors<types<CTor0, CTor...>> ctor{}; | ||
19741 | return new_usertype<Class>(name, ctor, std::forward<Args>(args)...); | ||
19742 | } | ||
19743 | |||
19744 | template <typename Class, typename... CArgs, typename... Args> | ||
19745 | basic_table_core& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { | ||
19746 | usertype<Class> utype(ctor, std::forward<Args>(args)...); | ||
19747 | set_usertype(name, utype); | ||
19748 | return *this; | ||
19749 | } | ||
19750 | |||
19751 | template <typename Class, typename... Args> | ||
19752 | basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { | ||
19753 | simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...); | ||
19754 | set_usertype(name, utype); | ||
19755 | return *this; | ||
19756 | } | ||
19757 | |||
19758 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
19759 | basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { | ||
19760 | constructors<types<CTor0, CTor...>> ctor{}; | ||
19761 | return new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...); | ||
19762 | } | ||
19763 | |||
19764 | template <typename Class, typename... CArgs, typename... Args> | ||
19765 | basic_table_core& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { | ||
19766 | simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...); | ||
19767 | set_usertype(name, utype); | ||
19768 | return *this; | ||
19769 | } | ||
19770 | |||
19771 | template <typename Class, typename... Args> | ||
19772 | simple_usertype<Class> create_simple_usertype(Args&&... args) { | ||
19773 | simple_usertype<Class> utype(base_t::lua_state(), std::forward<Args>(args)...); | ||
19774 | return utype; | ||
19775 | } | ||
19776 | |||
19777 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
19778 | simple_usertype<Class> create_simple_usertype(Args&&... args) { | ||
19779 | constructors<types<CTor0, CTor...>> ctor{}; | ||
19780 | return create_simple_usertype<Class>(ctor, std::forward<Args>(args)...); | ||
19781 | } | ||
19782 | |||
19783 | template <typename Class, typename... CArgs, typename... Args> | ||
19784 | simple_usertype<Class> create_simple_usertype(constructors<CArgs...> ctor, Args&&... args) { | ||
19785 | simple_usertype<Class> utype(base_t::lua_state(), ctor, std::forward<Args>(args)...); | ||
19786 | return utype; | ||
19787 | } | ||
19788 | |||
19789 | template <bool read_only = true, typename... Args> | ||
19790 | table new_enum(const string_view& name, Args&&... args) { | ||
19791 | table target = create_with(std::forward<Args>(args)...); | ||
19792 | if (read_only) { | ||
19793 | table x = create_with( | ||
19794 | meta_function::new_index, detail::fail_on_newindex, | ||
19795 | meta_function::index, target); | ||
19796 | table shim = create_named(name, metatable_key, x); | ||
19797 | return shim; | ||
19798 | } | ||
19799 | else { | ||
19800 | set(name, target); | ||
19801 | return target; | ||
19802 | } | ||
19803 | } | ||
19804 | |||
19805 | template <typename T, bool read_only = true> | ||
19806 | table new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) { | ||
19807 | table target = create(static_cast<int>(items.size()), static_cast<int>(0)); | ||
19808 | for (const auto& kvp : items) { | ||
19809 | target.set(kvp.first, kvp.second); | ||
19810 | } | ||
19811 | if (read_only) { | ||
19812 | table x = create_with( | ||
19813 | meta_function::new_index, detail::fail_on_newindex, | ||
19814 | meta_function::index, target); | ||
19815 | table shim = create_named(name, metatable_key, x); | ||
19816 | return shim; | ||
19817 | } | ||
19818 | else { | ||
19819 | set(name, target); | ||
19820 | return target; | ||
19821 | } | ||
19822 | } | ||
19823 | |||
19824 | template <typename Fx> | ||
19825 | void for_each(Fx&& fx) const { | ||
19826 | typedef meta::is_invokable<Fx(std::pair<object, object>)> is_paired; | ||
19827 | for_each(is_paired(), std::forward<Fx>(fx)); | ||
19828 | } | ||
19829 | |||
19830 | size_t size() const { | ||
19831 | auto pp = stack::push_pop(*this); | ||
19832 | lua_len(base_t::lua_state(), -1); | ||
19833 | return stack::pop<size_t>(base_t::lua_state()); | ||
19834 | } | ||
19835 | |||
19836 | bool empty() const { | ||
19837 | return cbegin() == cend(); | ||
19838 | } | ||
19839 | |||
19840 | template <typename T> | ||
19841 | proxy<basic_table_core&, T> operator[](T&& key) & { | ||
19842 | return proxy<basic_table_core&, T>(*this, std::forward<T>(key)); | ||
19843 | } | ||
19844 | |||
19845 | template <typename T> | ||
19846 | proxy<const basic_table_core&, T> operator[](T&& key) const& { | ||
19847 | return proxy<const basic_table_core&, T>(*this, std::forward<T>(key)); | ||
19848 | } | ||
19849 | |||
19850 | template <typename T> | ||
19851 | proxy<basic_table_core, T> operator[](T&& key) && { | ||
19852 | return proxy<basic_table_core, T>(*this, std::forward<T>(key)); | ||
19853 | } | ||
19854 | |||
19855 | template <typename Sig, typename Key, typename... Args> | ||
19856 | basic_table_core& set_function(Key&& key, Args&&... args) { | ||
19857 | set_fx(types<Sig>(), std::forward<Key>(key), std::forward<Args>(args)...); | ||
19858 | return *this; | ||
19859 | } | ||
19860 | |||
19861 | template <typename Key, typename... Args> | ||
19862 | basic_table_core& set_function(Key&& key, Args&&... args) { | ||
19863 | set_fx(types<>(), std::forward<Key>(key), std::forward<Args>(args)...); | ||
19864 | return *this; | ||
19865 | } | ||
19866 | |||
19867 | template <typename... Args> | ||
19868 | basic_table_core& add(Args&&... args) { | ||
19869 | auto pp = stack::push_pop(*this); | ||
19870 | (void)detail::swallow{ 0, | ||
19871 | (stack::set_ref(base_t::lua_state(), std::forward<Args>(args)), 0)... }; | ||
19872 | return *this; | ||
19873 | } | ||
19874 | |||
19875 | private: | ||
19876 | template <typename R, typename... Args, typename Fx, typename Key, typename = std::result_of_t<Fx(Args...)>> | ||
19877 | void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) { | ||
19878 | set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx)); | ||
19879 | } | ||
19880 | |||
19881 | template <typename Fx, typename Key, meta::enable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> | ||
19882 | void set_fx(types<>, Key&& key, Fx&& fx) { | ||
19883 | set(std::forward<Key>(key), std::forward<Fx>(fx)); | ||
19884 | } | ||
19885 | |||
19886 | template <typename Fx, typename Key, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<Fx>, overload_set>> = meta::enabler> | ||
19887 | void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { | ||
19888 | set(std::forward<Key>(key), as_function_reference(std::forward<Fx>(fx), std::forward<Args>(args)...)); | ||
19889 | } | ||
19890 | |||
19891 | template <typename... Sig, typename... Args, typename Key> | ||
19892 | void set_resolved_function(Key&& key, Args&&... args) { | ||
19893 | set(std::forward<Key>(key), as_function_reference<function_sig<Sig...>>(std::forward<Args>(args)...)); | ||
19894 | } | ||
19895 | |||
19896 | public: | ||
19897 | static inline table create(lua_State* L, int narr = 0, int nrec = 0) { | ||
19898 | lua_createtable(L, narr, nrec); | ||
19899 | table result(L); | ||
19900 | lua_pop(L, 1); | ||
19901 | return result; | ||
19902 | } | ||
19903 | |||
19904 | template <typename Key, typename Value, typename... Args> | ||
19905 | static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
19906 | lua_createtable(L, narr, nrec); | ||
19907 | table result(L); | ||
19908 | result.set(std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
19909 | lua_pop(L, 1); | ||
19910 | return result; | ||
19911 | } | ||
19912 | |||
19913 | template <typename... Args> | ||
19914 | static inline table create_with(lua_State* L, Args&&... args) { | ||
19915 | static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); | ||
19916 | static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value); | ||
19917 | return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...); | ||
19918 | } | ||
19919 | |||
19920 | table create(int narr = 0, int nrec = 0) { | ||
19921 | return create(base_t::lua_state(), narr, nrec); | ||
19922 | } | ||
19923 | |||
19924 | template <typename Key, typename Value, typename... Args> | ||
19925 | table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
19926 | return create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
19927 | } | ||
19928 | |||
19929 | template <typename Name> | ||
19930 | table create(Name&& name, int narr = 0, int nrec = 0) { | ||
19931 | table x = create(base_t::lua_state(), narr, nrec); | ||
19932 | this->set(std::forward<Name>(name), x); | ||
19933 | return x; | ||
19934 | } | ||
19935 | |||
19936 | template <typename Name, typename Key, typename Value, typename... Args> | ||
19937 | table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
19938 | table x = create(base_t::lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
19939 | this->set(std::forward<Name>(name), x); | ||
19940 | return x; | ||
19941 | } | ||
19942 | |||
19943 | template <typename... Args> | ||
19944 | table create_with(Args&&... args) { | ||
19945 | return create_with(base_t::lua_state(), std::forward<Args>(args)...); | ||
19946 | } | ||
19947 | |||
19948 | template <typename Name, typename... Args> | ||
19949 | table create_named(Name&& name, Args&&... args) { | ||
19950 | static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value); | ||
19951 | return create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...); | ||
19952 | } | ||
19953 | }; | ||
19954 | } // namespace sol | ||
19955 | |||
19956 | // end of sol/table_core.hpp | ||
19957 | |||
19958 | namespace sol { | ||
19959 | typedef table_core<false> table; | ||
19960 | |||
19961 | namespace stack { | ||
19962 | template <> | ||
19963 | struct getter<metatable_t> { | ||
19964 | static table get(lua_State* L, int index = -1) { | ||
19965 | if (lua_getmetatable(L, index) == 0) { | ||
19966 | return table(L, ref_index(LUA_REFNIL)); | ||
19967 | } | ||
19968 | return table(L, -1); | ||
19969 | } | ||
19970 | }; | ||
19971 | } // namespace stack | ||
19972 | } // namespace sol | ||
19973 | |||
19974 | // end of sol/table.hpp | ||
19975 | |||
19976 | // beginning of sol/environment.hpp | ||
19977 | |||
19978 | namespace sol { | ||
19979 | |||
19980 | template <typename base_type> | ||
19981 | struct basic_environment : basic_table<base_type> { | ||
19982 | private: | ||
19983 | typedef basic_table<base_type> base_t; | ||
19984 | |||
19985 | public: | ||
19986 | using base_t::lua_state; | ||
19987 | |||
19988 | basic_environment() noexcept = default; | ||
19989 | basic_environment(const basic_environment&) = default; | ||
19990 | basic_environment(basic_environment&&) = default; | ||
19991 | basic_environment& operator=(const basic_environment&) = default; | ||
19992 | basic_environment& operator=(basic_environment&&) = default; | ||
19993 | basic_environment(const stack_reference& r) | ||
19994 | : basic_environment(r.lua_state(), r.stack_index()) { | ||
19995 | } | ||
19996 | basic_environment(stack_reference&& r) | ||
19997 | : basic_environment(r.lua_state(), r.stack_index()) { | ||
19998 | } | ||
19999 | |||
20000 | basic_environment(lua_State* L, new_table nt) | ||
20001 | : base_t(L, std::move(nt)) { | ||
20002 | } | ||
20003 | template <bool b> | ||
20004 | basic_environment(lua_State* L, new_table t, const basic_reference<b>& fallback) | ||
20005 | : basic_environment(L, std::move(t)) { | ||
20006 | stack_table mt(L, new_table(0, 1)); | ||
20007 | mt.set(meta_function::index, fallback); | ||
20008 | this->set(metatable_key, mt); | ||
20009 | mt.pop(); | ||
20010 | } | ||
20011 | |||
20012 | basic_environment(env_t, const stack_reference& extraction_target) | ||
20013 | : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { | ||
20014 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20015 | constructor_handler handler{}; | ||
20016 | stack::check<env_t>(this->lua_state(), -1, handler); | ||
20017 | #endif // Safety | ||
20018 | lua_pop(this->lua_state(), 2); | ||
20019 | } | ||
20020 | template <bool b> | ||
20021 | basic_environment(env_t, const basic_reference<b>& extraction_target) | ||
20022 | : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { | ||
20023 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20024 | constructor_handler handler{}; | ||
20025 | stack::check<env_t>(this->lua_state(), -1, handler); | ||
20026 | #endif // Safety | ||
20027 | lua_pop(this->lua_state(), 2); | ||
20028 | } | ||
20029 | basic_environment(lua_State* L, int index = -1) | ||
20030 | : base_t(detail::no_safety, L, index) { | ||
20031 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20032 | constructor_handler handler{}; | ||
20033 | stack::check<basic_environment>(L, index, handler); | ||
20034 | #endif // Safety | ||
20035 | } | ||
20036 | basic_environment(lua_State* L, ref_index index) | ||
20037 | : base_t(detail::no_safety, L, index) { | ||
20038 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20039 | auto pp = stack::push_pop(*this); | ||
20040 | constructor_handler handler{}; | ||
20041 | stack::check<basic_environment>(L, -1, handler); | ||
20042 | #endif // Safety | ||
20043 | } | ||
20044 | template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
20045 | basic_environment(T&& r) noexcept | ||
20046 | : base_t(detail::no_safety, std::forward<T>(r)) { | ||
20047 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20048 | if (!is_environment<meta::unqualified_t<T>>::value) { | ||
20049 | auto pp = stack::push_pop(*this); | ||
20050 | constructor_handler handler{}; | ||
20051 | stack::check<basic_environment>(lua_state(), -1, handler); | ||
20052 | } | ||
20053 | #endif // Safety | ||
20054 | } | ||
20055 | basic_environment(lua_nil_t r) noexcept | ||
20056 | : base_t(detail::no_safety, r) { | ||
20057 | } | ||
20058 | |||
20059 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
20060 | basic_environment(lua_State* L, T&& r) noexcept | ||
20061 | : base_t(detail::no_safety, L, std::forward<T>(r)) { | ||
20062 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
20063 | if (!is_environment<meta::unqualified_t<T>>::value) { | ||
20064 | auto pp = stack::push_pop(*this); | ||
20065 | constructor_handler handler{}; | ||
20066 | stack::check<basic_environment>(lua_state(), -1, handler); | ||
20067 | } | ||
20068 | #endif // Safety | ||
20069 | } | ||
20070 | |||
20071 | template <typename T> | ||
20072 | void set_on(const T& target) const { | ||
20073 | lua_State* L = target.lua_state(); | ||
20074 | auto pp = stack::push_pop(target); | ||
20075 | #if SOL_LUA_VERSION < 502 | ||
20076 | // Use lua_setfenv | ||
20077 | this->push(); | ||
20078 | lua_setfenv(L, -2); | ||
20079 | #else | ||
20080 | // Use upvalues as explained in Lua 5.2 and beyond's manual | ||
20081 | this->push(); | ||
20082 | const char* name = lua_setupvalue(L, -2, 1); | ||
20083 | if (name == nullptr) { | ||
20084 | this->pop(); | ||
20085 | } | ||
20086 | #endif | ||
20087 | } | ||
20088 | }; | ||
20089 | |||
20090 | template <typename T, typename E> | ||
20091 | void set_environment(const basic_environment<E>& env, const T& target) { | ||
20092 | env.set_on(target); | ||
20093 | } | ||
20094 | |||
20095 | template <typename E = reference, typename T> | ||
20096 | basic_environment<E> get_environment(const T& target) { | ||
20097 | lua_State* L = target.lua_state(); | ||
20098 | auto pp = stack::pop_n(L, stack::push_environment_of(target)); | ||
20099 | return basic_environment<E>(L, -1); | ||
20100 | } | ||
20101 | |||
20102 | struct this_environment { | ||
20103 | optional<environment> env; | ||
20104 | |||
20105 | this_environment() | ||
20106 | : env(nullopt) { | ||
20107 | } | ||
20108 | this_environment(environment e) | ||
20109 | : env(std::move(e)) { | ||
20110 | } | ||
20111 | this_environment(const this_environment&) = default; | ||
20112 | this_environment(this_environment&&) = default; | ||
20113 | this_environment& operator=(const this_environment&) = default; | ||
20114 | this_environment& operator=(this_environment&&) = default; | ||
20115 | |||
20116 | explicit operator bool() const { | ||
20117 | return static_cast<bool>(env); | ||
20118 | } | ||
20119 | |||
20120 | operator optional<environment>&() { | ||
20121 | return env; | ||
20122 | } | ||
20123 | |||
20124 | operator const optional<environment>&() const { | ||
20125 | return env; | ||
20126 | } | ||
20127 | |||
20128 | operator environment&() { | ||
20129 | return env.value(); | ||
20130 | } | ||
20131 | |||
20132 | operator const environment&() const { | ||
20133 | return env.value(); | ||
20134 | } | ||
20135 | }; | ||
20136 | |||
20137 | namespace stack { | ||
20138 | template <> | ||
20139 | struct getter<env_t> { | ||
20140 | static environment get(lua_State* L, int index, record& tracking) { | ||
20141 | tracking.use(1); | ||
20142 | return get_environment(stack_reference(L, raw_index(index))); | ||
20143 | } | ||
20144 | }; | ||
20145 | |||
20146 | template <> | ||
20147 | struct getter<this_environment> { | ||
20148 | static this_environment get(lua_State* L, int, record& tracking) { | ||
20149 | tracking.use(0); | ||
20150 | lua_Debug info; | ||
20151 | // Level 0 means current function (this C function, which may or may not be useful for us?) | ||
20152 | // Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call) | ||
20153 | int pre_stack_size = lua_gettop(L); | ||
20154 | if (lua_getstack(L, 1, &info) != 1) { | ||
20155 | if (lua_getstack(L, 0, &info) != 1) { | ||
20156 | lua_settop(L, pre_stack_size); | ||
20157 | return this_environment(); | ||
20158 | } | ||
20159 | } | ||
20160 | if (lua_getinfo(L, "f", &info) == 0) { | ||
20161 | lua_settop(L, pre_stack_size); | ||
20162 | return this_environment(); | ||
20163 | } | ||
20164 | |||
20165 | stack_reference f(L, -1); | ||
20166 | environment env(env_key, f); | ||
20167 | if (!env.valid()) { | ||
20168 | lua_settop(L, pre_stack_size); | ||
20169 | return this_environment(); | ||
20170 | } | ||
20171 | return this_environment(std::move(env)); | ||
20172 | } | ||
20173 | }; | ||
20174 | } // namespace stack | ||
20175 | } // namespace sol | ||
20176 | |||
20177 | // end of sol/environment.hpp | ||
20178 | |||
20179 | // beginning of sol/load_result.hpp | ||
20180 | |||
20181 | namespace sol { | ||
20182 | struct load_result : public proxy_base<load_result> { | ||
20183 | private: | ||
20184 | lua_State* L; | ||
20185 | int index; | ||
20186 | int returncount; | ||
20187 | int popcount; | ||
20188 | load_status err; | ||
20189 | |||
20190 | template <typename T> | ||
20191 | decltype(auto) tagged_get(types<optional<T>>) const { | ||
20192 | if (!valid()) { | ||
20193 | return optional<T>(nullopt); | ||
20194 | } | ||
20195 | return stack::get<optional<T>>(L, index); | ||
20196 | } | ||
20197 | |||
20198 | template <typename T> | ||
20199 | decltype(auto) tagged_get(types<T>) const { | ||
20200 | #if defined(SOL_SAFE_PROXIES) && SOL_SAFE_PROXIES != 0 | ||
20201 | if (!valid()) { | ||
20202 | type_panic_c_str(L, index, type_of(L, index), type::none); | ||
20203 | } | ||
20204 | #endif // Check Argument Safety | ||
20205 | return stack::get<T>(L, index); | ||
20206 | } | ||
20207 | |||
20208 | optional<error> tagged_get(types<optional<error>>) const { | ||
20209 | if (valid()) { | ||
20210 | return nullopt; | ||
20211 | } | ||
20212 | return error(detail::direct_error, stack::get<std::string>(L, index)); | ||
20213 | } | ||
20214 | |||
20215 | error tagged_get(types<error>) const { | ||
20216 | #if defined(SOL_SAFE_PROXIES) && SOL_SAFE_PROXIES != 0 | ||
20217 | if (valid()) { | ||
20218 | type_panic_c_str(L, index, type_of(L, index), type::none, "expecting an error type (a string, from Lua)"); | ||
20219 | } | ||
20220 | #endif // Check Argument Safety | ||
20221 | return error(detail::direct_error, stack::get<std::string>(L, index)); | ||
20222 | } | ||
20223 | |||
20224 | public: | ||
20225 | load_result() = default; | ||
20226 | load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept | ||
20227 | : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) { | ||
20228 | } | ||
20229 | load_result(const load_result&) = default; | ||
20230 | load_result& operator=(const load_result&) = default; | ||
20231 | load_result(load_result&& o) noexcept | ||
20232 | : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { | ||
20233 | // Must be manual, otherwise destructor will screw us | ||
20234 | // return count being 0 is enough to keep things clean | ||
20235 | // but we will be thorough | ||
20236 | o.L = nullptr; | ||
20237 | o.index = 0; | ||
20238 | o.returncount = 0; | ||
20239 | o.popcount = 0; | ||
20240 | o.err = load_status::syntax; | ||
20241 | } | ||
20242 | load_result& operator=(load_result&& o) noexcept { | ||
20243 | L = o.L; | ||
20244 | index = o.index; | ||
20245 | returncount = o.returncount; | ||
20246 | popcount = o.popcount; | ||
20247 | err = o.err; | ||
20248 | // Must be manual, otherwise destructor will screw us | ||
20249 | // return count being 0 is enough to keep things clean | ||
20250 | // but we will be thorough | ||
20251 | o.L = nullptr; | ||
20252 | o.index = 0; | ||
20253 | o.returncount = 0; | ||
20254 | o.popcount = 0; | ||
20255 | o.err = load_status::syntax; | ||
20256 | return *this; | ||
20257 | } | ||
20258 | |||
20259 | load_status status() const noexcept { | ||
20260 | return err; | ||
20261 | } | ||
20262 | |||
20263 | bool valid() const noexcept { | ||
20264 | return status() == load_status::ok; | ||
20265 | } | ||
20266 | |||
20267 | template <typename T> | ||
20268 | T get() const { | ||
20269 | return tagged_get(types<meta::unqualified_t<T>>()); | ||
20270 | } | ||
20271 | |||
20272 | template <typename... Ret, typename... Args> | ||
20273 | decltype(auto) call(Args&&... args) { | ||
20274 | #if defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 191326131 && _MSC_FULL_VER >= 191200000 | ||
20275 | // MSVC is ass sometimes | ||
20276 | return get<protected_function>().call<Ret...>(std::forward<Args>(args)...); | ||
20277 | #else | ||
20278 | return get<protected_function>().template call<Ret...>(std::forward<Args>(args)...); | ||
20279 | #endif | ||
20280 | } | ||
20281 | |||
20282 | template <typename... Args> | ||
20283 | decltype(auto) operator()(Args&&... args) { | ||
20284 | return call<>(std::forward<Args>(args)...); | ||
20285 | } | ||
20286 | |||
20287 | lua_State* lua_state() const noexcept { | ||
20288 | return L; | ||
20289 | }; | ||
20290 | int stack_index() const noexcept { | ||
20291 | return index; | ||
20292 | }; | ||
20293 | |||
20294 | ~load_result() { | ||
20295 | stack::remove(L, index, popcount); | ||
20296 | } | ||
20297 | }; | ||
20298 | } // namespace sol | ||
20299 | |||
20300 | // end of sol/load_result.hpp | ||
20301 | |||
20302 | // beginning of sol/state_handling.hpp | ||
20303 | |||
20304 | #ifdef SOL_PRINT_ERRORS | ||
20305 | #endif | ||
20306 | |||
20307 | namespace sol { | ||
20308 | inline void register_main_thread(lua_State* L) { | ||
20309 | #if SOL_LUA_VERSION < 502 | ||
20310 | if (L == nullptr) { | ||
20311 | lua_pushnil(L); | ||
20312 | lua_setglobal(L, detail::default_main_thread_name()); | ||
20313 | return; | ||
20314 | } | ||
20315 | lua_pushthread(L); | ||
20316 | lua_setglobal(L, detail::default_main_thread_name()); | ||
20317 | #else | ||
20318 | (void)L; | ||
20319 | #endif | ||
20320 | } | ||
20321 | |||
20322 | inline int default_at_panic(lua_State* L) { | ||
20323 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
20324 | (void)L; | ||
20325 | return -1; | ||
20326 | #else | ||
20327 | size_t messagesize; | ||
20328 | const char* message = lua_tolstring(L, -1, &messagesize); | ||
20329 | if (message) { | ||
20330 | std::string err(message, messagesize); | ||
20331 | lua_settop(L, 0); | ||
20332 | #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS | ||
20333 | std::cerr << "[sol2] An error occurred and panic has been invoked: "; | ||
20334 | std::cerr << err; | ||
20335 | std::cerr << std::endl; | ||
20336 | #endif | ||
20337 | throw error(err); | ||
20338 | } | ||
20339 | lua_settop(L, 0); | ||
20340 | throw error(std::string("An unexpected error occurred and panic has been invoked")); | ||
20341 | #endif // Printing Errors | ||
20342 | } | ||
20343 | |||
20344 | inline int default_traceback_error_handler(lua_State* L) { | ||
20345 | std::string msg = "An unknown error has triggered the default error handler"; | ||
20346 | optional<string_view> maybetopmsg = stack::check_get<string_view>(L, 1); | ||
20347 | if (maybetopmsg) { | ||
20348 | const string_view& topmsg = maybetopmsg.value(); | ||
20349 | msg.assign(topmsg.data(), topmsg.size()); | ||
20350 | } | ||
20351 | luaL_traceback(L, L, msg.c_str(), 1); | ||
20352 | optional<string_view> maybetraceback = stack::check_get<string_view>(L, -1); | ||
20353 | if (maybetraceback) { | ||
20354 | const string_view& traceback = maybetraceback.value(); | ||
20355 | msg.assign(traceback.data(), traceback.size()); | ||
20356 | } | ||
20357 | #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS | ||
20358 | //std::cerr << "[sol2] An error occurred and was caught in traceback: "; | ||
20359 | //std::cerr << msg; | ||
20360 | //std::cerr << std::endl; | ||
20361 | #endif // Printing | ||
20362 | return stack::push(L, msg); | ||
20363 | } | ||
20364 | |||
20365 | inline void set_default_state(lua_State* L, lua_CFunction panic_function = &default_at_panic, lua_CFunction traceback_function = c_call<decltype(&default_traceback_error_handler), &default_traceback_error_handler>, exception_handler_function exf = detail::default_exception_handler) { | ||
20366 | lua_atpanic(L, panic_function); | ||
20367 | protected_function::set_default_handler(object(L, in_place, traceback_function)); | ||
20368 | set_default_exception_handler(L, exf); | ||
20369 | register_main_thread(L); | ||
20370 | stack::luajit_exception_handler(L); | ||
20371 | } | ||
20372 | |||
20373 | inline std::size_t total_memory_used(lua_State* L) { | ||
20374 | std::size_t kb = lua_gc(L, LUA_GCCOUNT, 0); | ||
20375 | kb *= 1024; | ||
20376 | kb += lua_gc(L, LUA_GCCOUNTB, 0); | ||
20377 | return kb; | ||
20378 | } | ||
20379 | |||
20380 | inline protected_function_result script_pass_on_error(lua_State*, protected_function_result result) { | ||
20381 | return result; | ||
20382 | } | ||
20383 | |||
20384 | inline protected_function_result script_throw_on_error(lua_State*L, protected_function_result result) { | ||
20385 | type t = type_of(L, result.stack_index()); | ||
20386 | std::string err = "sol: "; | ||
20387 | err += to_string(result.status()); | ||
20388 | err += " error"; | ||
20389 | #if !(defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS) | ||
20390 | std::exception_ptr eptr = std::current_exception(); | ||
20391 | if (eptr) { | ||
20392 | err += " with a "; | ||
20393 | try { | ||
20394 | std::rethrow_exception(eptr); | ||
20395 | } | ||
20396 | catch (const std::exception& ex) { | ||
20397 | err += "std::exception -- "; | ||
20398 | err.append(ex.what()); | ||
20399 | } | ||
20400 | catch (const std::string& message) { | ||
20401 | err += "thrown message -- "; | ||
20402 | err.append(message); | ||
20403 | } | ||
20404 | catch (const char* message) { | ||
20405 | err += "thrown message -- "; | ||
20406 | err.append(message); | ||
20407 | } | ||
20408 | catch (...) { | ||
20409 | err.append("thrown but unknown type, cannot serialize into error message"); | ||
20410 | } | ||
20411 | } | ||
20412 | #endif // serialize exception information if possible | ||
20413 | if (t == type::string) { | ||
20414 | err += ": "; | ||
20415 | string_view serr = stack::get<string_view>(L, result.stack_index()); | ||
20416 | err.append(serr.data(), serr.size()); | ||
20417 | } | ||
20418 | #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS | ||
20419 | std::cerr << "[sol2] An error occurred and has been passed to an error handler: "; | ||
20420 | std::cerr << err; | ||
20421 | std::cerr << std::endl; | ||
20422 | #endif | ||
20423 | // replacing information of stack error into pfr | ||
20424 | int target = result.stack_index(); | ||
20425 | if (result.pop_count() > 0) { | ||
20426 | stack::remove(L, target, result.pop_count()); | ||
20427 | } | ||
20428 | stack::push(L, err); | ||
20429 | int top = lua_gettop(L); | ||
20430 | int towards = top - target; | ||
20431 | if (towards != 0) { | ||
20432 | lua_rotate(L, top, towards); | ||
20433 | } | ||
20434 | #if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS | ||
20435 | return result; | ||
20436 | #else | ||
20437 | // just throw our error | ||
20438 | throw error(detail::direct_error, err); | ||
20439 | #endif // If exceptions are allowed | ||
20440 | } | ||
20441 | |||
20442 | inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) { | ||
20443 | #if defined(SOL_DEFAULT_PASS_ON_ERROR) && SOL_DEFAULT_PASS_ON_ERROR | ||
20444 | return script_pass_on_error(L, std::move(pfr)); | ||
20445 | #else | ||
20446 | return script_throw_on_error(L, std::move(pfr)); | ||
20447 | #endif | ||
20448 | } | ||
20449 | } // namespace sol | ||
20450 | |||
20451 | // end of sol/state_handling.hpp | ||
20452 | |||
20453 | namespace sol { | ||
20454 | |||
20455 | class state_view { | ||
20456 | private: | ||
20457 | lua_State* L; | ||
20458 | table reg; | ||
20459 | global_table global; | ||
20460 | |||
20461 | optional<object> is_loaded_package(const std::string& key) { | ||
20462 | auto loaded = reg.traverse_get<optional<object>>("_LOADED", key); | ||
20463 | bool is53mod = loaded && !(loaded->is<bool>() && !loaded->as<bool>()); | ||
20464 | if (is53mod) | ||
20465 | return loaded; | ||
20466 | #if SOL_LUA_VERSION <= 501 | ||
20467 | auto loaded51 = global.traverse_get<optional<object>>("package", "loaded", key); | ||
20468 | bool is51mod = loaded51 && !(loaded51->is<bool>() && !loaded51->as<bool>()); | ||
20469 | if (is51mod) | ||
20470 | return loaded51; | ||
20471 | #endif | ||
20472 | return nullopt; | ||
20473 | } | ||
20474 | |||
20475 | template <typename T> | ||
20476 | void ensure_package(const std::string& key, T&& sr) { | ||
20477 | #if SOL_LUA_VERSION <= 501 | ||
20478 | auto pkg = global["package"]; | ||
20479 | if (!pkg.valid()) { | ||
20480 | pkg = create_table_with("loaded", create_table_with(key, sr)); | ||
20481 | } | ||
20482 | else { | ||
20483 | auto ld = pkg["loaded"]; | ||
20484 | if (!ld.valid()) { | ||
20485 | ld = create_table_with(key, sr); | ||
20486 | } | ||
20487 | else { | ||
20488 | ld[key] = sr; | ||
20489 | } | ||
20490 | } | ||
20491 | #endif | ||
20492 | auto loaded = reg["_LOADED"]; | ||
20493 | if (!loaded.valid()) { | ||
20494 | loaded = create_table_with(key, sr); | ||
20495 | } | ||
20496 | else { | ||
20497 | loaded[key] = sr; | ||
20498 | } | ||
20499 | } | ||
20500 | |||
20501 | template <typename Fx> | ||
20502 | object require_core(const std::string& key, Fx&& action, bool create_global = true) { | ||
20503 | optional<object> loaded = is_loaded_package(key); | ||
20504 | if (loaded && loaded->valid()) | ||
20505 | return std::move(*loaded); | ||
20506 | action(); | ||
20507 | stack_reference sr(L, -1); | ||
20508 | if (create_global) | ||
20509 | set(key, sr); | ||
20510 | ensure_package(key, sr); | ||
20511 | return stack::pop<object>(L); | ||
20512 | } | ||
20513 | |||
20514 | public: | ||
20515 | typedef global_table::iterator iterator; | ||
20516 | typedef global_table::const_iterator const_iterator; | ||
20517 | |||
20518 | state_view(lua_State* Ls) | ||
20519 | : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, detail::global_) { | ||
20520 | } | ||
20521 | |||
20522 | state_view(this_state Ls) | ||
20523 | : state_view(Ls.L) { | ||
20524 | } | ||
20525 | |||
20526 | lua_State* lua_state() const { | ||
20527 | return L; | ||
20528 | } | ||
20529 | |||
20530 | template <typename... Args> | ||
20531 | void open_libraries(Args&&... args) { | ||
20532 | static_assert(meta::all_same<lib, Args...>::value, "all types must be libraries"); | ||
20533 | if (sizeof...(args) == 0) { | ||
20534 | luaL_openlibs(L); | ||
20535 | return; | ||
20536 | } | ||
20537 | |||
20538 | lib libraries[1 + sizeof...(args)] = {lib::count, std::forward<Args>(args)...}; | ||
20539 | |||
20540 | for (auto&& library : libraries) { | ||
20541 | switch (library) { | ||
20542 | #if SOL_LUA_VERSION <= 501 && defined(SOL_LUAJIT) | ||
20543 | case lib::coroutine: | ||
20544 | #endif // luajit opens coroutine base stuff | ||
20545 | case lib::base: | ||
20546 | luaL_requiref(L, "base", luaopen_base, 1); | ||
20547 | lua_pop(L, 1); | ||
20548 | break; | ||
20549 | case lib::package: | ||
20550 | luaL_requiref(L, "package", luaopen_package, 1); | ||
20551 | lua_pop(L, 1); | ||
20552 | break; | ||
20553 | #if !defined(SOL_LUAJIT) | ||
20554 | case lib::coroutine: | ||
20555 | #if SOL_LUA_VERSION > 501 | ||
20556 | luaL_requiref(L, "coroutine", luaopen_coroutine, 1); | ||
20557 | lua_pop(L, 1); | ||
20558 | #endif // Lua 5.2+ only | ||
20559 | break; | ||
20560 | #endif // Not LuaJIT - comes builtin | ||
20561 | case lib::string: | ||
20562 | luaL_requiref(L, "string", luaopen_string, 1); | ||
20563 | lua_pop(L, 1); | ||
20564 | break; | ||
20565 | case lib::table: | ||
20566 | luaL_requiref(L, "table", luaopen_table, 1); | ||
20567 | lua_pop(L, 1); | ||
20568 | break; | ||
20569 | case lib::math: | ||
20570 | luaL_requiref(L, "math", luaopen_math, 1); | ||
20571 | lua_pop(L, 1); | ||
20572 | break; | ||
20573 | case lib::bit32: | ||
20574 | #ifdef SOL_LUAJIT | ||
20575 | luaL_requiref(L, "bit32", luaopen_bit, 1); | ||
20576 | lua_pop(L, 1); | ||
20577 | #elif (SOL_LUA_VERSION == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2) | ||
20578 | luaL_requiref(L, "bit32", luaopen_bit32, 1); | ||
20579 | lua_pop(L, 1); | ||
20580 | #else | ||
20581 | #endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) | ||
20582 | break; | ||
20583 | case lib::io: | ||
20584 | luaL_requiref(L, "io", luaopen_io, 1); | ||
20585 | lua_pop(L, 1); | ||
20586 | break; | ||
20587 | case lib::os: | ||
20588 | luaL_requiref(L, "os", luaopen_os, 1); | ||
20589 | lua_pop(L, 1); | ||
20590 | break; | ||
20591 | case lib::debug: | ||
20592 | luaL_requiref(L, "debug", luaopen_debug, 1); | ||
20593 | lua_pop(L, 1); | ||
20594 | break; | ||
20595 | case lib::utf8: | ||
20596 | #if SOL_LUA_VERSION > 502 && !defined(SOL_LUAJIT) | ||
20597 | luaL_requiref(L, "utf8", luaopen_utf8, 1); | ||
20598 | lua_pop(L, 1); | ||
20599 | #endif // Lua 5.3+ only | ||
20600 | break; | ||
20601 | case lib::ffi: | ||
20602 | #ifdef SOL_LUAJIT | ||
20603 | luaL_requiref(L, "ffi", luaopen_ffi, 1); | ||
20604 | lua_pop(L, 1); | ||
20605 | #endif // LuaJIT only | ||
20606 | break; | ||
20607 | case lib::jit: | ||
20608 | #ifdef SOL_LUAJIT | ||
20609 | luaL_requiref(L, "jit", luaopen_jit, 0); | ||
20610 | lua_pop(L, 1); | ||
20611 | #endif // LuaJIT Only | ||
20612 | break; | ||
20613 | case lib::count: | ||
20614 | default: | ||
20615 | break; | ||
20616 | } | ||
20617 | } | ||
20618 | } | ||
20619 | |||
20620 | object require(const std::string& key, lua_CFunction open_function, bool create_global = true) { | ||
20621 | luaL_requiref(L, key.c_str(), open_function, create_global ? 1 : 0); | ||
20622 | return stack::pop<object>(L); | ||
20623 | } | ||
20624 | |||
20625 | object require_script(const std::string& key, const string_view& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20626 | auto action = [this, &code, &chunkname, &mode]() { | ||
20627 | stack::script(L, code, chunkname, mode); | ||
20628 | }; | ||
20629 | return require_core(key, action, create_global); | ||
20630 | } | ||
20631 | |||
20632 | object require_file(const std::string& key, const std::string& filename, bool create_global = true, load_mode mode = load_mode::any) { | ||
20633 | auto action = [this, &filename, &mode]() { | ||
20634 | stack::script_file(L, filename, mode); | ||
20635 | }; | ||
20636 | return require_core(key, action, create_global); | ||
20637 | } | ||
20638 | |||
20639 | template <typename E> | ||
20640 | protected_function_result do_string(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20641 | detail::typical_chunk_name_t basechunkname = {}; | ||
20642 | const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); | ||
20643 | load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); | ||
20644 | if (x != load_status::ok) { | ||
20645 | return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); | ||
20646 | } | ||
20647 | stack_aligned_protected_function pf(L, -1); | ||
20648 | set_environment(env, pf); | ||
20649 | return pf(); | ||
20650 | } | ||
20651 | |||
20652 | template <typename E> | ||
20653 | protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { | ||
20654 | load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); | ||
20655 | if (x != load_status::ok) { | ||
20656 | return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); | ||
20657 | } | ||
20658 | stack_aligned_protected_function pf(L, -1); | ||
20659 | set_environment(env, pf); | ||
20660 | return pf(); | ||
20661 | } | ||
20662 | |||
20663 | protected_function_result do_string(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20664 | detail::typical_chunk_name_t basechunkname = {}; | ||
20665 | const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); | ||
20666 | load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); | ||
20667 | if (x != load_status::ok) { | ||
20668 | return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); | ||
20669 | } | ||
20670 | stack_aligned_protected_function pf(L, -1); | ||
20671 | return pf(); | ||
20672 | } | ||
20673 | |||
20674 | protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20675 | load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); | ||
20676 | if (x != load_status::ok) { | ||
20677 | return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast<call_status>(x)); | ||
20678 | } | ||
20679 | stack_aligned_protected_function pf(L, -1); | ||
20680 | return pf(); | ||
20681 | } | ||
20682 | |||
20683 | template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> | ||
20684 | protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20685 | protected_function_result pfr = do_string(code, chunkname, mode); | ||
20686 | if (!pfr.valid()) { | ||
20687 | return on_error(L, std::move(pfr)); | ||
20688 | } | ||
20689 | return pfr; | ||
20690 | } | ||
20691 | |||
20692 | template <typename Fx, typename E> | ||
20693 | protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20694 | protected_function_result pfr = do_string(code, env, chunkname, mode); | ||
20695 | if (!pfr.valid()) { | ||
20696 | return on_error(L, std::move(pfr)); | ||
20697 | } | ||
20698 | return pfr; | ||
20699 | } | ||
20700 | |||
20701 | template <typename E> | ||
20702 | protected_function_result safe_script(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20703 | return safe_script(code, env, script_default_on_error, chunkname, mode); | ||
20704 | } | ||
20705 | |||
20706 | protected_function_result safe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20707 | return safe_script(code, script_default_on_error, chunkname, mode); | ||
20708 | } | ||
20709 | |||
20710 | template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> | ||
20711 | protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { | ||
20712 | protected_function_result pfr = do_file(filename, mode); | ||
20713 | if (!pfr.valid()) { | ||
20714 | return on_error(L, std::move(pfr)); | ||
20715 | } | ||
20716 | return pfr; | ||
20717 | } | ||
20718 | |||
20719 | template <typename Fx, typename E> | ||
20720 | protected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) { | ||
20721 | protected_function_result pfr = do_file(filename, env, mode); | ||
20722 | if (!pfr.valid()) { | ||
20723 | return on_error(L, std::move(pfr)); | ||
20724 | } | ||
20725 | return pfr; | ||
20726 | } | ||
20727 | |||
20728 | template <typename E> | ||
20729 | protected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { | ||
20730 | return safe_script_file(filename, env, script_default_on_error, mode); | ||
20731 | } | ||
20732 | |||
20733 | protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20734 | return safe_script_file(filename, script_default_on_error, mode); | ||
20735 | } | ||
20736 | |||
20737 | template <typename E> | ||
20738 | unsafe_function_result unsafe_script(const string_view& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20739 | detail::typical_chunk_name_t basechunkname = {}; | ||
20740 | const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); | ||
20741 | int index = lua_gettop(L); | ||
20742 | if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())) { | ||
20743 | lua_error(L); | ||
20744 | } | ||
20745 | set_environment(env, stack_reference(L, raw_index(index + 1))); | ||
20746 | if (lua_pcall(L, 0, LUA_MULTRET, 0)) { | ||
20747 | lua_error(L); | ||
20748 | } | ||
20749 | int postindex = lua_gettop(L); | ||
20750 | int returns = postindex - index; | ||
20751 | return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); | ||
20752 | } | ||
20753 | |||
20754 | unsafe_function_result unsafe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20755 | int index = lua_gettop(L); | ||
20756 | stack::script(L, code, chunkname, mode); | ||
20757 | int postindex = lua_gettop(L); | ||
20758 | int returns = postindex - index; | ||
20759 | return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); | ||
20760 | } | ||
20761 | |||
20762 | template <typename E> | ||
20763 | unsafe_function_result unsafe_script_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) { | ||
20764 | int index = lua_gettop(L); | ||
20765 | if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())) { | ||
20766 | lua_error(L); | ||
20767 | } | ||
20768 | set_environment(env, stack_reference(L, raw_index(index + 1))); | ||
20769 | if (lua_pcall(L, 0, LUA_MULTRET, 0)) { | ||
20770 | lua_error(L); | ||
20771 | } | ||
20772 | int postindex = lua_gettop(L); | ||
20773 | int returns = postindex - index; | ||
20774 | return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); | ||
20775 | } | ||
20776 | |||
20777 | unsafe_function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20778 | int index = lua_gettop(L); | ||
20779 | stack::script_file(L, filename, mode); | ||
20780 | int postindex = lua_gettop(L); | ||
20781 | int returns = postindex - index; | ||
20782 | return unsafe_function_result(L, (std::max)(postindex - (returns - 1), 1), returns); | ||
20783 | } | ||
20784 | |||
20785 | template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> | ||
20786 | protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20787 | return safe_script(code, std::forward<Fx>(on_error), chunkname, mode); | ||
20788 | } | ||
20789 | |||
20790 | template <typename Fx, meta::disable_any<meta::is_string_constructible<meta::unqualified_t<Fx>>, meta::is_specialization_of<meta::unqualified_t<Fx>, basic_environment>> = meta::enabler> | ||
20791 | protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { | ||
20792 | return safe_script_file(filename, std::forward<Fx>(on_error), mode); | ||
20793 | } | ||
20794 | |||
20795 | template <typename Fx, typename E> | ||
20796 | protected_function_result script(const string_view& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20797 | return safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode); | ||
20798 | } | ||
20799 | |||
20800 | template <typename Fx, typename E> | ||
20801 | protected_function_result script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) { | ||
20802 | return safe_script_file(filename, env, std::forward<Fx>(on_error), mode); | ||
20803 | } | ||
20804 | |||
20805 | protected_function_result script(const string_view& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20806 | return safe_script(code, env, script_default_on_error, chunkname, mode); | ||
20807 | } | ||
20808 | |||
20809 | protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) { | ||
20810 | return safe_script_file(filename, env, script_default_on_error, mode); | ||
20811 | } | ||
20812 | |||
20813 | #if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION | ||
20814 | protected_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20815 | return safe_script(code, chunkname, mode); | ||
20816 | } | ||
20817 | |||
20818 | protected_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20819 | return safe_script_file(filename, mode); | ||
20820 | } | ||
20821 | #else | ||
20822 | unsafe_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20823 | return unsafe_script(code, chunkname, mode); | ||
20824 | } | ||
20825 | |||
20826 | unsafe_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20827 | return unsafe_script_file(filename, mode); | ||
20828 | } | ||
20829 | #endif | ||
20830 | load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20831 | detail::typical_chunk_name_t basechunkname = {}; | ||
20832 | const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); | ||
20833 | load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); | ||
20834 | return load_result(L, absolute_index(L, -1), 1, 1, x); | ||
20835 | } | ||
20836 | |||
20837 | load_result load_buffer(const char* buff, size_t size, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20838 | return load(string_view(buff, size), chunkname, mode); | ||
20839 | } | ||
20840 | |||
20841 | load_result load_file(const std::string& filename, load_mode mode = load_mode::any) { | ||
20842 | load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); | ||
20843 | return load_result(L, absolute_index(L, -1), 1, 1, x); | ||
20844 | } | ||
20845 | |||
20846 | load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { | ||
20847 | detail::typical_chunk_name_t basechunkname = {}; | ||
20848 | const char* chunknametarget = detail::make_chunk_name("lua_Reader", chunkname, basechunkname); | ||
20849 | load_status x = static_cast<load_status>(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); | ||
20850 | return load_result(L, absolute_index(L, -1), 1, 1, x); | ||
20851 | } | ||
20852 | |||
20853 | iterator begin() const { | ||
20854 | return global.begin(); | ||
20855 | } | ||
20856 | |||
20857 | iterator end() const { | ||
20858 | return global.end(); | ||
20859 | } | ||
20860 | |||
20861 | const_iterator cbegin() const { | ||
20862 | return global.cbegin(); | ||
20863 | } | ||
20864 | |||
20865 | const_iterator cend() const { | ||
20866 | return global.cend(); | ||
20867 | } | ||
20868 | |||
20869 | global_table globals() const { | ||
20870 | return global; | ||
20871 | } | ||
20872 | |||
20873 | table registry() const { | ||
20874 | return reg; | ||
20875 | } | ||
20876 | |||
20877 | std::size_t memory_used() const { | ||
20878 | return total_memory_used(lua_state()); | ||
20879 | } | ||
20880 | |||
20881 | int stack_top() const { | ||
20882 | return stack::top(L); | ||
20883 | } | ||
20884 | |||
20885 | int stack_clear() { | ||
20886 | int s = stack_top(); | ||
20887 | lua_pop(L, s); | ||
20888 | return s; | ||
20889 | } | ||
20890 | |||
20891 | void collect_garbage() { | ||
20892 | lua_gc(lua_state(), LUA_GCCOLLECT, 0); | ||
20893 | } | ||
20894 | |||
20895 | operator lua_State*() const { | ||
20896 | return lua_state(); | ||
20897 | } | ||
20898 | |||
20899 | void set_panic(lua_CFunction panic) { | ||
20900 | lua_atpanic(lua_state(), panic); | ||
20901 | } | ||
20902 | |||
20903 | void set_exception_handler(exception_handler_function handler) { | ||
20904 | set_default_exception_handler(lua_state(), handler); | ||
20905 | } | ||
20906 | |||
20907 | template <typename... Args, typename... Keys> | ||
20908 | decltype(auto) get(Keys&&... keys) const { | ||
20909 | return global.get<Args...>(std::forward<Keys>(keys)...); | ||
20910 | } | ||
20911 | |||
20912 | template <typename T, typename Key> | ||
20913 | decltype(auto) get_or(Key&& key, T&& otherwise) const { | ||
20914 | return global.get_or(std::forward<Key>(key), std::forward<T>(otherwise)); | ||
20915 | } | ||
20916 | |||
20917 | template <typename T, typename Key, typename D> | ||
20918 | decltype(auto) get_or(Key&& key, D&& otherwise) const { | ||
20919 | return global.get_or<T>(std::forward<Key>(key), std::forward<D>(otherwise)); | ||
20920 | } | ||
20921 | |||
20922 | template <typename... Args> | ||
20923 | state_view& set(Args&&... args) { | ||
20924 | global.set(std::forward<Args>(args)...); | ||
20925 | return *this; | ||
20926 | } | ||
20927 | |||
20928 | template <typename T, typename... Keys> | ||
20929 | decltype(auto) traverse_get(Keys&&... keys) const { | ||
20930 | return global.traverse_get<T>(std::forward<Keys>(keys)...); | ||
20931 | } | ||
20932 | |||
20933 | template <typename... Args> | ||
20934 | state_view& traverse_set(Args&&... args) { | ||
20935 | global.traverse_set(std::forward<Args>(args)...); | ||
20936 | return *this; | ||
20937 | } | ||
20938 | |||
20939 | template <typename T> | ||
20940 | state_view& set_usertype(usertype<T>& user) { | ||
20941 | return set_usertype(usertype_traits<T>::name(), user); | ||
20942 | } | ||
20943 | |||
20944 | template <typename Key, typename T> | ||
20945 | state_view& set_usertype(Key&& key, usertype<T>& user) { | ||
20946 | global.set_usertype(std::forward<Key>(key), user); | ||
20947 | return *this; | ||
20948 | } | ||
20949 | |||
20950 | template <typename Class, typename... Args> | ||
20951 | state_view& new_usertype(const std::string& name, Args&&... args) { | ||
20952 | global.new_usertype<Class>(name, std::forward<Args>(args)...); | ||
20953 | return *this; | ||
20954 | } | ||
20955 | |||
20956 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
20957 | state_view& new_usertype(const std::string& name, Args&&... args) { | ||
20958 | global.new_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...); | ||
20959 | return *this; | ||
20960 | } | ||
20961 | |||
20962 | template <typename Class, typename... CArgs, typename... Args> | ||
20963 | state_view& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { | ||
20964 | global.new_usertype<Class>(name, ctor, std::forward<Args>(args)...); | ||
20965 | return *this; | ||
20966 | } | ||
20967 | |||
20968 | template <typename Class, typename... Args> | ||
20969 | state_view& new_simple_usertype(const std::string& name, Args&&... args) { | ||
20970 | global.new_simple_usertype<Class>(name, std::forward<Args>(args)...); | ||
20971 | return *this; | ||
20972 | } | ||
20973 | |||
20974 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
20975 | state_view& new_simple_usertype(const std::string& name, Args&&... args) { | ||
20976 | global.new_simple_usertype<Class, CTor0, CTor...>(name, std::forward<Args>(args)...); | ||
20977 | return *this; | ||
20978 | } | ||
20979 | |||
20980 | template <typename Class, typename... CArgs, typename... Args> | ||
20981 | state_view& new_simple_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args) { | ||
20982 | global.new_simple_usertype<Class>(name, ctor, std::forward<Args>(args)...); | ||
20983 | return *this; | ||
20984 | } | ||
20985 | |||
20986 | template <typename Class, typename... Args> | ||
20987 | simple_usertype<Class> create_simple_usertype(Args&&... args) { | ||
20988 | return global.create_simple_usertype<Class>(std::forward<Args>(args)...); | ||
20989 | } | ||
20990 | |||
20991 | template <typename Class, typename CTor0, typename... CTor, typename... Args> | ||
20992 | simple_usertype<Class> create_simple_usertype(Args&&... args) { | ||
20993 | return global.create_simple_usertype<Class, CTor0, CTor...>(std::forward<Args>(args)...); | ||
20994 | } | ||
20995 | |||
20996 | template <typename Class, typename... CArgs, typename... Args> | ||
20997 | simple_usertype<Class> create_simple_usertype(constructors<CArgs...> ctor, Args&&... args) { | ||
20998 | return global.create_simple_usertype<Class>(ctor, std::forward<Args>(args)...); | ||
20999 | } | ||
21000 | |||
21001 | template <bool read_only = true, typename... Args> | ||
21002 | state_view& new_enum(const string_view& name, Args&&... args) { | ||
21003 | global.new_enum<read_only>(name, std::forward<Args>(args)...); | ||
21004 | return *this; | ||
21005 | } | ||
21006 | |||
21007 | template <typename T, bool read_only = true> | ||
21008 | state_view& new_enum(const string_view& name, std::initializer_list<std::pair<string_view, T>> items) { | ||
21009 | global.new_enum<T, read_only>(name, std::move(items)); | ||
21010 | return *this; | ||
21011 | } | ||
21012 | |||
21013 | template <typename Fx> | ||
21014 | void for_each(Fx&& fx) { | ||
21015 | global.for_each(std::forward<Fx>(fx)); | ||
21016 | } | ||
21017 | |||
21018 | template <typename T> | ||
21019 | proxy<global_table&, T> operator[](T&& key) { | ||
21020 | return global[std::forward<T>(key)]; | ||
21021 | } | ||
21022 | |||
21023 | template <typename T> | ||
21024 | proxy<const global_table&, T> operator[](T&& key) const { | ||
21025 | return global[std::forward<T>(key)]; | ||
21026 | } | ||
21027 | |||
21028 | template <typename Sig, typename... Args, typename Key> | ||
21029 | state_view& set_function(Key&& key, Args&&... args) { | ||
21030 | global.set_function<Sig>(std::forward<Key>(key), std::forward<Args>(args)...); | ||
21031 | return *this; | ||
21032 | } | ||
21033 | |||
21034 | template <typename... Args, typename Key> | ||
21035 | state_view& set_function(Key&& key, Args&&... args) { | ||
21036 | global.set_function(std::forward<Key>(key), std::forward<Args>(args)...); | ||
21037 | return *this; | ||
21038 | } | ||
21039 | |||
21040 | template <typename Name> | ||
21041 | table create_table(Name&& name, int narr = 0, int nrec = 0) { | ||
21042 | return global.create(std::forward<Name>(name), narr, nrec); | ||
21043 | } | ||
21044 | |||
21045 | template <typename Name, typename Key, typename Value, typename... Args> | ||
21046 | table create_table(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
21047 | return global.create(std::forward<Name>(name), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
21048 | } | ||
21049 | |||
21050 | template <typename Name, typename... Args> | ||
21051 | table create_named_table(Name&& name, Args&&... args) { | ||
21052 | table x = global.create_with(std::forward<Args>(args)...); | ||
21053 | global.set(std::forward<Name>(name), x); | ||
21054 | return x; | ||
21055 | } | ||
21056 | |||
21057 | table create_table(int narr = 0, int nrec = 0) { | ||
21058 | return create_table(lua_state(), narr, nrec); | ||
21059 | } | ||
21060 | |||
21061 | template <typename Key, typename Value, typename... Args> | ||
21062 | table create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
21063 | return create_table(lua_state(), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
21064 | } | ||
21065 | |||
21066 | template <typename... Args> | ||
21067 | table create_table_with(Args&&... args) { | ||
21068 | return create_table_with(lua_state(), std::forward<Args>(args)...); | ||
21069 | } | ||
21070 | |||
21071 | static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) { | ||
21072 | return global_table::create(L, narr, nrec); | ||
21073 | } | ||
21074 | |||
21075 | template <typename Key, typename Value, typename... Args> | ||
21076 | static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { | ||
21077 | return global_table::create(L, narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...); | ||
21078 | } | ||
21079 | |||
21080 | template <typename... Args> | ||
21081 | static inline table create_table_with(lua_State* L, Args&&... args) { | ||
21082 | return global_table::create_with(L, std::forward<Args>(args)...); | ||
21083 | } | ||
21084 | }; | ||
21085 | } // namespace sol | ||
21086 | |||
21087 | // end of sol/state_view.hpp | ||
21088 | |||
21089 | // beginning of sol/thread.hpp | ||
21090 | |||
21091 | namespace sol { | ||
21092 | struct lua_thread_state { | ||
21093 | lua_State* L; | ||
21094 | |||
21095 | lua_thread_state(lua_State* Ls) | ||
21096 | : L(Ls) { | ||
21097 | } | ||
21098 | |||
21099 | lua_State* lua_state() const noexcept { | ||
21100 | return L; | ||
21101 | } | ||
21102 | operator lua_State*() const noexcept { | ||
21103 | return lua_state(); | ||
21104 | } | ||
21105 | lua_State* operator->() const noexcept { | ||
21106 | return lua_state(); | ||
21107 | } | ||
21108 | }; | ||
21109 | |||
21110 | namespace stack { | ||
21111 | template <> | ||
21112 | struct pusher<lua_thread_state> { | ||
21113 | int push(lua_State*, lua_thread_state lts) { | ||
21114 | lua_pushthread(lts.L); | ||
21115 | return 1; | ||
21116 | } | ||
21117 | }; | ||
21118 | |||
21119 | template <> | ||
21120 | struct getter<lua_thread_state> { | ||
21121 | lua_thread_state get(lua_State* L, int index, record& tracking) { | ||
21122 | tracking.use(1); | ||
21123 | lua_thread_state lts( lua_tothread(L, index) ); | ||
21124 | return lts; | ||
21125 | } | ||
21126 | }; | ||
21127 | |||
21128 | template <> | ||
21129 | struct check_getter<lua_thread_state> { | ||
21130 | template <typename Handler> | ||
21131 | optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) { | ||
21132 | lua_thread_state lts( lua_tothread(L, index) ); | ||
21133 | if (lts.lua_state() == nullptr) { | ||
21134 | handler(L, index, type::thread, type_of(L, index), "value is not a valid thread type"); | ||
21135 | return nullopt; | ||
21136 | } | ||
21137 | tracking.use(1); | ||
21138 | return lts; | ||
21139 | } | ||
21140 | }; | ||
21141 | } // namespace stack | ||
21142 | |||
21143 | template <typename base_t> | ||
21144 | class basic_thread : public base_t { | ||
21145 | public: | ||
21146 | using base_t::lua_state; | ||
21147 | |||
21148 | basic_thread() noexcept = default; | ||
21149 | basic_thread(const basic_thread&) = default; | ||
21150 | basic_thread(basic_thread&&) = default; | ||
21151 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_thread>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
21152 | basic_thread(T&& r) | ||
21153 | : base_t(std::forward<T>(r)) { | ||
21154 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21155 | auto pp = stack::push_pop(*this); | ||
21156 | constructor_handler handler{}; | ||
21157 | stack::check<basic_thread>(lua_state(), -1, handler); | ||
21158 | #endif // Safety | ||
21159 | } | ||
21160 | basic_thread(const stack_reference& r) | ||
21161 | : basic_thread(r.lua_state(), r.stack_index()){}; | ||
21162 | basic_thread(stack_reference&& r) | ||
21163 | : basic_thread(r.lua_state(), r.stack_index()){}; | ||
21164 | basic_thread& operator=(const basic_thread&) = default; | ||
21165 | basic_thread& operator=(basic_thread&&) = default; | ||
21166 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
21167 | basic_thread(lua_State* L, T&& r) | ||
21168 | : base_t(L, std::forward<T>(r)) { | ||
21169 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21170 | auto pp = stack::push_pop(*this); | ||
21171 | constructor_handler handler{}; | ||
21172 | stack::check<basic_thread>(lua_state(), -1, handler); | ||
21173 | #endif // Safety | ||
21174 | } | ||
21175 | basic_thread(lua_State* L, int index = -1) | ||
21176 | : base_t(L, index) { | ||
21177 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21178 | constructor_handler handler{}; | ||
21179 | stack::check<basic_thread>(L, index, handler); | ||
21180 | #endif // Safety | ||
21181 | } | ||
21182 | basic_thread(lua_State* L, ref_index index) | ||
21183 | : base_t(L, index) { | ||
21184 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21185 | auto pp = stack::push_pop(*this); | ||
21186 | constructor_handler handler{}; | ||
21187 | stack::check<basic_thread>(lua_state(), -1, handler); | ||
21188 | #endif // Safety | ||
21189 | } | ||
21190 | basic_thread(lua_State* L, lua_State* actualthread) | ||
21191 | : basic_thread(L, lua_thread_state{ actualthread }) { | ||
21192 | } | ||
21193 | basic_thread(lua_State* L, this_state actualthread) | ||
21194 | : basic_thread(L, lua_thread_state{ actualthread.L }) { | ||
21195 | } | ||
21196 | basic_thread(lua_State* L, lua_thread_state actualthread) | ||
21197 | : base_t(L, -stack::push(L, actualthread)) { | ||
21198 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21199 | constructor_handler handler{}; | ||
21200 | stack::check<basic_thread>(lua_state(), -1, handler); | ||
21201 | #endif // Safety | ||
21202 | if (!is_stack_based<base_t>::value) { | ||
21203 | lua_pop(lua_state(), 1); | ||
21204 | } | ||
21205 | } | ||
21206 | |||
21207 | state_view state() const { | ||
21208 | return state_view(this->thread_state()); | ||
21209 | } | ||
21210 | |||
21211 | bool is_main_thread() const { | ||
21212 | return stack::is_main_thread(this->thread_state()); | ||
21213 | } | ||
21214 | |||
21215 | lua_State* thread_state() const { | ||
21216 | auto pp = stack::push_pop(*this); | ||
21217 | lua_State* lthread = lua_tothread(lua_state(), -1); | ||
21218 | return lthread; | ||
21219 | } | ||
21220 | |||
21221 | thread_status status() const { | ||
21222 | lua_State* lthread = thread_state(); | ||
21223 | auto lstat = static_cast<thread_status>(lua_status(lthread)); | ||
21224 | if (lstat == thread_status::ok) { | ||
21225 | lua_Debug ar; | ||
21226 | if (lua_getstack(lthread, 0, &ar) > 0) | ||
21227 | return thread_status::ok; | ||
21228 | else if (lua_gettop(lthread) == 0) | ||
21229 | return thread_status::dead; | ||
21230 | else | ||
21231 | return thread_status::yielded; | ||
21232 | } | ||
21233 | return lstat; | ||
21234 | } | ||
21235 | |||
21236 | basic_thread create() { | ||
21237 | return create(lua_state()); | ||
21238 | } | ||
21239 | |||
21240 | static basic_thread create(lua_State* L) { | ||
21241 | lua_newthread(L); | ||
21242 | basic_thread result(L); | ||
21243 | if (!is_stack_based<base_t>::value) { | ||
21244 | lua_pop(L, 1); | ||
21245 | } | ||
21246 | return result; | ||
21247 | } | ||
21248 | }; | ||
21249 | |||
21250 | typedef basic_thread<reference> thread; | ||
21251 | typedef basic_thread<stack_reference> stack_thread; | ||
21252 | } // namespace sol | ||
21253 | |||
21254 | // end of sol/thread.hpp | ||
21255 | |||
21256 | namespace sol { | ||
21257 | |||
21258 | class state : private std::unique_ptr<lua_State, detail::state_deleter>, public state_view { | ||
21259 | private: | ||
21260 | typedef std::unique_ptr<lua_State, detail::state_deleter> unique_base; | ||
21261 | |||
21262 | public: | ||
21263 | state(lua_CFunction panic = default_at_panic) | ||
21264 | : unique_base(luaL_newstate()), state_view(unique_base::get()) { | ||
21265 | set_default_state(unique_base::get(), panic); | ||
21266 | } | ||
21267 | |||
21268 | state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) | ||
21269 | : unique_base(lua_newstate(alfunc, alpointer)), state_view(unique_base::get()) { | ||
21270 | set_default_state(unique_base::get(), panic); | ||
21271 | } | ||
21272 | |||
21273 | state(const state&) = delete; | ||
21274 | state(state&&) = default; | ||
21275 | state& operator=(const state&) = delete; | ||
21276 | state& operator=(state&& that) { | ||
21277 | state_view::operator=(std::move(that)); | ||
21278 | unique_base::operator=(std::move(that)); | ||
21279 | return *this; | ||
21280 | } | ||
21281 | |||
21282 | using state_view::get; | ||
21283 | |||
21284 | ~state() { | ||
21285 | } | ||
21286 | }; | ||
21287 | } // namespace sol | ||
21288 | |||
21289 | // end of sol/state.hpp | ||
21290 | |||
21291 | // beginning of sol/coroutine.hpp | ||
21292 | |||
21293 | namespace sol { | ||
21294 | template <typename base_t> | ||
21295 | class basic_coroutine : public base_t { | ||
21296 | public: | ||
21297 | typedef reference handler_t; | ||
21298 | handler_t error_handler; | ||
21299 | |||
21300 | private: | ||
21301 | call_status stats = call_status::yielded; | ||
21302 | |||
21303 | void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) { | ||
21304 | stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount))); | ||
21305 | } | ||
21306 | |||
21307 | template <std::size_t... I, typename... Ret> | ||
21308 | auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) { | ||
21309 | luacall(n, sizeof...(Ret)); | ||
21310 | return stack::pop<std::tuple<Ret...>>(lua_state()); | ||
21311 | } | ||
21312 | |||
21313 | template <std::size_t I, typename Ret> | ||
21314 | Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) { | ||
21315 | luacall(n, 1); | ||
21316 | return stack::pop<Ret>(lua_state()); | ||
21317 | } | ||
21318 | |||
21319 | template <std::size_t I> | ||
21320 | void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) { | ||
21321 | luacall(n, 0); | ||
21322 | } | ||
21323 | |||
21324 | protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { | ||
21325 | int firstreturn = 1; | ||
21326 | luacall(n, LUA_MULTRET); | ||
21327 | int poststacksize = lua_gettop(this->lua_state()); | ||
21328 | int returncount = poststacksize - (firstreturn - 1); | ||
21329 | if (error()) { | ||
21330 | if (error_handler.valid()) { | ||
21331 | string_view err = stack::get<string_view>(this->lua_state(), poststacksize); | ||
21332 | error_handler.push(); | ||
21333 | stack::push(this->lua_state(), err); | ||
21334 | lua_call(lua_state(), 1, 1); | ||
21335 | } | ||
21336 | return protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status()); | ||
21337 | } | ||
21338 | return protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status()); | ||
21339 | } | ||
21340 | |||
21341 | public: | ||
21342 | using base_t::lua_state; | ||
21343 | |||
21344 | basic_coroutine() = default; | ||
21345 | template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_coroutine>>, meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>>, meta::neg<std::is_same<base_t, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
21346 | basic_coroutine(T&& r) noexcept | ||
21347 | : base_t(std::forward<T>(r)), error_handler(detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { | ||
21348 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21349 | if (!is_function<meta::unqualified_t<T>>::value) { | ||
21350 | auto pp = stack::push_pop(*this); | ||
21351 | constructor_handler handler{}; | ||
21352 | stack::check<basic_coroutine>(lua_state(), -1, handler); | ||
21353 | } | ||
21354 | #endif // Safety | ||
21355 | } | ||
21356 | basic_coroutine(const basic_coroutine&) = default; | ||
21357 | basic_coroutine& operator=(const basic_coroutine&) = default; | ||
21358 | basic_coroutine(basic_coroutine&&) = default; | ||
21359 | basic_coroutine& operator=(basic_coroutine&&) = default; | ||
21360 | basic_coroutine(const basic_function<base_t>& b) | ||
21361 | : basic_coroutine(b, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { | ||
21362 | } | ||
21363 | basic_coroutine(basic_function<base_t>&& b) | ||
21364 | : basic_coroutine(std::move(b), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(b.lua_state())) { | ||
21365 | } | ||
21366 | basic_coroutine(const basic_function<base_t>& b, handler_t eh) | ||
21367 | : base_t(b), error_handler(std::move(eh)) { | ||
21368 | } | ||
21369 | basic_coroutine(basic_function<base_t>&& b, handler_t eh) | ||
21370 | : base_t(std::move(b)), error_handler(std::move(eh)) { | ||
21371 | } | ||
21372 | basic_coroutine(const stack_reference& r) | ||
21373 | : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { | ||
21374 | } | ||
21375 | basic_coroutine(stack_reference&& r) | ||
21376 | : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(r.lua_state())) { | ||
21377 | } | ||
21378 | basic_coroutine(const stack_reference& r, handler_t eh) | ||
21379 | : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { | ||
21380 | } | ||
21381 | basic_coroutine(stack_reference&& r, handler_t eh) | ||
21382 | : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { | ||
21383 | } | ||
21384 | |||
21385 | template <typename Super> | ||
21386 | basic_coroutine(const proxy_base<Super>& p) | ||
21387 | : basic_coroutine(p, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) { | ||
21388 | } | ||
21389 | template <typename Super> | ||
21390 | basic_coroutine(proxy_base<Super>&& p) | ||
21391 | : basic_coroutine(std::move(p), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(p.lua_state())) { | ||
21392 | } | ||
21393 | template <typename Proxy, typename Handler, meta::enable<std::is_base_of<proxy_base_tag, meta::unqualified_t<Proxy>>, meta::neg<is_lua_index<meta::unqualified_t<Handler>>>> = meta::enabler> | ||
21394 | basic_coroutine(Proxy&& p, Handler&& eh) | ||
21395 | : basic_coroutine(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) { | ||
21396 | } | ||
21397 | |||
21398 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
21399 | basic_coroutine(lua_State* L, T&& r) | ||
21400 | : basic_coroutine(L, std::forward<T>(r), detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { | ||
21401 | } | ||
21402 | template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> | ||
21403 | basic_coroutine(lua_State* L, T&& r, handler_t eh) | ||
21404 | : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) { | ||
21405 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21406 | auto pp = stack::push_pop(*this); | ||
21407 | constructor_handler handler{}; | ||
21408 | stack::check<basic_coroutine>(lua_state(), -1, handler); | ||
21409 | #endif // Safety | ||
21410 | } | ||
21411 | |||
21412 | basic_coroutine(lua_nil_t n) | ||
21413 | : base_t(n), error_handler(n) { | ||
21414 | } | ||
21415 | |||
21416 | basic_coroutine(lua_State* L, int index = -1) | ||
21417 | : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { | ||
21418 | } | ||
21419 | basic_coroutine(lua_State* L, int index, handler_t eh) | ||
21420 | : base_t(L, index), error_handler(std::move(eh)) { | ||
21421 | #ifdef SOL_SAFE_REFERENCES | ||
21422 | constructor_handler handler{}; | ||
21423 | stack::check<basic_coroutine>(L, index, handler); | ||
21424 | #endif // Safety | ||
21425 | } | ||
21426 | basic_coroutine(lua_State* L, absolute_index index) | ||
21427 | : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { | ||
21428 | } | ||
21429 | basic_coroutine(lua_State* L, absolute_index index, handler_t eh) | ||
21430 | : base_t(L, index), error_handler(std::move(eh)) { | ||
21431 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21432 | constructor_handler handler{}; | ||
21433 | stack::check<basic_coroutine>(L, index, handler); | ||
21434 | #endif // Safety | ||
21435 | } | ||
21436 | basic_coroutine(lua_State* L, raw_index index) | ||
21437 | : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { | ||
21438 | } | ||
21439 | basic_coroutine(lua_State* L, raw_index index, handler_t eh) | ||
21440 | : base_t(L, index), error_handler(std::move(eh)) { | ||
21441 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21442 | constructor_handler handler{}; | ||
21443 | stack::check<basic_coroutine>(L, index, handler); | ||
21444 | #endif // Safety | ||
21445 | } | ||
21446 | basic_coroutine(lua_State* L, ref_index index) | ||
21447 | : basic_coroutine(L, index, detail::get_default_handler<reference, is_main_threaded<base_t>::value>(L)) { | ||
21448 | } | ||
21449 | basic_coroutine(lua_State* L, ref_index index, handler_t eh) | ||
21450 | : base_t(L, index), error_handler(std::move(eh)) { | ||
21451 | #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES | ||
21452 | auto pp = stack::push_pop(*this); | ||
21453 | constructor_handler handler{}; | ||
21454 | stack::check<basic_coroutine>(lua_state(), -1, handler); | ||
21455 | #endif // Safety | ||
21456 | } | ||
21457 | |||
21458 | call_status status() const noexcept { | ||
21459 | return stats; | ||
21460 | } | ||
21461 | |||
21462 | bool error() const noexcept { | ||
21463 | call_status cs = status(); | ||
21464 | return cs != call_status::ok && cs != call_status::yielded; | ||
21465 | } | ||
21466 | |||
21467 | bool runnable() const noexcept { | ||
21468 | return base_t::valid() | ||
21469 | && (status() == call_status::yielded); | ||
21470 | } | ||
21471 | |||
21472 | explicit operator bool() const noexcept { | ||
21473 | return runnable(); | ||
21474 | } | ||
21475 | |||
21476 | template <typename... Args> | ||
21477 | protected_function_result operator()(Args&&... args) { | ||
21478 | return call<>(std::forward<Args>(args)...); | ||
21479 | } | ||
21480 | |||
21481 | template <typename... Ret, typename... Args> | ||
21482 | decltype(auto) operator()(types<Ret...>, Args&&... args) { | ||
21483 | return call<Ret...>(std::forward<Args>(args)...); | ||
21484 | } | ||
21485 | |||
21486 | template <typename... Ret, typename... Args> | ||
21487 | decltype(auto) call(Args&&... args) { | ||
21488 | // some users screw up coroutine.create | ||
21489 | // and try to use it with sol::coroutine without ever calling the first resume in Lua | ||
21490 | // this makes the stack incompatible with other kinds of stacks: protect against this | ||
21491 | // make sure coroutines don't screw us over | ||
21492 | base_t::push(); | ||
21493 | int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); | ||
21494 | return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount); | ||
21495 | } | ||
21496 | }; | ||
21497 | } // namespace sol | ||
21498 | |||
21499 | // end of sol/coroutine.hpp | ||
21500 | |||
21501 | // beginning of sol/variadic_results.hpp | ||
21502 | |||
21503 | // beginning of sol/as_returns.hpp | ||
21504 | |||
21505 | namespace sol { | ||
21506 | template <typename T> | ||
21507 | struct as_returns_t { | ||
21508 | T src; | ||
21509 | }; | ||
21510 | |||
21511 | template <typename Source> | ||
21512 | auto as_returns(Source&& source) { | ||
21513 | return as_returns_t<std::decay_t<Source>>{ std::forward<Source>(source) }; | ||
21514 | } | ||
21515 | |||
21516 | namespace stack { | ||
21517 | template <typename T> | ||
21518 | struct pusher<as_returns_t<T>> { | ||
21519 | int push(lua_State* L, const as_returns_t<T>& e) { | ||
21520 | auto& src = detail::unwrap(e.src); | ||
21521 | int p = 0; | ||
21522 | for (const auto& i : src) { | ||
21523 | p += stack::push(L, i); | ||
21524 | } | ||
21525 | return p; | ||
21526 | } | ||
21527 | }; | ||
21528 | } // namespace stack | ||
21529 | } // namespace sol | ||
21530 | |||
21531 | // end of sol/as_returns.hpp | ||
21532 | |||
21533 | namespace sol { | ||
21534 | |||
21535 | struct variadic_results : public std::vector<object> { | ||
21536 | using std::vector<object>::vector; | ||
21537 | }; | ||
21538 | |||
21539 | namespace stack { | ||
21540 | template <> | ||
21541 | struct pusher<variadic_results> { | ||
21542 | int push(lua_State* L, const variadic_results& e) { | ||
21543 | int p = 0; | ||
21544 | for (const auto& i : e) { | ||
21545 | p += stack::push(L, i); | ||
21546 | } | ||
21547 | return p; | ||
21548 | } | ||
21549 | }; | ||
21550 | } // namespace stack | ||
21551 | |||
21552 | } // namespace sol | ||
21553 | |||
21554 | // end of sol/variadic_results.hpp | ||
21555 | |||
21556 | #if defined(__GNUC__) | ||
21557 | #pragma GCC diagnostic pop | ||
21558 | #elif defined _MSC_VER | ||
21559 | #pragma warning( push ) | ||
21560 | #endif // g++ | ||
21561 | |||
21562 | #if defined(SOL_INSIDE_UNREAL) && SOL_INSIDE_UNREAL | ||
21563 | #if defined(SOL_INSIDE_UNREAL_REMOVED_CHECK) && SOL_INSIDE_UNREAL_REMOVED_CHECK | ||
21564 | #if DO_CHECK | ||
21565 | #define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } } | ||
21566 | #else | ||
21567 | #define check(expr) { CA_ASSUME(expr); } | ||
21568 | #endif | ||
21569 | #endif | ||
21570 | #endif // Unreal Engine 4 Bullshit | ||
21571 | |||
21572 | #endif // SOL_HPP | ||
21573 | // end of sol.hpp | ||
21574 | |||
21575 | #endif // SOL_SINGLE_INCLUDE_HPP | ||
diff --git a/vendor/stb_image.cpp b/vendor/stb_image.cpp new file mode 100644 index 0000000..e834e1e --- /dev/null +++ b/vendor/stb_image.cpp | |||
@@ -0,0 +1,4 @@ | |||
1 | #define STB_IMAGE_IMPLEMENTATION | ||
2 | #define STBI_ONLY_PNG | ||
3 | #define STBI_ONLY_BMP | ||
4 | #include "stb_image.h" | ||
diff --git a/vendor/stb_image.h b/vendor/stb_image.h new file mode 100644 index 0000000..cea66f5 --- /dev/null +++ b/vendor/stb_image.h | |||
@@ -0,0 +1,6326 @@ | |||
1 | /* stb_image - v2.02 - public domain image loader - http://nothings.org/stb_image.h | ||
2 | no warranty implied; use at your own risk | ||
3 | |||
4 | Do this: | ||
5 | #define STB_IMAGE_IMPLEMENTATION | ||
6 | before you include this file in *one* C or C++ file to create the implementation. | ||
7 | |||
8 | // i.e. it should look like this: | ||
9 | #include ... | ||
10 | #include ... | ||
11 | #include ... | ||
12 | #define STB_IMAGE_IMPLEMENTATION | ||
13 | #include "stb_image.h" | ||
14 | |||
15 | You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. | ||
16 | And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free | ||
17 | |||
18 | |||
19 | QUICK NOTES: | ||
20 | Primarily of interest to game developers and other people who can | ||
21 | avoid problematic images and only need the trivial interface | ||
22 | |||
23 | JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) | ||
24 | PNG 1/2/4/8-bit-per-channel (16 bpc not supported) | ||
25 | |||
26 | TGA (not sure what subset, if a subset) | ||
27 | BMP non-1bpp, non-RLE | ||
28 | PSD (composited view only, no extra channels) | ||
29 | |||
30 | GIF (*comp always reports as 4-channel) | ||
31 | HDR (radiance rgbE format) | ||
32 | PIC (Softimage PIC) | ||
33 | PNM (PPM and PGM binary only) | ||
34 | |||
35 | - decode from memory or through FILE (define STBI_NO_STDIO to remove code) | ||
36 | - decode from arbitrary I/O callbacks | ||
37 | - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) | ||
38 | |||
39 | Full documentation under "DOCUMENTATION" below. | ||
40 | |||
41 | |||
42 | Revision 2.00 release notes: | ||
43 | |||
44 | - Progressive JPEG is now supported. | ||
45 | |||
46 | - PPM and PGM binary formats are now supported, thanks to Ken Miller. | ||
47 | |||
48 | - x86 platforms now make use of SSE2 SIMD instructions for | ||
49 | JPEG decoding, and ARM platforms can use NEON SIMD if requested. | ||
50 | This work was done by Fabian "ryg" Giesen. SSE2 is used by | ||
51 | default, but NEON must be enabled explicitly; see docs. | ||
52 | |||
53 | With other JPEG optimizations included in this version, we see | ||
54 | 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup | ||
55 | on a JPEG on an ARM machine, relative to previous versions of this | ||
56 | library. The same results will not obtain for all JPGs and for all | ||
57 | x86/ARM machines. (Note that progressive JPEGs are significantly | ||
58 | slower to decode than regular JPEGs.) This doesn't mean that this | ||
59 | is the fastest JPEG decoder in the land; rather, it brings it | ||
60 | closer to parity with standard libraries. If you want the fastest | ||
61 | decode, look elsewhere. (See "Philosophy" section of docs below.) | ||
62 | |||
63 | See final bullet items below for more info on SIMD. | ||
64 | |||
65 | - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing | ||
66 | the memory allocator. Unlike other STBI libraries, these macros don't | ||
67 | support a context parameter, so if you need to pass a context in to | ||
68 | the allocator, you'll have to store it in a global or a thread-local | ||
69 | variable. | ||
70 | |||
71 | - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and | ||
72 | STBI_NO_LINEAR. | ||
73 | STBI_NO_HDR: suppress implementation of .hdr reader format | ||
74 | STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API | ||
75 | |||
76 | - You can suppress implementation of any of the decoders to reduce | ||
77 | your code footprint by #defining one or more of the following | ||
78 | symbols before creating the implementation. | ||
79 | |||
80 | STBI_NO_JPEG | ||
81 | STBI_NO_PNG | ||
82 | STBI_NO_BMP | ||
83 | STBI_NO_PSD | ||
84 | STBI_NO_TGA | ||
85 | STBI_NO_GIF | ||
86 | STBI_NO_HDR | ||
87 | STBI_NO_PIC | ||
88 | STBI_NO_PNM (.ppm and .pgm) | ||
89 | |||
90 | - You can request *only* certain decoders and suppress all other ones | ||
91 | (this will be more forward-compatible, as addition of new decoders | ||
92 | doesn't require you to disable them explicitly): | ||
93 | |||
94 | STBI_ONLY_JPEG | ||
95 | STBI_ONLY_PNG | ||
96 | STBI_ONLY_BMP | ||
97 | STBI_ONLY_PSD | ||
98 | STBI_ONLY_TGA | ||
99 | STBI_ONLY_GIF | ||
100 | STBI_ONLY_HDR | ||
101 | STBI_ONLY_PIC | ||
102 | STBI_ONLY_PNM (.ppm and .pgm) | ||
103 | |||
104 | Note that you can define multiples of these, and you will get all | ||
105 | of them ("only x" and "only y" is interpreted to mean "only x&y"). | ||
106 | |||
107 | - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still | ||
108 | want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB | ||
109 | |||
110 | - Compilation of all SIMD code can be suppressed with | ||
111 | #define STBI_NO_SIMD | ||
112 | It should not be necessary to disable SIMD unless you have issues | ||
113 | compiling (e.g. using an x86 compiler which doesn't support SSE | ||
114 | intrinsics or that doesn't support the method used to detect | ||
115 | SSE2 support at run-time), and even those can be reported as | ||
116 | bugs so I can refine the built-in compile-time checking to be | ||
117 | smarter. | ||
118 | |||
119 | - The old STBI_SIMD system which allowed installing a user-defined | ||
120 | IDCT etc. has been removed. If you need this, don't upgrade. My | ||
121 | assumption is that almost nobody was doing this, and those who | ||
122 | were will find the built-in SIMD more satisfactory anyway. | ||
123 | |||
124 | - RGB values computed for JPEG images are slightly different from | ||
125 | previous versions of stb_image. (This is due to using less | ||
126 | integer precision in SIMD.) The C code has been adjusted so | ||
127 | that the same RGB values will be computed regardless of whether | ||
128 | SIMD support is available, so your app should always produce | ||
129 | consistent results. But these results are slightly different from | ||
130 | previous versions. (Specifically, about 3% of available YCbCr values | ||
131 | will compute different RGB results from pre-1.49 versions by +-1; | ||
132 | most of the deviating values are one smaller in the G channel.) | ||
133 | |||
134 | - If you must produce consistent results with previous versions of | ||
135 | stb_image, #define STBI_JPEG_OLD and you will get the same results | ||
136 | you used to; however, you will not get the SIMD speedups for | ||
137 | the YCbCr-to-RGB conversion step (although you should still see | ||
138 | significant JPEG speedup from the other changes). | ||
139 | |||
140 | Please note that STBI_JPEG_OLD is a temporary feature; it will be | ||
141 | removed in future versions of the library. It is only intended for | ||
142 | near-term back-compatibility use. | ||
143 | |||
144 | |||
145 | Latest revision history: | ||
146 | 2.02 (2015-01-19) fix incorrect assert, fix warning | ||
147 | 2.01 (2015-01-17) fix various warnings | ||
148 | 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG | ||
149 | 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD | ||
150 | progressive JPEG | ||
151 | PGM/PPM support | ||
152 | STBI_MALLOC,STBI_REALLOC,STBI_FREE | ||
153 | STBI_NO_*, STBI_ONLY_* | ||
154 | GIF bugfix | ||
155 | 1.48 (2014-12-14) fix incorrectly-named assert() | ||
156 | 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) | ||
157 | optimize PNG | ||
158 | fix bug in interlaced PNG with user-specified channel count | ||
159 | 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG | ||
160 | 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc | ||
161 | |||
162 | See end of file for full revision history. | ||
163 | |||
164 | |||
165 | ============================ Contributors ========================= | ||
166 | |||
167 | Image formats Bug fixes & warning fixes | ||
168 | Sean Barrett (jpeg, png, bmp) Marc LeBlanc | ||
169 | Nicolas Schulz (hdr, psd) Christpher Lloyd | ||
170 | Jonathan Dummer (tga) Dave Moore | ||
171 | Jean-Marc Lienher (gif) Won Chun | ||
172 | Tom Seddon (pic) the Horde3D community | ||
173 | Thatcher Ulrich (psd) Janez Zemva | ||
174 | Ken Miller (pgm, ppm) Jonathan Blow | ||
175 | Laurent Gomila | ||
176 | Aruelien Pocheville | ||
177 | Extensions, features Ryamond Barbiero | ||
178 | Jetro Lauha (stbi_info) David Woo | ||
179 | Martin "SpartanJ" Golini (stbi_info) Martin Golini | ||
180 | James "moose2000" Brown (iPhone PNG) Roy Eltham | ||
181 | Ben "Disch" Wenger (io callbacks) Luke Graham | ||
182 | Omar Cornut (1/2/4-bit PNG) Thomas Ruf | ||
183 | John Bartholomew | ||
184 | Ken Hamada | ||
185 | Optimizations & bugfixes Cort Stratton | ||
186 | Fabian "ryg" Giesen Blazej Dariusz Roszkowski | ||
187 | Arseny Kapoulkine Thibault Reuille | ||
188 | Paul Du Bois | ||
189 | Guillaume George | ||
190 | If your name should be here but Jerry Jansson | ||
191 | isn't, let Sean know. Hayaki Saito | ||
192 | Johan Duparc | ||
193 | Ronny Chevalier | ||
194 | Michal Cichon | ||
195 | Tero Hanninen | ||
196 | Sergio Gonzalez | ||
197 | Cass Everitt | ||
198 | Engin Manap | ||
199 | |||
200 | License: | ||
201 | This software is in the public domain. Where that dedication is not | ||
202 | recognized, you are granted a perpetual, irrevocable license to copy | ||
203 | and modify this file however you want. | ||
204 | |||
205 | */ | ||
206 | |||
207 | #ifndef STBI_INCLUDE_STB_IMAGE_H | ||
208 | #define STBI_INCLUDE_STB_IMAGE_H | ||
209 | |||
210 | // DOCUMENTATION | ||
211 | // | ||
212 | // Limitations: | ||
213 | // - no 16-bit-per-channel PNG | ||
214 | // - no 12-bit-per-channel JPEG | ||
215 | // - no JPEGs with arithmetic coding | ||
216 | // - no 1-bit BMP | ||
217 | // - GIF always returns *comp=4 | ||
218 | // | ||
219 | // Basic usage (see HDR discussion below for HDR usage): | ||
220 | // int x,y,n; | ||
221 | // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); | ||
222 | // // ... process data if not NULL ... | ||
223 | // // ... x = width, y = height, n = # 8-bit components per pixel ... | ||
224 | // // ... replace '0' with '1'..'4' to force that many components per pixel | ||
225 | // // ... but 'n' will always be the number that it would have been if you said 0 | ||
226 | // stbi_image_free(data) | ||
227 | // | ||
228 | // Standard parameters: | ||
229 | // int *x -- outputs image width in pixels | ||
230 | // int *y -- outputs image height in pixels | ||
231 | // int *comp -- outputs # of image components in image file | ||
232 | // int req_comp -- if non-zero, # of image components requested in result | ||
233 | // | ||
234 | // The return value from an image loader is an 'unsigned char *' which points | ||
235 | // to the pixel data, or NULL on an allocation failure or if the image is | ||
236 | // corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, | ||
237 | // with each pixel consisting of N interleaved 8-bit components; the first | ||
238 | // pixel pointed to is top-left-most in the image. There is no padding between | ||
239 | // image scanlines or between pixels, regardless of format. The number of | ||
240 | // components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. | ||
241 | // If req_comp is non-zero, *comp has the number of components that _would_ | ||
242 | // have been output otherwise. E.g. if you set req_comp to 4, you will always | ||
243 | // get RGBA output, but you can check *comp to see if it's trivially opaque | ||
244 | // because e.g. there were only 3 channels in the source image. | ||
245 | // | ||
246 | // An output image with N components has the following components interleaved | ||
247 | // in this order in each pixel: | ||
248 | // | ||
249 | // N=#comp components | ||
250 | // 1 grey | ||
251 | // 2 grey, alpha | ||
252 | // 3 red, green, blue | ||
253 | // 4 red, green, blue, alpha | ||
254 | // | ||
255 | // If image loading fails for any reason, the return value will be NULL, | ||
256 | // and *x, *y, *comp will be unchanged. The function stbi_failure_reason() | ||
257 | // can be queried for an extremely brief, end-user unfriendly explanation | ||
258 | // of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid | ||
259 | // compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly | ||
260 | // more user-friendly ones. | ||
261 | // | ||
262 | // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. | ||
263 | // | ||
264 | // =========================================================================== | ||
265 | // | ||
266 | // Philosophy | ||
267 | // | ||
268 | // stb libraries are designed with the following priorities: | ||
269 | // | ||
270 | // 1. easy to use | ||
271 | // 2. easy to maintain | ||
272 | // 3. good performance | ||
273 | // | ||
274 | // Sometimes I let "good performance" creep up in priority over "easy to maintain", | ||
275 | // and for best performance I may provide less-easy-to-use APIs that give higher | ||
276 | // performance, in addition to the easy to use ones. Nevertheless, it's important | ||
277 | // to keep in mind that from the standpoint of you, a client of this library, | ||
278 | // all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. | ||
279 | // | ||
280 | // Some secondary priorities arise directly from the first two, some of which | ||
281 | // make more explicit reasons why performance can't be emphasized. | ||
282 | // | ||
283 | // - Portable ("ease of use") | ||
284 | // - Small footprint ("easy to maintain") | ||
285 | // - No dependencies ("ease of use") | ||
286 | // | ||
287 | // =========================================================================== | ||
288 | // | ||
289 | // I/O callbacks | ||
290 | // | ||
291 | // I/O callbacks allow you to read from arbitrary sources, like packaged | ||
292 | // files or some other source. Data read from callbacks are processed | ||
293 | // through a small internal buffer (currently 128 bytes) to try to reduce | ||
294 | // overhead. | ||
295 | // | ||
296 | // The three functions you must define are "read" (reads some bytes of data), | ||
297 | // "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). | ||
298 | // | ||
299 | // =========================================================================== | ||
300 | // | ||
301 | // SIMD support | ||
302 | // | ||
303 | // The JPEG decoder will try to automatically use SIMD kernels on x86 when | ||
304 | // supported by the compiler. For ARM Neon support, you must explicitly | ||
305 | // request it. | ||
306 | // | ||
307 | // (The old do-it-yourself SIMD API is no longer supported in the current | ||
308 | // code.) | ||
309 | // | ||
310 | // On x86, SSE2 will automatically be used when available based on a run-time | ||
311 | // test; if not, the generic C versions are used as a fall-back. On ARM targets, | ||
312 | // the typical path is to have separate builds for NEON and non-NEON devices | ||
313 | // (at least this is true for iOS and Android). Therefore, the NEON support is | ||
314 | // toggled by a build flag: define STBI_NEON to get NEON loops. | ||
315 | // | ||
316 | // The output of the JPEG decoder is slightly different from versions where | ||
317 | // SIMD support was introduced (that is, for versions before 1.49). The | ||
318 | // difference is only +-1 in the 8-bit RGB channels, and only on a small | ||
319 | // fraction of pixels. You can force the pre-1.49 behavior by defining | ||
320 | // STBI_JPEG_OLD, but this will disable some of the SIMD decoding path | ||
321 | // and hence cost some performance. | ||
322 | // | ||
323 | // If for some reason you do not want to use any of SIMD code, or if | ||
324 | // you have issues compiling it, you can disable it entirely by | ||
325 | // defining STBI_NO_SIMD. | ||
326 | // | ||
327 | // =========================================================================== | ||
328 | // | ||
329 | // HDR image support (disable by defining STBI_NO_HDR) | ||
330 | // | ||
331 | // stb_image now supports loading HDR images in general, and currently | ||
332 | // the Radiance .HDR file format, although the support is provided | ||
333 | // generically. You can still load any file through the existing interface; | ||
334 | // if you attempt to load an HDR file, it will be automatically remapped to | ||
335 | // LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; | ||
336 | // both of these constants can be reconfigured through this interface: | ||
337 | // | ||
338 | // stbi_hdr_to_ldr_gamma(2.2f); | ||
339 | // stbi_hdr_to_ldr_scale(1.0f); | ||
340 | // | ||
341 | // (note, do not use _inverse_ constants; stbi_image will invert them | ||
342 | // appropriately). | ||
343 | // | ||
344 | // Additionally, there is a new, parallel interface for loading files as | ||
345 | // (linear) floats to preserve the full dynamic range: | ||
346 | // | ||
347 | // float *data = stbi_loadf(filename, &x, &y, &n, 0); | ||
348 | // | ||
349 | // If you load LDR images through this interface, those images will | ||
350 | // be promoted to floating point values, run through the inverse of | ||
351 | // constants corresponding to the above: | ||
352 | // | ||
353 | // stbi_ldr_to_hdr_scale(1.0f); | ||
354 | // stbi_ldr_to_hdr_gamma(2.2f); | ||
355 | // | ||
356 | // Finally, given a filename (or an open file or memory block--see header | ||
357 | // file for details) containing image data, you can query for the "most | ||
358 | // appropriate" interface to use (that is, whether the image is HDR or | ||
359 | // not), using: | ||
360 | // | ||
361 | // stbi_is_hdr(char *filename); | ||
362 | // | ||
363 | // =========================================================================== | ||
364 | // | ||
365 | // iPhone PNG support: | ||
366 | // | ||
367 | // By default we convert iphone-formatted PNGs back to RGB, even though | ||
368 | // they are internally encoded differently. You can disable this conversion | ||
369 | // by by calling stbi_convert_iphone_png_to_rgb(0), in which case | ||
370 | // you will always just get the native iphone "format" through (which | ||
371 | // is BGR stored in RGB). | ||
372 | // | ||
373 | // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per | ||
374 | // pixel to remove any premultiplied alpha *only* if the image file explicitly | ||
375 | // says there's premultiplied data (currently only happens in iPhone images, | ||
376 | // and only if iPhone convert-to-rgb processing is on). | ||
377 | // | ||
378 | |||
379 | |||
380 | #ifndef STBI_NO_STDIO | ||
381 | #include <stdio.h> | ||
382 | #endif // STBI_NO_STDIO | ||
383 | |||
384 | #define STBI_VERSION 1 | ||
385 | |||
386 | enum | ||
387 | { | ||
388 | STBI_default = 0, // only used for req_comp | ||
389 | |||
390 | STBI_grey = 1, | ||
391 | STBI_grey_alpha = 2, | ||
392 | STBI_rgb = 3, | ||
393 | STBI_rgb_alpha = 4 | ||
394 | }; | ||
395 | |||
396 | typedef unsigned char stbi_uc; | ||
397 | |||
398 | #ifdef __cplusplus | ||
399 | extern "C" { | ||
400 | #endif | ||
401 | |||
402 | #ifdef STB_IMAGE_STATIC | ||
403 | #define STBIDEF static | ||
404 | #else | ||
405 | #define STBIDEF extern | ||
406 | #endif | ||
407 | |||
408 | ////////////////////////////////////////////////////////////////////////////// | ||
409 | // | ||
410 | // PRIMARY API - works on images of any type | ||
411 | // | ||
412 | |||
413 | // | ||
414 | // load image by filename, open file, or memory buffer | ||
415 | // | ||
416 | |||
417 | typedef struct | ||
418 | { | ||
419 | int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read | ||
420 | void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative | ||
421 | int (*eof) (void *user); // returns nonzero if we are at end of file/data | ||
422 | } stbi_io_callbacks; | ||
423 | |||
424 | STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); | ||
425 | STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); | ||
426 | STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); | ||
427 | |||
428 | #ifndef STBI_NO_STDIO | ||
429 | STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); | ||
430 | // for stbi_load_from_file, file pointer is left pointing immediately after image | ||
431 | #endif | ||
432 | |||
433 | #ifndef STBI_NO_LINEAR | ||
434 | STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); | ||
435 | STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); | ||
436 | STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); | ||
437 | |||
438 | #ifndef STBI_NO_STDIO | ||
439 | STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); | ||
440 | #endif | ||
441 | #endif | ||
442 | |||
443 | #ifndef STBI_NO_HDR | ||
444 | STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); | ||
445 | STBIDEF void stbi_hdr_to_ldr_scale(float scale); | ||
446 | #endif | ||
447 | |||
448 | #ifndef STBI_NO_LINEAR | ||
449 | STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); | ||
450 | STBIDEF void stbi_ldr_to_hdr_scale(float scale); | ||
451 | #endif // STBI_NO_HDR | ||
452 | |||
453 | // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR | ||
454 | STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); | ||
455 | STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); | ||
456 | #ifndef STBI_NO_STDIO | ||
457 | STBIDEF int stbi_is_hdr (char const *filename); | ||
458 | STBIDEF int stbi_is_hdr_from_file(FILE *f); | ||
459 | #endif // STBI_NO_STDIO | ||
460 | |||
461 | |||
462 | // get a VERY brief reason for failure | ||
463 | // NOT THREADSAFE | ||
464 | STBIDEF const char *stbi_failure_reason (void); | ||
465 | |||
466 | // free the loaded image -- this is just free() | ||
467 | STBIDEF void stbi_image_free (void *retval_from_stbi_load); | ||
468 | |||
469 | // get image dimensions & components without fully decoding | ||
470 | STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); | ||
471 | STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); | ||
472 | |||
473 | #ifndef STBI_NO_STDIO | ||
474 | STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); | ||
475 | STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); | ||
476 | |||
477 | #endif | ||
478 | |||
479 | |||
480 | |||
481 | // for image formats that explicitly notate that they have premultiplied alpha, | ||
482 | // we just return the colors as stored in the file. set this flag to force | ||
483 | // unpremultiplication. results are undefined if the unpremultiply overflow. | ||
484 | STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); | ||
485 | |||
486 | // indicate whether we should process iphone images back to canonical format, | ||
487 | // or just pass them through "as-is" | ||
488 | STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); | ||
489 | |||
490 | |||
491 | // ZLIB client - used by PNG, available for other purposes | ||
492 | |||
493 | STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); | ||
494 | STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); | ||
495 | STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); | ||
496 | STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); | ||
497 | |||
498 | STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); | ||
499 | STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); | ||
500 | |||
501 | |||
502 | #ifdef __cplusplus | ||
503 | } | ||
504 | #endif | ||
505 | |||
506 | // | ||
507 | // | ||
508 | //// end header file ///////////////////////////////////////////////////// | ||
509 | #endif // STBI_INCLUDE_STB_IMAGE_H | ||
510 | |||
511 | #ifdef STB_IMAGE_IMPLEMENTATION | ||
512 | |||
513 | #if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ | ||
514 | || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ | ||
515 | || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ | ||
516 | || defined(STBI_ONLY_ZLIB) | ||
517 | #ifndef STBI_ONLY_JPEG | ||
518 | #define STBI_NO_JPEG | ||
519 | #endif | ||
520 | #ifndef STBI_ONLY_PNG | ||
521 | #define STBI_NO_PNG | ||
522 | #endif | ||
523 | #ifndef STBI_ONLY_BMP | ||
524 | #define STBI_NO_BMP | ||
525 | #endif | ||
526 | #ifndef STBI_ONLY_PSD | ||
527 | #define STBI_NO_PSD | ||
528 | #endif | ||
529 | #ifndef STBI_ONLY_TGA | ||
530 | #define STBI_NO_TGA | ||
531 | #endif | ||
532 | #ifndef STBI_ONLY_GIF | ||
533 | #define STBI_NO_GIF | ||
534 | #endif | ||
535 | #ifndef STBI_ONLY_HDR | ||
536 | #define STBI_NO_HDR | ||
537 | #endif | ||
538 | #ifndef STBI_ONLY_PIC | ||
539 | #define STBI_NO_PIC | ||
540 | #endif | ||
541 | #ifndef STBI_ONLY_PNM | ||
542 | #define STBI_NO_PNM | ||
543 | #endif | ||
544 | #endif | ||
545 | |||
546 | #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) | ||
547 | #define STBI_NO_ZLIB | ||
548 | #endif | ||
549 | |||
550 | |||
551 | #include <stdarg.h> | ||
552 | #include <stddef.h> // ptrdiff_t on osx | ||
553 | #include <stdlib.h> | ||
554 | #include <string.h> | ||
555 | |||
556 | #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) | ||
557 | #include <math.h> // ldexp | ||
558 | #endif | ||
559 | |||
560 | #ifndef STBI_NO_STDIO | ||
561 | #include <stdio.h> | ||
562 | #endif | ||
563 | |||
564 | #ifndef STBI_ASSERT | ||
565 | #include <assert.h> | ||
566 | #define STBI_ASSERT(x) assert(x) | ||
567 | #endif | ||
568 | |||
569 | |||
570 | #ifndef _MSC_VER | ||
571 | #ifdef __cplusplus | ||
572 | #define stbi_inline inline | ||
573 | #else | ||
574 | #define stbi_inline | ||
575 | #endif | ||
576 | #else | ||
577 | #define stbi_inline __forceinline | ||
578 | #endif | ||
579 | |||
580 | |||
581 | #ifdef _MSC_VER | ||
582 | typedef unsigned short stbi__uint16; | ||
583 | typedef signed short stbi__int16; | ||
584 | typedef unsigned int stbi__uint32; | ||
585 | typedef signed int stbi__int32; | ||
586 | #else | ||
587 | #include <stdint.h> | ||
588 | typedef uint16_t stbi__uint16; | ||
589 | typedef int16_t stbi__int16; | ||
590 | typedef uint32_t stbi__uint32; | ||
591 | typedef int32_t stbi__int32; | ||
592 | #endif | ||
593 | |||
594 | // should produce compiler error if size is wrong | ||
595 | typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; | ||
596 | |||
597 | #ifdef _MSC_VER | ||
598 | #define STBI_NOTUSED(v) (void)(v) | ||
599 | #else | ||
600 | #define STBI_NOTUSED(v) (void)sizeof(v) | ||
601 | #endif | ||
602 | |||
603 | #ifdef _MSC_VER | ||
604 | #define STBI_HAS_LROTL | ||
605 | #endif | ||
606 | |||
607 | #ifdef STBI_HAS_LROTL | ||
608 | #define stbi_lrot(x,y) _lrotl(x,y) | ||
609 | #else | ||
610 | #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) | ||
611 | #endif | ||
612 | |||
613 | #if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) | ||
614 | // ok | ||
615 | #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) | ||
616 | // ok | ||
617 | #else | ||
618 | #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." | ||
619 | #endif | ||
620 | |||
621 | #ifndef STBI_MALLOC | ||
622 | #define STBI_MALLOC(sz) malloc(sz) | ||
623 | #define STBI_REALLOC(p,sz) realloc(p,sz) | ||
624 | #define STBI_FREE(p) free(p) | ||
625 | #endif | ||
626 | |||
627 | #if defined(__GNUC__) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) | ||
628 | // gcc doesn't support sse2 intrinsics unless you compile with -msse2, | ||
629 | // (but compiling with -msse2 allows the compiler to use SSE2 everywhere; | ||
630 | // this is just broken and gcc are jerks for not fixing it properly | ||
631 | // http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) | ||
632 | #define STBI_NO_SIMD | ||
633 | #endif | ||
634 | |||
635 | #if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) | ||
636 | #define STBI_SSE2 | ||
637 | #include <emmintrin.h> | ||
638 | |||
639 | #ifdef _MSC_VER | ||
640 | |||
641 | #if _MSC_VER >= 1400 // not VC6 | ||
642 | #include <intrin.h> // __cpuid | ||
643 | static int stbi__cpuid3(void) | ||
644 | { | ||
645 | int info[4]; | ||
646 | __cpuid(info,1); | ||
647 | return info[3]; | ||
648 | } | ||
649 | #else | ||
650 | static int stbi__cpuid3(void) | ||
651 | { | ||
652 | int res; | ||
653 | __asm { | ||
654 | mov eax,1 | ||
655 | cpuid | ||
656 | mov res,edx | ||
657 | } | ||
658 | return res; | ||
659 | } | ||
660 | #endif | ||
661 | |||
662 | #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name | ||
663 | |||
664 | static int stbi__sse2_available() | ||
665 | { | ||
666 | int info3 = stbi__cpuid3(); | ||
667 | return ((info3 >> 26) & 1) != 0; | ||
668 | } | ||
669 | #else // assume GCC-style if not VC++ | ||
670 | #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) | ||
671 | |||
672 | static int stbi__sse2_available() | ||
673 | { | ||
674 | #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later | ||
675 | // GCC 4.8+ has a nice way to do this | ||
676 | return __builtin_cpu_supports("sse2"); | ||
677 | #else | ||
678 | // portable way to do this, preferably without using GCC inline ASM? | ||
679 | // just bail for now. | ||
680 | return 0; | ||
681 | #endif | ||
682 | } | ||
683 | #endif | ||
684 | #endif | ||
685 | |||
686 | // ARM NEON | ||
687 | #if defined(STBI_NO_SIMD) && defined(STBI_NEON) | ||
688 | #undef STBI_NEON | ||
689 | #endif | ||
690 | |||
691 | #ifdef STBI_NEON | ||
692 | #include <arm_neon.h> | ||
693 | // assume GCC or Clang on ARM targets | ||
694 | #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) | ||
695 | #endif | ||
696 | |||
697 | #ifndef STBI_SIMD_ALIGN | ||
698 | #define STBI_SIMD_ALIGN(type, name) type name | ||
699 | #endif | ||
700 | |||
701 | /////////////////////////////////////////////// | ||
702 | // | ||
703 | // stbi__context struct and start_xxx functions | ||
704 | |||
705 | // stbi__context structure is our basic context used by all images, so it | ||
706 | // contains all the IO context, plus some basic image information | ||
707 | typedef struct | ||
708 | { | ||
709 | stbi__uint32 img_x, img_y; | ||
710 | int img_n, img_out_n; | ||
711 | |||
712 | stbi_io_callbacks io; | ||
713 | void *io_user_data; | ||
714 | |||
715 | int read_from_callbacks; | ||
716 | int buflen; | ||
717 | stbi_uc buffer_start[128]; | ||
718 | |||
719 | stbi_uc *img_buffer, *img_buffer_end; | ||
720 | stbi_uc *img_buffer_original; | ||
721 | } stbi__context; | ||
722 | |||
723 | |||
724 | static void stbi__refill_buffer(stbi__context *s); | ||
725 | |||
726 | // initialize a memory-decode context | ||
727 | static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) | ||
728 | { | ||
729 | s->io.read = NULL; | ||
730 | s->read_from_callbacks = 0; | ||
731 | s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; | ||
732 | s->img_buffer_end = (stbi_uc *) buffer+len; | ||
733 | } | ||
734 | |||
735 | // initialize a callback-based context | ||
736 | static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) | ||
737 | { | ||
738 | s->io = *c; | ||
739 | s->io_user_data = user; | ||
740 | s->buflen = sizeof(s->buffer_start); | ||
741 | s->read_from_callbacks = 1; | ||
742 | s->img_buffer_original = s->buffer_start; | ||
743 | stbi__refill_buffer(s); | ||
744 | } | ||
745 | |||
746 | #ifndef STBI_NO_STDIO | ||
747 | |||
748 | static int stbi__stdio_read(void *user, char *data, int size) | ||
749 | { | ||
750 | return (int) fread(data,1,size,(FILE*) user); | ||
751 | } | ||
752 | |||
753 | static void stbi__stdio_skip(void *user, int n) | ||
754 | { | ||
755 | fseek((FILE*) user, n, SEEK_CUR); | ||
756 | } | ||
757 | |||
758 | static int stbi__stdio_eof(void *user) | ||
759 | { | ||
760 | return feof((FILE*) user); | ||
761 | } | ||
762 | |||
763 | static stbi_io_callbacks stbi__stdio_callbacks = | ||
764 | { | ||
765 | stbi__stdio_read, | ||
766 | stbi__stdio_skip, | ||
767 | stbi__stdio_eof, | ||
768 | }; | ||
769 | |||
770 | static void stbi__start_file(stbi__context *s, FILE *f) | ||
771 | { | ||
772 | stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); | ||
773 | } | ||
774 | |||
775 | //static void stop_file(stbi__context *s) { } | ||
776 | |||
777 | #endif // !STBI_NO_STDIO | ||
778 | |||
779 | static void stbi__rewind(stbi__context *s) | ||
780 | { | ||
781 | // conceptually rewind SHOULD rewind to the beginning of the stream, | ||
782 | // but we just rewind to the beginning of the initial buffer, because | ||
783 | // we only use it after doing 'test', which only ever looks at at most 92 bytes | ||
784 | s->img_buffer = s->img_buffer_original; | ||
785 | } | ||
786 | |||
787 | #ifndef STBI_NO_JPEG | ||
788 | static int stbi__jpeg_test(stbi__context *s); | ||
789 | static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
790 | static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); | ||
791 | #endif | ||
792 | |||
793 | #ifndef STBI_NO_PNG | ||
794 | static int stbi__png_test(stbi__context *s); | ||
795 | static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
796 | static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); | ||
797 | #endif | ||
798 | |||
799 | #ifndef STBI_NO_BMP | ||
800 | static int stbi__bmp_test(stbi__context *s); | ||
801 | static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
802 | static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); | ||
803 | #endif | ||
804 | |||
805 | #ifndef STBI_NO_TGA | ||
806 | static int stbi__tga_test(stbi__context *s); | ||
807 | static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
808 | static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); | ||
809 | #endif | ||
810 | |||
811 | #ifndef STBI_NO_PSD | ||
812 | static int stbi__psd_test(stbi__context *s); | ||
813 | static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
814 | static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); | ||
815 | #endif | ||
816 | |||
817 | #ifndef STBI_NO_HDR | ||
818 | static int stbi__hdr_test(stbi__context *s); | ||
819 | static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
820 | static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); | ||
821 | #endif | ||
822 | |||
823 | #ifndef STBI_NO_PIC | ||
824 | static int stbi__pic_test(stbi__context *s); | ||
825 | static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
826 | static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); | ||
827 | #endif | ||
828 | |||
829 | #ifndef STBI_NO_GIF | ||
830 | static int stbi__gif_test(stbi__context *s); | ||
831 | static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
832 | static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); | ||
833 | #endif | ||
834 | |||
835 | #ifndef STBI_NO_PNM | ||
836 | static int stbi__pnm_test(stbi__context *s); | ||
837 | static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); | ||
838 | static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); | ||
839 | #endif | ||
840 | |||
841 | // this is not threadsafe | ||
842 | static const char *stbi__g_failure_reason; | ||
843 | |||
844 | STBIDEF const char *stbi_failure_reason(void) | ||
845 | { | ||
846 | return stbi__g_failure_reason; | ||
847 | } | ||
848 | |||
849 | static int stbi__err(const char *str) | ||
850 | { | ||
851 | stbi__g_failure_reason = str; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static void *stbi__malloc(size_t size) | ||
856 | { | ||
857 | return STBI_MALLOC(size); | ||
858 | } | ||
859 | |||
860 | // stbi__err - error | ||
861 | // stbi__errpf - error returning pointer to float | ||
862 | // stbi__errpuc - error returning pointer to unsigned char | ||
863 | |||
864 | #ifdef STBI_NO_FAILURE_STRINGS | ||
865 | #define stbi__err(x,y) 0 | ||
866 | #elif defined(STBI_FAILURE_USERMSG) | ||
867 | #define stbi__err(x,y) stbi__err(y) | ||
868 | #else | ||
869 | #define stbi__err(x,y) stbi__err(x) | ||
870 | #endif | ||
871 | |||
872 | #define stbi__errpf(x,y) ((float *) (stbi__err(x,y)?NULL:NULL)) | ||
873 | #define stbi__errpuc(x,y) ((unsigned char *) (stbi__err(x,y)?NULL:NULL)) | ||
874 | |||
875 | STBIDEF void stbi_image_free(void *retval_from_stbi_load) | ||
876 | { | ||
877 | STBI_FREE(retval_from_stbi_load); | ||
878 | } | ||
879 | |||
880 | #ifndef STBI_NO_LINEAR | ||
881 | static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); | ||
882 | #endif | ||
883 | |||
884 | #ifndef STBI_NO_HDR | ||
885 | static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); | ||
886 | #endif | ||
887 | |||
888 | static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
889 | { | ||
890 | #ifndef STBI_NO_JPEG | ||
891 | if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); | ||
892 | #endif | ||
893 | #ifndef STBI_NO_PNG | ||
894 | if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); | ||
895 | #endif | ||
896 | #ifndef STBI_NO_BMP | ||
897 | if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); | ||
898 | #endif | ||
899 | #ifndef STBI_NO_GIF | ||
900 | if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); | ||
901 | #endif | ||
902 | #ifndef STBI_NO_PSD | ||
903 | if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); | ||
904 | #endif | ||
905 | #ifndef STBI_NO_PIC | ||
906 | if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); | ||
907 | #endif | ||
908 | #ifndef STBI_NO_PNM | ||
909 | if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); | ||
910 | #endif | ||
911 | |||
912 | #ifndef STBI_NO_HDR | ||
913 | if (stbi__hdr_test(s)) { | ||
914 | float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); | ||
915 | return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); | ||
916 | } | ||
917 | #endif | ||
918 | |||
919 | #ifndef STBI_NO_TGA | ||
920 | // test tga last because it's a crappy test! | ||
921 | if (stbi__tga_test(s)) | ||
922 | return stbi__tga_load(s,x,y,comp,req_comp); | ||
923 | #endif | ||
924 | |||
925 | return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); | ||
926 | } | ||
927 | |||
928 | #ifndef STBI_NO_STDIO | ||
929 | |||
930 | static FILE *stbi__fopen(char const *filename, char const *mode) | ||
931 | { | ||
932 | FILE *f; | ||
933 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | ||
934 | if (0 != fopen_s(&f, filename, mode)) | ||
935 | f=0; | ||
936 | #else | ||
937 | f = fopen(filename, mode); | ||
938 | #endif | ||
939 | return f; | ||
940 | } | ||
941 | |||
942 | |||
943 | STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) | ||
944 | { | ||
945 | FILE *f = stbi__fopen(filename, "rb"); | ||
946 | unsigned char *result; | ||
947 | if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); | ||
948 | result = stbi_load_from_file(f,x,y,comp,req_comp); | ||
949 | fclose(f); | ||
950 | return result; | ||
951 | } | ||
952 | |||
953 | STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) | ||
954 | { | ||
955 | unsigned char *result; | ||
956 | stbi__context s; | ||
957 | stbi__start_file(&s,f); | ||
958 | result = stbi_load_main(&s,x,y,comp,req_comp); | ||
959 | if (result) { | ||
960 | // need to 'unget' all the characters in the IO buffer | ||
961 | fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); | ||
962 | } | ||
963 | return result; | ||
964 | } | ||
965 | #endif //!STBI_NO_STDIO | ||
966 | |||
967 | STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) | ||
968 | { | ||
969 | stbi__context s; | ||
970 | stbi__start_mem(&s,buffer,len); | ||
971 | return stbi_load_main(&s,x,y,comp,req_comp); | ||
972 | } | ||
973 | |||
974 | STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) | ||
975 | { | ||
976 | stbi__context s; | ||
977 | stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); | ||
978 | return stbi_load_main(&s,x,y,comp,req_comp); | ||
979 | } | ||
980 | |||
981 | #ifndef STBI_NO_LINEAR | ||
982 | static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
983 | { | ||
984 | unsigned char *data; | ||
985 | #ifndef STBI_NO_HDR | ||
986 | if (stbi__hdr_test(s)) | ||
987 | return stbi__hdr_load(s,x,y,comp,req_comp); | ||
988 | #endif | ||
989 | data = stbi_load_main(s, x, y, comp, req_comp); | ||
990 | if (data) | ||
991 | return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); | ||
992 | return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); | ||
993 | } | ||
994 | |||
995 | STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) | ||
996 | { | ||
997 | stbi__context s; | ||
998 | stbi__start_mem(&s,buffer,len); | ||
999 | return stbi_loadf_main(&s,x,y,comp,req_comp); | ||
1000 | } | ||
1001 | |||
1002 | STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) | ||
1003 | { | ||
1004 | stbi__context s; | ||
1005 | stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); | ||
1006 | return stbi_loadf_main(&s,x,y,comp,req_comp); | ||
1007 | } | ||
1008 | |||
1009 | #ifndef STBI_NO_STDIO | ||
1010 | STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) | ||
1011 | { | ||
1012 | float *result; | ||
1013 | FILE *f = stbi__fopen(filename, "rb"); | ||
1014 | if (!f) return stbi__errpf("can't fopen", "Unable to open file"); | ||
1015 | result = stbi_loadf_from_file(f,x,y,comp,req_comp); | ||
1016 | fclose(f); | ||
1017 | return result; | ||
1018 | } | ||
1019 | |||
1020 | STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) | ||
1021 | { | ||
1022 | stbi__context s; | ||
1023 | stbi__start_file(&s,f); | ||
1024 | return stbi_loadf_main(&s,x,y,comp,req_comp); | ||
1025 | } | ||
1026 | #endif // !STBI_NO_STDIO | ||
1027 | |||
1028 | #endif // !STBI_NO_LINEAR | ||
1029 | |||
1030 | // these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is | ||
1031 | // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always | ||
1032 | // reports false! | ||
1033 | |||
1034 | STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) | ||
1035 | { | ||
1036 | #ifndef STBI_NO_HDR | ||
1037 | stbi__context s; | ||
1038 | stbi__start_mem(&s,buffer,len); | ||
1039 | return stbi__hdr_test(&s); | ||
1040 | #else | ||
1041 | STBI_NOTUSED(buffer); | ||
1042 | STBI_NOTUSED(len); | ||
1043 | return 0; | ||
1044 | #endif | ||
1045 | } | ||
1046 | |||
1047 | #ifndef STBI_NO_STDIO | ||
1048 | STBIDEF int stbi_is_hdr (char const *filename) | ||
1049 | { | ||
1050 | FILE *f = stbi__fopen(filename, "rb"); | ||
1051 | int result=0; | ||
1052 | if (f) { | ||
1053 | result = stbi_is_hdr_from_file(f); | ||
1054 | fclose(f); | ||
1055 | } | ||
1056 | return result; | ||
1057 | } | ||
1058 | |||
1059 | STBIDEF int stbi_is_hdr_from_file(FILE *f) | ||
1060 | { | ||
1061 | #ifndef STBI_NO_HDR | ||
1062 | stbi__context s; | ||
1063 | stbi__start_file(&s,f); | ||
1064 | return stbi__hdr_test(&s); | ||
1065 | #else | ||
1066 | return 0; | ||
1067 | #endif | ||
1068 | } | ||
1069 | #endif // !STBI_NO_STDIO | ||
1070 | |||
1071 | STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) | ||
1072 | { | ||
1073 | #ifndef STBI_NO_HDR | ||
1074 | stbi__context s; | ||
1075 | stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); | ||
1076 | return stbi__hdr_test(&s); | ||
1077 | #else | ||
1078 | return 0; | ||
1079 | #endif | ||
1080 | } | ||
1081 | |||
1082 | static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; | ||
1083 | static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; | ||
1084 | |||
1085 | #ifndef STBI_NO_LINEAR | ||
1086 | STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } | ||
1087 | STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } | ||
1088 | #endif | ||
1089 | |||
1090 | STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } | ||
1091 | STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } | ||
1092 | |||
1093 | |||
1094 | ////////////////////////////////////////////////////////////////////////////// | ||
1095 | // | ||
1096 | // Common code used by all image loaders | ||
1097 | // | ||
1098 | |||
1099 | enum | ||
1100 | { | ||
1101 | STBI__SCAN_load=0, | ||
1102 | STBI__SCAN_type, | ||
1103 | STBI__SCAN_header | ||
1104 | }; | ||
1105 | |||
1106 | static void stbi__refill_buffer(stbi__context *s) | ||
1107 | { | ||
1108 | int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); | ||
1109 | if (n == 0) { | ||
1110 | // at end of file, treat same as if from memory, but need to handle case | ||
1111 | // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file | ||
1112 | s->read_from_callbacks = 0; | ||
1113 | s->img_buffer = s->buffer_start; | ||
1114 | s->img_buffer_end = s->buffer_start+1; | ||
1115 | *s->img_buffer = 0; | ||
1116 | } else { | ||
1117 | s->img_buffer = s->buffer_start; | ||
1118 | s->img_buffer_end = s->buffer_start + n; | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | stbi_inline static stbi_uc stbi__get8(stbi__context *s) | ||
1123 | { | ||
1124 | if (s->img_buffer < s->img_buffer_end) | ||
1125 | return *s->img_buffer++; | ||
1126 | if (s->read_from_callbacks) { | ||
1127 | stbi__refill_buffer(s); | ||
1128 | return *s->img_buffer++; | ||
1129 | } | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | stbi_inline static int stbi__at_eof(stbi__context *s) | ||
1134 | { | ||
1135 | if (s->io.read) { | ||
1136 | if (!(s->io.eof)(s->io_user_data)) return 0; | ||
1137 | // if feof() is true, check if buffer = end | ||
1138 | // special case: we've only got the special 0 character at the end | ||
1139 | if (s->read_from_callbacks == 0) return 1; | ||
1140 | } | ||
1141 | |||
1142 | return s->img_buffer >= s->img_buffer_end; | ||
1143 | } | ||
1144 | |||
1145 | static void stbi__skip(stbi__context *s, int n) | ||
1146 | { | ||
1147 | if (s->io.read) { | ||
1148 | int blen = (int) (s->img_buffer_end - s->img_buffer); | ||
1149 | if (blen < n) { | ||
1150 | s->img_buffer = s->img_buffer_end; | ||
1151 | (s->io.skip)(s->io_user_data, n - blen); | ||
1152 | return; | ||
1153 | } | ||
1154 | } | ||
1155 | s->img_buffer += n; | ||
1156 | } | ||
1157 | |||
1158 | static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) | ||
1159 | { | ||
1160 | if (s->io.read) { | ||
1161 | int blen = (int) (s->img_buffer_end - s->img_buffer); | ||
1162 | if (blen < n) { | ||
1163 | int res, count; | ||
1164 | |||
1165 | memcpy(buffer, s->img_buffer, blen); | ||
1166 | |||
1167 | count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); | ||
1168 | res = (count == (n-blen)); | ||
1169 | s->img_buffer = s->img_buffer_end; | ||
1170 | return res; | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | if (s->img_buffer+n <= s->img_buffer_end) { | ||
1175 | memcpy(buffer, s->img_buffer, n); | ||
1176 | s->img_buffer += n; | ||
1177 | return 1; | ||
1178 | } else | ||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | static int stbi__get16be(stbi__context *s) | ||
1183 | { | ||
1184 | int z = stbi__get8(s); | ||
1185 | return (z << 8) + stbi__get8(s); | ||
1186 | } | ||
1187 | |||
1188 | static stbi__uint32 stbi__get32be(stbi__context *s) | ||
1189 | { | ||
1190 | stbi__uint32 z = stbi__get16be(s); | ||
1191 | return (z << 16) + stbi__get16be(s); | ||
1192 | } | ||
1193 | |||
1194 | static int stbi__get16le(stbi__context *s) | ||
1195 | { | ||
1196 | int z = stbi__get8(s); | ||
1197 | return z + (stbi__get8(s) << 8); | ||
1198 | } | ||
1199 | |||
1200 | static stbi__uint32 stbi__get32le(stbi__context *s) | ||
1201 | { | ||
1202 | stbi__uint32 z = stbi__get16le(s); | ||
1203 | return z + (stbi__get16le(s) << 16); | ||
1204 | } | ||
1205 | |||
1206 | #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings | ||
1207 | |||
1208 | |||
1209 | ////////////////////////////////////////////////////////////////////////////// | ||
1210 | // | ||
1211 | // generic converter from built-in img_n to req_comp | ||
1212 | // individual types do this automatically as much as possible (e.g. jpeg | ||
1213 | // does all cases internally since it needs to colorspace convert anyway, | ||
1214 | // and it never has alpha, so very few cases ). png can automatically | ||
1215 | // interleave an alpha=255 channel, but falls back to this for other cases | ||
1216 | // | ||
1217 | // assume data buffer is malloced, so malloc a new one and free that one | ||
1218 | // only failure mode is malloc failing | ||
1219 | |||
1220 | static stbi_uc stbi__compute_y(int r, int g, int b) | ||
1221 | { | ||
1222 | return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); | ||
1223 | } | ||
1224 | |||
1225 | static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) | ||
1226 | { | ||
1227 | int i,j; | ||
1228 | unsigned char *good; | ||
1229 | |||
1230 | if (req_comp == img_n) return data; | ||
1231 | STBI_ASSERT(req_comp >= 1 && req_comp <= 4); | ||
1232 | |||
1233 | good = (unsigned char *) stbi__malloc(req_comp * x * y); | ||
1234 | if (good == NULL) { | ||
1235 | STBI_FREE(data); | ||
1236 | return stbi__errpuc("outofmem", "Out of memory"); | ||
1237 | } | ||
1238 | |||
1239 | for (j=0; j < (int) y; ++j) { | ||
1240 | unsigned char *src = data + j * x * img_n ; | ||
1241 | unsigned char *dest = good + j * x * req_comp; | ||
1242 | |||
1243 | #define COMBO(a,b) ((a)*8+(b)) | ||
1244 | #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) | ||
1245 | // convert source image with img_n components to one with req_comp components; | ||
1246 | // avoid switch per pixel, so use switch per scanline and massive macros | ||
1247 | switch (COMBO(img_n, req_comp)) { | ||
1248 | CASE(1,2) dest[0]=src[0], dest[1]=255; break; | ||
1249 | CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; | ||
1250 | CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; | ||
1251 | CASE(2,1) dest[0]=src[0]; break; | ||
1252 | CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; | ||
1253 | CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; | ||
1254 | CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; | ||
1255 | CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; | ||
1256 | CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; | ||
1257 | CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; | ||
1258 | CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; | ||
1259 | CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; | ||
1260 | default: STBI_ASSERT(0); | ||
1261 | } | ||
1262 | #undef CASE | ||
1263 | } | ||
1264 | |||
1265 | STBI_FREE(data); | ||
1266 | return good; | ||
1267 | } | ||
1268 | |||
1269 | #ifndef STBI_NO_LINEAR | ||
1270 | static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) | ||
1271 | { | ||
1272 | int i,k,n; | ||
1273 | float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); | ||
1274 | if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } | ||
1275 | // compute number of non-alpha components | ||
1276 | if (comp & 1) n = comp; else n = comp-1; | ||
1277 | for (i=0; i < x*y; ++i) { | ||
1278 | for (k=0; k < n; ++k) { | ||
1279 | output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); | ||
1280 | } | ||
1281 | if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; | ||
1282 | } | ||
1283 | STBI_FREE(data); | ||
1284 | return output; | ||
1285 | } | ||
1286 | #endif | ||
1287 | |||
1288 | #ifndef STBI_NO_HDR | ||
1289 | #define stbi__float2int(x) ((int) (x)) | ||
1290 | static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) | ||
1291 | { | ||
1292 | int i,k,n; | ||
1293 | stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); | ||
1294 | if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } | ||
1295 | // compute number of non-alpha components | ||
1296 | if (comp & 1) n = comp; else n = comp-1; | ||
1297 | for (i=0; i < x*y; ++i) { | ||
1298 | for (k=0; k < n; ++k) { | ||
1299 | float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; | ||
1300 | if (z < 0) z = 0; | ||
1301 | if (z > 255) z = 255; | ||
1302 | output[i*comp + k] = (stbi_uc) stbi__float2int(z); | ||
1303 | } | ||
1304 | if (k < comp) { | ||
1305 | float z = data[i*comp+k] * 255 + 0.5f; | ||
1306 | if (z < 0) z = 0; | ||
1307 | if (z > 255) z = 255; | ||
1308 | output[i*comp + k] = (stbi_uc) stbi__float2int(z); | ||
1309 | } | ||
1310 | } | ||
1311 | STBI_FREE(data); | ||
1312 | return output; | ||
1313 | } | ||
1314 | #endif | ||
1315 | |||
1316 | ////////////////////////////////////////////////////////////////////////////// | ||
1317 | // | ||
1318 | // "baseline" JPEG/JFIF decoder | ||
1319 | // | ||
1320 | // simple implementation | ||
1321 | // - doesn't support delayed output of y-dimension | ||
1322 | // - simple interface (only one output format: 8-bit interleaved RGB) | ||
1323 | // - doesn't try to recover corrupt jpegs | ||
1324 | // - doesn't allow partial loading, loading multiple at once | ||
1325 | // - still fast on x86 (copying globals into locals doesn't help x86) | ||
1326 | // - allocates lots of intermediate memory (full size of all components) | ||
1327 | // - non-interleaved case requires this anyway | ||
1328 | // - allows good upsampling (see next) | ||
1329 | // high-quality | ||
1330 | // - upsampled channels are bilinearly interpolated, even across blocks | ||
1331 | // - quality integer IDCT derived from IJG's 'slow' | ||
1332 | // performance | ||
1333 | // - fast huffman; reasonable integer IDCT | ||
1334 | // - some SIMD kernels for common paths on targets with SSE2/NEON | ||
1335 | // - uses a lot of intermediate memory, could cache poorly | ||
1336 | |||
1337 | #ifndef STBI_NO_JPEG | ||
1338 | |||
1339 | // huffman decoding acceleration | ||
1340 | #define FAST_BITS 9 // larger handles more cases; smaller stomps less cache | ||
1341 | |||
1342 | typedef struct | ||
1343 | { | ||
1344 | stbi_uc fast[1 << FAST_BITS]; | ||
1345 | // weirdly, repacking this into AoS is a 10% speed loss, instead of a win | ||
1346 | stbi__uint16 code[256]; | ||
1347 | stbi_uc values[256]; | ||
1348 | stbi_uc size[257]; | ||
1349 | unsigned int maxcode[18]; | ||
1350 | int delta[17]; // old 'firstsymbol' - old 'firstcode' | ||
1351 | } stbi__huffman; | ||
1352 | |||
1353 | typedef struct | ||
1354 | { | ||
1355 | stbi__context *s; | ||
1356 | stbi__huffman huff_dc[4]; | ||
1357 | stbi__huffman huff_ac[4]; | ||
1358 | stbi_uc dequant[4][64]; | ||
1359 | stbi__int16 fast_ac[4][1 << FAST_BITS]; | ||
1360 | |||
1361 | // sizes for components, interleaved MCUs | ||
1362 | int img_h_max, img_v_max; | ||
1363 | int img_mcu_x, img_mcu_y; | ||
1364 | int img_mcu_w, img_mcu_h; | ||
1365 | |||
1366 | // definition of jpeg image component | ||
1367 | struct | ||
1368 | { | ||
1369 | int id; | ||
1370 | int h,v; | ||
1371 | int tq; | ||
1372 | int hd,ha; | ||
1373 | int dc_pred; | ||
1374 | |||
1375 | int x,y,w2,h2; | ||
1376 | stbi_uc *data; | ||
1377 | void *raw_data, *raw_coeff; | ||
1378 | stbi_uc *linebuf; | ||
1379 | short *coeff; // progressive only | ||
1380 | int coeff_w, coeff_h; // number of 8x8 coefficient blocks | ||
1381 | } img_comp[4]; | ||
1382 | |||
1383 | stbi__uint32 code_buffer; // jpeg entropy-coded buffer | ||
1384 | int code_bits; // number of valid bits | ||
1385 | unsigned char marker; // marker seen while filling entropy buffer | ||
1386 | int nomore; // flag if we saw a marker so must stop | ||
1387 | |||
1388 | int progressive; | ||
1389 | int spec_start; | ||
1390 | int spec_end; | ||
1391 | int succ_high; | ||
1392 | int succ_low; | ||
1393 | int eob_run; | ||
1394 | |||
1395 | int scan_n, order[4]; | ||
1396 | int restart_interval, todo; | ||
1397 | |||
1398 | // kernels | ||
1399 | void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); | ||
1400 | void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); | ||
1401 | stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); | ||
1402 | } stbi__jpeg; | ||
1403 | |||
1404 | static int stbi__build_huffman(stbi__huffman *h, int *count) | ||
1405 | { | ||
1406 | int i,j,k=0,code; | ||
1407 | // build size list for each symbol (from JPEG spec) | ||
1408 | for (i=0; i < 16; ++i) | ||
1409 | for (j=0; j < count[i]; ++j) | ||
1410 | h->size[k++] = (stbi_uc) (i+1); | ||
1411 | h->size[k] = 0; | ||
1412 | |||
1413 | // compute actual symbols (from jpeg spec) | ||
1414 | code = 0; | ||
1415 | k = 0; | ||
1416 | for(j=1; j <= 16; ++j) { | ||
1417 | // compute delta to add to code to compute symbol id | ||
1418 | h->delta[j] = k - code; | ||
1419 | if (h->size[k] == j) { | ||
1420 | while (h->size[k] == j) | ||
1421 | h->code[k++] = (stbi__uint16) (code++); | ||
1422 | if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); | ||
1423 | } | ||
1424 | // compute largest code + 1 for this size, preshifted as needed later | ||
1425 | h->maxcode[j] = code << (16-j); | ||
1426 | code <<= 1; | ||
1427 | } | ||
1428 | h->maxcode[j] = 0xffffffff; | ||
1429 | |||
1430 | // build non-spec acceleration table; 255 is flag for not-accelerated | ||
1431 | memset(h->fast, 255, 1 << FAST_BITS); | ||
1432 | for (i=0; i < k; ++i) { | ||
1433 | int s = h->size[i]; | ||
1434 | if (s <= FAST_BITS) { | ||
1435 | int c = h->code[i] << (FAST_BITS-s); | ||
1436 | int m = 1 << (FAST_BITS-s); | ||
1437 | for (j=0; j < m; ++j) { | ||
1438 | h->fast[c+j] = (stbi_uc) i; | ||
1439 | } | ||
1440 | } | ||
1441 | } | ||
1442 | return 1; | ||
1443 | } | ||
1444 | |||
1445 | // build a table that decodes both magnitude and value of small ACs in | ||
1446 | // one go. | ||
1447 | static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) | ||
1448 | { | ||
1449 | int i; | ||
1450 | for (i=0; i < (1 << FAST_BITS); ++i) { | ||
1451 | stbi_uc fast = h->fast[i]; | ||
1452 | fast_ac[i] = 0; | ||
1453 | if (fast < 255) { | ||
1454 | int rs = h->values[fast]; | ||
1455 | int run = (rs >> 4) & 15; | ||
1456 | int magbits = rs & 15; | ||
1457 | int len = h->size[fast]; | ||
1458 | |||
1459 | if (magbits && len + magbits <= FAST_BITS) { | ||
1460 | // magnitude code followed by receive_extend code | ||
1461 | int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); | ||
1462 | int m = 1 << (magbits - 1); | ||
1463 | if (k < m) k += (-1 << magbits) + 1; | ||
1464 | // if the result is small enough, we can fit it in fast_ac table | ||
1465 | if (k >= -128 && k <= 127) | ||
1466 | fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); | ||
1467 | } | ||
1468 | } | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | static void stbi__grow_buffer_unsafe(stbi__jpeg *j) | ||
1473 | { | ||
1474 | do { | ||
1475 | int b = j->nomore ? 0 : stbi__get8(j->s); | ||
1476 | if (b == 0xff) { | ||
1477 | int c = stbi__get8(j->s); | ||
1478 | if (c != 0) { | ||
1479 | j->marker = (unsigned char) c; | ||
1480 | j->nomore = 1; | ||
1481 | return; | ||
1482 | } | ||
1483 | } | ||
1484 | j->code_buffer |= b << (24 - j->code_bits); | ||
1485 | j->code_bits += 8; | ||
1486 | } while (j->code_bits <= 24); | ||
1487 | } | ||
1488 | |||
1489 | // (1 << n) - 1 | ||
1490 | static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; | ||
1491 | |||
1492 | // decode a jpeg huffman value from the bitstream | ||
1493 | stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) | ||
1494 | { | ||
1495 | unsigned int temp; | ||
1496 | int c,k; | ||
1497 | |||
1498 | if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); | ||
1499 | |||
1500 | // look at the top FAST_BITS and determine what symbol ID it is, | ||
1501 | // if the code is <= FAST_BITS | ||
1502 | c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); | ||
1503 | k = h->fast[c]; | ||
1504 | if (k < 255) { | ||
1505 | int s = h->size[k]; | ||
1506 | if (s > j->code_bits) | ||
1507 | return -1; | ||
1508 | j->code_buffer <<= s; | ||
1509 | j->code_bits -= s; | ||
1510 | return h->values[k]; | ||
1511 | } | ||
1512 | |||
1513 | // naive test is to shift the code_buffer down so k bits are | ||
1514 | // valid, then test against maxcode. To speed this up, we've | ||
1515 | // preshifted maxcode left so that it has (16-k) 0s at the | ||
1516 | // end; in other words, regardless of the number of bits, it | ||
1517 | // wants to be compared against something shifted to have 16; | ||
1518 | // that way we don't need to shift inside the loop. | ||
1519 | temp = j->code_buffer >> 16; | ||
1520 | for (k=FAST_BITS+1 ; ; ++k) | ||
1521 | if (temp < h->maxcode[k]) | ||
1522 | break; | ||
1523 | if (k == 17) { | ||
1524 | // error! code not found | ||
1525 | j->code_bits -= 16; | ||
1526 | return -1; | ||
1527 | } | ||
1528 | |||
1529 | if (k > j->code_bits) | ||
1530 | return -1; | ||
1531 | |||
1532 | // convert the huffman code to the symbol id | ||
1533 | c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; | ||
1534 | STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); | ||
1535 | |||
1536 | // convert the id to a symbol | ||
1537 | j->code_bits -= k; | ||
1538 | j->code_buffer <<= k; | ||
1539 | return h->values[c]; | ||
1540 | } | ||
1541 | |||
1542 | // bias[n] = (-1<<n) + 1 | ||
1543 | static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; | ||
1544 | |||
1545 | // combined JPEG 'receive' and JPEG 'extend', since baseline | ||
1546 | // always extends everything it receives. | ||
1547 | stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) | ||
1548 | { | ||
1549 | unsigned int k; | ||
1550 | int sgn; | ||
1551 | if (j->code_bits < n) stbi__grow_buffer_unsafe(j); | ||
1552 | |||
1553 | sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB | ||
1554 | k = stbi_lrot(j->code_buffer, n); | ||
1555 | j->code_buffer = k & ~stbi__bmask[n]; | ||
1556 | k &= stbi__bmask[n]; | ||
1557 | j->code_bits -= n; | ||
1558 | return k + (stbi__jbias[n] & ~sgn); | ||
1559 | } | ||
1560 | |||
1561 | // get some unsigned bits | ||
1562 | stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) | ||
1563 | { | ||
1564 | unsigned int k; | ||
1565 | if (j->code_bits < n) stbi__grow_buffer_unsafe(j); | ||
1566 | k = stbi_lrot(j->code_buffer, n); | ||
1567 | j->code_buffer = k & ~stbi__bmask[n]; | ||
1568 | k &= stbi__bmask[n]; | ||
1569 | j->code_bits -= n; | ||
1570 | return k; | ||
1571 | } | ||
1572 | |||
1573 | stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) | ||
1574 | { | ||
1575 | unsigned int k; | ||
1576 | if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); | ||
1577 | k = j->code_buffer; | ||
1578 | j->code_buffer <<= 1; | ||
1579 | --j->code_bits; | ||
1580 | return k & 0x80000000; | ||
1581 | } | ||
1582 | |||
1583 | // given a value that's at position X in the zigzag stream, | ||
1584 | // where does it appear in the 8x8 matrix coded as row-major? | ||
1585 | static stbi_uc stbi__jpeg_dezigzag[64+15] = | ||
1586 | { | ||
1587 | 0, 1, 8, 16, 9, 2, 3, 10, | ||
1588 | 17, 24, 32, 25, 18, 11, 4, 5, | ||
1589 | 12, 19, 26, 33, 40, 48, 41, 34, | ||
1590 | 27, 20, 13, 6, 7, 14, 21, 28, | ||
1591 | 35, 42, 49, 56, 57, 50, 43, 36, | ||
1592 | 29, 22, 15, 23, 30, 37, 44, 51, | ||
1593 | 58, 59, 52, 45, 38, 31, 39, 46, | ||
1594 | 53, 60, 61, 54, 47, 55, 62, 63, | ||
1595 | // let corrupt input sample past end | ||
1596 | 63, 63, 63, 63, 63, 63, 63, 63, | ||
1597 | 63, 63, 63, 63, 63, 63, 63 | ||
1598 | }; | ||
1599 | |||
1600 | // decode one 64-entry block-- | ||
1601 | static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) | ||
1602 | { | ||
1603 | int diff,dc,k; | ||
1604 | int t; | ||
1605 | |||
1606 | if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); | ||
1607 | t = stbi__jpeg_huff_decode(j, hdc); | ||
1608 | if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); | ||
1609 | |||
1610 | // 0 all the ac values now so we can do it 32-bits at a time | ||
1611 | memset(data,0,64*sizeof(data[0])); | ||
1612 | |||
1613 | diff = t ? stbi__extend_receive(j, t) : 0; | ||
1614 | dc = j->img_comp[b].dc_pred + diff; | ||
1615 | j->img_comp[b].dc_pred = dc; | ||
1616 | data[0] = (short) (dc * dequant[0]); | ||
1617 | |||
1618 | // decode AC components, see JPEG spec | ||
1619 | k = 1; | ||
1620 | do { | ||
1621 | unsigned int zig; | ||
1622 | int c,r,s; | ||
1623 | if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); | ||
1624 | c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); | ||
1625 | r = fac[c]; | ||
1626 | if (r) { // fast-AC path | ||
1627 | k += (r >> 4) & 15; // run | ||
1628 | s = r & 15; // combined length | ||
1629 | j->code_buffer <<= s; | ||
1630 | j->code_bits -= s; | ||
1631 | // decode into unzigzag'd location | ||
1632 | zig = stbi__jpeg_dezigzag[k++]; | ||
1633 | data[zig] = (short) ((r >> 8) * dequant[zig]); | ||
1634 | } else { | ||
1635 | int rs = stbi__jpeg_huff_decode(j, hac); | ||
1636 | if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); | ||
1637 | s = rs & 15; | ||
1638 | r = rs >> 4; | ||
1639 | if (s == 0) { | ||
1640 | if (rs != 0xf0) break; // end block | ||
1641 | k += 16; | ||
1642 | } else { | ||
1643 | k += r; | ||
1644 | // decode into unzigzag'd location | ||
1645 | zig = stbi__jpeg_dezigzag[k++]; | ||
1646 | data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); | ||
1647 | } | ||
1648 | } | ||
1649 | } while (k < 64); | ||
1650 | return 1; | ||
1651 | } | ||
1652 | |||
1653 | static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) | ||
1654 | { | ||
1655 | int diff,dc; | ||
1656 | int t; | ||
1657 | if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); | ||
1658 | |||
1659 | if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); | ||
1660 | |||
1661 | if (j->succ_high == 0) { | ||
1662 | // first scan for DC coefficient, must be first | ||
1663 | memset(data,0,64*sizeof(data[0])); // 0 all the ac values now | ||
1664 | t = stbi__jpeg_huff_decode(j, hdc); | ||
1665 | diff = t ? stbi__extend_receive(j, t) : 0; | ||
1666 | |||
1667 | dc = j->img_comp[b].dc_pred + diff; | ||
1668 | j->img_comp[b].dc_pred = dc; | ||
1669 | data[0] = (short) (dc << j->succ_low); | ||
1670 | } else { | ||
1671 | // refinement scan for DC coefficient | ||
1672 | if (stbi__jpeg_get_bit(j)) | ||
1673 | data[0] += (short) (1 << j->succ_low); | ||
1674 | } | ||
1675 | return 1; | ||
1676 | } | ||
1677 | |||
1678 | // @OPTIMIZE: store non-zigzagged during the decode passes, | ||
1679 | // and only de-zigzag when dequantizing | ||
1680 | static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) | ||
1681 | { | ||
1682 | int k; | ||
1683 | if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); | ||
1684 | |||
1685 | if (j->succ_high == 0) { | ||
1686 | int shift = j->succ_low; | ||
1687 | |||
1688 | if (j->eob_run) { | ||
1689 | --j->eob_run; | ||
1690 | return 1; | ||
1691 | } | ||
1692 | |||
1693 | k = j->spec_start; | ||
1694 | do { | ||
1695 | unsigned int zig; | ||
1696 | int c,r,s; | ||
1697 | if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); | ||
1698 | c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); | ||
1699 | r = fac[c]; | ||
1700 | if (r) { // fast-AC path | ||
1701 | k += (r >> 4) & 15; // run | ||
1702 | s = r & 15; // combined length | ||
1703 | j->code_buffer <<= s; | ||
1704 | j->code_bits -= s; | ||
1705 | zig = stbi__jpeg_dezigzag[k++]; | ||
1706 | data[zig] = (short) ((r >> 8) << shift); | ||
1707 | } else { | ||
1708 | int rs = stbi__jpeg_huff_decode(j, hac); | ||
1709 | if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); | ||
1710 | s = rs & 15; | ||
1711 | r = rs >> 4; | ||
1712 | if (s == 0) { | ||
1713 | if (r < 15) { | ||
1714 | j->eob_run = (1 << r); | ||
1715 | if (r) | ||
1716 | j->eob_run += stbi__jpeg_get_bits(j, r); | ||
1717 | --j->eob_run; | ||
1718 | break; | ||
1719 | } | ||
1720 | k += 16; | ||
1721 | } else { | ||
1722 | k += r; | ||
1723 | zig = stbi__jpeg_dezigzag[k++]; | ||
1724 | data[zig] = (short) (stbi__extend_receive(j,s) << shift); | ||
1725 | } | ||
1726 | } | ||
1727 | } while (k <= j->spec_end); | ||
1728 | } else { | ||
1729 | // refinement scan for these AC coefficients | ||
1730 | |||
1731 | short bit = (short) (1 << j->succ_low); | ||
1732 | |||
1733 | if (j->eob_run) { | ||
1734 | --j->eob_run; | ||
1735 | for (k = j->spec_start; k <= j->spec_end; ++k) { | ||
1736 | short *p = &data[stbi__jpeg_dezigzag[k]]; | ||
1737 | if (*p != 0) | ||
1738 | if (stbi__jpeg_get_bit(j)) | ||
1739 | if ((*p & bit)==0) { | ||
1740 | if (*p > 0) | ||
1741 | *p += bit; | ||
1742 | else | ||
1743 | *p -= bit; | ||
1744 | } | ||
1745 | } | ||
1746 | } else { | ||
1747 | k = j->spec_start; | ||
1748 | do { | ||
1749 | int r,s; | ||
1750 | int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh | ||
1751 | if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); | ||
1752 | s = rs & 15; | ||
1753 | r = rs >> 4; | ||
1754 | if (s == 0) { | ||
1755 | if (r < 15) { | ||
1756 | j->eob_run = (1 << r) - 1; | ||
1757 | if (r) | ||
1758 | j->eob_run += stbi__jpeg_get_bits(j, r); | ||
1759 | r = 64; // force end of block | ||
1760 | } else | ||
1761 | r = 16; // r=15 is the code for 16 0s | ||
1762 | } else { | ||
1763 | if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); | ||
1764 | // sign bit | ||
1765 | if (stbi__jpeg_get_bit(j)) | ||
1766 | s = bit; | ||
1767 | else | ||
1768 | s = -bit; | ||
1769 | } | ||
1770 | |||
1771 | // advance by r | ||
1772 | while (k <= j->spec_end) { | ||
1773 | short *p = &data[stbi__jpeg_dezigzag[k]]; | ||
1774 | if (*p != 0) { | ||
1775 | if (stbi__jpeg_get_bit(j)) | ||
1776 | if ((*p & bit)==0) { | ||
1777 | if (*p > 0) | ||
1778 | *p += bit; | ||
1779 | else | ||
1780 | *p -= bit; | ||
1781 | } | ||
1782 | ++k; | ||
1783 | } else { | ||
1784 | if (r == 0) { | ||
1785 | if (s) | ||
1786 | data[stbi__jpeg_dezigzag[k++]] = (short) s; | ||
1787 | break; | ||
1788 | } | ||
1789 | --r; | ||
1790 | ++k; | ||
1791 | } | ||
1792 | } | ||
1793 | } while (k <= j->spec_end); | ||
1794 | } | ||
1795 | } | ||
1796 | return 1; | ||
1797 | } | ||
1798 | |||
1799 | // take a -128..127 value and stbi__clamp it and convert to 0..255 | ||
1800 | stbi_inline static stbi_uc stbi__clamp(int x) | ||
1801 | { | ||
1802 | // trick to use a single test to catch both cases | ||
1803 | if ((unsigned int) x > 255) { | ||
1804 | if (x < 0) return 0; | ||
1805 | if (x > 255) return 255; | ||
1806 | } | ||
1807 | return (stbi_uc) x; | ||
1808 | } | ||
1809 | |||
1810 | #define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) | ||
1811 | #define stbi__fsh(x) ((x) << 12) | ||
1812 | |||
1813 | // derived from jidctint -- DCT_ISLOW | ||
1814 | #define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ | ||
1815 | int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ | ||
1816 | p2 = s2; \ | ||
1817 | p3 = s6; \ | ||
1818 | p1 = (p2+p3) * stbi__f2f(0.5411961f); \ | ||
1819 | t2 = p1 + p3*stbi__f2f(-1.847759065f); \ | ||
1820 | t3 = p1 + p2*stbi__f2f( 0.765366865f); \ | ||
1821 | p2 = s0; \ | ||
1822 | p3 = s4; \ | ||
1823 | t0 = stbi__fsh(p2+p3); \ | ||
1824 | t1 = stbi__fsh(p2-p3); \ | ||
1825 | x0 = t0+t3; \ | ||
1826 | x3 = t0-t3; \ | ||
1827 | x1 = t1+t2; \ | ||
1828 | x2 = t1-t2; \ | ||
1829 | t0 = s7; \ | ||
1830 | t1 = s5; \ | ||
1831 | t2 = s3; \ | ||
1832 | t3 = s1; \ | ||
1833 | p3 = t0+t2; \ | ||
1834 | p4 = t1+t3; \ | ||
1835 | p1 = t0+t3; \ | ||
1836 | p2 = t1+t2; \ | ||
1837 | p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ | ||
1838 | t0 = t0*stbi__f2f( 0.298631336f); \ | ||
1839 | t1 = t1*stbi__f2f( 2.053119869f); \ | ||
1840 | t2 = t2*stbi__f2f( 3.072711026f); \ | ||
1841 | t3 = t3*stbi__f2f( 1.501321110f); \ | ||
1842 | p1 = p5 + p1*stbi__f2f(-0.899976223f); \ | ||
1843 | p2 = p5 + p2*stbi__f2f(-2.562915447f); \ | ||
1844 | p3 = p3*stbi__f2f(-1.961570560f); \ | ||
1845 | p4 = p4*stbi__f2f(-0.390180644f); \ | ||
1846 | t3 += p1+p4; \ | ||
1847 | t2 += p2+p3; \ | ||
1848 | t1 += p2+p4; \ | ||
1849 | t0 += p1+p3; | ||
1850 | |||
1851 | static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) | ||
1852 | { | ||
1853 | int i,val[64],*v=val; | ||
1854 | stbi_uc *o; | ||
1855 | short *d = data; | ||
1856 | |||
1857 | // columns | ||
1858 | for (i=0; i < 8; ++i,++d, ++v) { | ||
1859 | // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing | ||
1860 | if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 | ||
1861 | && d[40]==0 && d[48]==0 && d[56]==0) { | ||
1862 | // no shortcut 0 seconds | ||
1863 | // (1|2|3|4|5|6|7)==0 0 seconds | ||
1864 | // all separate -0.047 seconds | ||
1865 | // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds | ||
1866 | int dcterm = d[0] << 2; | ||
1867 | v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; | ||
1868 | } else { | ||
1869 | STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) | ||
1870 | // constants scaled things up by 1<<12; let's bring them back | ||
1871 | // down, but keep 2 extra bits of precision | ||
1872 | x0 += 512; x1 += 512; x2 += 512; x3 += 512; | ||
1873 | v[ 0] = (x0+t3) >> 10; | ||
1874 | v[56] = (x0-t3) >> 10; | ||
1875 | v[ 8] = (x1+t2) >> 10; | ||
1876 | v[48] = (x1-t2) >> 10; | ||
1877 | v[16] = (x2+t1) >> 10; | ||
1878 | v[40] = (x2-t1) >> 10; | ||
1879 | v[24] = (x3+t0) >> 10; | ||
1880 | v[32] = (x3-t0) >> 10; | ||
1881 | } | ||
1882 | } | ||
1883 | |||
1884 | for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { | ||
1885 | // no fast case since the first 1D IDCT spread components out | ||
1886 | STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) | ||
1887 | // constants scaled things up by 1<<12, plus we had 1<<2 from first | ||
1888 | // loop, plus horizontal and vertical each scale by sqrt(8) so together | ||
1889 | // we've got an extra 1<<3, so 1<<17 total we need to remove. | ||
1890 | // so we want to round that, which means adding 0.5 * 1<<17, | ||
1891 | // aka 65536. Also, we'll end up with -128 to 127 that we want | ||
1892 | // to encode as 0..255 by adding 128, so we'll add that before the shift | ||
1893 | x0 += 65536 + (128<<17); | ||
1894 | x1 += 65536 + (128<<17); | ||
1895 | x2 += 65536 + (128<<17); | ||
1896 | x3 += 65536 + (128<<17); | ||
1897 | // tried computing the shifts into temps, or'ing the temps to see | ||
1898 | // if any were out of range, but that was slower | ||
1899 | o[0] = stbi__clamp((x0+t3) >> 17); | ||
1900 | o[7] = stbi__clamp((x0-t3) >> 17); | ||
1901 | o[1] = stbi__clamp((x1+t2) >> 17); | ||
1902 | o[6] = stbi__clamp((x1-t2) >> 17); | ||
1903 | o[2] = stbi__clamp((x2+t1) >> 17); | ||
1904 | o[5] = stbi__clamp((x2-t1) >> 17); | ||
1905 | o[3] = stbi__clamp((x3+t0) >> 17); | ||
1906 | o[4] = stbi__clamp((x3-t0) >> 17); | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | #ifdef STBI_SSE2 | ||
1911 | // sse2 integer IDCT. not the fastest possible implementation but it | ||
1912 | // produces bit-identical results to the generic C version so it's | ||
1913 | // fully "transparent". | ||
1914 | static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) | ||
1915 | { | ||
1916 | // This is constructed to match our regular (generic) integer IDCT exactly. | ||
1917 | __m128i row0, row1, row2, row3, row4, row5, row6, row7; | ||
1918 | __m128i tmp; | ||
1919 | |||
1920 | // dot product constant: even elems=x, odd elems=y | ||
1921 | #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) | ||
1922 | |||
1923 | // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) | ||
1924 | // out(1) = c1[even]*x + c1[odd]*y | ||
1925 | #define dct_rot(out0,out1, x,y,c0,c1) \ | ||
1926 | __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ | ||
1927 | __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ | ||
1928 | __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ | ||
1929 | __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ | ||
1930 | __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ | ||
1931 | __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) | ||
1932 | |||
1933 | // out = in << 12 (in 16-bit, out 32-bit) | ||
1934 | #define dct_widen(out, in) \ | ||
1935 | __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ | ||
1936 | __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) | ||
1937 | |||
1938 | // wide add | ||
1939 | #define dct_wadd(out, a, b) \ | ||
1940 | __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ | ||
1941 | __m128i out##_h = _mm_add_epi32(a##_h, b##_h) | ||
1942 | |||
1943 | // wide sub | ||
1944 | #define dct_wsub(out, a, b) \ | ||
1945 | __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ | ||
1946 | __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) | ||
1947 | |||
1948 | // butterfly a/b, add bias, then shift by "s" and pack | ||
1949 | #define dct_bfly32o(out0, out1, a,b,bias,s) \ | ||
1950 | { \ | ||
1951 | __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ | ||
1952 | __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ | ||
1953 | dct_wadd(sum, abiased, b); \ | ||
1954 | dct_wsub(dif, abiased, b); \ | ||
1955 | out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ | ||
1956 | out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ | ||
1957 | } | ||
1958 | |||
1959 | // 8-bit interleave step (for transposes) | ||
1960 | #define dct_interleave8(a, b) \ | ||
1961 | tmp = a; \ | ||
1962 | a = _mm_unpacklo_epi8(a, b); \ | ||
1963 | b = _mm_unpackhi_epi8(tmp, b) | ||
1964 | |||
1965 | // 16-bit interleave step (for transposes) | ||
1966 | #define dct_interleave16(a, b) \ | ||
1967 | tmp = a; \ | ||
1968 | a = _mm_unpacklo_epi16(a, b); \ | ||
1969 | b = _mm_unpackhi_epi16(tmp, b) | ||
1970 | |||
1971 | #define dct_pass(bias,shift) \ | ||
1972 | { \ | ||
1973 | /* even part */ \ | ||
1974 | dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ | ||
1975 | __m128i sum04 = _mm_add_epi16(row0, row4); \ | ||
1976 | __m128i dif04 = _mm_sub_epi16(row0, row4); \ | ||
1977 | dct_widen(t0e, sum04); \ | ||
1978 | dct_widen(t1e, dif04); \ | ||
1979 | dct_wadd(x0, t0e, t3e); \ | ||
1980 | dct_wsub(x3, t0e, t3e); \ | ||
1981 | dct_wadd(x1, t1e, t2e); \ | ||
1982 | dct_wsub(x2, t1e, t2e); \ | ||
1983 | /* odd part */ \ | ||
1984 | dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ | ||
1985 | dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ | ||
1986 | __m128i sum17 = _mm_add_epi16(row1, row7); \ | ||
1987 | __m128i sum35 = _mm_add_epi16(row3, row5); \ | ||
1988 | dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ | ||
1989 | dct_wadd(x4, y0o, y4o); \ | ||
1990 | dct_wadd(x5, y1o, y5o); \ | ||
1991 | dct_wadd(x6, y2o, y5o); \ | ||
1992 | dct_wadd(x7, y3o, y4o); \ | ||
1993 | dct_bfly32o(row0,row7, x0,x7,bias,shift); \ | ||
1994 | dct_bfly32o(row1,row6, x1,x6,bias,shift); \ | ||
1995 | dct_bfly32o(row2,row5, x2,x5,bias,shift); \ | ||
1996 | dct_bfly32o(row3,row4, x3,x4,bias,shift); \ | ||
1997 | } | ||
1998 | |||
1999 | __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); | ||
2000 | __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); | ||
2001 | __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); | ||
2002 | __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); | ||
2003 | __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); | ||
2004 | __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); | ||
2005 | __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); | ||
2006 | __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); | ||
2007 | |||
2008 | // rounding biases in column/row passes, see stbi__idct_block for explanation. | ||
2009 | __m128i bias_0 = _mm_set1_epi32(512); | ||
2010 | __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); | ||
2011 | |||
2012 | // load | ||
2013 | row0 = _mm_load_si128((const __m128i *) (data + 0*8)); | ||
2014 | row1 = _mm_load_si128((const __m128i *) (data + 1*8)); | ||
2015 | row2 = _mm_load_si128((const __m128i *) (data + 2*8)); | ||
2016 | row3 = _mm_load_si128((const __m128i *) (data + 3*8)); | ||
2017 | row4 = _mm_load_si128((const __m128i *) (data + 4*8)); | ||
2018 | row5 = _mm_load_si128((const __m128i *) (data + 5*8)); | ||
2019 | row6 = _mm_load_si128((const __m128i *) (data + 6*8)); | ||
2020 | row7 = _mm_load_si128((const __m128i *) (data + 7*8)); | ||
2021 | |||
2022 | // column pass | ||
2023 | dct_pass(bias_0, 10); | ||
2024 | |||
2025 | { | ||
2026 | // 16bit 8x8 transpose pass 1 | ||
2027 | dct_interleave16(row0, row4); | ||
2028 | dct_interleave16(row1, row5); | ||
2029 | dct_interleave16(row2, row6); | ||
2030 | dct_interleave16(row3, row7); | ||
2031 | |||
2032 | // transpose pass 2 | ||
2033 | dct_interleave16(row0, row2); | ||
2034 | dct_interleave16(row1, row3); | ||
2035 | dct_interleave16(row4, row6); | ||
2036 | dct_interleave16(row5, row7); | ||
2037 | |||
2038 | // transpose pass 3 | ||
2039 | dct_interleave16(row0, row1); | ||
2040 | dct_interleave16(row2, row3); | ||
2041 | dct_interleave16(row4, row5); | ||
2042 | dct_interleave16(row6, row7); | ||
2043 | } | ||
2044 | |||
2045 | // row pass | ||
2046 | dct_pass(bias_1, 17); | ||
2047 | |||
2048 | { | ||
2049 | // pack | ||
2050 | __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 | ||
2051 | __m128i p1 = _mm_packus_epi16(row2, row3); | ||
2052 | __m128i p2 = _mm_packus_epi16(row4, row5); | ||
2053 | __m128i p3 = _mm_packus_epi16(row6, row7); | ||
2054 | |||
2055 | // 8bit 8x8 transpose pass 1 | ||
2056 | dct_interleave8(p0, p2); // a0e0a1e1... | ||
2057 | dct_interleave8(p1, p3); // c0g0c1g1... | ||
2058 | |||
2059 | // transpose pass 2 | ||
2060 | dct_interleave8(p0, p1); // a0c0e0g0... | ||
2061 | dct_interleave8(p2, p3); // b0d0f0h0... | ||
2062 | |||
2063 | // transpose pass 3 | ||
2064 | dct_interleave8(p0, p2); // a0b0c0d0... | ||
2065 | dct_interleave8(p1, p3); // a4b4c4d4... | ||
2066 | |||
2067 | // store | ||
2068 | _mm_storel_epi64((__m128i *) out, p0); out += out_stride; | ||
2069 | _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; | ||
2070 | _mm_storel_epi64((__m128i *) out, p2); out += out_stride; | ||
2071 | _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; | ||
2072 | _mm_storel_epi64((__m128i *) out, p1); out += out_stride; | ||
2073 | _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; | ||
2074 | _mm_storel_epi64((__m128i *) out, p3); out += out_stride; | ||
2075 | _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); | ||
2076 | } | ||
2077 | |||
2078 | #undef dct_const | ||
2079 | #undef dct_rot | ||
2080 | #undef dct_widen | ||
2081 | #undef dct_wadd | ||
2082 | #undef dct_wsub | ||
2083 | #undef dct_bfly32o | ||
2084 | #undef dct_interleave8 | ||
2085 | #undef dct_interleave16 | ||
2086 | #undef dct_pass | ||
2087 | } | ||
2088 | |||
2089 | #endif // STBI_SSE2 | ||
2090 | |||
2091 | #ifdef STBI_NEON | ||
2092 | |||
2093 | // NEON integer IDCT. should produce bit-identical | ||
2094 | // results to the generic C version. | ||
2095 | static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) | ||
2096 | { | ||
2097 | int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; | ||
2098 | |||
2099 | int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); | ||
2100 | int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); | ||
2101 | int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); | ||
2102 | int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); | ||
2103 | int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); | ||
2104 | int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); | ||
2105 | int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); | ||
2106 | int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); | ||
2107 | int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); | ||
2108 | int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); | ||
2109 | int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); | ||
2110 | int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); | ||
2111 | |||
2112 | #define dct_long_mul(out, inq, coeff) \ | ||
2113 | int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ | ||
2114 | int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) | ||
2115 | |||
2116 | #define dct_long_mac(out, acc, inq, coeff) \ | ||
2117 | int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ | ||
2118 | int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) | ||
2119 | |||
2120 | #define dct_widen(out, inq) \ | ||
2121 | int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ | ||
2122 | int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) | ||
2123 | |||
2124 | // wide add | ||
2125 | #define dct_wadd(out, a, b) \ | ||
2126 | int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ | ||
2127 | int32x4_t out##_h = vaddq_s32(a##_h, b##_h) | ||
2128 | |||
2129 | // wide sub | ||
2130 | #define dct_wsub(out, a, b) \ | ||
2131 | int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ | ||
2132 | int32x4_t out##_h = vsubq_s32(a##_h, b##_h) | ||
2133 | |||
2134 | // butterfly a/b, then shift using "shiftop" by "s" and pack | ||
2135 | #define dct_bfly32o(out0,out1, a,b,shiftop,s) \ | ||
2136 | { \ | ||
2137 | dct_wadd(sum, a, b); \ | ||
2138 | dct_wsub(dif, a, b); \ | ||
2139 | out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ | ||
2140 | out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ | ||
2141 | } | ||
2142 | |||
2143 | #define dct_pass(shiftop, shift) \ | ||
2144 | { \ | ||
2145 | /* even part */ \ | ||
2146 | int16x8_t sum26 = vaddq_s16(row2, row6); \ | ||
2147 | dct_long_mul(p1e, sum26, rot0_0); \ | ||
2148 | dct_long_mac(t2e, p1e, row6, rot0_1); \ | ||
2149 | dct_long_mac(t3e, p1e, row2, rot0_2); \ | ||
2150 | int16x8_t sum04 = vaddq_s16(row0, row4); \ | ||
2151 | int16x8_t dif04 = vsubq_s16(row0, row4); \ | ||
2152 | dct_widen(t0e, sum04); \ | ||
2153 | dct_widen(t1e, dif04); \ | ||
2154 | dct_wadd(x0, t0e, t3e); \ | ||
2155 | dct_wsub(x3, t0e, t3e); \ | ||
2156 | dct_wadd(x1, t1e, t2e); \ | ||
2157 | dct_wsub(x2, t1e, t2e); \ | ||
2158 | /* odd part */ \ | ||
2159 | int16x8_t sum15 = vaddq_s16(row1, row5); \ | ||
2160 | int16x8_t sum17 = vaddq_s16(row1, row7); \ | ||
2161 | int16x8_t sum35 = vaddq_s16(row3, row5); \ | ||
2162 | int16x8_t sum37 = vaddq_s16(row3, row7); \ | ||
2163 | int16x8_t sumodd = vaddq_s16(sum17, sum35); \ | ||
2164 | dct_long_mul(p5o, sumodd, rot1_0); \ | ||
2165 | dct_long_mac(p1o, p5o, sum17, rot1_1); \ | ||
2166 | dct_long_mac(p2o, p5o, sum35, rot1_2); \ | ||
2167 | dct_long_mul(p3o, sum37, rot2_0); \ | ||
2168 | dct_long_mul(p4o, sum15, rot2_1); \ | ||
2169 | dct_wadd(sump13o, p1o, p3o); \ | ||
2170 | dct_wadd(sump24o, p2o, p4o); \ | ||
2171 | dct_wadd(sump23o, p2o, p3o); \ | ||
2172 | dct_wadd(sump14o, p1o, p4o); \ | ||
2173 | dct_long_mac(x4, sump13o, row7, rot3_0); \ | ||
2174 | dct_long_mac(x5, sump24o, row5, rot3_1); \ | ||
2175 | dct_long_mac(x6, sump23o, row3, rot3_2); \ | ||
2176 | dct_long_mac(x7, sump14o, row1, rot3_3); \ | ||
2177 | dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ | ||
2178 | dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ | ||
2179 | dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ | ||
2180 | dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ | ||
2181 | } | ||
2182 | |||
2183 | // load | ||
2184 | row0 = vld1q_s16(data + 0*8); | ||
2185 | row1 = vld1q_s16(data + 1*8); | ||
2186 | row2 = vld1q_s16(data + 2*8); | ||
2187 | row3 = vld1q_s16(data + 3*8); | ||
2188 | row4 = vld1q_s16(data + 4*8); | ||
2189 | row5 = vld1q_s16(data + 5*8); | ||
2190 | row6 = vld1q_s16(data + 6*8); | ||
2191 | row7 = vld1q_s16(data + 7*8); | ||
2192 | |||
2193 | // add DC bias | ||
2194 | row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); | ||
2195 | |||
2196 | // column pass | ||
2197 | dct_pass(vrshrn_n_s32, 10); | ||
2198 | |||
2199 | // 16bit 8x8 transpose | ||
2200 | { | ||
2201 | // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. | ||
2202 | // whether compilers actually get this is another story, sadly. | ||
2203 | #define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } | ||
2204 | #define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } | ||
2205 | #define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } | ||
2206 | |||
2207 | // pass 1 | ||
2208 | dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 | ||
2209 | dct_trn16(row2, row3); | ||
2210 | dct_trn16(row4, row5); | ||
2211 | dct_trn16(row6, row7); | ||
2212 | |||
2213 | // pass 2 | ||
2214 | dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 | ||
2215 | dct_trn32(row1, row3); | ||
2216 | dct_trn32(row4, row6); | ||
2217 | dct_trn32(row5, row7); | ||
2218 | |||
2219 | // pass 3 | ||
2220 | dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 | ||
2221 | dct_trn64(row1, row5); | ||
2222 | dct_trn64(row2, row6); | ||
2223 | dct_trn64(row3, row7); | ||
2224 | |||
2225 | #undef dct_trn16 | ||
2226 | #undef dct_trn32 | ||
2227 | #undef dct_trn64 | ||
2228 | } | ||
2229 | |||
2230 | // row pass | ||
2231 | // vrshrn_n_s32 only supports shifts up to 16, we need | ||
2232 | // 17. so do a non-rounding shift of 16 first then follow | ||
2233 | // up with a rounding shift by 1. | ||
2234 | dct_pass(vshrn_n_s32, 16); | ||
2235 | |||
2236 | { | ||
2237 | // pack and round | ||
2238 | uint8x8_t p0 = vqrshrun_n_s16(row0, 1); | ||
2239 | uint8x8_t p1 = vqrshrun_n_s16(row1, 1); | ||
2240 | uint8x8_t p2 = vqrshrun_n_s16(row2, 1); | ||
2241 | uint8x8_t p3 = vqrshrun_n_s16(row3, 1); | ||
2242 | uint8x8_t p4 = vqrshrun_n_s16(row4, 1); | ||
2243 | uint8x8_t p5 = vqrshrun_n_s16(row5, 1); | ||
2244 | uint8x8_t p6 = vqrshrun_n_s16(row6, 1); | ||
2245 | uint8x8_t p7 = vqrshrun_n_s16(row7, 1); | ||
2246 | |||
2247 | // again, these can translate into one instruction, but often don't. | ||
2248 | #define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } | ||
2249 | #define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } | ||
2250 | #define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } | ||
2251 | |||
2252 | // sadly can't use interleaved stores here since we only write | ||
2253 | // 8 bytes to each scan line! | ||
2254 | |||
2255 | // 8x8 8-bit transpose pass 1 | ||
2256 | dct_trn8_8(p0, p1); | ||
2257 | dct_trn8_8(p2, p3); | ||
2258 | dct_trn8_8(p4, p5); | ||
2259 | dct_trn8_8(p6, p7); | ||
2260 | |||
2261 | // pass 2 | ||
2262 | dct_trn8_16(p0, p2); | ||
2263 | dct_trn8_16(p1, p3); | ||
2264 | dct_trn8_16(p4, p6); | ||
2265 | dct_trn8_16(p5, p7); | ||
2266 | |||
2267 | // pass 3 | ||
2268 | dct_trn8_32(p0, p4); | ||
2269 | dct_trn8_32(p1, p5); | ||
2270 | dct_trn8_32(p2, p6); | ||
2271 | dct_trn8_32(p3, p7); | ||
2272 | |||
2273 | // store | ||
2274 | vst1_u8(out, p0); out += out_stride; | ||
2275 | vst1_u8(out, p1); out += out_stride; | ||
2276 | vst1_u8(out, p2); out += out_stride; | ||
2277 | vst1_u8(out, p3); out += out_stride; | ||
2278 | vst1_u8(out, p4); out += out_stride; | ||
2279 | vst1_u8(out, p5); out += out_stride; | ||
2280 | vst1_u8(out, p6); out += out_stride; | ||
2281 | vst1_u8(out, p7); | ||
2282 | |||
2283 | #undef dct_trn8_8 | ||
2284 | #undef dct_trn8_16 | ||
2285 | #undef dct_trn8_32 | ||
2286 | } | ||
2287 | |||
2288 | #undef dct_long_mul | ||
2289 | #undef dct_long_mac | ||
2290 | #undef dct_widen | ||
2291 | #undef dct_wadd | ||
2292 | #undef dct_wsub | ||
2293 | #undef dct_bfly32o | ||
2294 | #undef dct_pass | ||
2295 | } | ||
2296 | |||
2297 | #endif // STBI_NEON | ||
2298 | |||
2299 | #define STBI__MARKER_none 0xff | ||
2300 | // if there's a pending marker from the entropy stream, return that | ||
2301 | // otherwise, fetch from the stream and get a marker. if there's no | ||
2302 | // marker, return 0xff, which is never a valid marker value | ||
2303 | static stbi_uc stbi__get_marker(stbi__jpeg *j) | ||
2304 | { | ||
2305 | stbi_uc x; | ||
2306 | if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } | ||
2307 | x = stbi__get8(j->s); | ||
2308 | if (x != 0xff) return STBI__MARKER_none; | ||
2309 | while (x == 0xff) | ||
2310 | x = stbi__get8(j->s); | ||
2311 | return x; | ||
2312 | } | ||
2313 | |||
2314 | // in each scan, we'll have scan_n components, and the order | ||
2315 | // of the components is specified by order[] | ||
2316 | #define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) | ||
2317 | |||
2318 | // after a restart interval, stbi__jpeg_reset the entropy decoder and | ||
2319 | // the dc prediction | ||
2320 | static void stbi__jpeg_reset(stbi__jpeg *j) | ||
2321 | { | ||
2322 | j->code_bits = 0; | ||
2323 | j->code_buffer = 0; | ||
2324 | j->nomore = 0; | ||
2325 | j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; | ||
2326 | j->marker = STBI__MARKER_none; | ||
2327 | j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; | ||
2328 | j->eob_run = 0; | ||
2329 | // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, | ||
2330 | // since we don't even allow 1<<30 pixels | ||
2331 | } | ||
2332 | |||
2333 | static int stbi__parse_entropy_coded_data(stbi__jpeg *z) | ||
2334 | { | ||
2335 | stbi__jpeg_reset(z); | ||
2336 | if (!z->progressive) { | ||
2337 | if (z->scan_n == 1) { | ||
2338 | int i,j; | ||
2339 | STBI_SIMD_ALIGN(short, data[64]); | ||
2340 | int n = z->order[0]; | ||
2341 | // non-interleaved data, we just need to process one block at a time, | ||
2342 | // in trivial scanline order | ||
2343 | // number of blocks to do just depends on how many actual "pixels" this | ||
2344 | // component has, independent of interleaved MCU blocking and such | ||
2345 | int w = (z->img_comp[n].x+7) >> 3; | ||
2346 | int h = (z->img_comp[n].y+7) >> 3; | ||
2347 | for (j=0; j < h; ++j) { | ||
2348 | for (i=0; i < w; ++i) { | ||
2349 | int ha = z->img_comp[n].ha; | ||
2350 | if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; | ||
2351 | z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); | ||
2352 | // every data block is an MCU, so countdown the restart interval | ||
2353 | if (--z->todo <= 0) { | ||
2354 | if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); | ||
2355 | // if it's NOT a restart, then just bail, so we get corrupt data | ||
2356 | // rather than no data | ||
2357 | if (!STBI__RESTART(z->marker)) return 1; | ||
2358 | stbi__jpeg_reset(z); | ||
2359 | } | ||
2360 | } | ||
2361 | } | ||
2362 | return 1; | ||
2363 | } else { // interleaved | ||
2364 | int i,j,k,x,y; | ||
2365 | STBI_SIMD_ALIGN(short, data[64]); | ||
2366 | for (j=0; j < z->img_mcu_y; ++j) { | ||
2367 | for (i=0; i < z->img_mcu_x; ++i) { | ||
2368 | // scan an interleaved mcu... process scan_n components in order | ||
2369 | for (k=0; k < z->scan_n; ++k) { | ||
2370 | int n = z->order[k]; | ||
2371 | // scan out an mcu's worth of this component; that's just determined | ||
2372 | // by the basic H and V specified for the component | ||
2373 | for (y=0; y < z->img_comp[n].v; ++y) { | ||
2374 | for (x=0; x < z->img_comp[n].h; ++x) { | ||
2375 | int x2 = (i*z->img_comp[n].h + x)*8; | ||
2376 | int y2 = (j*z->img_comp[n].v + y)*8; | ||
2377 | int ha = z->img_comp[n].ha; | ||
2378 | if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; | ||
2379 | z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); | ||
2380 | } | ||
2381 | } | ||
2382 | } | ||
2383 | // after all interleaved components, that's an interleaved MCU, | ||
2384 | // so now count down the restart interval | ||
2385 | if (--z->todo <= 0) { | ||
2386 | if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); | ||
2387 | if (!STBI__RESTART(z->marker)) return 1; | ||
2388 | stbi__jpeg_reset(z); | ||
2389 | } | ||
2390 | } | ||
2391 | } | ||
2392 | return 1; | ||
2393 | } | ||
2394 | } else { | ||
2395 | if (z->scan_n == 1) { | ||
2396 | int i,j; | ||
2397 | int n = z->order[0]; | ||
2398 | // non-interleaved data, we just need to process one block at a time, | ||
2399 | // in trivial scanline order | ||
2400 | // number of blocks to do just depends on how many actual "pixels" this | ||
2401 | // component has, independent of interleaved MCU blocking and such | ||
2402 | int w = (z->img_comp[n].x+7) >> 3; | ||
2403 | int h = (z->img_comp[n].y+7) >> 3; | ||
2404 | for (j=0; j < h; ++j) { | ||
2405 | for (i=0; i < w; ++i) { | ||
2406 | short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); | ||
2407 | if (z->spec_start == 0) { | ||
2408 | if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) | ||
2409 | return 0; | ||
2410 | } else { | ||
2411 | int ha = z->img_comp[n].ha; | ||
2412 | if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) | ||
2413 | return 0; | ||
2414 | } | ||
2415 | // every data block is an MCU, so countdown the restart interval | ||
2416 | if (--z->todo <= 0) { | ||
2417 | if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); | ||
2418 | if (!STBI__RESTART(z->marker)) return 1; | ||
2419 | stbi__jpeg_reset(z); | ||
2420 | } | ||
2421 | } | ||
2422 | } | ||
2423 | return 1; | ||
2424 | } else { // interleaved | ||
2425 | int i,j,k,x,y; | ||
2426 | for (j=0; j < z->img_mcu_y; ++j) { | ||
2427 | for (i=0; i < z->img_mcu_x; ++i) { | ||
2428 | // scan an interleaved mcu... process scan_n components in order | ||
2429 | for (k=0; k < z->scan_n; ++k) { | ||
2430 | int n = z->order[k]; | ||
2431 | // scan out an mcu's worth of this component; that's just determined | ||
2432 | // by the basic H and V specified for the component | ||
2433 | for (y=0; y < z->img_comp[n].v; ++y) { | ||
2434 | for (x=0; x < z->img_comp[n].h; ++x) { | ||
2435 | int x2 = (i*z->img_comp[n].h + x); | ||
2436 | int y2 = (j*z->img_comp[n].v + y); | ||
2437 | short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); | ||
2438 | if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) | ||
2439 | return 0; | ||
2440 | } | ||
2441 | } | ||
2442 | } | ||
2443 | // after all interleaved components, that's an interleaved MCU, | ||
2444 | // so now count down the restart interval | ||
2445 | if (--z->todo <= 0) { | ||
2446 | if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); | ||
2447 | if (!STBI__RESTART(z->marker)) return 1; | ||
2448 | stbi__jpeg_reset(z); | ||
2449 | } | ||
2450 | } | ||
2451 | } | ||
2452 | return 1; | ||
2453 | } | ||
2454 | } | ||
2455 | } | ||
2456 | |||
2457 | static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) | ||
2458 | { | ||
2459 | int i; | ||
2460 | for (i=0; i < 64; ++i) | ||
2461 | data[i] *= dequant[i]; | ||
2462 | } | ||
2463 | |||
2464 | static void stbi__jpeg_finish(stbi__jpeg *z) | ||
2465 | { | ||
2466 | if (z->progressive) { | ||
2467 | // dequantize and idct the data | ||
2468 | int i,j,n; | ||
2469 | for (n=0; n < z->s->img_n; ++n) { | ||
2470 | int w = (z->img_comp[n].x+7) >> 3; | ||
2471 | int h = (z->img_comp[n].y+7) >> 3; | ||
2472 | for (j=0; j < h; ++j) { | ||
2473 | for (i=0; i < w; ++i) { | ||
2474 | short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); | ||
2475 | stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); | ||
2476 | z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); | ||
2477 | } | ||
2478 | } | ||
2479 | } | ||
2480 | } | ||
2481 | } | ||
2482 | |||
2483 | static int stbi__process_marker(stbi__jpeg *z, int m) | ||
2484 | { | ||
2485 | int L; | ||
2486 | switch (m) { | ||
2487 | case STBI__MARKER_none: // no marker found | ||
2488 | return stbi__err("expected marker","Corrupt JPEG"); | ||
2489 | |||
2490 | case 0xDD: // DRI - specify restart interval | ||
2491 | if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); | ||
2492 | z->restart_interval = stbi__get16be(z->s); | ||
2493 | return 1; | ||
2494 | |||
2495 | case 0xDB: // DQT - define quantization table | ||
2496 | L = stbi__get16be(z->s)-2; | ||
2497 | while (L > 0) { | ||
2498 | int q = stbi__get8(z->s); | ||
2499 | int p = q >> 4; | ||
2500 | int t = q & 15,i; | ||
2501 | if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); | ||
2502 | if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); | ||
2503 | for (i=0; i < 64; ++i) | ||
2504 | z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); | ||
2505 | L -= 65; | ||
2506 | } | ||
2507 | return L==0; | ||
2508 | |||
2509 | case 0xC4: // DHT - define huffman table | ||
2510 | L = stbi__get16be(z->s)-2; | ||
2511 | while (L > 0) { | ||
2512 | stbi_uc *v; | ||
2513 | int sizes[16],i,n=0; | ||
2514 | int q = stbi__get8(z->s); | ||
2515 | int tc = q >> 4; | ||
2516 | int th = q & 15; | ||
2517 | if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); | ||
2518 | for (i=0; i < 16; ++i) { | ||
2519 | sizes[i] = stbi__get8(z->s); | ||
2520 | n += sizes[i]; | ||
2521 | } | ||
2522 | L -= 17; | ||
2523 | if (tc == 0) { | ||
2524 | if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; | ||
2525 | v = z->huff_dc[th].values; | ||
2526 | } else { | ||
2527 | if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; | ||
2528 | v = z->huff_ac[th].values; | ||
2529 | } | ||
2530 | for (i=0; i < n; ++i) | ||
2531 | v[i] = stbi__get8(z->s); | ||
2532 | if (tc != 0) | ||
2533 | stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); | ||
2534 | L -= n; | ||
2535 | } | ||
2536 | return L==0; | ||
2537 | } | ||
2538 | // check for comment block or APP blocks | ||
2539 | if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { | ||
2540 | stbi__skip(z->s, stbi__get16be(z->s)-2); | ||
2541 | return 1; | ||
2542 | } | ||
2543 | return 0; | ||
2544 | } | ||
2545 | |||
2546 | // after we see SOS | ||
2547 | static int stbi__process_scan_header(stbi__jpeg *z) | ||
2548 | { | ||
2549 | int i; | ||
2550 | int Ls = stbi__get16be(z->s); | ||
2551 | z->scan_n = stbi__get8(z->s); | ||
2552 | if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); | ||
2553 | if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); | ||
2554 | for (i=0; i < z->scan_n; ++i) { | ||
2555 | int id = stbi__get8(z->s), which; | ||
2556 | int q = stbi__get8(z->s); | ||
2557 | for (which = 0; which < z->s->img_n; ++which) | ||
2558 | if (z->img_comp[which].id == id) | ||
2559 | break; | ||
2560 | if (which == z->s->img_n) return 0; // no match | ||
2561 | z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); | ||
2562 | z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); | ||
2563 | z->order[i] = which; | ||
2564 | } | ||
2565 | |||
2566 | { | ||
2567 | int aa; | ||
2568 | z->spec_start = stbi__get8(z->s); | ||
2569 | z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 | ||
2570 | aa = stbi__get8(z->s); | ||
2571 | z->succ_high = (aa >> 4); | ||
2572 | z->succ_low = (aa & 15); | ||
2573 | if (z->progressive) { | ||
2574 | if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) | ||
2575 | return stbi__err("bad SOS", "Corrupt JPEG"); | ||
2576 | } else { | ||
2577 | if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); | ||
2578 | if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); | ||
2579 | z->spec_end = 63; | ||
2580 | } | ||
2581 | } | ||
2582 | |||
2583 | return 1; | ||
2584 | } | ||
2585 | |||
2586 | static int stbi__process_frame_header(stbi__jpeg *z, int scan) | ||
2587 | { | ||
2588 | stbi__context *s = z->s; | ||
2589 | int Lf,p,i,q, h_max=1,v_max=1,c; | ||
2590 | Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG | ||
2591 | p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline | ||
2592 | s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG | ||
2593 | s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires | ||
2594 | c = stbi__get8(s); | ||
2595 | if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires | ||
2596 | s->img_n = c; | ||
2597 | for (i=0; i < c; ++i) { | ||
2598 | z->img_comp[i].data = NULL; | ||
2599 | z->img_comp[i].linebuf = NULL; | ||
2600 | } | ||
2601 | |||
2602 | if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); | ||
2603 | |||
2604 | for (i=0; i < s->img_n; ++i) { | ||
2605 | z->img_comp[i].id = stbi__get8(s); | ||
2606 | if (z->img_comp[i].id != i+1) // JFIF requires | ||
2607 | if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! | ||
2608 | return stbi__err("bad component ID","Corrupt JPEG"); | ||
2609 | q = stbi__get8(s); | ||
2610 | z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); | ||
2611 | z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); | ||
2612 | z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); | ||
2613 | } | ||
2614 | |||
2615 | if (scan != STBI__SCAN_load) return 1; | ||
2616 | |||
2617 | if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); | ||
2618 | |||
2619 | for (i=0; i < s->img_n; ++i) { | ||
2620 | if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; | ||
2621 | if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; | ||
2622 | } | ||
2623 | |||
2624 | // compute interleaved mcu info | ||
2625 | z->img_h_max = h_max; | ||
2626 | z->img_v_max = v_max; | ||
2627 | z->img_mcu_w = h_max * 8; | ||
2628 | z->img_mcu_h = v_max * 8; | ||
2629 | z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; | ||
2630 | z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; | ||
2631 | |||
2632 | for (i=0; i < s->img_n; ++i) { | ||
2633 | // number of effective pixels (e.g. for non-interleaved MCU) | ||
2634 | z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; | ||
2635 | z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; | ||
2636 | // to simplify generation, we'll allocate enough memory to decode | ||
2637 | // the bogus oversized data from using interleaved MCUs and their | ||
2638 | // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't | ||
2639 | // discard the extra data until colorspace conversion | ||
2640 | z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; | ||
2641 | z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; | ||
2642 | z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); | ||
2643 | |||
2644 | if (z->img_comp[i].raw_data == NULL) { | ||
2645 | for(--i; i >= 0; --i) { | ||
2646 | STBI_FREE(z->img_comp[i].raw_data); | ||
2647 | z->img_comp[i].data = NULL; | ||
2648 | } | ||
2649 | return stbi__err("outofmem", "Out of memory"); | ||
2650 | } | ||
2651 | // align blocks for idct using mmx/sse | ||
2652 | z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); | ||
2653 | z->img_comp[i].linebuf = NULL; | ||
2654 | if (z->progressive) { | ||
2655 | z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; | ||
2656 | z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; | ||
2657 | z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); | ||
2658 | z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); | ||
2659 | } else { | ||
2660 | z->img_comp[i].coeff = 0; | ||
2661 | z->img_comp[i].raw_coeff = 0; | ||
2662 | } | ||
2663 | } | ||
2664 | |||
2665 | return 1; | ||
2666 | } | ||
2667 | |||
2668 | // use comparisons since in some cases we handle more than one case (e.g. SOF) | ||
2669 | #define stbi__DNL(x) ((x) == 0xdc) | ||
2670 | #define stbi__SOI(x) ((x) == 0xd8) | ||
2671 | #define stbi__EOI(x) ((x) == 0xd9) | ||
2672 | #define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) | ||
2673 | #define stbi__SOS(x) ((x) == 0xda) | ||
2674 | |||
2675 | #define stbi__SOF_progressive(x) ((x) == 0xc2) | ||
2676 | |||
2677 | static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) | ||
2678 | { | ||
2679 | int m; | ||
2680 | z->marker = STBI__MARKER_none; // initialize cached marker to empty | ||
2681 | m = stbi__get_marker(z); | ||
2682 | if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); | ||
2683 | if (scan == STBI__SCAN_type) return 1; | ||
2684 | m = stbi__get_marker(z); | ||
2685 | while (!stbi__SOF(m)) { | ||
2686 | if (!stbi__process_marker(z,m)) return 0; | ||
2687 | m = stbi__get_marker(z); | ||
2688 | while (m == STBI__MARKER_none) { | ||
2689 | // some files have extra padding after their blocks, so ok, we'll scan | ||
2690 | if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); | ||
2691 | m = stbi__get_marker(z); | ||
2692 | } | ||
2693 | } | ||
2694 | z->progressive = stbi__SOF_progressive(m); | ||
2695 | if (!stbi__process_frame_header(z, scan)) return 0; | ||
2696 | return 1; | ||
2697 | } | ||
2698 | |||
2699 | // decode image to YCbCr format | ||
2700 | static int stbi__decode_jpeg_image(stbi__jpeg *j) | ||
2701 | { | ||
2702 | int m; | ||
2703 | j->restart_interval = 0; | ||
2704 | if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; | ||
2705 | m = stbi__get_marker(j); | ||
2706 | while (!stbi__EOI(m)) { | ||
2707 | if (stbi__SOS(m)) { | ||
2708 | if (!stbi__process_scan_header(j)) return 0; | ||
2709 | if (!stbi__parse_entropy_coded_data(j)) return 0; | ||
2710 | if (j->marker == STBI__MARKER_none ) { | ||
2711 | // handle 0s at the end of image data from IP Kamera 9060 | ||
2712 | while (!stbi__at_eof(j->s)) { | ||
2713 | int x = stbi__get8(j->s); | ||
2714 | if (x == 255) { | ||
2715 | j->marker = stbi__get8(j->s); | ||
2716 | break; | ||
2717 | } else if (x != 0) { | ||
2718 | return stbi__err("junk before marker", "Corrupt JPEG"); | ||
2719 | } | ||
2720 | } | ||
2721 | // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 | ||
2722 | } | ||
2723 | } else { | ||
2724 | if (!stbi__process_marker(j, m)) return 0; | ||
2725 | } | ||
2726 | m = stbi__get_marker(j); | ||
2727 | } | ||
2728 | if (j->progressive) | ||
2729 | stbi__jpeg_finish(j); | ||
2730 | return 1; | ||
2731 | } | ||
2732 | |||
2733 | // static jfif-centered resampling (across block boundaries) | ||
2734 | |||
2735 | typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, | ||
2736 | int w, int hs); | ||
2737 | |||
2738 | #define stbi__div4(x) ((stbi_uc) ((x) >> 2)) | ||
2739 | |||
2740 | static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2741 | { | ||
2742 | STBI_NOTUSED(out); | ||
2743 | STBI_NOTUSED(in_far); | ||
2744 | STBI_NOTUSED(w); | ||
2745 | STBI_NOTUSED(hs); | ||
2746 | return in_near; | ||
2747 | } | ||
2748 | |||
2749 | static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2750 | { | ||
2751 | // need to generate two samples vertically for every one in input | ||
2752 | int i; | ||
2753 | STBI_NOTUSED(hs); | ||
2754 | for (i=0; i < w; ++i) | ||
2755 | out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); | ||
2756 | return out; | ||
2757 | } | ||
2758 | |||
2759 | static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2760 | { | ||
2761 | // need to generate two samples horizontally for every one in input | ||
2762 | int i; | ||
2763 | stbi_uc *input = in_near; | ||
2764 | |||
2765 | if (w == 1) { | ||
2766 | // if only one sample, can't do any interpolation | ||
2767 | out[0] = out[1] = input[0]; | ||
2768 | return out; | ||
2769 | } | ||
2770 | |||
2771 | out[0] = input[0]; | ||
2772 | out[1] = stbi__div4(input[0]*3 + input[1] + 2); | ||
2773 | for (i=1; i < w-1; ++i) { | ||
2774 | int n = 3*input[i]+2; | ||
2775 | out[i*2+0] = stbi__div4(n+input[i-1]); | ||
2776 | out[i*2+1] = stbi__div4(n+input[i+1]); | ||
2777 | } | ||
2778 | out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); | ||
2779 | out[i*2+1] = input[w-1]; | ||
2780 | |||
2781 | STBI_NOTUSED(in_far); | ||
2782 | STBI_NOTUSED(hs); | ||
2783 | |||
2784 | return out; | ||
2785 | } | ||
2786 | |||
2787 | #define stbi__div16(x) ((stbi_uc) ((x) >> 4)) | ||
2788 | |||
2789 | static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2790 | { | ||
2791 | // need to generate 2x2 samples for every one in input | ||
2792 | int i,t0,t1; | ||
2793 | if (w == 1) { | ||
2794 | out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); | ||
2795 | return out; | ||
2796 | } | ||
2797 | |||
2798 | t1 = 3*in_near[0] + in_far[0]; | ||
2799 | out[0] = stbi__div4(t1+2); | ||
2800 | for (i=1; i < w; ++i) { | ||
2801 | t0 = t1; | ||
2802 | t1 = 3*in_near[i]+in_far[i]; | ||
2803 | out[i*2-1] = stbi__div16(3*t0 + t1 + 8); | ||
2804 | out[i*2 ] = stbi__div16(3*t1 + t0 + 8); | ||
2805 | } | ||
2806 | out[w*2-1] = stbi__div4(t1+2); | ||
2807 | |||
2808 | STBI_NOTUSED(hs); | ||
2809 | |||
2810 | return out; | ||
2811 | } | ||
2812 | |||
2813 | #if defined(STBI_SSE2) || defined(STBI_NEON) | ||
2814 | static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2815 | { | ||
2816 | // need to generate 2x2 samples for every one in input | ||
2817 | int i=0,t0,t1; | ||
2818 | |||
2819 | if (w == 1) { | ||
2820 | out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); | ||
2821 | return out; | ||
2822 | } | ||
2823 | |||
2824 | t1 = 3*in_near[0] + in_far[0]; | ||
2825 | // process groups of 8 pixels for as long as we can. | ||
2826 | // note we can't handle the last pixel in a row in this loop | ||
2827 | // because we need to handle the filter boundary conditions. | ||
2828 | for (; i < ((w-1) & ~7); i += 8) { | ||
2829 | #if defined(STBI_SSE2) | ||
2830 | // load and perform the vertical filtering pass | ||
2831 | // this uses 3*x + y = 4*x + (y - x) | ||
2832 | __m128i zero = _mm_setzero_si128(); | ||
2833 | __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); | ||
2834 | __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); | ||
2835 | __m128i farw = _mm_unpacklo_epi8(farb, zero); | ||
2836 | __m128i nearw = _mm_unpacklo_epi8(nearb, zero); | ||
2837 | __m128i diff = _mm_sub_epi16(farw, nearw); | ||
2838 | __m128i nears = _mm_slli_epi16(nearw, 2); | ||
2839 | __m128i curr = _mm_add_epi16(nears, diff); // current row | ||
2840 | |||
2841 | // horizontal filter works the same based on shifted vers of current | ||
2842 | // row. "prev" is current row shifted right by 1 pixel; we need to | ||
2843 | // insert the previous pixel value (from t1). | ||
2844 | // "next" is current row shifted left by 1 pixel, with first pixel | ||
2845 | // of next block of 8 pixels added in. | ||
2846 | __m128i prv0 = _mm_slli_si128(curr, 2); | ||
2847 | __m128i nxt0 = _mm_srli_si128(curr, 2); | ||
2848 | __m128i prev = _mm_insert_epi16(prv0, t1, 0); | ||
2849 | __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); | ||
2850 | |||
2851 | // horizontal filter, polyphase implementation since it's convenient: | ||
2852 | // even pixels = 3*cur + prev = cur*4 + (prev - cur) | ||
2853 | // odd pixels = 3*cur + next = cur*4 + (next - cur) | ||
2854 | // note the shared term. | ||
2855 | __m128i bias = _mm_set1_epi16(8); | ||
2856 | __m128i curs = _mm_slli_epi16(curr, 2); | ||
2857 | __m128i prvd = _mm_sub_epi16(prev, curr); | ||
2858 | __m128i nxtd = _mm_sub_epi16(next, curr); | ||
2859 | __m128i curb = _mm_add_epi16(curs, bias); | ||
2860 | __m128i even = _mm_add_epi16(prvd, curb); | ||
2861 | __m128i odd = _mm_add_epi16(nxtd, curb); | ||
2862 | |||
2863 | // interleave even and odd pixels, then undo scaling. | ||
2864 | __m128i int0 = _mm_unpacklo_epi16(even, odd); | ||
2865 | __m128i int1 = _mm_unpackhi_epi16(even, odd); | ||
2866 | __m128i de0 = _mm_srli_epi16(int0, 4); | ||
2867 | __m128i de1 = _mm_srli_epi16(int1, 4); | ||
2868 | |||
2869 | // pack and write output | ||
2870 | __m128i outv = _mm_packus_epi16(de0, de1); | ||
2871 | _mm_storeu_si128((__m128i *) (out + i*2), outv); | ||
2872 | #elif defined(STBI_NEON) | ||
2873 | // load and perform the vertical filtering pass | ||
2874 | // this uses 3*x + y = 4*x + (y - x) | ||
2875 | uint8x8_t farb = vld1_u8(in_far + i); | ||
2876 | uint8x8_t nearb = vld1_u8(in_near + i); | ||
2877 | int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); | ||
2878 | int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); | ||
2879 | int16x8_t curr = vaddq_s16(nears, diff); // current row | ||
2880 | |||
2881 | // horizontal filter works the same based on shifted vers of current | ||
2882 | // row. "prev" is current row shifted right by 1 pixel; we need to | ||
2883 | // insert the previous pixel value (from t1). | ||
2884 | // "next" is current row shifted left by 1 pixel, with first pixel | ||
2885 | // of next block of 8 pixels added in. | ||
2886 | int16x8_t prv0 = vextq_s16(curr, curr, 7); | ||
2887 | int16x8_t nxt0 = vextq_s16(curr, curr, 1); | ||
2888 | int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); | ||
2889 | int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); | ||
2890 | |||
2891 | // horizontal filter, polyphase implementation since it's convenient: | ||
2892 | // even pixels = 3*cur + prev = cur*4 + (prev - cur) | ||
2893 | // odd pixels = 3*cur + next = cur*4 + (next - cur) | ||
2894 | // note the shared term. | ||
2895 | int16x8_t curs = vshlq_n_s16(curr, 2); | ||
2896 | int16x8_t prvd = vsubq_s16(prev, curr); | ||
2897 | int16x8_t nxtd = vsubq_s16(next, curr); | ||
2898 | int16x8_t even = vaddq_s16(curs, prvd); | ||
2899 | int16x8_t odd = vaddq_s16(curs, nxtd); | ||
2900 | |||
2901 | // undo scaling and round, then store with even/odd phases interleaved | ||
2902 | uint8x8x2_t o; | ||
2903 | o.val[0] = vqrshrun_n_s16(even, 4); | ||
2904 | o.val[1] = vqrshrun_n_s16(odd, 4); | ||
2905 | vst2_u8(out + i*2, o); | ||
2906 | #endif | ||
2907 | |||
2908 | // "previous" value for next iter | ||
2909 | t1 = 3*in_near[i+7] + in_far[i+7]; | ||
2910 | } | ||
2911 | |||
2912 | t0 = t1; | ||
2913 | t1 = 3*in_near[i] + in_far[i]; | ||
2914 | out[i*2] = stbi__div16(3*t1 + t0 + 8); | ||
2915 | |||
2916 | for (++i; i < w; ++i) { | ||
2917 | t0 = t1; | ||
2918 | t1 = 3*in_near[i]+in_far[i]; | ||
2919 | out[i*2-1] = stbi__div16(3*t0 + t1 + 8); | ||
2920 | out[i*2 ] = stbi__div16(3*t1 + t0 + 8); | ||
2921 | } | ||
2922 | out[w*2-1] = stbi__div4(t1+2); | ||
2923 | |||
2924 | STBI_NOTUSED(hs); | ||
2925 | |||
2926 | return out; | ||
2927 | } | ||
2928 | #endif | ||
2929 | |||
2930 | static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) | ||
2931 | { | ||
2932 | // resample with nearest-neighbor | ||
2933 | int i,j; | ||
2934 | STBI_NOTUSED(in_far); | ||
2935 | for (i=0; i < w; ++i) | ||
2936 | for (j=0; j < hs; ++j) | ||
2937 | out[i*hs+j] = in_near[i]; | ||
2938 | return out; | ||
2939 | } | ||
2940 | |||
2941 | #ifdef STBI_JPEG_OLD | ||
2942 | // this is the same YCbCr-to-RGB calculation that stb_image has used | ||
2943 | // historically before the algorithm changes in 1.49 | ||
2944 | #define float2fixed(x) ((int) ((x) * 65536 + 0.5)) | ||
2945 | static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) | ||
2946 | { | ||
2947 | int i; | ||
2948 | for (i=0; i < count; ++i) { | ||
2949 | int y_fixed = (y[i] << 16) + 32768; // rounding | ||
2950 | int r,g,b; | ||
2951 | int cr = pcr[i] - 128; | ||
2952 | int cb = pcb[i] - 128; | ||
2953 | r = y_fixed + cr*float2fixed(1.40200f); | ||
2954 | g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); | ||
2955 | b = y_fixed + cb*float2fixed(1.77200f); | ||
2956 | r >>= 16; | ||
2957 | g >>= 16; | ||
2958 | b >>= 16; | ||
2959 | if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } | ||
2960 | if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } | ||
2961 | if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } | ||
2962 | out[0] = (stbi_uc)r; | ||
2963 | out[1] = (stbi_uc)g; | ||
2964 | out[2] = (stbi_uc)b; | ||
2965 | out[3] = 255; | ||
2966 | out += step; | ||
2967 | } | ||
2968 | } | ||
2969 | #else | ||
2970 | // this is a reduced-precision calculation of YCbCr-to-RGB introduced | ||
2971 | // to make sure the code produces the same results in both SIMD and scalar | ||
2972 | #define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) | ||
2973 | static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) | ||
2974 | { | ||
2975 | int i; | ||
2976 | for (i=0; i < count; ++i) { | ||
2977 | int y_fixed = (y[i] << 20) + (1<<19); // rounding | ||
2978 | int r,g,b; | ||
2979 | int cr = pcr[i] - 128; | ||
2980 | int cb = pcb[i] - 128; | ||
2981 | r = y_fixed + cr* float2fixed(1.40200f); | ||
2982 | g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); | ||
2983 | b = y_fixed + cb* float2fixed(1.77200f); | ||
2984 | r >>= 20; | ||
2985 | g >>= 20; | ||
2986 | b >>= 20; | ||
2987 | if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } | ||
2988 | if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } | ||
2989 | if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } | ||
2990 | out[0] = (stbi_uc)r; | ||
2991 | out[1] = (stbi_uc)g; | ||
2992 | out[2] = (stbi_uc)b; | ||
2993 | out[3] = 255; | ||
2994 | out += step; | ||
2995 | } | ||
2996 | } | ||
2997 | #endif | ||
2998 | |||
2999 | #if defined(STBI_SSE2) || defined(STBI_NEON) | ||
3000 | static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) | ||
3001 | { | ||
3002 | int i = 0; | ||
3003 | |||
3004 | #ifdef STBI_SSE2 | ||
3005 | // step == 3 is pretty ugly on the final interleave, and i'm not convinced | ||
3006 | // it's useful in practice (you wouldn't use it for textures, for example). | ||
3007 | // so just accelerate step == 4 case. | ||
3008 | if (step == 4) { | ||
3009 | // this is a fairly straightforward implementation and not super-optimized. | ||
3010 | __m128i signflip = _mm_set1_epi8(-0x80); | ||
3011 | __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); | ||
3012 | __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); | ||
3013 | __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); | ||
3014 | __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); | ||
3015 | __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); | ||
3016 | __m128i xw = _mm_set1_epi16(255); // alpha channel | ||
3017 | |||
3018 | for (; i+7 < count; i += 8) { | ||
3019 | // load | ||
3020 | __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); | ||
3021 | __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); | ||
3022 | __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); | ||
3023 | __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 | ||
3024 | __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 | ||
3025 | |||
3026 | // unpack to short (and left-shift cr, cb by 8) | ||
3027 | __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); | ||
3028 | __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); | ||
3029 | __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); | ||
3030 | |||
3031 | // color transform | ||
3032 | __m128i yws = _mm_srli_epi16(yw, 4); | ||
3033 | __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); | ||
3034 | __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); | ||
3035 | __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); | ||
3036 | __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); | ||
3037 | __m128i rws = _mm_add_epi16(cr0, yws); | ||
3038 | __m128i gwt = _mm_add_epi16(cb0, yws); | ||
3039 | __m128i bws = _mm_add_epi16(yws, cb1); | ||
3040 | __m128i gws = _mm_add_epi16(gwt, cr1); | ||
3041 | |||
3042 | // descale | ||
3043 | __m128i rw = _mm_srai_epi16(rws, 4); | ||
3044 | __m128i bw = _mm_srai_epi16(bws, 4); | ||
3045 | __m128i gw = _mm_srai_epi16(gws, 4); | ||
3046 | |||
3047 | // back to byte, set up for transpose | ||
3048 | __m128i brb = _mm_packus_epi16(rw, bw); | ||
3049 | __m128i gxb = _mm_packus_epi16(gw, xw); | ||
3050 | |||
3051 | // transpose to interleave channels | ||
3052 | __m128i t0 = _mm_unpacklo_epi8(brb, gxb); | ||
3053 | __m128i t1 = _mm_unpackhi_epi8(brb, gxb); | ||
3054 | __m128i o0 = _mm_unpacklo_epi16(t0, t1); | ||
3055 | __m128i o1 = _mm_unpackhi_epi16(t0, t1); | ||
3056 | |||
3057 | // store | ||
3058 | _mm_storeu_si128((__m128i *) (out + 0), o0); | ||
3059 | _mm_storeu_si128((__m128i *) (out + 16), o1); | ||
3060 | out += 32; | ||
3061 | } | ||
3062 | } | ||
3063 | #endif | ||
3064 | |||
3065 | #ifdef STBI_NEON | ||
3066 | // in this version, step=3 support would be easy to add. but is there demand? | ||
3067 | if (step == 4) { | ||
3068 | // this is a fairly straightforward implementation and not super-optimized. | ||
3069 | uint8x8_t signflip = vdup_n_u8(0x80); | ||
3070 | int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); | ||
3071 | int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); | ||
3072 | int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); | ||
3073 | int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); | ||
3074 | |||
3075 | for (; i+7 < count; i += 8) { | ||
3076 | // load | ||
3077 | uint8x8_t y_bytes = vld1_u8(y + i); | ||
3078 | uint8x8_t cr_bytes = vld1_u8(pcr + i); | ||
3079 | uint8x8_t cb_bytes = vld1_u8(pcb + i); | ||
3080 | int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); | ||
3081 | int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); | ||
3082 | |||
3083 | // expand to s16 | ||
3084 | int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); | ||
3085 | int16x8_t crw = vshll_n_s8(cr_biased, 7); | ||
3086 | int16x8_t cbw = vshll_n_s8(cb_biased, 7); | ||
3087 | |||
3088 | // color transform | ||
3089 | int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); | ||
3090 | int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); | ||
3091 | int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); | ||
3092 | int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); | ||
3093 | int16x8_t rws = vaddq_s16(yws, cr0); | ||
3094 | int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); | ||
3095 | int16x8_t bws = vaddq_s16(yws, cb1); | ||
3096 | |||
3097 | // undo scaling, round, convert to byte | ||
3098 | uint8x8x4_t o; | ||
3099 | o.val[0] = vqrshrun_n_s16(rws, 4); | ||
3100 | o.val[1] = vqrshrun_n_s16(gws, 4); | ||
3101 | o.val[2] = vqrshrun_n_s16(bws, 4); | ||
3102 | o.val[3] = vdup_n_u8(255); | ||
3103 | |||
3104 | // store, interleaving r/g/b/a | ||
3105 | vst4_u8(out, o); | ||
3106 | out += 8*4; | ||
3107 | } | ||
3108 | } | ||
3109 | #endif | ||
3110 | |||
3111 | for (; i < count; ++i) { | ||
3112 | int y_fixed = (y[i] << 20) + (1<<19); // rounding | ||
3113 | int r,g,b; | ||
3114 | int cr = pcr[i] - 128; | ||
3115 | int cb = pcb[i] - 128; | ||
3116 | r = y_fixed + cr* float2fixed(1.40200f); | ||
3117 | g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); | ||
3118 | b = y_fixed + cb* float2fixed(1.77200f); | ||
3119 | r >>= 20; | ||
3120 | g >>= 20; | ||
3121 | b >>= 20; | ||
3122 | if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } | ||
3123 | if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } | ||
3124 | if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } | ||
3125 | out[0] = (stbi_uc)r; | ||
3126 | out[1] = (stbi_uc)g; | ||
3127 | out[2] = (stbi_uc)b; | ||
3128 | out[3] = 255; | ||
3129 | out += step; | ||
3130 | } | ||
3131 | } | ||
3132 | #endif | ||
3133 | |||
3134 | // set up the kernels | ||
3135 | static void stbi__setup_jpeg(stbi__jpeg *j) | ||
3136 | { | ||
3137 | j->idct_block_kernel = stbi__idct_block; | ||
3138 | j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; | ||
3139 | j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; | ||
3140 | |||
3141 | #ifdef STBI_SSE2 | ||
3142 | if (stbi__sse2_available()) { | ||
3143 | j->idct_block_kernel = stbi__idct_simd; | ||
3144 | #ifndef STBI_JPEG_OLD | ||
3145 | j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; | ||
3146 | #endif | ||
3147 | j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; | ||
3148 | } | ||
3149 | #endif | ||
3150 | |||
3151 | #ifdef STBI_NEON | ||
3152 | j->idct_block_kernel = stbi__idct_simd; | ||
3153 | #ifndef STBI_JPEG_OLD | ||
3154 | j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; | ||
3155 | #endif | ||
3156 | j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; | ||
3157 | #endif | ||
3158 | } | ||
3159 | |||
3160 | // clean up the temporary component buffers | ||
3161 | static void stbi__cleanup_jpeg(stbi__jpeg *j) | ||
3162 | { | ||
3163 | int i; | ||
3164 | for (i=0; i < j->s->img_n; ++i) { | ||
3165 | if (j->img_comp[i].raw_data) { | ||
3166 | STBI_FREE(j->img_comp[i].raw_data); | ||
3167 | j->img_comp[i].raw_data = NULL; | ||
3168 | j->img_comp[i].data = NULL; | ||
3169 | } | ||
3170 | if (j->img_comp[i].raw_coeff) { | ||
3171 | STBI_FREE(j->img_comp[i].raw_coeff); | ||
3172 | j->img_comp[i].raw_coeff = 0; | ||
3173 | j->img_comp[i].coeff = 0; | ||
3174 | } | ||
3175 | if (j->img_comp[i].linebuf) { | ||
3176 | STBI_FREE(j->img_comp[i].linebuf); | ||
3177 | j->img_comp[i].linebuf = NULL; | ||
3178 | } | ||
3179 | } | ||
3180 | } | ||
3181 | |||
3182 | typedef struct | ||
3183 | { | ||
3184 | resample_row_func resample; | ||
3185 | stbi_uc *line0,*line1; | ||
3186 | int hs,vs; // expansion factor in each axis | ||
3187 | int w_lores; // horizontal pixels pre-expansion | ||
3188 | int ystep; // how far through vertical expansion we are | ||
3189 | int ypos; // which pre-expansion row we're on | ||
3190 | } stbi__resample; | ||
3191 | |||
3192 | static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) | ||
3193 | { | ||
3194 | int n, decode_n; | ||
3195 | z->s->img_n = 0; // make stbi__cleanup_jpeg safe | ||
3196 | |||
3197 | // validate req_comp | ||
3198 | if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); | ||
3199 | |||
3200 | // load a jpeg image from whichever source, but leave in YCbCr format | ||
3201 | if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } | ||
3202 | |||
3203 | // determine actual number of components to generate | ||
3204 | n = req_comp ? req_comp : z->s->img_n; | ||
3205 | |||
3206 | if (z->s->img_n == 3 && n < 3) | ||
3207 | decode_n = 1; | ||
3208 | else | ||
3209 | decode_n = z->s->img_n; | ||
3210 | |||
3211 | // resample and color-convert | ||
3212 | { | ||
3213 | int k; | ||
3214 | unsigned int i,j; | ||
3215 | stbi_uc *output; | ||
3216 | stbi_uc *coutput[4]; | ||
3217 | |||
3218 | stbi__resample res_comp[4]; | ||
3219 | |||
3220 | for (k=0; k < decode_n; ++k) { | ||
3221 | stbi__resample *r = &res_comp[k]; | ||
3222 | |||
3223 | // allocate line buffer big enough for upsampling off the edges | ||
3224 | // with upsample factor of 4 | ||
3225 | z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); | ||
3226 | if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } | ||
3227 | |||
3228 | r->hs = z->img_h_max / z->img_comp[k].h; | ||
3229 | r->vs = z->img_v_max / z->img_comp[k].v; | ||
3230 | r->ystep = r->vs >> 1; | ||
3231 | r->w_lores = (z->s->img_x + r->hs-1) / r->hs; | ||
3232 | r->ypos = 0; | ||
3233 | r->line0 = r->line1 = z->img_comp[k].data; | ||
3234 | |||
3235 | if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; | ||
3236 | else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; | ||
3237 | else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; | ||
3238 | else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; | ||
3239 | else r->resample = stbi__resample_row_generic; | ||
3240 | } | ||
3241 | |||
3242 | // can't error after this so, this is safe | ||
3243 | output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); | ||
3244 | if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } | ||
3245 | |||
3246 | // now go ahead and resample | ||
3247 | for (j=0; j < z->s->img_y; ++j) { | ||
3248 | stbi_uc *out = output + n * z->s->img_x * j; | ||
3249 | for (k=0; k < decode_n; ++k) { | ||
3250 | stbi__resample *r = &res_comp[k]; | ||
3251 | int y_bot = r->ystep >= (r->vs >> 1); | ||
3252 | coutput[k] = r->resample(z->img_comp[k].linebuf, | ||
3253 | y_bot ? r->line1 : r->line0, | ||
3254 | y_bot ? r->line0 : r->line1, | ||
3255 | r->w_lores, r->hs); | ||
3256 | if (++r->ystep >= r->vs) { | ||
3257 | r->ystep = 0; | ||
3258 | r->line0 = r->line1; | ||
3259 | if (++r->ypos < z->img_comp[k].y) | ||
3260 | r->line1 += z->img_comp[k].w2; | ||
3261 | } | ||
3262 | } | ||
3263 | if (n >= 3) { | ||
3264 | stbi_uc *y = coutput[0]; | ||
3265 | if (z->s->img_n == 3) { | ||
3266 | z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); | ||
3267 | } else | ||
3268 | for (i=0; i < z->s->img_x; ++i) { | ||
3269 | out[0] = out[1] = out[2] = y[i]; | ||
3270 | out[3] = 255; // not used if n==3 | ||
3271 | out += n; | ||
3272 | } | ||
3273 | } else { | ||
3274 | stbi_uc *y = coutput[0]; | ||
3275 | if (n == 1) | ||
3276 | for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; | ||
3277 | else | ||
3278 | for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; | ||
3279 | } | ||
3280 | } | ||
3281 | stbi__cleanup_jpeg(z); | ||
3282 | *out_x = z->s->img_x; | ||
3283 | *out_y = z->s->img_y; | ||
3284 | if (comp) *comp = z->s->img_n; // report original components, not output | ||
3285 | return output; | ||
3286 | } | ||
3287 | } | ||
3288 | |||
3289 | static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
3290 | { | ||
3291 | stbi__jpeg j; | ||
3292 | j.s = s; | ||
3293 | stbi__setup_jpeg(&j); | ||
3294 | return load_jpeg_image(&j, x,y,comp,req_comp); | ||
3295 | } | ||
3296 | |||
3297 | static int stbi__jpeg_test(stbi__context *s) | ||
3298 | { | ||
3299 | int r; | ||
3300 | stbi__jpeg j; | ||
3301 | j.s = s; | ||
3302 | stbi__setup_jpeg(&j); | ||
3303 | r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); | ||
3304 | stbi__rewind(s); | ||
3305 | return r; | ||
3306 | } | ||
3307 | |||
3308 | static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) | ||
3309 | { | ||
3310 | if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { | ||
3311 | stbi__rewind( j->s ); | ||
3312 | return 0; | ||
3313 | } | ||
3314 | if (x) *x = j->s->img_x; | ||
3315 | if (y) *y = j->s->img_y; | ||
3316 | if (comp) *comp = j->s->img_n; | ||
3317 | return 1; | ||
3318 | } | ||
3319 | |||
3320 | static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) | ||
3321 | { | ||
3322 | stbi__jpeg j; | ||
3323 | j.s = s; | ||
3324 | return stbi__jpeg_info_raw(&j, x, y, comp); | ||
3325 | } | ||
3326 | #endif | ||
3327 | |||
3328 | // public domain zlib decode v0.2 Sean Barrett 2006-11-18 | ||
3329 | // simple implementation | ||
3330 | // - all input must be provided in an upfront buffer | ||
3331 | // - all output is written to a single output buffer (can malloc/realloc) | ||
3332 | // performance | ||
3333 | // - fast huffman | ||
3334 | |||
3335 | #ifndef STBI_NO_ZLIB | ||
3336 | |||
3337 | // fast-way is faster to check than jpeg huffman, but slow way is slower | ||
3338 | #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables | ||
3339 | #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) | ||
3340 | |||
3341 | // zlib-style huffman encoding | ||
3342 | // (jpegs packs from left, zlib from right, so can't share code) | ||
3343 | typedef struct | ||
3344 | { | ||
3345 | stbi__uint16 fast[1 << STBI__ZFAST_BITS]; | ||
3346 | stbi__uint16 firstcode[16]; | ||
3347 | int maxcode[17]; | ||
3348 | stbi__uint16 firstsymbol[16]; | ||
3349 | stbi_uc size[288]; | ||
3350 | stbi__uint16 value[288]; | ||
3351 | } stbi__zhuffman; | ||
3352 | |||
3353 | stbi_inline static int stbi__bitreverse16(int n) | ||
3354 | { | ||
3355 | n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); | ||
3356 | n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); | ||
3357 | n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); | ||
3358 | n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); | ||
3359 | return n; | ||
3360 | } | ||
3361 | |||
3362 | stbi_inline static int stbi__bit_reverse(int v, int bits) | ||
3363 | { | ||
3364 | STBI_ASSERT(bits <= 16); | ||
3365 | // to bit reverse n bits, reverse 16 and shift | ||
3366 | // e.g. 11 bits, bit reverse and shift away 5 | ||
3367 | return stbi__bitreverse16(v) >> (16-bits); | ||
3368 | } | ||
3369 | |||
3370 | static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) | ||
3371 | { | ||
3372 | int i,k=0; | ||
3373 | int code, next_code[16], sizes[17]; | ||
3374 | |||
3375 | // DEFLATE spec for generating codes | ||
3376 | memset(sizes, 0, sizeof(sizes)); | ||
3377 | memset(z->fast, 0, sizeof(z->fast)); | ||
3378 | for (i=0; i < num; ++i) | ||
3379 | ++sizes[sizelist[i]]; | ||
3380 | sizes[0] = 0; | ||
3381 | for (i=1; i < 16; ++i) | ||
3382 | STBI_ASSERT(sizes[i] <= (1 << i)); | ||
3383 | code = 0; | ||
3384 | for (i=1; i < 16; ++i) { | ||
3385 | next_code[i] = code; | ||
3386 | z->firstcode[i] = (stbi__uint16) code; | ||
3387 | z->firstsymbol[i] = (stbi__uint16) k; | ||
3388 | code = (code + sizes[i]); | ||
3389 | if (sizes[i]) | ||
3390 | if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG"); | ||
3391 | z->maxcode[i] = code << (16-i); // preshift for inner loop | ||
3392 | code <<= 1; | ||
3393 | k += sizes[i]; | ||
3394 | } | ||
3395 | z->maxcode[16] = 0x10000; // sentinel | ||
3396 | for (i=0; i < num; ++i) { | ||
3397 | int s = sizelist[i]; | ||
3398 | if (s) { | ||
3399 | int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; | ||
3400 | stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); | ||
3401 | z->size [c] = (stbi_uc ) s; | ||
3402 | z->value[c] = (stbi__uint16) i; | ||
3403 | if (s <= STBI__ZFAST_BITS) { | ||
3404 | int k = stbi__bit_reverse(next_code[s],s); | ||
3405 | while (k < (1 << STBI__ZFAST_BITS)) { | ||
3406 | z->fast[k] = fastv; | ||
3407 | k += (1 << s); | ||
3408 | } | ||
3409 | } | ||
3410 | ++next_code[s]; | ||
3411 | } | ||
3412 | } | ||
3413 | return 1; | ||
3414 | } | ||
3415 | |||
3416 | // zlib-from-memory implementation for PNG reading | ||
3417 | // because PNG allows splitting the zlib stream arbitrarily, | ||
3418 | // and it's annoying structurally to have PNG call ZLIB call PNG, | ||
3419 | // we require PNG read all the IDATs and combine them into a single | ||
3420 | // memory buffer | ||
3421 | |||
3422 | typedef struct | ||
3423 | { | ||
3424 | stbi_uc *zbuffer, *zbuffer_end; | ||
3425 | int num_bits; | ||
3426 | stbi__uint32 code_buffer; | ||
3427 | |||
3428 | char *zout; | ||
3429 | char *zout_start; | ||
3430 | char *zout_end; | ||
3431 | int z_expandable; | ||
3432 | |||
3433 | stbi__zhuffman z_length, z_distance; | ||
3434 | } stbi__zbuf; | ||
3435 | |||
3436 | stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) | ||
3437 | { | ||
3438 | if (z->zbuffer >= z->zbuffer_end) return 0; | ||
3439 | return *z->zbuffer++; | ||
3440 | } | ||
3441 | |||
3442 | static void stbi__fill_bits(stbi__zbuf *z) | ||
3443 | { | ||
3444 | do { | ||
3445 | STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); | ||
3446 | z->code_buffer |= stbi__zget8(z) << z->num_bits; | ||
3447 | z->num_bits += 8; | ||
3448 | } while (z->num_bits <= 24); | ||
3449 | } | ||
3450 | |||
3451 | stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) | ||
3452 | { | ||
3453 | unsigned int k; | ||
3454 | if (z->num_bits < n) stbi__fill_bits(z); | ||
3455 | k = z->code_buffer & ((1 << n) - 1); | ||
3456 | z->code_buffer >>= n; | ||
3457 | z->num_bits -= n; | ||
3458 | return k; | ||
3459 | } | ||
3460 | |||
3461 | static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) | ||
3462 | { | ||
3463 | int b,s,k; | ||
3464 | // not resolved by fast table, so compute it the slow way | ||
3465 | // use jpeg approach, which requires MSbits at top | ||
3466 | k = stbi__bit_reverse(a->code_buffer, 16); | ||
3467 | for (s=STBI__ZFAST_BITS+1; ; ++s) | ||
3468 | if (k < z->maxcode[s]) | ||
3469 | break; | ||
3470 | if (s == 16) return -1; // invalid code! | ||
3471 | // code size is s, so: | ||
3472 | b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; | ||
3473 | STBI_ASSERT(z->size[b] == s); | ||
3474 | a->code_buffer >>= s; | ||
3475 | a->num_bits -= s; | ||
3476 | return z->value[b]; | ||
3477 | } | ||
3478 | |||
3479 | stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) | ||
3480 | { | ||
3481 | int b,s; | ||
3482 | if (a->num_bits < 16) stbi__fill_bits(a); | ||
3483 | b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; | ||
3484 | if (b) { | ||
3485 | s = b >> 9; | ||
3486 | a->code_buffer >>= s; | ||
3487 | a->num_bits -= s; | ||
3488 | return b & 511; | ||
3489 | } | ||
3490 | return stbi__zhuffman_decode_slowpath(a, z); | ||
3491 | } | ||
3492 | |||
3493 | static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes | ||
3494 | { | ||
3495 | char *q; | ||
3496 | int cur, limit; | ||
3497 | z->zout = zout; | ||
3498 | if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); | ||
3499 | cur = (int) (z->zout - z->zout_start); | ||
3500 | limit = (int) (z->zout_end - z->zout_start); | ||
3501 | while (cur + n > limit) | ||
3502 | limit *= 2; | ||
3503 | q = (char *) STBI_REALLOC(z->zout_start, limit); | ||
3504 | if (q == NULL) return stbi__err("outofmem", "Out of memory"); | ||
3505 | z->zout_start = q; | ||
3506 | z->zout = q + cur; | ||
3507 | z->zout_end = q + limit; | ||
3508 | return 1; | ||
3509 | } | ||
3510 | |||
3511 | static int stbi__zlength_base[31] = { | ||
3512 | 3,4,5,6,7,8,9,10,11,13, | ||
3513 | 15,17,19,23,27,31,35,43,51,59, | ||
3514 | 67,83,99,115,131,163,195,227,258,0,0 }; | ||
3515 | |||
3516 | static int stbi__zlength_extra[31]= | ||
3517 | { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; | ||
3518 | |||
3519 | static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, | ||
3520 | 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; | ||
3521 | |||
3522 | static int stbi__zdist_extra[32] = | ||
3523 | { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; | ||
3524 | |||
3525 | static int stbi__parse_huffman_block(stbi__zbuf *a) | ||
3526 | { | ||
3527 | char *zout = a->zout; | ||
3528 | for(;;) { | ||
3529 | int z = stbi__zhuffman_decode(a, &a->z_length); | ||
3530 | if (z < 256) { | ||
3531 | if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes | ||
3532 | if (zout >= a->zout_end) { | ||
3533 | if (!stbi__zexpand(a, zout, 1)) return 0; | ||
3534 | zout = a->zout; | ||
3535 | } | ||
3536 | *zout++ = (char) z; | ||
3537 | } else { | ||
3538 | stbi_uc *p; | ||
3539 | int len,dist; | ||
3540 | if (z == 256) { | ||
3541 | a->zout = zout; | ||
3542 | return 1; | ||
3543 | } | ||
3544 | z -= 257; | ||
3545 | len = stbi__zlength_base[z]; | ||
3546 | if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); | ||
3547 | z = stbi__zhuffman_decode(a, &a->z_distance); | ||
3548 | if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); | ||
3549 | dist = stbi__zdist_base[z]; | ||
3550 | if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); | ||
3551 | if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); | ||
3552 | if (zout + len > a->zout_end) { | ||
3553 | if (!stbi__zexpand(a, zout, len)) return 0; | ||
3554 | zout = a->zout; | ||
3555 | } | ||
3556 | p = (stbi_uc *) (zout - dist); | ||
3557 | if (dist == 1) { // run of one byte; common in images. | ||
3558 | stbi_uc v = *p; | ||
3559 | do *zout++ = v; while (--len); | ||
3560 | } else { | ||
3561 | do *zout++ = *p++; while (--len); | ||
3562 | } | ||
3563 | } | ||
3564 | } | ||
3565 | } | ||
3566 | |||
3567 | static int stbi__compute_huffman_codes(stbi__zbuf *a) | ||
3568 | { | ||
3569 | static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; | ||
3570 | stbi__zhuffman z_codelength; | ||
3571 | stbi_uc lencodes[286+32+137];//padding for maximum single op | ||
3572 | stbi_uc codelength_sizes[19]; | ||
3573 | int i,n; | ||
3574 | |||
3575 | int hlit = stbi__zreceive(a,5) + 257; | ||
3576 | int hdist = stbi__zreceive(a,5) + 1; | ||
3577 | int hclen = stbi__zreceive(a,4) + 4; | ||
3578 | |||
3579 | memset(codelength_sizes, 0, sizeof(codelength_sizes)); | ||
3580 | for (i=0; i < hclen; ++i) { | ||
3581 | int s = stbi__zreceive(a,3); | ||
3582 | codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; | ||
3583 | } | ||
3584 | if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; | ||
3585 | |||
3586 | n = 0; | ||
3587 | while (n < hlit + hdist) { | ||
3588 | int c = stbi__zhuffman_decode(a, &z_codelength); | ||
3589 | STBI_ASSERT(c >= 0 && c < 19); | ||
3590 | if (c < 16) | ||
3591 | lencodes[n++] = (stbi_uc) c; | ||
3592 | else if (c == 16) { | ||
3593 | c = stbi__zreceive(a,2)+3; | ||
3594 | memset(lencodes+n, lencodes[n-1], c); | ||
3595 | n += c; | ||
3596 | } else if (c == 17) { | ||
3597 | c = stbi__zreceive(a,3)+3; | ||
3598 | memset(lencodes+n, 0, c); | ||
3599 | n += c; | ||
3600 | } else { | ||
3601 | STBI_ASSERT(c == 18); | ||
3602 | c = stbi__zreceive(a,7)+11; | ||
3603 | memset(lencodes+n, 0, c); | ||
3604 | n += c; | ||
3605 | } | ||
3606 | } | ||
3607 | if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); | ||
3608 | if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; | ||
3609 | if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; | ||
3610 | return 1; | ||
3611 | } | ||
3612 | |||
3613 | static int stbi__parse_uncomperssed_block(stbi__zbuf *a) | ||
3614 | { | ||
3615 | stbi_uc header[4]; | ||
3616 | int len,nlen,k; | ||
3617 | if (a->num_bits & 7) | ||
3618 | stbi__zreceive(a, a->num_bits & 7); // discard | ||
3619 | // drain the bit-packed data into header | ||
3620 | k = 0; | ||
3621 | while (a->num_bits > 0) { | ||
3622 | header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check | ||
3623 | a->code_buffer >>= 8; | ||
3624 | a->num_bits -= 8; | ||
3625 | } | ||
3626 | STBI_ASSERT(a->num_bits == 0); | ||
3627 | // now fill header the normal way | ||
3628 | while (k < 4) | ||
3629 | header[k++] = stbi__zget8(a); | ||
3630 | len = header[1] * 256 + header[0]; | ||
3631 | nlen = header[3] * 256 + header[2]; | ||
3632 | if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); | ||
3633 | if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); | ||
3634 | if (a->zout + len > a->zout_end) | ||
3635 | if (!stbi__zexpand(a, a->zout, len)) return 0; | ||
3636 | memcpy(a->zout, a->zbuffer, len); | ||
3637 | a->zbuffer += len; | ||
3638 | a->zout += len; | ||
3639 | return 1; | ||
3640 | } | ||
3641 | |||
3642 | static int stbi__parse_zlib_header(stbi__zbuf *a) | ||
3643 | { | ||
3644 | int cmf = stbi__zget8(a); | ||
3645 | int cm = cmf & 15; | ||
3646 | /* int cinfo = cmf >> 4; */ | ||
3647 | int flg = stbi__zget8(a); | ||
3648 | if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec | ||
3649 | if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png | ||
3650 | if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png | ||
3651 | // window = 1 << (8 + cinfo)... but who cares, we fully buffer output | ||
3652 | return 1; | ||
3653 | } | ||
3654 | |||
3655 | // @TODO: should statically initialize these for optimal thread safety | ||
3656 | static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; | ||
3657 | static void stbi__init_zdefaults(void) | ||
3658 | { | ||
3659 | int i; // use <= to match clearly with spec | ||
3660 | for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; | ||
3661 | for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; | ||
3662 | for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; | ||
3663 | for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; | ||
3664 | |||
3665 | for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; | ||
3666 | } | ||
3667 | |||
3668 | static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) | ||
3669 | { | ||
3670 | int final, type; | ||
3671 | if (parse_header) | ||
3672 | if (!stbi__parse_zlib_header(a)) return 0; | ||
3673 | a->num_bits = 0; | ||
3674 | a->code_buffer = 0; | ||
3675 | do { | ||
3676 | final = stbi__zreceive(a,1); | ||
3677 | type = stbi__zreceive(a,2); | ||
3678 | if (type == 0) { | ||
3679 | if (!stbi__parse_uncomperssed_block(a)) return 0; | ||
3680 | } else if (type == 3) { | ||
3681 | return 0; | ||
3682 | } else { | ||
3683 | if (type == 1) { | ||
3684 | // use fixed code lengths | ||
3685 | if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); | ||
3686 | if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; | ||
3687 | if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; | ||
3688 | } else { | ||
3689 | if (!stbi__compute_huffman_codes(a)) return 0; | ||
3690 | } | ||
3691 | if (!stbi__parse_huffman_block(a)) return 0; | ||
3692 | } | ||
3693 | } while (!final); | ||
3694 | return 1; | ||
3695 | } | ||
3696 | |||
3697 | static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) | ||
3698 | { | ||
3699 | a->zout_start = obuf; | ||
3700 | a->zout = obuf; | ||
3701 | a->zout_end = obuf + olen; | ||
3702 | a->z_expandable = exp; | ||
3703 | |||
3704 | return stbi__parse_zlib(a, parse_header); | ||
3705 | } | ||
3706 | |||
3707 | STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) | ||
3708 | { | ||
3709 | stbi__zbuf a; | ||
3710 | char *p = (char *) stbi__malloc(initial_size); | ||
3711 | if (p == NULL) return NULL; | ||
3712 | a.zbuffer = (stbi_uc *) buffer; | ||
3713 | a.zbuffer_end = (stbi_uc *) buffer + len; | ||
3714 | if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { | ||
3715 | if (outlen) *outlen = (int) (a.zout - a.zout_start); | ||
3716 | return a.zout_start; | ||
3717 | } else { | ||
3718 | STBI_FREE(a.zout_start); | ||
3719 | return NULL; | ||
3720 | } | ||
3721 | } | ||
3722 | |||
3723 | STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) | ||
3724 | { | ||
3725 | return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); | ||
3726 | } | ||
3727 | |||
3728 | STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) | ||
3729 | { | ||
3730 | stbi__zbuf a; | ||
3731 | char *p = (char *) stbi__malloc(initial_size); | ||
3732 | if (p == NULL) return NULL; | ||
3733 | a.zbuffer = (stbi_uc *) buffer; | ||
3734 | a.zbuffer_end = (stbi_uc *) buffer + len; | ||
3735 | if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { | ||
3736 | if (outlen) *outlen = (int) (a.zout - a.zout_start); | ||
3737 | return a.zout_start; | ||
3738 | } else { | ||
3739 | STBI_FREE(a.zout_start); | ||
3740 | return NULL; | ||
3741 | } | ||
3742 | } | ||
3743 | |||
3744 | STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) | ||
3745 | { | ||
3746 | stbi__zbuf a; | ||
3747 | a.zbuffer = (stbi_uc *) ibuffer; | ||
3748 | a.zbuffer_end = (stbi_uc *) ibuffer + ilen; | ||
3749 | if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) | ||
3750 | return (int) (a.zout - a.zout_start); | ||
3751 | else | ||
3752 | return -1; | ||
3753 | } | ||
3754 | |||
3755 | STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) | ||
3756 | { | ||
3757 | stbi__zbuf a; | ||
3758 | char *p = (char *) stbi__malloc(16384); | ||
3759 | if (p == NULL) return NULL; | ||
3760 | a.zbuffer = (stbi_uc *) buffer; | ||
3761 | a.zbuffer_end = (stbi_uc *) buffer+len; | ||
3762 | if (stbi__do_zlib(&a, p, 16384, 1, 0)) { | ||
3763 | if (outlen) *outlen = (int) (a.zout - a.zout_start); | ||
3764 | return a.zout_start; | ||
3765 | } else { | ||
3766 | STBI_FREE(a.zout_start); | ||
3767 | return NULL; | ||
3768 | } | ||
3769 | } | ||
3770 | |||
3771 | STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) | ||
3772 | { | ||
3773 | stbi__zbuf a; | ||
3774 | a.zbuffer = (stbi_uc *) ibuffer; | ||
3775 | a.zbuffer_end = (stbi_uc *) ibuffer + ilen; | ||
3776 | if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) | ||
3777 | return (int) (a.zout - a.zout_start); | ||
3778 | else | ||
3779 | return -1; | ||
3780 | } | ||
3781 | #endif | ||
3782 | |||
3783 | // public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 | ||
3784 | // simple implementation | ||
3785 | // - only 8-bit samples | ||
3786 | // - no CRC checking | ||
3787 | // - allocates lots of intermediate memory | ||
3788 | // - avoids problem of streaming data between subsystems | ||
3789 | // - avoids explicit window management | ||
3790 | // performance | ||
3791 | // - uses stb_zlib, a PD zlib implementation with fast huffman decoding | ||
3792 | |||
3793 | #ifndef STBI_NO_PNG | ||
3794 | typedef struct | ||
3795 | { | ||
3796 | stbi__uint32 length; | ||
3797 | stbi__uint32 type; | ||
3798 | } stbi__pngchunk; | ||
3799 | |||
3800 | static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) | ||
3801 | { | ||
3802 | stbi__pngchunk c; | ||
3803 | c.length = stbi__get32be(s); | ||
3804 | c.type = stbi__get32be(s); | ||
3805 | return c; | ||
3806 | } | ||
3807 | |||
3808 | static int stbi__check_png_header(stbi__context *s) | ||
3809 | { | ||
3810 | static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; | ||
3811 | int i; | ||
3812 | for (i=0; i < 8; ++i) | ||
3813 | if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); | ||
3814 | return 1; | ||
3815 | } | ||
3816 | |||
3817 | typedef struct | ||
3818 | { | ||
3819 | stbi__context *s; | ||
3820 | stbi_uc *idata, *expanded, *out; | ||
3821 | } stbi__png; | ||
3822 | |||
3823 | |||
3824 | enum { | ||
3825 | STBI__F_none=0, | ||
3826 | STBI__F_sub=1, | ||
3827 | STBI__F_up=2, | ||
3828 | STBI__F_avg=3, | ||
3829 | STBI__F_paeth=4, | ||
3830 | // synthetic filters used for first scanline to avoid needing a dummy row of 0s | ||
3831 | STBI__F_avg_first, | ||
3832 | STBI__F_paeth_first | ||
3833 | }; | ||
3834 | |||
3835 | static stbi_uc first_row_filter[5] = | ||
3836 | { | ||
3837 | STBI__F_none, | ||
3838 | STBI__F_sub, | ||
3839 | STBI__F_none, | ||
3840 | STBI__F_avg_first, | ||
3841 | STBI__F_paeth_first | ||
3842 | }; | ||
3843 | |||
3844 | static int stbi__paeth(int a, int b, int c) | ||
3845 | { | ||
3846 | int p = a + b - c; | ||
3847 | int pa = abs(p-a); | ||
3848 | int pb = abs(p-b); | ||
3849 | int pc = abs(p-c); | ||
3850 | if (pa <= pb && pa <= pc) return a; | ||
3851 | if (pb <= pc) return b; | ||
3852 | return c; | ||
3853 | } | ||
3854 | |||
3855 | static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; | ||
3856 | |||
3857 | // create the png data from post-deflated data | ||
3858 | static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) | ||
3859 | { | ||
3860 | stbi__context *s = a->s; | ||
3861 | stbi__uint32 i,j,stride = x*out_n; | ||
3862 | stbi__uint32 img_len, img_width_bytes; | ||
3863 | int k; | ||
3864 | int img_n = s->img_n; // copy it into a local for later | ||
3865 | |||
3866 | STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); | ||
3867 | a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into | ||
3868 | if (!a->out) return stbi__err("outofmem", "Out of memory"); | ||
3869 | |||
3870 | img_width_bytes = (((img_n * x * depth) + 7) >> 3); | ||
3871 | img_len = (img_width_bytes + 1) * y; | ||
3872 | if (s->img_x == x && s->img_y == y) { | ||
3873 | if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); | ||
3874 | } else { // interlaced: | ||
3875 | if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); | ||
3876 | } | ||
3877 | |||
3878 | for (j=0; j < y; ++j) { | ||
3879 | stbi_uc *cur = a->out + stride*j; | ||
3880 | stbi_uc *prior = cur - stride; | ||
3881 | int filter = *raw++; | ||
3882 | int filter_bytes = img_n; | ||
3883 | int width = x; | ||
3884 | if (filter > 4) | ||
3885 | return stbi__err("invalid filter","Corrupt PNG"); | ||
3886 | |||
3887 | if (depth < 8) { | ||
3888 | STBI_ASSERT(img_width_bytes <= x); | ||
3889 | cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place | ||
3890 | filter_bytes = 1; | ||
3891 | width = img_width_bytes; | ||
3892 | } | ||
3893 | |||
3894 | // if first row, use special filter that doesn't sample previous row | ||
3895 | if (j == 0) filter = first_row_filter[filter]; | ||
3896 | |||
3897 | // handle first byte explicitly | ||
3898 | for (k=0; k < filter_bytes; ++k) { | ||
3899 | switch (filter) { | ||
3900 | case STBI__F_none : cur[k] = raw[k]; break; | ||
3901 | case STBI__F_sub : cur[k] = raw[k]; break; | ||
3902 | case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; | ||
3903 | case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; | ||
3904 | case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; | ||
3905 | case STBI__F_avg_first : cur[k] = raw[k]; break; | ||
3906 | case STBI__F_paeth_first: cur[k] = raw[k]; break; | ||
3907 | } | ||
3908 | } | ||
3909 | |||
3910 | if (depth == 8) { | ||
3911 | if (img_n != out_n) | ||
3912 | cur[img_n] = 255; // first pixel | ||
3913 | raw += img_n; | ||
3914 | cur += out_n; | ||
3915 | prior += out_n; | ||
3916 | } else { | ||
3917 | raw += 1; | ||
3918 | cur += 1; | ||
3919 | prior += 1; | ||
3920 | } | ||
3921 | |||
3922 | // this is a little gross, so that we don't switch per-pixel or per-component | ||
3923 | if (depth < 8 || img_n == out_n) { | ||
3924 | int nk = (width - 1)*img_n; | ||
3925 | #define CASE(f) \ | ||
3926 | case f: \ | ||
3927 | for (k=0; k < nk; ++k) | ||
3928 | switch (filter) { | ||
3929 | // "none" filter turns into a memcpy here; make that explicit. | ||
3930 | case STBI__F_none: memcpy(cur, raw, nk); break; | ||
3931 | CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; | ||
3932 | CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; | ||
3933 | CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; | ||
3934 | CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; | ||
3935 | CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; | ||
3936 | CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; | ||
3937 | } | ||
3938 | #undef CASE | ||
3939 | raw += nk; | ||
3940 | } else { | ||
3941 | STBI_ASSERT(img_n+1 == out_n); | ||
3942 | #define CASE(f) \ | ||
3943 | case f: \ | ||
3944 | for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ | ||
3945 | for (k=0; k < img_n; ++k) | ||
3946 | switch (filter) { | ||
3947 | CASE(STBI__F_none) cur[k] = raw[k]; break; | ||
3948 | CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; | ||
3949 | CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; | ||
3950 | CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; | ||
3951 | CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; | ||
3952 | CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; | ||
3953 | CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; | ||
3954 | } | ||
3955 | #undef CASE | ||
3956 | } | ||
3957 | } | ||
3958 | |||
3959 | // we make a separate pass to expand bits to pixels; for performance, | ||
3960 | // this could run two scanlines behind the above code, so it won't | ||
3961 | // intefere with filtering but will still be in the cache. | ||
3962 | if (depth < 8) { | ||
3963 | for (j=0; j < y; ++j) { | ||
3964 | stbi_uc *cur = a->out + stride*j; | ||
3965 | stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; | ||
3966 | // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit | ||
3967 | // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop | ||
3968 | stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range | ||
3969 | |||
3970 | // note that the final byte might overshoot and write more data than desired. | ||
3971 | // we can allocate enough data that this never writes out of memory, but it | ||
3972 | // could also overwrite the next scanline. can it overwrite non-empty data | ||
3973 | // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. | ||
3974 | // so we need to explicitly clamp the final ones | ||
3975 | |||
3976 | if (depth == 4) { | ||
3977 | for (k=x*img_n; k >= 2; k-=2, ++in) { | ||
3978 | *cur++ = scale * ((*in >> 4) ); | ||
3979 | *cur++ = scale * ((*in ) & 0x0f); | ||
3980 | } | ||
3981 | if (k > 0) *cur++ = scale * ((*in >> 4) ); | ||
3982 | } else if (depth == 2) { | ||
3983 | for (k=x*img_n; k >= 4; k-=4, ++in) { | ||
3984 | *cur++ = scale * ((*in >> 6) ); | ||
3985 | *cur++ = scale * ((*in >> 4) & 0x03); | ||
3986 | *cur++ = scale * ((*in >> 2) & 0x03); | ||
3987 | *cur++ = scale * ((*in ) & 0x03); | ||
3988 | } | ||
3989 | if (k > 0) *cur++ = scale * ((*in >> 6) ); | ||
3990 | if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); | ||
3991 | if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); | ||
3992 | } else if (depth == 1) { | ||
3993 | for (k=x*img_n; k >= 8; k-=8, ++in) { | ||
3994 | *cur++ = scale * ((*in >> 7) ); | ||
3995 | *cur++ = scale * ((*in >> 6) & 0x01); | ||
3996 | *cur++ = scale * ((*in >> 5) & 0x01); | ||
3997 | *cur++ = scale * ((*in >> 4) & 0x01); | ||
3998 | *cur++ = scale * ((*in >> 3) & 0x01); | ||
3999 | *cur++ = scale * ((*in >> 2) & 0x01); | ||
4000 | *cur++ = scale * ((*in >> 1) & 0x01); | ||
4001 | *cur++ = scale * ((*in ) & 0x01); | ||
4002 | } | ||
4003 | if (k > 0) *cur++ = scale * ((*in >> 7) ); | ||
4004 | if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); | ||
4005 | if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); | ||
4006 | if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); | ||
4007 | if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); | ||
4008 | if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); | ||
4009 | if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); | ||
4010 | } | ||
4011 | if (img_n != out_n) { | ||
4012 | // insert alpha = 255 | ||
4013 | stbi_uc *cur = a->out + stride*j; | ||
4014 | int i; | ||
4015 | if (img_n == 1) { | ||
4016 | for (i=x-1; i >= 0; --i) { | ||
4017 | cur[i*2+1] = 255; | ||
4018 | cur[i*2+0] = cur[i]; | ||
4019 | } | ||
4020 | } else { | ||
4021 | STBI_ASSERT(img_n == 3); | ||
4022 | for (i=x-1; i >= 0; --i) { | ||
4023 | cur[i*4+3] = 255; | ||
4024 | cur[i*4+2] = cur[i*3+2]; | ||
4025 | cur[i*4+1] = cur[i*3+1]; | ||
4026 | cur[i*4+0] = cur[i*3+0]; | ||
4027 | } | ||
4028 | } | ||
4029 | } | ||
4030 | } | ||
4031 | } | ||
4032 | |||
4033 | return 1; | ||
4034 | } | ||
4035 | |||
4036 | static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) | ||
4037 | { | ||
4038 | stbi_uc *final; | ||
4039 | int p; | ||
4040 | if (!interlaced) | ||
4041 | return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); | ||
4042 | |||
4043 | // de-interlacing | ||
4044 | final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); | ||
4045 | for (p=0; p < 7; ++p) { | ||
4046 | int xorig[] = { 0,4,0,2,0,1,0 }; | ||
4047 | int yorig[] = { 0,0,4,0,2,0,1 }; | ||
4048 | int xspc[] = { 8,8,4,4,2,2,1 }; | ||
4049 | int yspc[] = { 8,8,8,4,4,2,2 }; | ||
4050 | int i,j,x,y; | ||
4051 | // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 | ||
4052 | x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; | ||
4053 | y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; | ||
4054 | if (x && y) { | ||
4055 | stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; | ||
4056 | if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { | ||
4057 | STBI_FREE(final); | ||
4058 | return 0; | ||
4059 | } | ||
4060 | for (j=0; j < y; ++j) { | ||
4061 | for (i=0; i < x; ++i) { | ||
4062 | int out_y = j*yspc[p]+yorig[p]; | ||
4063 | int out_x = i*xspc[p]+xorig[p]; | ||
4064 | memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, | ||
4065 | a->out + (j*x+i)*out_n, out_n); | ||
4066 | } | ||
4067 | } | ||
4068 | STBI_FREE(a->out); | ||
4069 | image_data += img_len; | ||
4070 | image_data_len -= img_len; | ||
4071 | } | ||
4072 | } | ||
4073 | a->out = final; | ||
4074 | |||
4075 | return 1; | ||
4076 | } | ||
4077 | |||
4078 | static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) | ||
4079 | { | ||
4080 | stbi__context *s = z->s; | ||
4081 | stbi__uint32 i, pixel_count = s->img_x * s->img_y; | ||
4082 | stbi_uc *p = z->out; | ||
4083 | |||
4084 | // compute color-based transparency, assuming we've | ||
4085 | // already got 255 as the alpha value in the output | ||
4086 | STBI_ASSERT(out_n == 2 || out_n == 4); | ||
4087 | |||
4088 | if (out_n == 2) { | ||
4089 | for (i=0; i < pixel_count; ++i) { | ||
4090 | p[1] = (p[0] == tc[0] ? 0 : 255); | ||
4091 | p += 2; | ||
4092 | } | ||
4093 | } else { | ||
4094 | for (i=0; i < pixel_count; ++i) { | ||
4095 | if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) | ||
4096 | p[3] = 0; | ||
4097 | p += 4; | ||
4098 | } | ||
4099 | } | ||
4100 | return 1; | ||
4101 | } | ||
4102 | |||
4103 | static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) | ||
4104 | { | ||
4105 | stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; | ||
4106 | stbi_uc *p, *temp_out, *orig = a->out; | ||
4107 | |||
4108 | p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); | ||
4109 | if (p == NULL) return stbi__err("outofmem", "Out of memory"); | ||
4110 | |||
4111 | // between here and free(out) below, exitting would leak | ||
4112 | temp_out = p; | ||
4113 | |||
4114 | if (pal_img_n == 3) { | ||
4115 | for (i=0; i < pixel_count; ++i) { | ||
4116 | int n = orig[i]*4; | ||
4117 | p[0] = palette[n ]; | ||
4118 | p[1] = palette[n+1]; | ||
4119 | p[2] = palette[n+2]; | ||
4120 | p += 3; | ||
4121 | } | ||
4122 | } else { | ||
4123 | for (i=0; i < pixel_count; ++i) { | ||
4124 | int n = orig[i]*4; | ||
4125 | p[0] = palette[n ]; | ||
4126 | p[1] = palette[n+1]; | ||
4127 | p[2] = palette[n+2]; | ||
4128 | p[3] = palette[n+3]; | ||
4129 | p += 4; | ||
4130 | } | ||
4131 | } | ||
4132 | STBI_FREE(a->out); | ||
4133 | a->out = temp_out; | ||
4134 | |||
4135 | STBI_NOTUSED(len); | ||
4136 | |||
4137 | return 1; | ||
4138 | } | ||
4139 | |||
4140 | static int stbi__unpremultiply_on_load = 0; | ||
4141 | static int stbi__de_iphone_flag = 0; | ||
4142 | |||
4143 | STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) | ||
4144 | { | ||
4145 | stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; | ||
4146 | } | ||
4147 | |||
4148 | STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) | ||
4149 | { | ||
4150 | stbi__de_iphone_flag = flag_true_if_should_convert; | ||
4151 | } | ||
4152 | |||
4153 | static void stbi__de_iphone(stbi__png *z) | ||
4154 | { | ||
4155 | stbi__context *s = z->s; | ||
4156 | stbi__uint32 i, pixel_count = s->img_x * s->img_y; | ||
4157 | stbi_uc *p = z->out; | ||
4158 | |||
4159 | if (s->img_out_n == 3) { // convert bgr to rgb | ||
4160 | for (i=0; i < pixel_count; ++i) { | ||
4161 | stbi_uc t = p[0]; | ||
4162 | p[0] = p[2]; | ||
4163 | p[2] = t; | ||
4164 | p += 3; | ||
4165 | } | ||
4166 | } else { | ||
4167 | STBI_ASSERT(s->img_out_n == 4); | ||
4168 | if (stbi__unpremultiply_on_load) { | ||
4169 | // convert bgr to rgb and unpremultiply | ||
4170 | for (i=0; i < pixel_count; ++i) { | ||
4171 | stbi_uc a = p[3]; | ||
4172 | stbi_uc t = p[0]; | ||
4173 | if (a) { | ||
4174 | p[0] = p[2] * 255 / a; | ||
4175 | p[1] = p[1] * 255 / a; | ||
4176 | p[2] = t * 255 / a; | ||
4177 | } else { | ||
4178 | p[0] = p[2]; | ||
4179 | p[2] = t; | ||
4180 | } | ||
4181 | p += 4; | ||
4182 | } | ||
4183 | } else { | ||
4184 | // convert bgr to rgb | ||
4185 | for (i=0; i < pixel_count; ++i) { | ||
4186 | stbi_uc t = p[0]; | ||
4187 | p[0] = p[2]; | ||
4188 | p[2] = t; | ||
4189 | p += 4; | ||
4190 | } | ||
4191 | } | ||
4192 | } | ||
4193 | } | ||
4194 | |||
4195 | #define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) | ||
4196 | |||
4197 | static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) | ||
4198 | { | ||
4199 | stbi_uc palette[1024], pal_img_n=0; | ||
4200 | stbi_uc has_trans=0, tc[3]; | ||
4201 | stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; | ||
4202 | int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; | ||
4203 | stbi__context *s = z->s; | ||
4204 | |||
4205 | z->expanded = NULL; | ||
4206 | z->idata = NULL; | ||
4207 | z->out = NULL; | ||
4208 | |||
4209 | if (!stbi__check_png_header(s)) return 0; | ||
4210 | |||
4211 | if (scan == STBI__SCAN_type) return 1; | ||
4212 | |||
4213 | for (;;) { | ||
4214 | stbi__pngchunk c = stbi__get_chunk_header(s); | ||
4215 | switch (c.type) { | ||
4216 | case STBI__PNG_TYPE('C','g','B','I'): | ||
4217 | is_iphone = 1; | ||
4218 | stbi__skip(s, c.length); | ||
4219 | break; | ||
4220 | case STBI__PNG_TYPE('I','H','D','R'): { | ||
4221 | int comp,filter; | ||
4222 | if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); | ||
4223 | first = 0; | ||
4224 | if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); | ||
4225 | s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); | ||
4226 | s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); | ||
4227 | depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); | ||
4228 | color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); | ||
4229 | if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); | ||
4230 | comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); | ||
4231 | filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); | ||
4232 | interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); | ||
4233 | if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); | ||
4234 | if (!pal_img_n) { | ||
4235 | s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); | ||
4236 | if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); | ||
4237 | if (scan == STBI__SCAN_header) return 1; | ||
4238 | } else { | ||
4239 | // if paletted, then pal_n is our final components, and | ||
4240 | // img_n is # components to decompress/filter. | ||
4241 | s->img_n = 1; | ||
4242 | if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); | ||
4243 | // if SCAN_header, have to scan to see if we have a tRNS | ||
4244 | } | ||
4245 | break; | ||
4246 | } | ||
4247 | |||
4248 | case STBI__PNG_TYPE('P','L','T','E'): { | ||
4249 | if (first) return stbi__err("first not IHDR", "Corrupt PNG"); | ||
4250 | if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); | ||
4251 | pal_len = c.length / 3; | ||
4252 | if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); | ||
4253 | for (i=0; i < pal_len; ++i) { | ||
4254 | palette[i*4+0] = stbi__get8(s); | ||
4255 | palette[i*4+1] = stbi__get8(s); | ||
4256 | palette[i*4+2] = stbi__get8(s); | ||
4257 | palette[i*4+3] = 255; | ||
4258 | } | ||
4259 | break; | ||
4260 | } | ||
4261 | |||
4262 | case STBI__PNG_TYPE('t','R','N','S'): { | ||
4263 | if (first) return stbi__err("first not IHDR", "Corrupt PNG"); | ||
4264 | if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); | ||
4265 | if (pal_img_n) { | ||
4266 | if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } | ||
4267 | if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); | ||
4268 | if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); | ||
4269 | pal_img_n = 4; | ||
4270 | for (i=0; i < c.length; ++i) | ||
4271 | palette[i*4+3] = stbi__get8(s); | ||
4272 | } else { | ||
4273 | if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); | ||
4274 | if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); | ||
4275 | has_trans = 1; | ||
4276 | for (k=0; k < s->img_n; ++k) | ||
4277 | tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger | ||
4278 | } | ||
4279 | break; | ||
4280 | } | ||
4281 | |||
4282 | case STBI__PNG_TYPE('I','D','A','T'): { | ||
4283 | if (first) return stbi__err("first not IHDR", "Corrupt PNG"); | ||
4284 | if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); | ||
4285 | if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } | ||
4286 | if (ioff + c.length > idata_limit) { | ||
4287 | stbi_uc *p; | ||
4288 | if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; | ||
4289 | while (ioff + c.length > idata_limit) | ||
4290 | idata_limit *= 2; | ||
4291 | p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); | ||
4292 | z->idata = p; | ||
4293 | } | ||
4294 | if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); | ||
4295 | ioff += c.length; | ||
4296 | break; | ||
4297 | } | ||
4298 | |||
4299 | case STBI__PNG_TYPE('I','E','N','D'): { | ||
4300 | stbi__uint32 raw_len, bpl; | ||
4301 | if (first) return stbi__err("first not IHDR", "Corrupt PNG"); | ||
4302 | if (scan != STBI__SCAN_load) return 1; | ||
4303 | if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); | ||
4304 | // initial guess for decoded data size to avoid unnecessary reallocs | ||
4305 | bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component | ||
4306 | raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; | ||
4307 | z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); | ||
4308 | if (z->expanded == NULL) return 0; // zlib should set error | ||
4309 | STBI_FREE(z->idata); z->idata = NULL; | ||
4310 | if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) | ||
4311 | s->img_out_n = s->img_n+1; | ||
4312 | else | ||
4313 | s->img_out_n = s->img_n; | ||
4314 | if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; | ||
4315 | if (has_trans) | ||
4316 | if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; | ||
4317 | if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) | ||
4318 | stbi__de_iphone(z); | ||
4319 | if (pal_img_n) { | ||
4320 | // pal_img_n == 3 or 4 | ||
4321 | s->img_n = pal_img_n; // record the actual colors we had | ||
4322 | s->img_out_n = pal_img_n; | ||
4323 | if (req_comp >= 3) s->img_out_n = req_comp; | ||
4324 | if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) | ||
4325 | return 0; | ||
4326 | } | ||
4327 | STBI_FREE(z->expanded); z->expanded = NULL; | ||
4328 | return 1; | ||
4329 | } | ||
4330 | |||
4331 | default: | ||
4332 | // if critical, fail | ||
4333 | if (first) return stbi__err("first not IHDR", "Corrupt PNG"); | ||
4334 | if ((c.type & (1 << 29)) == 0) { | ||
4335 | #ifndef STBI_NO_FAILURE_STRINGS | ||
4336 | // not threadsafe | ||
4337 | static char invalid_chunk[] = "XXXX PNG chunk not known"; | ||
4338 | invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); | ||
4339 | invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); | ||
4340 | invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); | ||
4341 | invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); | ||
4342 | #endif | ||
4343 | return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); | ||
4344 | } | ||
4345 | stbi__skip(s, c.length); | ||
4346 | break; | ||
4347 | } | ||
4348 | // end of PNG chunk, read and skip CRC | ||
4349 | stbi__get32be(s); | ||
4350 | } | ||
4351 | } | ||
4352 | |||
4353 | static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) | ||
4354 | { | ||
4355 | unsigned char *result=NULL; | ||
4356 | if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); | ||
4357 | if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { | ||
4358 | result = p->out; | ||
4359 | p->out = NULL; | ||
4360 | if (req_comp && req_comp != p->s->img_out_n) { | ||
4361 | result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); | ||
4362 | p->s->img_out_n = req_comp; | ||
4363 | if (result == NULL) return result; | ||
4364 | } | ||
4365 | *x = p->s->img_x; | ||
4366 | *y = p->s->img_y; | ||
4367 | if (n) *n = p->s->img_out_n; | ||
4368 | } | ||
4369 | STBI_FREE(p->out); p->out = NULL; | ||
4370 | STBI_FREE(p->expanded); p->expanded = NULL; | ||
4371 | STBI_FREE(p->idata); p->idata = NULL; | ||
4372 | |||
4373 | return result; | ||
4374 | } | ||
4375 | |||
4376 | static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
4377 | { | ||
4378 | stbi__png p; | ||
4379 | p.s = s; | ||
4380 | return stbi__do_png(&p, x,y,comp,req_comp); | ||
4381 | } | ||
4382 | |||
4383 | static int stbi__png_test(stbi__context *s) | ||
4384 | { | ||
4385 | int r; | ||
4386 | r = stbi__check_png_header(s); | ||
4387 | stbi__rewind(s); | ||
4388 | return r; | ||
4389 | } | ||
4390 | |||
4391 | static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) | ||
4392 | { | ||
4393 | if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { | ||
4394 | stbi__rewind( p->s ); | ||
4395 | return 0; | ||
4396 | } | ||
4397 | if (x) *x = p->s->img_x; | ||
4398 | if (y) *y = p->s->img_y; | ||
4399 | if (comp) *comp = p->s->img_n; | ||
4400 | return 1; | ||
4401 | } | ||
4402 | |||
4403 | static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) | ||
4404 | { | ||
4405 | stbi__png p; | ||
4406 | p.s = s; | ||
4407 | return stbi__png_info_raw(&p, x, y, comp); | ||
4408 | } | ||
4409 | #endif | ||
4410 | |||
4411 | // Microsoft/Windows BMP image | ||
4412 | |||
4413 | #ifndef STBI_NO_BMP | ||
4414 | static int stbi__bmp_test_raw(stbi__context *s) | ||
4415 | { | ||
4416 | int r; | ||
4417 | int sz; | ||
4418 | if (stbi__get8(s) != 'B') return 0; | ||
4419 | if (stbi__get8(s) != 'M') return 0; | ||
4420 | stbi__get32le(s); // discard filesize | ||
4421 | stbi__get16le(s); // discard reserved | ||
4422 | stbi__get16le(s); // discard reserved | ||
4423 | stbi__get32le(s); // discard data offset | ||
4424 | sz = stbi__get32le(s); | ||
4425 | r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); | ||
4426 | return r; | ||
4427 | } | ||
4428 | |||
4429 | static int stbi__bmp_test(stbi__context *s) | ||
4430 | { | ||
4431 | int r = stbi__bmp_test_raw(s); | ||
4432 | stbi__rewind(s); | ||
4433 | return r; | ||
4434 | } | ||
4435 | |||
4436 | |||
4437 | // returns 0..31 for the highest set bit | ||
4438 | static int stbi__high_bit(unsigned int z) | ||
4439 | { | ||
4440 | int n=0; | ||
4441 | if (z == 0) return -1; | ||
4442 | if (z >= 0x10000) n += 16, z >>= 16; | ||
4443 | if (z >= 0x00100) n += 8, z >>= 8; | ||
4444 | if (z >= 0x00010) n += 4, z >>= 4; | ||
4445 | if (z >= 0x00004) n += 2, z >>= 2; | ||
4446 | if (z >= 0x00002) n += 1, z >>= 1; | ||
4447 | return n; | ||
4448 | } | ||
4449 | |||
4450 | static int stbi__bitcount(unsigned int a) | ||
4451 | { | ||
4452 | a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 | ||
4453 | a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 | ||
4454 | a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits | ||
4455 | a = (a + (a >> 8)); // max 16 per 8 bits | ||
4456 | a = (a + (a >> 16)); // max 32 per 8 bits | ||
4457 | return a & 0xff; | ||
4458 | } | ||
4459 | |||
4460 | static int stbi__shiftsigned(int v, int shift, int bits) | ||
4461 | { | ||
4462 | int result; | ||
4463 | int z=0; | ||
4464 | |||
4465 | if (shift < 0) v <<= -shift; | ||
4466 | else v >>= shift; | ||
4467 | result = v; | ||
4468 | |||
4469 | z = bits; | ||
4470 | while (z < 8) { | ||
4471 | result += v >> z; | ||
4472 | z += bits; | ||
4473 | } | ||
4474 | return result; | ||
4475 | } | ||
4476 | |||
4477 | static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
4478 | { | ||
4479 | stbi_uc *out; | ||
4480 | unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; | ||
4481 | stbi_uc pal[256][4]; | ||
4482 | int psize=0,i,j,compress=0,width; | ||
4483 | int bpp, flip_vertically, pad, target, offset, hsz; | ||
4484 | if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); | ||
4485 | stbi__get32le(s); // discard filesize | ||
4486 | stbi__get16le(s); // discard reserved | ||
4487 | stbi__get16le(s); // discard reserved | ||
4488 | offset = stbi__get32le(s); | ||
4489 | hsz = stbi__get32le(s); | ||
4490 | if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); | ||
4491 | if (hsz == 12) { | ||
4492 | s->img_x = stbi__get16le(s); | ||
4493 | s->img_y = stbi__get16le(s); | ||
4494 | } else { | ||
4495 | s->img_x = stbi__get32le(s); | ||
4496 | s->img_y = stbi__get32le(s); | ||
4497 | } | ||
4498 | if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); | ||
4499 | bpp = stbi__get16le(s); | ||
4500 | if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); | ||
4501 | flip_vertically = ((int) s->img_y) > 0; | ||
4502 | s->img_y = abs((int) s->img_y); | ||
4503 | if (hsz == 12) { | ||
4504 | if (bpp < 24) | ||
4505 | psize = (offset - 14 - 24) / 3; | ||
4506 | } else { | ||
4507 | compress = stbi__get32le(s); | ||
4508 | if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); | ||
4509 | stbi__get32le(s); // discard sizeof | ||
4510 | stbi__get32le(s); // discard hres | ||
4511 | stbi__get32le(s); // discard vres | ||
4512 | stbi__get32le(s); // discard colorsused | ||
4513 | stbi__get32le(s); // discard max important | ||
4514 | if (hsz == 40 || hsz == 56) { | ||
4515 | if (hsz == 56) { | ||
4516 | stbi__get32le(s); | ||
4517 | stbi__get32le(s); | ||
4518 | stbi__get32le(s); | ||
4519 | stbi__get32le(s); | ||
4520 | } | ||
4521 | if (bpp == 16 || bpp == 32) { | ||
4522 | mr = mg = mb = 0; | ||
4523 | if (compress == 0) { | ||
4524 | if (bpp == 32) { | ||
4525 | mr = 0xffu << 16; | ||
4526 | mg = 0xffu << 8; | ||
4527 | mb = 0xffu << 0; | ||
4528 | ma = 0xffu << 24; | ||
4529 | fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 | ||
4530 | STBI_NOTUSED(fake_a); | ||
4531 | } else { | ||
4532 | mr = 31u << 10; | ||
4533 | mg = 31u << 5; | ||
4534 | mb = 31u << 0; | ||
4535 | } | ||
4536 | } else if (compress == 3) { | ||
4537 | mr = stbi__get32le(s); | ||
4538 | mg = stbi__get32le(s); | ||
4539 | mb = stbi__get32le(s); | ||
4540 | // not documented, but generated by photoshop and handled by mspaint | ||
4541 | if (mr == mg && mg == mb) { | ||
4542 | // ?!?!? | ||
4543 | return stbi__errpuc("bad BMP", "bad BMP"); | ||
4544 | } | ||
4545 | } else | ||
4546 | return stbi__errpuc("bad BMP", "bad BMP"); | ||
4547 | } | ||
4548 | } else { | ||
4549 | STBI_ASSERT(hsz == 108 || hsz == 124); | ||
4550 | mr = stbi__get32le(s); | ||
4551 | mg = stbi__get32le(s); | ||
4552 | mb = stbi__get32le(s); | ||
4553 | ma = stbi__get32le(s); | ||
4554 | stbi__get32le(s); // discard color space | ||
4555 | for (i=0; i < 12; ++i) | ||
4556 | stbi__get32le(s); // discard color space parameters | ||
4557 | if (hsz == 124) { | ||
4558 | stbi__get32le(s); // discard rendering intent | ||
4559 | stbi__get32le(s); // discard offset of profile data | ||
4560 | stbi__get32le(s); // discard size of profile data | ||
4561 | stbi__get32le(s); // discard reserved | ||
4562 | } | ||
4563 | } | ||
4564 | if (bpp < 16) | ||
4565 | psize = (offset - 14 - hsz) >> 2; | ||
4566 | } | ||
4567 | s->img_n = ma ? 4 : 3; | ||
4568 | if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 | ||
4569 | target = req_comp; | ||
4570 | else | ||
4571 | target = s->img_n; // if they want monochrome, we'll post-convert | ||
4572 | out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); | ||
4573 | if (!out) return stbi__errpuc("outofmem", "Out of memory"); | ||
4574 | if (bpp < 16) { | ||
4575 | int z=0; | ||
4576 | if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } | ||
4577 | for (i=0; i < psize; ++i) { | ||
4578 | pal[i][2] = stbi__get8(s); | ||
4579 | pal[i][1] = stbi__get8(s); | ||
4580 | pal[i][0] = stbi__get8(s); | ||
4581 | if (hsz != 12) stbi__get8(s); | ||
4582 | pal[i][3] = 255; | ||
4583 | } | ||
4584 | stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); | ||
4585 | if (bpp == 4) width = (s->img_x + 1) >> 1; | ||
4586 | else if (bpp == 8) width = s->img_x; | ||
4587 | else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } | ||
4588 | pad = (-width)&3; | ||
4589 | for (j=0; j < (int) s->img_y; ++j) { | ||
4590 | for (i=0; i < (int) s->img_x; i += 2) { | ||
4591 | int v=stbi__get8(s),v2=0; | ||
4592 | if (bpp == 4) { | ||
4593 | v2 = v & 15; | ||
4594 | v >>= 4; | ||
4595 | } | ||
4596 | out[z++] = pal[v][0]; | ||
4597 | out[z++] = pal[v][1]; | ||
4598 | out[z++] = pal[v][2]; | ||
4599 | if (target == 4) out[z++] = 255; | ||
4600 | if (i+1 == (int) s->img_x) break; | ||
4601 | v = (bpp == 8) ? stbi__get8(s) : v2; | ||
4602 | out[z++] = pal[v][0]; | ||
4603 | out[z++] = pal[v][1]; | ||
4604 | out[z++] = pal[v][2]; | ||
4605 | if (target == 4) out[z++] = 255; | ||
4606 | } | ||
4607 | stbi__skip(s, pad); | ||
4608 | } | ||
4609 | } else { | ||
4610 | int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; | ||
4611 | int z = 0; | ||
4612 | int easy=0; | ||
4613 | stbi__skip(s, offset - 14 - hsz); | ||
4614 | if (bpp == 24) width = 3 * s->img_x; | ||
4615 | else if (bpp == 16) width = 2*s->img_x; | ||
4616 | else /* bpp = 32 and pad = 0 */ width=0; | ||
4617 | pad = (-width) & 3; | ||
4618 | if (bpp == 24) { | ||
4619 | easy = 1; | ||
4620 | } else if (bpp == 32) { | ||
4621 | if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) | ||
4622 | easy = 2; | ||
4623 | } | ||
4624 | if (!easy) { | ||
4625 | if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } | ||
4626 | // right shift amt to put high bit in position #7 | ||
4627 | rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); | ||
4628 | gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); | ||
4629 | bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); | ||
4630 | ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); | ||
4631 | } | ||
4632 | for (j=0; j < (int) s->img_y; ++j) { | ||
4633 | if (easy) { | ||
4634 | for (i=0; i < (int) s->img_x; ++i) { | ||
4635 | unsigned char a; | ||
4636 | out[z+2] = stbi__get8(s); | ||
4637 | out[z+1] = stbi__get8(s); | ||
4638 | out[z+0] = stbi__get8(s); | ||
4639 | z += 3; | ||
4640 | a = (easy == 2 ? stbi__get8(s) : 255); | ||
4641 | if (target == 4) out[z++] = a; | ||
4642 | } | ||
4643 | } else { | ||
4644 | for (i=0; i < (int) s->img_x; ++i) { | ||
4645 | stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s)); | ||
4646 | int a; | ||
4647 | out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); | ||
4648 | out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); | ||
4649 | out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); | ||
4650 | a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); | ||
4651 | if (target == 4) out[z++] = STBI__BYTECAST(a); | ||
4652 | } | ||
4653 | } | ||
4654 | stbi__skip(s, pad); | ||
4655 | } | ||
4656 | } | ||
4657 | if (flip_vertically) { | ||
4658 | stbi_uc t; | ||
4659 | for (j=0; j < (int) s->img_y>>1; ++j) { | ||
4660 | stbi_uc *p1 = out + j *s->img_x*target; | ||
4661 | stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; | ||
4662 | for (i=0; i < (int) s->img_x*target; ++i) { | ||
4663 | t = p1[i], p1[i] = p2[i], p2[i] = t; | ||
4664 | } | ||
4665 | } | ||
4666 | } | ||
4667 | |||
4668 | if (req_comp && req_comp != target) { | ||
4669 | out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); | ||
4670 | if (out == NULL) return out; // stbi__convert_format frees input on failure | ||
4671 | } | ||
4672 | |||
4673 | *x = s->img_x; | ||
4674 | *y = s->img_y; | ||
4675 | if (comp) *comp = s->img_n; | ||
4676 | return out; | ||
4677 | } | ||
4678 | #endif | ||
4679 | |||
4680 | // Targa Truevision - TGA | ||
4681 | // by Jonathan Dummer | ||
4682 | #ifndef STBI_NO_TGA | ||
4683 | static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) | ||
4684 | { | ||
4685 | int tga_w, tga_h, tga_comp; | ||
4686 | int sz; | ||
4687 | stbi__get8(s); // discard Offset | ||
4688 | sz = stbi__get8(s); // color type | ||
4689 | if( sz > 1 ) { | ||
4690 | stbi__rewind(s); | ||
4691 | return 0; // only RGB or indexed allowed | ||
4692 | } | ||
4693 | sz = stbi__get8(s); // image type | ||
4694 | // only RGB or grey allowed, +/- RLE | ||
4695 | if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; | ||
4696 | stbi__skip(s,9); | ||
4697 | tga_w = stbi__get16le(s); | ||
4698 | if( tga_w < 1 ) { | ||
4699 | stbi__rewind(s); | ||
4700 | return 0; // test width | ||
4701 | } | ||
4702 | tga_h = stbi__get16le(s); | ||
4703 | if( tga_h < 1 ) { | ||
4704 | stbi__rewind(s); | ||
4705 | return 0; // test height | ||
4706 | } | ||
4707 | sz = stbi__get8(s); // bits per pixel | ||
4708 | // only RGB or RGBA or grey allowed | ||
4709 | if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { | ||
4710 | stbi__rewind(s); | ||
4711 | return 0; | ||
4712 | } | ||
4713 | tga_comp = sz; | ||
4714 | if (x) *x = tga_w; | ||
4715 | if (y) *y = tga_h; | ||
4716 | if (comp) *comp = tga_comp / 8; | ||
4717 | return 1; // seems to have passed everything | ||
4718 | } | ||
4719 | |||
4720 | static int stbi__tga_test(stbi__context *s) | ||
4721 | { | ||
4722 | int res; | ||
4723 | int sz; | ||
4724 | stbi__get8(s); // discard Offset | ||
4725 | sz = stbi__get8(s); // color type | ||
4726 | if ( sz > 1 ) return 0; // only RGB or indexed allowed | ||
4727 | sz = stbi__get8(s); // image type | ||
4728 | if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE | ||
4729 | stbi__get16be(s); // discard palette start | ||
4730 | stbi__get16be(s); // discard palette length | ||
4731 | stbi__get8(s); // discard bits per palette color entry | ||
4732 | stbi__get16be(s); // discard x origin | ||
4733 | stbi__get16be(s); // discard y origin | ||
4734 | if ( stbi__get16be(s) < 1 ) return 0; // test width | ||
4735 | if ( stbi__get16be(s) < 1 ) return 0; // test height | ||
4736 | sz = stbi__get8(s); // bits per pixel | ||
4737 | if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) | ||
4738 | res = 0; | ||
4739 | else | ||
4740 | res = 1; | ||
4741 | stbi__rewind(s); | ||
4742 | return res; | ||
4743 | } | ||
4744 | |||
4745 | static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
4746 | { | ||
4747 | // read in the TGA header stuff | ||
4748 | int tga_offset = stbi__get8(s); | ||
4749 | int tga_indexed = stbi__get8(s); | ||
4750 | int tga_image_type = stbi__get8(s); | ||
4751 | int tga_is_RLE = 0; | ||
4752 | int tga_palette_start = stbi__get16le(s); | ||
4753 | int tga_palette_len = stbi__get16le(s); | ||
4754 | int tga_palette_bits = stbi__get8(s); | ||
4755 | int tga_x_origin = stbi__get16le(s); | ||
4756 | int tga_y_origin = stbi__get16le(s); | ||
4757 | int tga_width = stbi__get16le(s); | ||
4758 | int tga_height = stbi__get16le(s); | ||
4759 | int tga_bits_per_pixel = stbi__get8(s); | ||
4760 | int tga_comp = tga_bits_per_pixel / 8; | ||
4761 | int tga_inverted = stbi__get8(s); | ||
4762 | // image data | ||
4763 | unsigned char *tga_data; | ||
4764 | unsigned char *tga_palette = NULL; | ||
4765 | int i, j; | ||
4766 | unsigned char raw_data[4]; | ||
4767 | int RLE_count = 0; | ||
4768 | int RLE_repeating = 0; | ||
4769 | int read_next_pixel = 1; | ||
4770 | |||
4771 | // do a tiny bit of precessing | ||
4772 | if ( tga_image_type >= 8 ) | ||
4773 | { | ||
4774 | tga_image_type -= 8; | ||
4775 | tga_is_RLE = 1; | ||
4776 | } | ||
4777 | /* int tga_alpha_bits = tga_inverted & 15; */ | ||
4778 | tga_inverted = 1 - ((tga_inverted >> 5) & 1); | ||
4779 | |||
4780 | // error check | ||
4781 | if ( //(tga_indexed) || | ||
4782 | (tga_width < 1) || (tga_height < 1) || | ||
4783 | (tga_image_type < 1) || (tga_image_type > 3) || | ||
4784 | ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && | ||
4785 | (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) | ||
4786 | ) | ||
4787 | { | ||
4788 | return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA | ||
4789 | } | ||
4790 | |||
4791 | // If I'm paletted, then I'll use the number of bits from the palette | ||
4792 | if ( tga_indexed ) | ||
4793 | { | ||
4794 | tga_comp = tga_palette_bits / 8; | ||
4795 | } | ||
4796 | |||
4797 | // tga info | ||
4798 | *x = tga_width; | ||
4799 | *y = tga_height; | ||
4800 | if (comp) *comp = tga_comp; | ||
4801 | |||
4802 | tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp ); | ||
4803 | if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); | ||
4804 | |||
4805 | // skip to the data's starting position (offset usually = 0) | ||
4806 | stbi__skip(s, tga_offset ); | ||
4807 | |||
4808 | if ( !tga_indexed && !tga_is_RLE) { | ||
4809 | for (i=0; i < tga_height; ++i) { | ||
4810 | int y = tga_inverted ? tga_height -i - 1 : i; | ||
4811 | stbi_uc *tga_row = tga_data + y*tga_width*tga_comp; | ||
4812 | stbi__getn(s, tga_row, tga_width * tga_comp); | ||
4813 | } | ||
4814 | } else { | ||
4815 | // do I need to load a palette? | ||
4816 | if ( tga_indexed) | ||
4817 | { | ||
4818 | // any data to skip? (offset usually = 0) | ||
4819 | stbi__skip(s, tga_palette_start ); | ||
4820 | // load the palette | ||
4821 | tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); | ||
4822 | if (!tga_palette) { | ||
4823 | STBI_FREE(tga_data); | ||
4824 | return stbi__errpuc("outofmem", "Out of memory"); | ||
4825 | } | ||
4826 | if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { | ||
4827 | STBI_FREE(tga_data); | ||
4828 | STBI_FREE(tga_palette); | ||
4829 | return stbi__errpuc("bad palette", "Corrupt TGA"); | ||
4830 | } | ||
4831 | } | ||
4832 | // load the data | ||
4833 | for (i=0; i < tga_width * tga_height; ++i) | ||
4834 | { | ||
4835 | // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? | ||
4836 | if ( tga_is_RLE ) | ||
4837 | { | ||
4838 | if ( RLE_count == 0 ) | ||
4839 | { | ||
4840 | // yep, get the next byte as a RLE command | ||
4841 | int RLE_cmd = stbi__get8(s); | ||
4842 | RLE_count = 1 + (RLE_cmd & 127); | ||
4843 | RLE_repeating = RLE_cmd >> 7; | ||
4844 | read_next_pixel = 1; | ||
4845 | } else if ( !RLE_repeating ) | ||
4846 | { | ||
4847 | read_next_pixel = 1; | ||
4848 | } | ||
4849 | } else | ||
4850 | { | ||
4851 | read_next_pixel = 1; | ||
4852 | } | ||
4853 | // OK, if I need to read a pixel, do it now | ||
4854 | if ( read_next_pixel ) | ||
4855 | { | ||
4856 | // load however much data we did have | ||
4857 | if ( tga_indexed ) | ||
4858 | { | ||
4859 | // read in 1 byte, then perform the lookup | ||
4860 | int pal_idx = stbi__get8(s); | ||
4861 | if ( pal_idx >= tga_palette_len ) | ||
4862 | { | ||
4863 | // invalid index | ||
4864 | pal_idx = 0; | ||
4865 | } | ||
4866 | pal_idx *= tga_bits_per_pixel / 8; | ||
4867 | for (j = 0; j*8 < tga_bits_per_pixel; ++j) | ||
4868 | { | ||
4869 | raw_data[j] = tga_palette[pal_idx+j]; | ||
4870 | } | ||
4871 | } else | ||
4872 | { | ||
4873 | // read in the data raw | ||
4874 | for (j = 0; j*8 < tga_bits_per_pixel; ++j) | ||
4875 | { | ||
4876 | raw_data[j] = stbi__get8(s); | ||
4877 | } | ||
4878 | } | ||
4879 | // clear the reading flag for the next pixel | ||
4880 | read_next_pixel = 0; | ||
4881 | } // end of reading a pixel | ||
4882 | |||
4883 | // copy data | ||
4884 | for (j = 0; j < tga_comp; ++j) | ||
4885 | tga_data[i*tga_comp+j] = raw_data[j]; | ||
4886 | |||
4887 | // in case we're in RLE mode, keep counting down | ||
4888 | --RLE_count; | ||
4889 | } | ||
4890 | // do I need to invert the image? | ||
4891 | if ( tga_inverted ) | ||
4892 | { | ||
4893 | for (j = 0; j*2 < tga_height; ++j) | ||
4894 | { | ||
4895 | int index1 = j * tga_width * tga_comp; | ||
4896 | int index2 = (tga_height - 1 - j) * tga_width * tga_comp; | ||
4897 | for (i = tga_width * tga_comp; i > 0; --i) | ||
4898 | { | ||
4899 | unsigned char temp = tga_data[index1]; | ||
4900 | tga_data[index1] = tga_data[index2]; | ||
4901 | tga_data[index2] = temp; | ||
4902 | ++index1; | ||
4903 | ++index2; | ||
4904 | } | ||
4905 | } | ||
4906 | } | ||
4907 | // clear my palette, if I had one | ||
4908 | if ( tga_palette != NULL ) | ||
4909 | { | ||
4910 | STBI_FREE( tga_palette ); | ||
4911 | } | ||
4912 | } | ||
4913 | |||
4914 | // swap RGB | ||
4915 | if (tga_comp >= 3) | ||
4916 | { | ||
4917 | unsigned char* tga_pixel = tga_data; | ||
4918 | for (i=0; i < tga_width * tga_height; ++i) | ||
4919 | { | ||
4920 | unsigned char temp = tga_pixel[0]; | ||
4921 | tga_pixel[0] = tga_pixel[2]; | ||
4922 | tga_pixel[2] = temp; | ||
4923 | tga_pixel += tga_comp; | ||
4924 | } | ||
4925 | } | ||
4926 | |||
4927 | // convert to target component count | ||
4928 | if (req_comp && req_comp != tga_comp) | ||
4929 | tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); | ||
4930 | |||
4931 | // the things I do to get rid of an error message, and yet keep | ||
4932 | // Microsoft's C compilers happy... [8^( | ||
4933 | tga_palette_start = tga_palette_len = tga_palette_bits = | ||
4934 | tga_x_origin = tga_y_origin = 0; | ||
4935 | // OK, done | ||
4936 | return tga_data; | ||
4937 | } | ||
4938 | #endif | ||
4939 | |||
4940 | // ************************************************************************************************* | ||
4941 | // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB | ||
4942 | |||
4943 | #ifndef STBI_NO_PSD | ||
4944 | static int stbi__psd_test(stbi__context *s) | ||
4945 | { | ||
4946 | int r = (stbi__get32be(s) == 0x38425053); | ||
4947 | stbi__rewind(s); | ||
4948 | return r; | ||
4949 | } | ||
4950 | |||
4951 | static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
4952 | { | ||
4953 | int pixelCount; | ||
4954 | int channelCount, compression; | ||
4955 | int channel, i, count, len; | ||
4956 | int w,h; | ||
4957 | stbi_uc *out; | ||
4958 | |||
4959 | // Check identifier | ||
4960 | if (stbi__get32be(s) != 0x38425053) // "8BPS" | ||
4961 | return stbi__errpuc("not PSD", "Corrupt PSD image"); | ||
4962 | |||
4963 | // Check file type version. | ||
4964 | if (stbi__get16be(s) != 1) | ||
4965 | return stbi__errpuc("wrong version", "Unsupported version of PSD image"); | ||
4966 | |||
4967 | // Skip 6 reserved bytes. | ||
4968 | stbi__skip(s, 6 ); | ||
4969 | |||
4970 | // Read the number of channels (R, G, B, A, etc). | ||
4971 | channelCount = stbi__get16be(s); | ||
4972 | if (channelCount < 0 || channelCount > 16) | ||
4973 | return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); | ||
4974 | |||
4975 | // Read the rows and columns of the image. | ||
4976 | h = stbi__get32be(s); | ||
4977 | w = stbi__get32be(s); | ||
4978 | |||
4979 | // Make sure the depth is 8 bits. | ||
4980 | if (stbi__get16be(s) != 8) | ||
4981 | return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit"); | ||
4982 | |||
4983 | // Make sure the color mode is RGB. | ||
4984 | // Valid options are: | ||
4985 | // 0: Bitmap | ||
4986 | // 1: Grayscale | ||
4987 | // 2: Indexed color | ||
4988 | // 3: RGB color | ||
4989 | // 4: CMYK color | ||
4990 | // 7: Multichannel | ||
4991 | // 8: Duotone | ||
4992 | // 9: Lab color | ||
4993 | if (stbi__get16be(s) != 3) | ||
4994 | return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); | ||
4995 | |||
4996 | // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) | ||
4997 | stbi__skip(s,stbi__get32be(s) ); | ||
4998 | |||
4999 | // Skip the image resources. (resolution, pen tool paths, etc) | ||
5000 | stbi__skip(s, stbi__get32be(s) ); | ||
5001 | |||
5002 | // Skip the reserved data. | ||
5003 | stbi__skip(s, stbi__get32be(s) ); | ||
5004 | |||
5005 | // Find out if the data is compressed. | ||
5006 | // Known values: | ||
5007 | // 0: no compression | ||
5008 | // 1: RLE compressed | ||
5009 | compression = stbi__get16be(s); | ||
5010 | if (compression > 1) | ||
5011 | return stbi__errpuc("bad compression", "PSD has an unknown compression format"); | ||
5012 | |||
5013 | // Create the destination image. | ||
5014 | out = (stbi_uc *) stbi__malloc(4 * w*h); | ||
5015 | if (!out) return stbi__errpuc("outofmem", "Out of memory"); | ||
5016 | pixelCount = w*h; | ||
5017 | |||
5018 | // Initialize the data to zero. | ||
5019 | //memset( out, 0, pixelCount * 4 ); | ||
5020 | |||
5021 | // Finally, the image data. | ||
5022 | if (compression) { | ||
5023 | // RLE as used by .PSD and .TIFF | ||
5024 | // Loop until you get the number of unpacked bytes you are expecting: | ||
5025 | // Read the next source byte into n. | ||
5026 | // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. | ||
5027 | // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. | ||
5028 | // Else if n is 128, noop. | ||
5029 | // Endloop | ||
5030 | |||
5031 | // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, | ||
5032 | // which we're going to just skip. | ||
5033 | stbi__skip(s, h * channelCount * 2 ); | ||
5034 | |||
5035 | // Read the RLE data by channel. | ||
5036 | for (channel = 0; channel < 4; channel++) { | ||
5037 | stbi_uc *p; | ||
5038 | |||
5039 | p = out+channel; | ||
5040 | if (channel >= channelCount) { | ||
5041 | // Fill this channel with default data. | ||
5042 | for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; | ||
5043 | } else { | ||
5044 | // Read the RLE data. | ||
5045 | count = 0; | ||
5046 | while (count < pixelCount) { | ||
5047 | len = stbi__get8(s); | ||
5048 | if (len == 128) { | ||
5049 | // No-op. | ||
5050 | } else if (len < 128) { | ||
5051 | // Copy next len+1 bytes literally. | ||
5052 | len++; | ||
5053 | count += len; | ||
5054 | while (len) { | ||
5055 | *p = stbi__get8(s); | ||
5056 | p += 4; | ||
5057 | len--; | ||
5058 | } | ||
5059 | } else if (len > 128) { | ||
5060 | stbi_uc val; | ||
5061 | // Next -len+1 bytes in the dest are replicated from next source byte. | ||
5062 | // (Interpret len as a negative 8-bit int.) | ||
5063 | len ^= 0x0FF; | ||
5064 | len += 2; | ||
5065 | val = stbi__get8(s); | ||
5066 | count += len; | ||
5067 | while (len) { | ||
5068 | *p = val; | ||
5069 | p += 4; | ||
5070 | len--; | ||
5071 | } | ||
5072 | } | ||
5073 | } | ||
5074 | } | ||
5075 | } | ||
5076 | |||
5077 | } else { | ||
5078 | // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) | ||
5079 | // where each channel consists of an 8-bit value for each pixel in the image. | ||
5080 | |||
5081 | // Read the data by channel. | ||
5082 | for (channel = 0; channel < 4; channel++) { | ||
5083 | stbi_uc *p; | ||
5084 | |||
5085 | p = out + channel; | ||
5086 | if (channel > channelCount) { | ||
5087 | // Fill this channel with default data. | ||
5088 | for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; | ||
5089 | } else { | ||
5090 | // Read the data. | ||
5091 | for (i = 0; i < pixelCount; i++) | ||
5092 | *p = stbi__get8(s), p += 4; | ||
5093 | } | ||
5094 | } | ||
5095 | } | ||
5096 | |||
5097 | if (req_comp && req_comp != 4) { | ||
5098 | out = stbi__convert_format(out, 4, req_comp, w, h); | ||
5099 | if (out == NULL) return out; // stbi__convert_format frees input on failure | ||
5100 | } | ||
5101 | |||
5102 | if (comp) *comp = channelCount; | ||
5103 | *y = h; | ||
5104 | *x = w; | ||
5105 | |||
5106 | return out; | ||
5107 | } | ||
5108 | #endif | ||
5109 | |||
5110 | // ************************************************************************************************* | ||
5111 | // Softimage PIC loader | ||
5112 | // by Tom Seddon | ||
5113 | // | ||
5114 | // See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format | ||
5115 | // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ | ||
5116 | |||
5117 | #ifndef STBI_NO_PIC | ||
5118 | static int stbi__pic_is4(stbi__context *s,const char *str) | ||
5119 | { | ||
5120 | int i; | ||
5121 | for (i=0; i<4; ++i) | ||
5122 | if (stbi__get8(s) != (stbi_uc)str[i]) | ||
5123 | return 0; | ||
5124 | |||
5125 | return 1; | ||
5126 | } | ||
5127 | |||
5128 | static int stbi__pic_test_core(stbi__context *s) | ||
5129 | { | ||
5130 | int i; | ||
5131 | |||
5132 | if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) | ||
5133 | return 0; | ||
5134 | |||
5135 | for(i=0;i<84;++i) | ||
5136 | stbi__get8(s); | ||
5137 | |||
5138 | if (!stbi__pic_is4(s,"PICT")) | ||
5139 | return 0; | ||
5140 | |||
5141 | return 1; | ||
5142 | } | ||
5143 | |||
5144 | typedef struct | ||
5145 | { | ||
5146 | stbi_uc size,type,channel; | ||
5147 | } stbi__pic_packet; | ||
5148 | |||
5149 | static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) | ||
5150 | { | ||
5151 | int mask=0x80, i; | ||
5152 | |||
5153 | for (i=0; i<4; ++i, mask>>=1) { | ||
5154 | if (channel & mask) { | ||
5155 | if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); | ||
5156 | dest[i]=stbi__get8(s); | ||
5157 | } | ||
5158 | } | ||
5159 | |||
5160 | return dest; | ||
5161 | } | ||
5162 | |||
5163 | static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) | ||
5164 | { | ||
5165 | int mask=0x80,i; | ||
5166 | |||
5167 | for (i=0;i<4; ++i, mask>>=1) | ||
5168 | if (channel&mask) | ||
5169 | dest[i]=src[i]; | ||
5170 | } | ||
5171 | |||
5172 | static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) | ||
5173 | { | ||
5174 | int act_comp=0,num_packets=0,y,chained; | ||
5175 | stbi__pic_packet packets[10]; | ||
5176 | |||
5177 | // this will (should...) cater for even some bizarre stuff like having data | ||
5178 | // for the same channel in multiple packets. | ||
5179 | do { | ||
5180 | stbi__pic_packet *packet; | ||
5181 | |||
5182 | if (num_packets==sizeof(packets)/sizeof(packets[0])) | ||
5183 | return stbi__errpuc("bad format","too many packets"); | ||
5184 | |||
5185 | packet = &packets[num_packets++]; | ||
5186 | |||
5187 | chained = stbi__get8(s); | ||
5188 | packet->size = stbi__get8(s); | ||
5189 | packet->type = stbi__get8(s); | ||
5190 | packet->channel = stbi__get8(s); | ||
5191 | |||
5192 | act_comp |= packet->channel; | ||
5193 | |||
5194 | if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); | ||
5195 | if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); | ||
5196 | } while (chained); | ||
5197 | |||
5198 | *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? | ||
5199 | |||
5200 | for(y=0; y<height; ++y) { | ||
5201 | int packet_idx; | ||
5202 | |||
5203 | for(packet_idx=0; packet_idx < num_packets; ++packet_idx) { | ||
5204 | stbi__pic_packet *packet = &packets[packet_idx]; | ||
5205 | stbi_uc *dest = result+y*width*4; | ||
5206 | |||
5207 | switch (packet->type) { | ||
5208 | default: | ||
5209 | return stbi__errpuc("bad format","packet has bad compression type"); | ||
5210 | |||
5211 | case 0: {//uncompressed | ||
5212 | int x; | ||
5213 | |||
5214 | for(x=0;x<width;++x, dest+=4) | ||
5215 | if (!stbi__readval(s,packet->channel,dest)) | ||
5216 | return 0; | ||
5217 | break; | ||
5218 | } | ||
5219 | |||
5220 | case 1://Pure RLE | ||
5221 | { | ||
5222 | int left=width, i; | ||
5223 | |||
5224 | while (left>0) { | ||
5225 | stbi_uc count,value[4]; | ||
5226 | |||
5227 | count=stbi__get8(s); | ||
5228 | if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); | ||
5229 | |||
5230 | if (count > left) | ||
5231 | count = (stbi_uc) left; | ||
5232 | |||
5233 | if (!stbi__readval(s,packet->channel,value)) return 0; | ||
5234 | |||
5235 | for(i=0; i<count; ++i,dest+=4) | ||
5236 | stbi__copyval(packet->channel,dest,value); | ||
5237 | left -= count; | ||
5238 | } | ||
5239 | } | ||
5240 | break; | ||
5241 | |||
5242 | case 2: {//Mixed RLE | ||
5243 | int left=width; | ||
5244 | while (left>0) { | ||
5245 | int count = stbi__get8(s), i; | ||
5246 | if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); | ||
5247 | |||
5248 | if (count >= 128) { // Repeated | ||
5249 | stbi_uc value[4]; | ||
5250 | int i; | ||
5251 | |||
5252 | if (count==128) | ||
5253 | count = stbi__get16be(s); | ||
5254 | else | ||
5255 | count -= 127; | ||
5256 | if (count > left) | ||
5257 | return stbi__errpuc("bad file","scanline overrun"); | ||
5258 | |||
5259 | if (!stbi__readval(s,packet->channel,value)) | ||
5260 | return 0; | ||
5261 | |||
5262 | for(i=0;i<count;++i, dest += 4) | ||
5263 | stbi__copyval(packet->channel,dest,value); | ||
5264 | } else { // Raw | ||
5265 | ++count; | ||
5266 | if (count>left) return stbi__errpuc("bad file","scanline overrun"); | ||
5267 | |||
5268 | for(i=0;i<count;++i, dest+=4) | ||
5269 | if (!stbi__readval(s,packet->channel,dest)) | ||
5270 | return 0; | ||
5271 | } | ||
5272 | left-=count; | ||
5273 | } | ||
5274 | break; | ||
5275 | } | ||
5276 | } | ||
5277 | } | ||
5278 | } | ||
5279 | |||
5280 | return result; | ||
5281 | } | ||
5282 | |||
5283 | static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) | ||
5284 | { | ||
5285 | stbi_uc *result; | ||
5286 | int i, x,y; | ||
5287 | |||
5288 | for (i=0; i<92; ++i) | ||
5289 | stbi__get8(s); | ||
5290 | |||
5291 | x = stbi__get16be(s); | ||
5292 | y = stbi__get16be(s); | ||
5293 | if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); | ||
5294 | if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); | ||
5295 | |||
5296 | stbi__get32be(s); //skip `ratio' | ||
5297 | stbi__get16be(s); //skip `fields' | ||
5298 | stbi__get16be(s); //skip `pad' | ||
5299 | |||
5300 | // intermediate buffer is RGBA | ||
5301 | result = (stbi_uc *) stbi__malloc(x*y*4); | ||
5302 | memset(result, 0xff, x*y*4); | ||
5303 | |||
5304 | if (!stbi__pic_load_core(s,x,y,comp, result)) { | ||
5305 | STBI_FREE(result); | ||
5306 | result=0; | ||
5307 | } | ||
5308 | *px = x; | ||
5309 | *py = y; | ||
5310 | if (req_comp == 0) req_comp = *comp; | ||
5311 | result=stbi__convert_format(result,4,req_comp,x,y); | ||
5312 | |||
5313 | return result; | ||
5314 | } | ||
5315 | |||
5316 | static int stbi__pic_test(stbi__context *s) | ||
5317 | { | ||
5318 | int r = stbi__pic_test_core(s); | ||
5319 | stbi__rewind(s); | ||
5320 | return r; | ||
5321 | } | ||
5322 | #endif | ||
5323 | |||
5324 | // ************************************************************************************************* | ||
5325 | // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb | ||
5326 | |||
5327 | #ifndef STBI_NO_GIF | ||
5328 | typedef struct | ||
5329 | { | ||
5330 | stbi__int16 prefix; | ||
5331 | stbi_uc first; | ||
5332 | stbi_uc suffix; | ||
5333 | } stbi__gif_lzw; | ||
5334 | |||
5335 | typedef struct | ||
5336 | { | ||
5337 | int w,h; | ||
5338 | stbi_uc *out; // output buffer (always 4 components) | ||
5339 | int flags, bgindex, ratio, transparent, eflags; | ||
5340 | stbi_uc pal[256][4]; | ||
5341 | stbi_uc lpal[256][4]; | ||
5342 | stbi__gif_lzw codes[4096]; | ||
5343 | stbi_uc *color_table; | ||
5344 | int parse, step; | ||
5345 | int lflags; | ||
5346 | int start_x, start_y; | ||
5347 | int max_x, max_y; | ||
5348 | int cur_x, cur_y; | ||
5349 | int line_size; | ||
5350 | } stbi__gif; | ||
5351 | |||
5352 | static int stbi__gif_test_raw(stbi__context *s) | ||
5353 | { | ||
5354 | int sz; | ||
5355 | if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; | ||
5356 | sz = stbi__get8(s); | ||
5357 | if (sz != '9' && sz != '7') return 0; | ||
5358 | if (stbi__get8(s) != 'a') return 0; | ||
5359 | return 1; | ||
5360 | } | ||
5361 | |||
5362 | static int stbi__gif_test(stbi__context *s) | ||
5363 | { | ||
5364 | int r = stbi__gif_test_raw(s); | ||
5365 | stbi__rewind(s); | ||
5366 | return r; | ||
5367 | } | ||
5368 | |||
5369 | static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) | ||
5370 | { | ||
5371 | int i; | ||
5372 | for (i=0; i < num_entries; ++i) { | ||
5373 | pal[i][2] = stbi__get8(s); | ||
5374 | pal[i][1] = stbi__get8(s); | ||
5375 | pal[i][0] = stbi__get8(s); | ||
5376 | pal[i][3] = transp == i ? 0 : 255; | ||
5377 | } | ||
5378 | } | ||
5379 | |||
5380 | static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) | ||
5381 | { | ||
5382 | stbi_uc version; | ||
5383 | if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') | ||
5384 | return stbi__err("not GIF", "Corrupt GIF"); | ||
5385 | |||
5386 | version = stbi__get8(s); | ||
5387 | if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); | ||
5388 | if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); | ||
5389 | |||
5390 | stbi__g_failure_reason = ""; | ||
5391 | g->w = stbi__get16le(s); | ||
5392 | g->h = stbi__get16le(s); | ||
5393 | g->flags = stbi__get8(s); | ||
5394 | g->bgindex = stbi__get8(s); | ||
5395 | g->ratio = stbi__get8(s); | ||
5396 | g->transparent = -1; | ||
5397 | |||
5398 | if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments | ||
5399 | |||
5400 | if (is_info) return 1; | ||
5401 | |||
5402 | if (g->flags & 0x80) | ||
5403 | stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); | ||
5404 | |||
5405 | return 1; | ||
5406 | } | ||
5407 | |||
5408 | static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) | ||
5409 | { | ||
5410 | stbi__gif g; | ||
5411 | if (!stbi__gif_header(s, &g, comp, 1)) { | ||
5412 | stbi__rewind( s ); | ||
5413 | return 0; | ||
5414 | } | ||
5415 | if (x) *x = g.w; | ||
5416 | if (y) *y = g.h; | ||
5417 | return 1; | ||
5418 | } | ||
5419 | |||
5420 | static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) | ||
5421 | { | ||
5422 | stbi_uc *p, *c; | ||
5423 | |||
5424 | // recurse to decode the prefixes, since the linked-list is backwards, | ||
5425 | // and working backwards through an interleaved image would be nasty | ||
5426 | if (g->codes[code].prefix >= 0) | ||
5427 | stbi__out_gif_code(g, g->codes[code].prefix); | ||
5428 | |||
5429 | if (g->cur_y >= g->max_y) return; | ||
5430 | |||
5431 | p = &g->out[g->cur_x + g->cur_y]; | ||
5432 | c = &g->color_table[g->codes[code].suffix * 4]; | ||
5433 | |||
5434 | if (c[3] >= 128) { | ||
5435 | p[0] = c[2]; | ||
5436 | p[1] = c[1]; | ||
5437 | p[2] = c[0]; | ||
5438 | p[3] = c[3]; | ||
5439 | } | ||
5440 | g->cur_x += 4; | ||
5441 | |||
5442 | if (g->cur_x >= g->max_x) { | ||
5443 | g->cur_x = g->start_x; | ||
5444 | g->cur_y += g->step; | ||
5445 | |||
5446 | while (g->cur_y >= g->max_y && g->parse > 0) { | ||
5447 | g->step = (1 << g->parse) * g->line_size; | ||
5448 | g->cur_y = g->start_y + (g->step >> 1); | ||
5449 | --g->parse; | ||
5450 | } | ||
5451 | } | ||
5452 | } | ||
5453 | |||
5454 | static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) | ||
5455 | { | ||
5456 | stbi_uc lzw_cs; | ||
5457 | stbi__int32 len, code; | ||
5458 | stbi__uint32 first; | ||
5459 | stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; | ||
5460 | stbi__gif_lzw *p; | ||
5461 | |||
5462 | lzw_cs = stbi__get8(s); | ||
5463 | clear = 1 << lzw_cs; | ||
5464 | first = 1; | ||
5465 | codesize = lzw_cs + 1; | ||
5466 | codemask = (1 << codesize) - 1; | ||
5467 | bits = 0; | ||
5468 | valid_bits = 0; | ||
5469 | for (code = 0; code < clear; code++) { | ||
5470 | g->codes[code].prefix = -1; | ||
5471 | g->codes[code].first = (stbi_uc) code; | ||
5472 | g->codes[code].suffix = (stbi_uc) code; | ||
5473 | } | ||
5474 | |||
5475 | // support no starting clear code | ||
5476 | avail = clear+2; | ||
5477 | oldcode = -1; | ||
5478 | |||
5479 | len = 0; | ||
5480 | for(;;) { | ||
5481 | if (valid_bits < codesize) { | ||
5482 | if (len == 0) { | ||
5483 | len = stbi__get8(s); // start new block | ||
5484 | if (len == 0) | ||
5485 | return g->out; | ||
5486 | } | ||
5487 | --len; | ||
5488 | bits |= (stbi__int32) stbi__get8(s) << valid_bits; | ||
5489 | valid_bits += 8; | ||
5490 | } else { | ||
5491 | stbi__int32 code = bits & codemask; | ||
5492 | bits >>= codesize; | ||
5493 | valid_bits -= codesize; | ||
5494 | // @OPTIMIZE: is there some way we can accelerate the non-clear path? | ||
5495 | if (code == clear) { // clear code | ||
5496 | codesize = lzw_cs + 1; | ||
5497 | codemask = (1 << codesize) - 1; | ||
5498 | avail = clear + 2; | ||
5499 | oldcode = -1; | ||
5500 | first = 0; | ||
5501 | } else if (code == clear + 1) { // end of stream code | ||
5502 | stbi__skip(s, len); | ||
5503 | while ((len = stbi__get8(s)) > 0) | ||
5504 | stbi__skip(s,len); | ||
5505 | return g->out; | ||
5506 | } else if (code <= avail) { | ||
5507 | if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); | ||
5508 | |||
5509 | if (oldcode >= 0) { | ||
5510 | p = &g->codes[avail++]; | ||
5511 | if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); | ||
5512 | p->prefix = (stbi__int16) oldcode; | ||
5513 | p->first = g->codes[oldcode].first; | ||
5514 | p->suffix = (code == avail) ? p->first : g->codes[code].first; | ||
5515 | } else if (code == avail) | ||
5516 | return stbi__errpuc("illegal code in raster", "Corrupt GIF"); | ||
5517 | |||
5518 | stbi__out_gif_code(g, (stbi__uint16) code); | ||
5519 | |||
5520 | if ((avail & codemask) == 0 && avail <= 0x0FFF) { | ||
5521 | codesize++; | ||
5522 | codemask = (1 << codesize) - 1; | ||
5523 | } | ||
5524 | |||
5525 | oldcode = code; | ||
5526 | } else { | ||
5527 | return stbi__errpuc("illegal code in raster", "Corrupt GIF"); | ||
5528 | } | ||
5529 | } | ||
5530 | } | ||
5531 | } | ||
5532 | |||
5533 | static void stbi__fill_gif_background(stbi__gif *g) | ||
5534 | { | ||
5535 | int i; | ||
5536 | stbi_uc *c = g->pal[g->bgindex]; | ||
5537 | // @OPTIMIZE: write a dword at a time | ||
5538 | for (i = 0; i < g->w * g->h * 4; i += 4) { | ||
5539 | stbi_uc *p = &g->out[i]; | ||
5540 | p[0] = c[2]; | ||
5541 | p[1] = c[1]; | ||
5542 | p[2] = c[0]; | ||
5543 | p[3] = c[3]; | ||
5544 | } | ||
5545 | } | ||
5546 | |||
5547 | // this function is designed to support animated gifs, although stb_image doesn't support it | ||
5548 | static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) | ||
5549 | { | ||
5550 | int i; | ||
5551 | stbi_uc *old_out = 0; | ||
5552 | |||
5553 | if (g->out == 0) { | ||
5554 | if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header | ||
5555 | g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); | ||
5556 | if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); | ||
5557 | stbi__fill_gif_background(g); | ||
5558 | } else { | ||
5559 | // animated-gif-only path | ||
5560 | if (((g->eflags & 0x1C) >> 2) == 3) { | ||
5561 | old_out = g->out; | ||
5562 | g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); | ||
5563 | if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); | ||
5564 | memcpy(g->out, old_out, g->w*g->h*4); | ||
5565 | } | ||
5566 | } | ||
5567 | |||
5568 | for (;;) { | ||
5569 | switch (stbi__get8(s)) { | ||
5570 | case 0x2C: /* Image Descriptor */ | ||
5571 | { | ||
5572 | stbi__int32 x, y, w, h; | ||
5573 | stbi_uc *o; | ||
5574 | |||
5575 | x = stbi__get16le(s); | ||
5576 | y = stbi__get16le(s); | ||
5577 | w = stbi__get16le(s); | ||
5578 | h = stbi__get16le(s); | ||
5579 | if (((x + w) > (g->w)) || ((y + h) > (g->h))) | ||
5580 | return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); | ||
5581 | |||
5582 | g->line_size = g->w * 4; | ||
5583 | g->start_x = x * 4; | ||
5584 | g->start_y = y * g->line_size; | ||
5585 | g->max_x = g->start_x + w * 4; | ||
5586 | g->max_y = g->start_y + h * g->line_size; | ||
5587 | g->cur_x = g->start_x; | ||
5588 | g->cur_y = g->start_y; | ||
5589 | |||
5590 | g->lflags = stbi__get8(s); | ||
5591 | |||
5592 | if (g->lflags & 0x40) { | ||
5593 | g->step = 8 * g->line_size; // first interlaced spacing | ||
5594 | g->parse = 3; | ||
5595 | } else { | ||
5596 | g->step = g->line_size; | ||
5597 | g->parse = 0; | ||
5598 | } | ||
5599 | |||
5600 | if (g->lflags & 0x80) { | ||
5601 | stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); | ||
5602 | g->color_table = (stbi_uc *) g->lpal; | ||
5603 | } else if (g->flags & 0x80) { | ||
5604 | for (i=0; i < 256; ++i) // @OPTIMIZE: stbi__jpeg_reset only the previous transparent | ||
5605 | g->pal[i][3] = 255; | ||
5606 | if (g->transparent >= 0 && (g->eflags & 0x01)) | ||
5607 | g->pal[g->transparent][3] = 0; | ||
5608 | g->color_table = (stbi_uc *) g->pal; | ||
5609 | } else | ||
5610 | return stbi__errpuc("missing color table", "Corrupt GIF"); | ||
5611 | |||
5612 | o = stbi__process_gif_raster(s, g); | ||
5613 | if (o == NULL) return NULL; | ||
5614 | |||
5615 | if (req_comp && req_comp != 4) | ||
5616 | o = stbi__convert_format(o, 4, req_comp, g->w, g->h); | ||
5617 | return o; | ||
5618 | } | ||
5619 | |||
5620 | case 0x21: // Comment Extension. | ||
5621 | { | ||
5622 | int len; | ||
5623 | if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. | ||
5624 | len = stbi__get8(s); | ||
5625 | if (len == 4) { | ||
5626 | g->eflags = stbi__get8(s); | ||
5627 | stbi__get16le(s); // delay | ||
5628 | g->transparent = stbi__get8(s); | ||
5629 | } else { | ||
5630 | stbi__skip(s, len); | ||
5631 | break; | ||
5632 | } | ||
5633 | } | ||
5634 | while ((len = stbi__get8(s)) != 0) | ||
5635 | stbi__skip(s, len); | ||
5636 | break; | ||
5637 | } | ||
5638 | |||
5639 | case 0x3B: // gif stream termination code | ||
5640 | return (stbi_uc *) s; // using '1' causes warning on some compilers | ||
5641 | |||
5642 | default: | ||
5643 | return stbi__errpuc("unknown code", "Corrupt GIF"); | ||
5644 | } | ||
5645 | } | ||
5646 | } | ||
5647 | |||
5648 | static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
5649 | { | ||
5650 | stbi_uc *u = 0; | ||
5651 | stbi__gif g; | ||
5652 | memset(&g, 0, sizeof(g)); | ||
5653 | |||
5654 | u = stbi__gif_load_next(s, &g, comp, req_comp); | ||
5655 | if (u == (stbi_uc *) s) u = 0; // end of animated gif marker | ||
5656 | if (u) { | ||
5657 | *x = g.w; | ||
5658 | *y = g.h; | ||
5659 | } | ||
5660 | |||
5661 | return u; | ||
5662 | } | ||
5663 | |||
5664 | static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) | ||
5665 | { | ||
5666 | return stbi__gif_info_raw(s,x,y,comp); | ||
5667 | } | ||
5668 | #endif | ||
5669 | |||
5670 | // ************************************************************************************************* | ||
5671 | // Radiance RGBE HDR loader | ||
5672 | // originally by Nicolas Schulz | ||
5673 | #ifndef STBI_NO_HDR | ||
5674 | static int stbi__hdr_test_core(stbi__context *s) | ||
5675 | { | ||
5676 | const char *signature = "#?RADIANCE\n"; | ||
5677 | int i; | ||
5678 | for (i=0; signature[i]; ++i) | ||
5679 | if (stbi__get8(s) != signature[i]) | ||
5680 | return 0; | ||
5681 | return 1; | ||
5682 | } | ||
5683 | |||
5684 | static int stbi__hdr_test(stbi__context* s) | ||
5685 | { | ||
5686 | int r = stbi__hdr_test_core(s); | ||
5687 | stbi__rewind(s); | ||
5688 | return r; | ||
5689 | } | ||
5690 | |||
5691 | #define STBI__HDR_BUFLEN 1024 | ||
5692 | static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) | ||
5693 | { | ||
5694 | int len=0; | ||
5695 | char c = '\0'; | ||
5696 | |||
5697 | c = (char) stbi__get8(z); | ||
5698 | |||
5699 | while (!stbi__at_eof(z) && c != '\n') { | ||
5700 | buffer[len++] = c; | ||
5701 | if (len == STBI__HDR_BUFLEN-1) { | ||
5702 | // flush to end of line | ||
5703 | while (!stbi__at_eof(z) && stbi__get8(z) != '\n') | ||
5704 | ; | ||
5705 | break; | ||
5706 | } | ||
5707 | c = (char) stbi__get8(z); | ||
5708 | } | ||
5709 | |||
5710 | buffer[len] = 0; | ||
5711 | return buffer; | ||
5712 | } | ||
5713 | |||
5714 | static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) | ||
5715 | { | ||
5716 | if ( input[3] != 0 ) { | ||
5717 | float f1; | ||
5718 | // Exponent | ||
5719 | f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); | ||
5720 | if (req_comp <= 2) | ||
5721 | output[0] = (input[0] + input[1] + input[2]) * f1 / 3; | ||
5722 | else { | ||
5723 | output[0] = input[0] * f1; | ||
5724 | output[1] = input[1] * f1; | ||
5725 | output[2] = input[2] * f1; | ||
5726 | } | ||
5727 | if (req_comp == 2) output[1] = 1; | ||
5728 | if (req_comp == 4) output[3] = 1; | ||
5729 | } else { | ||
5730 | switch (req_comp) { | ||
5731 | case 4: output[3] = 1; /* fallthrough */ | ||
5732 | case 3: output[0] = output[1] = output[2] = 0; | ||
5733 | break; | ||
5734 | case 2: output[1] = 1; /* fallthrough */ | ||
5735 | case 1: output[0] = 0; | ||
5736 | break; | ||
5737 | } | ||
5738 | } | ||
5739 | } | ||
5740 | |||
5741 | static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
5742 | { | ||
5743 | char buffer[STBI__HDR_BUFLEN]; | ||
5744 | char *token; | ||
5745 | int valid = 0; | ||
5746 | int width, height; | ||
5747 | stbi_uc *scanline; | ||
5748 | float *hdr_data; | ||
5749 | int len; | ||
5750 | unsigned char count, value; | ||
5751 | int i, j, k, c1,c2, z; | ||
5752 | |||
5753 | |||
5754 | // Check identifier | ||
5755 | if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) | ||
5756 | return stbi__errpf("not HDR", "Corrupt HDR image"); | ||
5757 | |||
5758 | // Parse header | ||
5759 | for(;;) { | ||
5760 | token = stbi__hdr_gettoken(s,buffer); | ||
5761 | if (token[0] == 0) break; | ||
5762 | if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; | ||
5763 | } | ||
5764 | |||
5765 | if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); | ||
5766 | |||
5767 | // Parse width and height | ||
5768 | // can't use sscanf() if we're not using stdio! | ||
5769 | token = stbi__hdr_gettoken(s,buffer); | ||
5770 | if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); | ||
5771 | token += 3; | ||
5772 | height = (int) strtol(token, &token, 10); | ||
5773 | while (*token == ' ') ++token; | ||
5774 | if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); | ||
5775 | token += 3; | ||
5776 | width = (int) strtol(token, NULL, 10); | ||
5777 | |||
5778 | *x = width; | ||
5779 | *y = height; | ||
5780 | |||
5781 | if (comp) *comp = 3; | ||
5782 | if (req_comp == 0) req_comp = 3; | ||
5783 | |||
5784 | // Read data | ||
5785 | hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); | ||
5786 | |||
5787 | // Load image data | ||
5788 | // image data is stored as some number of sca | ||
5789 | if ( width < 8 || width >= 32768) { | ||
5790 | // Read flat data | ||
5791 | for (j=0; j < height; ++j) { | ||
5792 | for (i=0; i < width; ++i) { | ||
5793 | stbi_uc rgbe[4]; | ||
5794 | main_decode_loop: | ||
5795 | stbi__getn(s, rgbe, 4); | ||
5796 | stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); | ||
5797 | } | ||
5798 | } | ||
5799 | } else { | ||
5800 | // Read RLE-encoded data | ||
5801 | scanline = NULL; | ||
5802 | |||
5803 | for (j = 0; j < height; ++j) { | ||
5804 | c1 = stbi__get8(s); | ||
5805 | c2 = stbi__get8(s); | ||
5806 | len = stbi__get8(s); | ||
5807 | if (c1 != 2 || c2 != 2 || (len & 0x80)) { | ||
5808 | // not run-length encoded, so we have to actually use THIS data as a decoded | ||
5809 | // pixel (note this can't be a valid pixel--one of RGB must be >= 128) | ||
5810 | stbi_uc rgbe[4]; | ||
5811 | rgbe[0] = (stbi_uc) c1; | ||
5812 | rgbe[1] = (stbi_uc) c2; | ||
5813 | rgbe[2] = (stbi_uc) len; | ||
5814 | rgbe[3] = (stbi_uc) stbi__get8(s); | ||
5815 | stbi__hdr_convert(hdr_data, rgbe, req_comp); | ||
5816 | i = 1; | ||
5817 | j = 0; | ||
5818 | STBI_FREE(scanline); | ||
5819 | goto main_decode_loop; // yes, this makes no sense | ||
5820 | } | ||
5821 | len <<= 8; | ||
5822 | len |= stbi__get8(s); | ||
5823 | if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } | ||
5824 | if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); | ||
5825 | |||
5826 | for (k = 0; k < 4; ++k) { | ||
5827 | i = 0; | ||
5828 | while (i < width) { | ||
5829 | count = stbi__get8(s); | ||
5830 | if (count > 128) { | ||
5831 | // Run | ||
5832 | value = stbi__get8(s); | ||
5833 | count -= 128; | ||
5834 | for (z = 0; z < count; ++z) | ||
5835 | scanline[i++ * 4 + k] = value; | ||
5836 | } else { | ||
5837 | // Dump | ||
5838 | for (z = 0; z < count; ++z) | ||
5839 | scanline[i++ * 4 + k] = stbi__get8(s); | ||
5840 | } | ||
5841 | } | ||
5842 | } | ||
5843 | for (i=0; i < width; ++i) | ||
5844 | stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); | ||
5845 | } | ||
5846 | STBI_FREE(scanline); | ||
5847 | } | ||
5848 | |||
5849 | return hdr_data; | ||
5850 | } | ||
5851 | |||
5852 | static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) | ||
5853 | { | ||
5854 | char buffer[STBI__HDR_BUFLEN]; | ||
5855 | char *token; | ||
5856 | int valid = 0; | ||
5857 | |||
5858 | if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { | ||
5859 | stbi__rewind( s ); | ||
5860 | return 0; | ||
5861 | } | ||
5862 | |||
5863 | for(;;) { | ||
5864 | token = stbi__hdr_gettoken(s,buffer); | ||
5865 | if (token[0] == 0) break; | ||
5866 | if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; | ||
5867 | } | ||
5868 | |||
5869 | if (!valid) { | ||
5870 | stbi__rewind( s ); | ||
5871 | return 0; | ||
5872 | } | ||
5873 | token = stbi__hdr_gettoken(s,buffer); | ||
5874 | if (strncmp(token, "-Y ", 3)) { | ||
5875 | stbi__rewind( s ); | ||
5876 | return 0; | ||
5877 | } | ||
5878 | token += 3; | ||
5879 | *y = (int) strtol(token, &token, 10); | ||
5880 | while (*token == ' ') ++token; | ||
5881 | if (strncmp(token, "+X ", 3)) { | ||
5882 | stbi__rewind( s ); | ||
5883 | return 0; | ||
5884 | } | ||
5885 | token += 3; | ||
5886 | *x = (int) strtol(token, NULL, 10); | ||
5887 | *comp = 3; | ||
5888 | return 1; | ||
5889 | } | ||
5890 | #endif // STBI_NO_HDR | ||
5891 | |||
5892 | #ifndef STBI_NO_BMP | ||
5893 | static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) | ||
5894 | { | ||
5895 | int hsz; | ||
5896 | if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { | ||
5897 | stbi__rewind( s ); | ||
5898 | return 0; | ||
5899 | } | ||
5900 | stbi__skip(s,12); | ||
5901 | hsz = stbi__get32le(s); | ||
5902 | if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { | ||
5903 | stbi__rewind( s ); | ||
5904 | return 0; | ||
5905 | } | ||
5906 | if (hsz == 12) { | ||
5907 | *x = stbi__get16le(s); | ||
5908 | *y = stbi__get16le(s); | ||
5909 | } else { | ||
5910 | *x = stbi__get32le(s); | ||
5911 | *y = stbi__get32le(s); | ||
5912 | } | ||
5913 | if (stbi__get16le(s) != 1) { | ||
5914 | stbi__rewind( s ); | ||
5915 | return 0; | ||
5916 | } | ||
5917 | *comp = stbi__get16le(s) / 8; | ||
5918 | return 1; | ||
5919 | } | ||
5920 | #endif | ||
5921 | |||
5922 | #ifndef STBI_NO_PSD | ||
5923 | static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) | ||
5924 | { | ||
5925 | int channelCount; | ||
5926 | if (stbi__get32be(s) != 0x38425053) { | ||
5927 | stbi__rewind( s ); | ||
5928 | return 0; | ||
5929 | } | ||
5930 | if (stbi__get16be(s) != 1) { | ||
5931 | stbi__rewind( s ); | ||
5932 | return 0; | ||
5933 | } | ||
5934 | stbi__skip(s, 6); | ||
5935 | channelCount = stbi__get16be(s); | ||
5936 | if (channelCount < 0 || channelCount > 16) { | ||
5937 | stbi__rewind( s ); | ||
5938 | return 0; | ||
5939 | } | ||
5940 | *y = stbi__get32be(s); | ||
5941 | *x = stbi__get32be(s); | ||
5942 | if (stbi__get16be(s) != 8) { | ||
5943 | stbi__rewind( s ); | ||
5944 | return 0; | ||
5945 | } | ||
5946 | if (stbi__get16be(s) != 3) { | ||
5947 | stbi__rewind( s ); | ||
5948 | return 0; | ||
5949 | } | ||
5950 | *comp = 4; | ||
5951 | return 1; | ||
5952 | } | ||
5953 | #endif | ||
5954 | |||
5955 | #ifndef STBI_NO_PIC | ||
5956 | static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) | ||
5957 | { | ||
5958 | int act_comp=0,num_packets=0,chained; | ||
5959 | stbi__pic_packet packets[10]; | ||
5960 | |||
5961 | stbi__skip(s, 92); | ||
5962 | |||
5963 | *x = stbi__get16be(s); | ||
5964 | *y = stbi__get16be(s); | ||
5965 | if (stbi__at_eof(s)) return 0; | ||
5966 | if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { | ||
5967 | stbi__rewind( s ); | ||
5968 | return 0; | ||
5969 | } | ||
5970 | |||
5971 | stbi__skip(s, 8); | ||
5972 | |||
5973 | do { | ||
5974 | stbi__pic_packet *packet; | ||
5975 | |||
5976 | if (num_packets==sizeof(packets)/sizeof(packets[0])) | ||
5977 | return 0; | ||
5978 | |||
5979 | packet = &packets[num_packets++]; | ||
5980 | chained = stbi__get8(s); | ||
5981 | packet->size = stbi__get8(s); | ||
5982 | packet->type = stbi__get8(s); | ||
5983 | packet->channel = stbi__get8(s); | ||
5984 | act_comp |= packet->channel; | ||
5985 | |||
5986 | if (stbi__at_eof(s)) { | ||
5987 | stbi__rewind( s ); | ||
5988 | return 0; | ||
5989 | } | ||
5990 | if (packet->size != 8) { | ||
5991 | stbi__rewind( s ); | ||
5992 | return 0; | ||
5993 | } | ||
5994 | } while (chained); | ||
5995 | |||
5996 | *comp = (act_comp & 0x10 ? 4 : 3); | ||
5997 | |||
5998 | return 1; | ||
5999 | } | ||
6000 | #endif | ||
6001 | |||
6002 | // ************************************************************************************************* | ||
6003 | // Portable Gray Map and Portable Pixel Map loader | ||
6004 | // by Ken Miller | ||
6005 | // | ||
6006 | // PGM: http://netpbm.sourceforge.net/doc/pgm.html | ||
6007 | // PPM: http://netpbm.sourceforge.net/doc/ppm.html | ||
6008 | // | ||
6009 | // Known limitations: | ||
6010 | // Does not support comments in the header section | ||
6011 | // Does not support ASCII image data (formats P2 and P3) | ||
6012 | // Does not support 16-bit-per-channel | ||
6013 | |||
6014 | #ifndef STBI_NO_PNM | ||
6015 | |||
6016 | static int stbi__pnm_test(stbi__context *s) | ||
6017 | { | ||
6018 | char p, t; | ||
6019 | p = (char) stbi__get8(s); | ||
6020 | t = (char) stbi__get8(s); | ||
6021 | if (p != 'P' || (t != '5' && t != '6')) { | ||
6022 | stbi__rewind( s ); | ||
6023 | return 0; | ||
6024 | } | ||
6025 | return 1; | ||
6026 | } | ||
6027 | |||
6028 | static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) | ||
6029 | { | ||
6030 | stbi_uc *out; | ||
6031 | if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) | ||
6032 | return 0; | ||
6033 | *x = s->img_x; | ||
6034 | *y = s->img_y; | ||
6035 | *comp = s->img_n; | ||
6036 | |||
6037 | out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); | ||
6038 | if (!out) return stbi__errpuc("outofmem", "Out of memory"); | ||
6039 | stbi__getn(s, out, s->img_n * s->img_x * s->img_y); | ||
6040 | |||
6041 | if (req_comp && req_comp != s->img_n) { | ||
6042 | out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); | ||
6043 | if (out == NULL) return out; // stbi__convert_format frees input on failure | ||
6044 | } | ||
6045 | return out; | ||
6046 | } | ||
6047 | |||
6048 | static int stbi__pnm_isspace(char c) | ||
6049 | { | ||
6050 | return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; | ||
6051 | } | ||
6052 | |||
6053 | static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) | ||
6054 | { | ||
6055 | while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) | ||
6056 | *c = (char) stbi__get8(s); | ||
6057 | } | ||
6058 | |||
6059 | static int stbi__pnm_isdigit(char c) | ||
6060 | { | ||
6061 | return c >= '0' && c <= '9'; | ||
6062 | } | ||
6063 | |||
6064 | static int stbi__pnm_getinteger(stbi__context *s, char *c) | ||
6065 | { | ||
6066 | int value = 0; | ||
6067 | |||
6068 | while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { | ||
6069 | value = value*10 + (*c - '0'); | ||
6070 | *c = (char) stbi__get8(s); | ||
6071 | } | ||
6072 | |||
6073 | return value; | ||
6074 | } | ||
6075 | |||
6076 | static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) | ||
6077 | { | ||
6078 | int maxv; | ||
6079 | char c, p, t; | ||
6080 | |||
6081 | stbi__rewind( s ); | ||
6082 | |||
6083 | // Get identifier | ||
6084 | p = (char) stbi__get8(s); | ||
6085 | t = (char) stbi__get8(s); | ||
6086 | if (p != 'P' || (t != '5' && t != '6')) { | ||
6087 | stbi__rewind( s ); | ||
6088 | return 0; | ||
6089 | } | ||
6090 | |||
6091 | *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm | ||
6092 | |||
6093 | c = (char) stbi__get8(s); | ||
6094 | stbi__pnm_skip_whitespace(s, &c); | ||
6095 | |||
6096 | *x = stbi__pnm_getinteger(s, &c); // read width | ||
6097 | stbi__pnm_skip_whitespace(s, &c); | ||
6098 | |||
6099 | *y = stbi__pnm_getinteger(s, &c); // read height | ||
6100 | stbi__pnm_skip_whitespace(s, &c); | ||
6101 | |||
6102 | maxv = stbi__pnm_getinteger(s, &c); // read max value | ||
6103 | |||
6104 | if (maxv > 255) | ||
6105 | return stbi__err("max value > 255", "PPM image not 8-bit"); | ||
6106 | else | ||
6107 | return 1; | ||
6108 | } | ||
6109 | #endif | ||
6110 | |||
6111 | static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) | ||
6112 | { | ||
6113 | #ifndef STBI_NO_JPEG | ||
6114 | if (stbi__jpeg_info(s, x, y, comp)) return 1; | ||
6115 | #endif | ||
6116 | |||
6117 | #ifndef STBI_NO_PNG | ||
6118 | if (stbi__png_info(s, x, y, comp)) return 1; | ||
6119 | #endif | ||
6120 | |||
6121 | #ifndef STBI_NO_GIF | ||
6122 | if (stbi__gif_info(s, x, y, comp)) return 1; | ||
6123 | #endif | ||
6124 | |||
6125 | #ifndef STBI_NO_BMP | ||
6126 | if (stbi__bmp_info(s, x, y, comp)) return 1; | ||
6127 | #endif | ||
6128 | |||
6129 | #ifndef STBI_NO_PSD | ||
6130 | if (stbi__psd_info(s, x, y, comp)) return 1; | ||
6131 | #endif | ||
6132 | |||
6133 | #ifndef STBI_NO_PIC | ||
6134 | if (stbi__pic_info(s, x, y, comp)) return 1; | ||
6135 | #endif | ||
6136 | |||
6137 | #ifndef STBI_NO_PNM | ||
6138 | if (stbi__pnm_info(s, x, y, comp)) return 1; | ||
6139 | #endif | ||
6140 | |||
6141 | #ifndef STBI_NO_HDR | ||
6142 | if (stbi__hdr_info(s, x, y, comp)) return 1; | ||
6143 | #endif | ||
6144 | |||
6145 | // test tga last because it's a crappy test! | ||
6146 | #ifndef STBI_NO_TGA | ||
6147 | if (stbi__tga_info(s, x, y, comp)) | ||
6148 | return 1; | ||
6149 | #endif | ||
6150 | return stbi__err("unknown image type", "Image not of any known type, or corrupt"); | ||
6151 | } | ||
6152 | |||
6153 | #ifndef STBI_NO_STDIO | ||
6154 | STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) | ||
6155 | { | ||
6156 | FILE *f = stbi__fopen(filename, "rb"); | ||
6157 | int result; | ||
6158 | if (!f) return stbi__err("can't fopen", "Unable to open file"); | ||
6159 | result = stbi_info_from_file(f, x, y, comp); | ||
6160 | fclose(f); | ||
6161 | return result; | ||
6162 | } | ||
6163 | |||
6164 | STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) | ||
6165 | { | ||
6166 | int r; | ||
6167 | stbi__context s; | ||
6168 | long pos = ftell(f); | ||
6169 | stbi__start_file(&s, f); | ||
6170 | r = stbi__info_main(&s,x,y,comp); | ||
6171 | fseek(f,pos,SEEK_SET); | ||
6172 | return r; | ||
6173 | } | ||
6174 | #endif // !STBI_NO_STDIO | ||
6175 | |||
6176 | STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) | ||
6177 | { | ||
6178 | stbi__context s; | ||
6179 | stbi__start_mem(&s,buffer,len); | ||
6180 | return stbi__info_main(&s,x,y,comp); | ||
6181 | } | ||
6182 | |||
6183 | STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) | ||
6184 | { | ||
6185 | stbi__context s; | ||
6186 | stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); | ||
6187 | return stbi__info_main(&s,x,y,comp); | ||
6188 | } | ||
6189 | |||
6190 | #endif // STB_IMAGE_IMPLEMENTATION | ||
6191 | |||
6192 | /* | ||
6193 | revision history: | ||
6194 | 2.02 (2015-01-19) fix incorrect assert, fix warning | ||
6195 | 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 | ||
6196 | 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG | ||
6197 | 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) | ||
6198 | progressive JPEG (stb) | ||
6199 | PGM/PPM support (Ken Miller) | ||
6200 | STBI_MALLOC,STBI_REALLOC,STBI_FREE | ||
6201 | GIF bugfix -- seemingly never worked | ||
6202 | STBI_NO_*, STBI_ONLY_* | ||
6203 | 1.48 (2014-12-14) fix incorrectly-named assert() | ||
6204 | 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) | ||
6205 | optimize PNG (ryg) | ||
6206 | fix bug in interlaced PNG with user-specified channel count (stb) | ||
6207 | 1.46 (2014-08-26) | ||
6208 | fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG | ||
6209 | 1.45 (2014-08-16) | ||
6210 | fix MSVC-ARM internal compiler error by wrapping malloc | ||
6211 | 1.44 (2014-08-07) | ||
6212 | various warning fixes from Ronny Chevalier | ||
6213 | 1.43 (2014-07-15) | ||
6214 | fix MSVC-only compiler problem in code changed in 1.42 | ||
6215 | 1.42 (2014-07-09) | ||
6216 | don't define _CRT_SECURE_NO_WARNINGS (affects user code) | ||
6217 | fixes to stbi__cleanup_jpeg path | ||
6218 | added STBI_ASSERT to avoid requiring assert.h | ||
6219 | 1.41 (2014-06-25) | ||
6220 | fix search&replace from 1.36 that messed up comments/error messages | ||
6221 | 1.40 (2014-06-22) | ||
6222 | fix gcc struct-initialization warning | ||
6223 | 1.39 (2014-06-15) | ||
6224 | fix to TGA optimization when req_comp != number of components in TGA; | ||
6225 | fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) | ||
6226 | add support for BMP version 5 (more ignored fields) | ||
6227 | 1.38 (2014-06-06) | ||
6228 | suppress MSVC warnings on integer casts truncating values | ||
6229 | fix accidental rename of 'skip' field of I/O | ||
6230 | 1.37 (2014-06-04) | ||
6231 | remove duplicate typedef | ||
6232 | 1.36 (2014-06-03) | ||
6233 | convert to header file single-file library | ||
6234 | if de-iphone isn't set, load iphone images color-swapped instead of returning NULL | ||
6235 | 1.35 (2014-05-27) | ||
6236 | various warnings | ||
6237 | fix broken STBI_SIMD path | ||
6238 | fix bug where stbi_load_from_file no longer left file pointer in correct place | ||
6239 | fix broken non-easy path for 32-bit BMP (possibly never used) | ||
6240 | TGA optimization by Arseny Kapoulkine | ||
6241 | 1.34 (unknown) | ||
6242 | use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case | ||
6243 | 1.33 (2011-07-14) | ||
6244 | make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements | ||
6245 | 1.32 (2011-07-13) | ||
6246 | support for "info" function for all supported filetypes (SpartanJ) | ||
6247 | 1.31 (2011-06-20) | ||
6248 | a few more leak fixes, bug in PNG handling (SpartanJ) | ||
6249 | 1.30 (2011-06-11) | ||
6250 | added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) | ||
6251 | removed deprecated format-specific test/load functions | ||
6252 | removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway | ||
6253 | error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) | ||
6254 | fix inefficiency in decoding 32-bit BMP (David Woo) | ||
6255 | 1.29 (2010-08-16) | ||
6256 | various warning fixes from Aurelien Pocheville | ||
6257 | 1.28 (2010-08-01) | ||
6258 | fix bug in GIF palette transparency (SpartanJ) | ||
6259 | 1.27 (2010-08-01) | ||
6260 | cast-to-stbi_uc to fix warnings | ||
6261 | 1.26 (2010-07-24) | ||
6262 | fix bug in file buffering for PNG reported by SpartanJ | ||
6263 | 1.25 (2010-07-17) | ||
6264 | refix trans_data warning (Won Chun) | ||
6265 | 1.24 (2010-07-12) | ||
6266 | perf improvements reading from files on platforms with lock-heavy fgetc() | ||
6267 | minor perf improvements for jpeg | ||
6268 | deprecated type-specific functions so we'll get feedback if they're needed | ||
6269 | attempt to fix trans_data warning (Won Chun) | ||
6270 | 1.23 fixed bug in iPhone support | ||
6271 | 1.22 (2010-07-10) | ||
6272 | removed image *writing* support | ||
6273 | stbi_info support from Jetro Lauha | ||
6274 | GIF support from Jean-Marc Lienher | ||
6275 | iPhone PNG-extensions from James Brown | ||
6276 | warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) | ||
6277 | 1.21 fix use of 'stbi_uc' in header (reported by jon blow) | ||
6278 | 1.20 added support for Softimage PIC, by Tom Seddon | ||
6279 | 1.19 bug in interlaced PNG corruption check (found by ryg) | ||
6280 | 1.18 2008-08-02 | ||
6281 | fix a threading bug (local mutable static) | ||
6282 | 1.17 support interlaced PNG | ||
6283 | 1.16 major bugfix - stbi__convert_format converted one too many pixels | ||
6284 | 1.15 initialize some fields for thread safety | ||
6285 | 1.14 fix threadsafe conversion bug | ||
6286 | header-file-only version (#define STBI_HEADER_FILE_ONLY before including) | ||
6287 | 1.13 threadsafe | ||
6288 | 1.12 const qualifiers in the API | ||
6289 | 1.11 Support installable IDCT, colorspace conversion routines | ||
6290 | 1.10 Fixes for 64-bit (don't use "unsigned long") | ||
6291 | optimized upsampling by Fabian "ryg" Giesen | ||
6292 | 1.09 Fix format-conversion for PSD code (bad global variables!) | ||
6293 | 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz | ||
6294 | 1.07 attempt to fix C++ warning/errors again | ||
6295 | 1.06 attempt to fix C++ warning/errors again | ||
6296 | 1.05 fix TGA loading to return correct *comp and use good luminance calc | ||
6297 | 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free | ||
6298 | 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR | ||
6299 | 1.02 support for (subset of) HDR files, float interface for preferred access to them | ||
6300 | 1.01 fix bug: possible bug in handling right-side up bmps... not sure | ||
6301 | fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all | ||
6302 | 1.00 interface to zlib that skips zlib header | ||
6303 | 0.99 correct handling of alpha in palette | ||
6304 | 0.98 TGA loader by lonesock; dynamically add loaders (untested) | ||
6305 | 0.97 jpeg errors on too large a file; also catch another malloc failure | ||
6306 | 0.96 fix detection of invalid v value - particleman@mollyrocket forum | ||
6307 | 0.95 during header scan, seek to markers in case of padding | ||
6308 | 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same | ||
6309 | 0.93 handle jpegtran output; verbose errors | ||
6310 | 0.92 read 4,8,16,24,32-bit BMP files of several formats | ||
6311 | 0.91 output 24-bit Windows 3.0 BMP files | ||
6312 | 0.90 fix a few more warnings; bump version number to approach 1.0 | ||
6313 | 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd | ||
6314 | 0.60 fix compiling as c++ | ||
6315 | 0.59 fix warnings: merge Dave Moore's -Wall fixes | ||
6316 | 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian | ||
6317 | 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available | ||
6318 | 0.56 fix bug: zlib uncompressed mode len vs. nlen | ||
6319 | 0.55 fix bug: restart_interval not initialized to 0 | ||
6320 | 0.54 allow NULL for 'int *comp' | ||
6321 | 0.53 fix bug in png 3->4; speedup png decoding | ||
6322 | 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments | ||
6323 | 0.51 obey req_comp requests, 1-component jpegs return as 1-component, | ||
6324 | on 'test' only check type, not whether we support this variant | ||
6325 | 0.50 first released version | ||
6326 | */ \ No newline at end of file | ||