Mercurial > code
comparison C++/modules/Js/Js.h @ 397:6b2db5425836
Js: initial support for objects as shared_ptr
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 29 Sep 2015 12:50:28 +0200 |
parents | 69adcefe73ae |
children | 94bfe7ba9a13 |
comparison
equal
deleted
inserted
replaced
396:30788c97c58c | 397:6b2db5425836 |
---|---|
147 Context(const Context &&) = delete; | 147 Context(const Context &&) = delete; |
148 Context &operator=(const Context &&) = delete; | 148 Context &operator=(const Context &&) = delete; |
149 | 149 |
150 | 150 |
151 public: | 151 public: |
152 /** | |
153 * Create default context. | |
154 */ | |
152 inline Context() | 155 inline Context() |
153 : m_handle{duk_create_heap_default(), duk_destroy_heap} | 156 : m_handle{duk_create_heap_default(), duk_destroy_heap} |
154 { | 157 { |
155 } | 158 } |
156 | 159 |
160 /** | |
161 * Create borrowed context that will not be deleted. | |
162 * | |
163 * @param ctx the pointer to duk_context | |
164 */ | |
157 inline Context(ContextPtr ctx) noexcept | 165 inline Context(ContextPtr ctx) noexcept |
158 : m_handle{ctx, [] (ContextPtr) {}} | 166 : m_handle{ctx, [] (ContextPtr) {}} |
159 { | 167 { |
160 } | 168 } |
161 | 169 |
162 #if 0 | |
163 /** | 170 /** |
164 * Convert the context to the native Duktape/C type. | 171 * Convert the context to the native Duktape/C type. |
165 * | 172 * |
166 * @return the duk_context | 173 * @return the duk_context |
167 */ | 174 */ |
168 inline operator duk_context *() noexcept | 175 inline operator duk_context *() noexcept |
169 { | 176 { |
170 return get(); | 177 return m_handle.get(); |
171 } | 178 } |
172 | 179 |
173 /** | 180 /** |
174 * Convert the context to the native Duktape/C type. | 181 * Convert the context to the native Duktape/C type. |
175 * | 182 * |
176 * @return the duk_context | 183 * @return the duk_context |
177 */ | 184 */ |
178 inline operator duk_context *() const noexcept | 185 inline operator duk_context *() const noexcept |
179 { | 186 { |
180 return get(); | 187 return m_handle.get(); |
181 } | 188 } |
182 #endif | |
183 | |
184 /* -------------------------------------------------------- | |
185 * Push functions | |
186 * -------------------------------------------------------- */ | |
187 | |
188 #if 0 | |
189 | |
190 /** | |
191 * Push a boolean. | |
192 * | |
193 * @param ctx the context | |
194 * @param value the boolean value | |
195 */ | |
196 inline void push(bool value) | |
197 { | |
198 duk_push_boolean(m_handle.get(), value); | |
199 } | |
200 | |
201 /** | |
202 * Push an integer. | |
203 * | |
204 * @param ctx the context | |
205 * @param value the integer value | |
206 */ | |
207 inline void push(int value) | |
208 { | |
209 duk_push_int(m_handle.get(), value); | |
210 } | |
211 | |
212 /** | |
213 * Push a real value. | |
214 * | |
215 * @param ctx the context | |
216 * @param value the value | |
217 */ | |
218 void push(double value) | |
219 { | |
220 duk_push_number(m_handle.get(), value); | |
221 } | |
222 | |
223 /** | |
224 * Push a string. | |
225 * | |
226 * @param ctx the context | |
227 * @param value the string | |
228 */ | |
229 void push(const std::string &value) | |
230 { | |
231 duk_push_lstring(m_handle.get(), value.c_str(), value.length()); | |
232 } | |
233 | |
234 /** | |
235 * Push a literal or C-string. | |
236 * | |
237 * @param ctx the context | |
238 * @param value the value | |
239 */ | |
240 void push(const char *value) | |
241 { | |
242 duk_push_string(m_handle.get(), value); | |
243 } | |
244 | |
245 /** | |
246 * Push a Duktape/C function. | |
247 * | |
248 * @param ctx the context | |
249 * @param function the function | |
250 */ | |
251 void push(const Function &fn) | |
252 { | |
253 assert(fn.function); | |
254 | |
255 duk_push_c_function(m_handle.get(), fn.function, fn.nargs); | |
256 } | |
257 | |
258 /** | |
259 * Push an empty object on the stack. | |
260 * | |
261 * @param ctx the context | |
262 * @param object the empty object | |
263 */ | |
264 void push(const Object &) | |
265 { | |
266 duk_push_object(m_handle.get()); | |
267 } | |
268 | |
269 /** | |
270 * Push an empty array at the top of the stack. | |
271 * | |
272 * @param ctx the context | |
273 * @param array the empty array | |
274 */ | |
275 void push(const Array &) | |
276 { | |
277 duk_push_array(m_handle.get()); | |
278 } | |
279 | |
280 /* -------------------------------------------------------- | |
281 * Get functions | |
282 * -------------------------------------------------------- */ | |
283 | |
284 /** | |
285 * Get a boolean. | |
286 * | |
287 * @param ctx the context | |
288 * @param index the index | |
289 * @param value the reference where to store the value | |
290 */ | |
291 void get(ContextPtr ctx, duk_idx_t index, bool &value); | |
292 | |
293 /** | |
294 * Get an integer. | |
295 * | |
296 * @param ctx the context | |
297 * @param index the index | |
298 * @param value the reference where to store the value | |
299 */ | |
300 void get(ContextPtr ctx, duk_idx_t index, int &value); | |
301 | |
302 /** | |
303 * Get a real. | |
304 * | |
305 * @param ctx the context | |
306 * @param index the index | |
307 * @param value the reference where to store the value | |
308 */ | |
309 void get(ContextPtr ctx, duk_idx_t index, double &value); | |
310 | |
311 /** | |
312 * Get a string. | |
313 * | |
314 * @param ctx the context | |
315 * @param index the index | |
316 * @param value the reference where to store the value | |
317 */ | |
318 void get(ContextPtr ctx, duk_idx_t index, std::string &value); | |
319 | |
320 #endif | |
321 | 189 |
322 /* ---------------------------------------------------------- | 190 /* ---------------------------------------------------------- |
323 * Push / Get / Require | 191 * Push / Get / Require |
324 * ---------------------------------------------------------- */ | 192 * ---------------------------------------------------------- */ |
325 | 193 |
194 /** | |
195 * Push a value into the stack. Calls TypeInfo<T>::push(*this, value); | |
196 * | |
197 * @param value the value to forward | |
198 */ | |
326 template <typename Type> | 199 template <typename Type> |
327 inline void push(Type &&value) | 200 inline void push(Type &&value) |
328 { | 201 { |
329 TypeInfo<std::decay_t<Type>>::push(m_handle.get(), std::forward<Type>(value)); | 202 TypeInfo<std::decay_t<Type>>::push(*this, std::forward<Type>(value)); |
330 } | 203 } |
331 | 204 |
332 /** | 205 /** |
333 * Generic template function to get a value from the stack. | 206 * Generic template function to get a value from the stack. |
334 * | 207 * |
335 * @param index the index | 208 * @param index the index |
336 * @return the value | 209 * @return the value |
337 */ | 210 */ |
338 template <typename Type> | 211 template <typename Type> |
339 inline Type get(duk_idx_t index) | 212 inline auto get(duk_idx_t index) -> decltype(TypeInfo<Type>::get(*this, 0)) |
340 { | 213 { |
341 return TypeInfo<Type>::get(m_handle.get(), index); | 214 return TypeInfo<Type>::get(*this, index); |
342 } | 215 } |
343 | 216 |
344 template <typename Type> | 217 template <typename Type> |
345 inline Type require(duk_idx_t index) | 218 inline auto require(duk_idx_t index) -> decltype(TypeInfo<Type>::require(*this, 0)) |
346 { | 219 { |
347 return TypeInfo<Type>::require(m_handle.get(), index); | 220 return TypeInfo<Type>::require(*this, index); |
348 } | 221 } |
349 | 222 |
350 /* -------------------------------------------------------- | 223 /* -------------------------------------------------------- |
351 * Get functions (for object) | 224 * Get functions (for object) |
352 * -------------------------------------------------------- */ | 225 * -------------------------------------------------------- */ |
353 | 226 |
354 template <typename Type> | 227 template <typename Type> |
355 inline Type getObject(duk_idx_t index, const std::string &name) | 228 inline auto getObject(duk_idx_t index, const std::string &name) -> decltype(get<Type>(0)) |
356 { | 229 { |
357 assertBegin(m_handle.get()); | 230 assertBegin(m_handle.get()); |
358 duk_get_prop_string(m_handle.get(), index, name.c_str()); | 231 duk_get_prop_string(m_handle.get(), index, name.c_str()); |
359 Type value = get<Type>(-1); | 232 auto &&value = get<Type>(-1); |
360 duk_pop(m_handle.get()); | 233 duk_pop(m_handle.get()); |
361 assertEquals(m_handle.get()); | 234 assertEquals(m_handle.get()); |
362 | 235 |
363 return value; | 236 return value; |
364 } | 237 } |
377 duk_put_prop_string(m_handle.get(), index, name.c_str()); | 250 duk_put_prop_string(m_handle.get(), index, name.c_str()); |
378 assertEquals(m_handle.get()); | 251 assertEquals(m_handle.get()); |
379 } | 252 } |
380 | 253 |
381 /* -------------------------------------------------------- | 254 /* -------------------------------------------------------- |
382 * Require functions | |
383 * -------------------------------------------------------- */ | |
384 | |
385 #if 0 | |
386 | |
387 /** | |
388 * Requires a value or throw an exception if not a boolean. | |
389 * | |
390 * @param ctx the context | |
391 * @param index the index | |
392 * @param value the reference where to store the value | |
393 */ | |
394 void require(ContextPtr ctx, duk_idx_t index, bool &value); | |
395 | |
396 /** | |
397 * Requires a value or throw an exception if not an integer. | |
398 * | |
399 * @param ctx the context | |
400 * @param index the index | |
401 * @param value the reference where to store the value | |
402 */ | |
403 void require(ContextPtr ctx, duk_idx_t index, int &value); | |
404 | |
405 /** | |
406 * Requires a value or throw an exception if not a double. | |
407 * | |
408 * @param ctx the context | |
409 * @param index the index | |
410 * @param value the reference where to store the value | |
411 */ | |
412 void require(ContextPtr ctx, duk_idx_t index, double &value); | |
413 | |
414 /** | |
415 * Requires a value or throw an exception if not a string. | |
416 * | |
417 * @param ctx the context | |
418 * @param index the index | |
419 * @param value the reference where to store string | |
420 */ | |
421 void require(ContextPtr ctx, duk_idx_t index, std::string &value); | |
422 | |
423 /** | |
424 * Generic function to require a value from the stack. | |
425 * | |
426 * @param ctx the context | |
427 * @param index the specified index | |
428 * @return the value | |
429 */ | |
430 template <typename Type> | |
431 inline Type require(ContextPtr ctx, duk_idx_t index) | |
432 { | |
433 Type value; | |
434 | |
435 require(ctx, index, value); | |
436 | |
437 return value; | |
438 } | |
439 #endif | |
440 | |
441 /* -------------------------------------------------------- | |
442 * Basic functions | 255 * Basic functions |
443 * -------------------------------------------------------- */ | 256 * -------------------------------------------------------- */ |
444 | 257 |
445 /** | 258 /** |
446 * Get the type of the value at the specified index. | 259 * Get the type of the value at the specified index. |
587 * @param ctx the context | 400 * @param ctx the context |
588 * @param name the name of the global variable | 401 * @param name the name of the global variable |
589 * @return the value | 402 * @return the value |
590 */ | 403 */ |
591 template <typename Type> | 404 template <typename Type> |
592 inline Type getGlobal(const std::string &name) | 405 inline auto getGlobal(const std::string &name) -> decltype(get<Type>(0)) |
593 { | 406 { |
594 assertBegin(m_handle.get()); | 407 assertBegin(m_handle.get()); |
595 duk_get_global_string(m_handle.get(), name.c_str()); | 408 duk_get_global_string(m_handle.get(), name.c_str()); |
596 Type value = get<Type>(-1); | 409 auto &&value = get<Type>(-1); |
597 duk_pop(m_handle.get()); | 410 duk_pop(m_handle.get()); |
598 assertEquals(m_handle.get()); | 411 assertEquals(m_handle.get()); |
599 | 412 |
600 return value; | 413 return value; |
601 } | 414 } |
629 | 442 |
630 duk_push_string(m_handle.get(), ex.name().c_str()); | 443 duk_push_string(m_handle.get(), ex.name().c_str()); |
631 duk_put_prop_string(m_handle.get(), -2, "name"); | 444 duk_put_prop_string(m_handle.get(), -2, "name"); |
632 duk_throw(m_handle.get()); | 445 duk_throw(m_handle.get()); |
633 } | 446 } |
447 | |
448 template <typename T> | |
449 inline auto self() -> decltype(TypeInfo<T>::get(*this, 0)) | |
450 { | |
451 duk_push_this(m_handle.get()); | |
452 auto &&value = TypeInfo<T>::get(*this, -1); | |
453 duk_pop(m_handle.get()); | |
454 | |
455 return value; | |
456 } | |
634 }; | 457 }; |
635 | 458 |
636 /* ------------------------------------------------------------------ | 459 /* ------------------------------------------------------------------ |
637 * Exception handling | 460 * Exception handling |
638 * ------------------------------------------------------------------ */ | 461 * ------------------------------------------------------------------ */ |
754 }; | 577 }; |
755 | 578 |
756 template <> | 579 template <> |
757 class TypeInfo<bool> { | 580 class TypeInfo<bool> { |
758 public: | 581 public: |
759 static bool get(ContextPtr ctx, duk_idx_t index) | 582 static bool get(Context &ctx, duk_idx_t index) |
760 { | 583 { |
761 return duk_get_boolean(ctx, index); | 584 return duk_get_boolean(ctx, index); |
762 } | 585 } |
763 | 586 |
764 static void push(ContextPtr ctx, bool value) | 587 static void push(Context &ctx, bool value) |
765 { | 588 { |
766 duk_push_boolean(ctx, value); | 589 duk_push_boolean(ctx, value); |
767 } | 590 } |
768 }; | 591 }; |
769 | 592 |
770 template <> | 593 template <> |
771 class TypeInfo<double> { | 594 class TypeInfo<double> { |
772 public: | 595 public: |
773 static double get(ContextPtr ctx, duk_idx_t index) | 596 static double get(Context &ctx, duk_idx_t index) |
774 { | 597 { |
775 return duk_get_number(ctx, index); | 598 return duk_get_number(ctx, index); |
776 } | 599 } |
777 | 600 |
778 static void push(ContextPtr ctx, double value) | 601 static void push(Context &ctx, double value) |
779 { | 602 { |
780 duk_push_number(ctx, value); | 603 duk_push_number(ctx, value); |
781 } | 604 } |
782 }; | 605 }; |
783 | 606 |
784 template <> | 607 template <> |
785 class TypeInfo<std::string> { | 608 class TypeInfo<std::string> { |
786 public: | 609 public: |
787 static std::string get(ContextPtr ctx, duk_idx_t index) | 610 static std::string get(Context &ctx, duk_idx_t index) |
788 { | 611 { |
789 duk_size_t size; | 612 duk_size_t size; |
790 const char *text = duk_get_lstring(ctx, index, &size); | 613 const char *text = duk_get_lstring(ctx, index, &size); |
791 | 614 |
792 return std::string{text, size}; | 615 return std::string{text, size}; |
793 } | 616 } |
794 | 617 |
795 static void push(ContextPtr ctx, const std::string &value) | 618 static void push(Context &ctx, const std::string &value) |
796 { | 619 { |
797 duk_push_lstring(ctx, value.c_str(), value.length()); | 620 duk_push_lstring(ctx, value.c_str(), value.length()); |
798 } | 621 } |
799 }; | 622 }; |
800 | 623 |
801 template <> | 624 template <> |
802 class TypeInfo<const char *> { | 625 class TypeInfo<const char *> { |
803 public: | 626 public: |
804 static void push(ContextPtr ctx, const char *value) | 627 static void push(Context &ctx, const char *value) |
805 { | 628 { |
806 duk_push_string(ctx, value); | 629 duk_push_string(ctx, value); |
807 } | 630 } |
808 }; | 631 }; |
809 | 632 |
810 template <> | 633 template <> |
811 class TypeInfo<Function> { | 634 class TypeInfo<Function> { |
812 public: | 635 public: |
813 static void push(ContextPtr ctx, const Function &fn) | 636 static void push(Context &ctx, const Function &fn) |
814 { | 637 { |
815 assert(fn.function); | 638 assert(fn.function); |
816 | 639 |
817 duk_push_c_function(ctx, fn.function, fn.nargs); | 640 duk_push_c_function(ctx, fn.function, fn.nargs); |
818 } | 641 } |
819 }; | 642 }; |
820 | 643 |
821 template <> | 644 template <> |
822 class TypeInfo<Object> { | 645 class TypeInfo<Object> { |
823 public: | 646 public: |
824 static void push(ContextPtr ctx, const Object &) | 647 static void push(Context &ctx, const Object &) |
825 { | 648 { |
826 duk_push_object(ctx); | 649 duk_push_object(ctx); |
827 } | 650 } |
828 }; | 651 }; |
829 | 652 |
830 template <> | 653 template <> |
831 class TypeInfo<Array> { | 654 class TypeInfo<Array> { |
832 public: | 655 public: |
833 static void push(ContextPtr ctx, const Array &) | 656 static void push(Context &ctx, const Array &) |
834 { | 657 { |
835 duk_push_array(ctx); | 658 duk_push_array(ctx); |
836 } | 659 } |
837 }; | 660 }; |
838 | 661 |
662 /* ------------------------------------------------------------------ | |
663 * Helpers for pointers and std::shared_ptr | |
664 * ------------------------------------------------------------------ */ | |
665 | |
666 /** | |
667 * @class TypeInfoShared | |
668 * @brief Generates push / get / require for std::shared_ptr<T> | |
669 * | |
670 * Specialize TypeInfo<std::shared_ptr<T>> and inherits from this class to implement the push(), | |
671 * get() and require() functions. | |
672 * | |
673 * You only need to implement `static void prototype(Context &ctx)` which must push the prototype | |
674 * to use for the underlying object. | |
675 */ | |
676 template <typename T> | |
677 class TypeInfoShared { | |
678 public: | |
679 static void push(Context &ctx, std::shared_ptr<T> value); | |
680 static std::shared_ptr<T> get(Context &ctx, duk_idx_t index); | |
681 }; | |
682 | |
683 template <typename T> | |
684 void TypeInfoShared<T>::push(Context &ctx, std::shared_ptr<T> value) | |
685 { | |
686 duk_push_object(ctx); | |
687 duk_push_boolean(ctx, false); | |
688 duk_put_prop_string(ctx, -2, "\xff""\xff""js-deleted"); | |
689 duk_push_pointer(ctx, new std::shared_ptr<T>(value)); | |
690 duk_put_prop_string(ctx, -2, "\xff""\xff""js-shared-ptr"); | |
691 | |
692 TypeInfo<std::shared_ptr<T>>::prototype(ctx); | |
693 | |
694 // TODO: set deleter | |
695 | |
696 duk_set_prototype(ctx, -2); | |
697 } | |
698 | |
699 template <typename T> | |
700 std::shared_ptr<T> TypeInfoShared<T>::get(Context &ctx, duk_idx_t index) | |
701 { | |
702 duk_get_prop_string(ctx, index, "\xff""\xff""js-shared-ptr"); | |
703 std::shared_ptr<T> value = *static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); | |
704 duk_pop(ctx); | |
705 | |
706 return value; | |
707 } | |
708 | |
839 } // !js | 709 } // !js |
840 | 710 |
841 #endif // !_JS_H_ | 711 #endif // !_JS_H_ |