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_