Mercurial > code
changeset 417:865224c2191a
Js: update documentation
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 08 Oct 2015 10:02:37 +0200 |
parents | a93dfbb65648 |
children | 30e4a93f86c7 |
files | C++/modules/Js/Js.h C++/tests/Js/main.cpp |
diffstat | 2 files changed, 722 insertions(+), 323 deletions(-) [+] |
line wrap: on
line diff
--- a/C++/modules/Js/Js.h Thu Oct 08 08:39:47 2015 +0200 +++ b/C++/modules/Js/Js.h Thu Oct 08 10:02:37 2015 +0200 @@ -39,6 +39,9 @@ #include <duktape.h> +/** + * Duktape C++ namespace wrapper. + */ namespace js { class Context; @@ -120,7 +123,7 @@ using FunctionMap = std::unordered_map<std::string, Function>; /** - * Map of string to type constant. + * Map of string to type, ideal for setting constants like enums. */ template <typename Type> using Map = std::unordered_map<std::string, Type>; @@ -194,13 +197,26 @@ */ class File { public: + /** + * Path to the file. + */ std::string path; + /** + * Evaluate the file. + * + * @param ctx the context + */ inline void eval(duk_context *ctx) { duk_eval_file(ctx, path.c_str()); } + /** + * Evaluate in protected mode the file. + * + * @param ctx the context + */ inline int peval(duk_context *ctx) { return duk_peval_file(ctx, path.c_str()); @@ -215,13 +231,26 @@ */ class Script { public: + /** + * The script content. + */ std::string text; + /** + * Evaluate the script. + * + * @param ctx the context + */ inline void eval(duk_context *ctx) { duk_eval_string(ctx, text.c_str()); } + /** + * Evaluate in protected mode the script. + * + * @param ctx the context + */ inline int peval(duk_context *ctx) { return duk_peval_string(ctx, text.c_str()); @@ -286,212 +315,13 @@ return m_handle.get(); } - /* ---------------------------------------------------------- - * Push / Get / Require / Is / Optional - * ---------------------------------------------------------- */ - - /** - * Push a value into the stack. Calls TypeInfo<T>::push(*this, value); - * - * @param value the value to forward - */ - template <typename Type> - inline void push(Type &&value) - { - TypeInfo<std::decay_t<Type>>::push(*this, std::forward<Type>(value)); - } - - /** - * Generic template function to get a value from the stack. - * - * @param index the index - * @return the value - */ - template <typename Type> - inline auto get(int index) -> decltype(TypeInfo<Type>::get(*this, 0)) - { - return TypeInfo<Type>::get(*this, index); - } - - /** - * Require a type at the specified index. - * - * @param index the index - * @return the value - */ - template <typename Type> - inline auto require(int index) -> decltype(TypeInfo<Type>::require(*this, 0)) - { - return TypeInfo<Type>::require(*this, index); - } - - /** - * Check if a value is a type of T. - * - * The TypeInfo<T> must have `static bool is(ContextPtr ptr, int index)`. + /* + * Basic functions + * ---------------------------------------------------------- * - * @param index the value index - * @return true if is the type - */ - template <typename T> - inline bool is(int index) - { - return TypeInfo<T>::is(*this, index); - } - - /** - * Get an optional value from the stack, if the value is not available of not the correct type, - * return defaultValue instead. - * - * The TypeInfo<T> must have `static T optional(Context &, int index, T &&defaultValue)`. - * - * @param index the value index - * @param defaultValue the value replacement - * @return the value or defaultValue - */ - template <typename Type> - inline auto optional(int index, Type &&defaultValue) - { - return TypeInfo<std::decay_t<Type>>::optional(*this, index, std::forward<Type>(defaultValue)); - } - - /* -------------------------------------------------------- - * Get properties (for objects and arrays) - * -------------------------------------------------------- */ - - /** - * Get the property `name' as value from the object at the specified index. - * - * @param index the object index - * @param name the property name - * @return the value - * @note The stack is unchanged - */ - template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> - inline auto getProperty(int index, const std::string &name) -> decltype(get<Type>(0)) - { - duk_get_prop_string(m_handle.get(), index, name.c_str()); - decltype(get<Type>(0)) value = get<Type>(-1); - duk_pop(m_handle.get()); - - return value; - } - - /** - * Get a property by index, for arrays. - * - * @param index the object index - * @param position the position int the object - * @return the value - * @note The stack is unchanged + * The following functions are just standard wrappers around the native Duktape C functions, they are + * defined with the same signature except that for convenience some parameters have default sane values. */ - template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> - inline auto getProperty(int index, int position) -> decltype(get<Type>(0)) - { - duk_get_prop_index(m_handle.get(), index, position); - decltype(get<Type>(0)) value = get<Type>(-1); - duk_pop(m_handle.get()); - - return value; - } - - /** - * Get the property `name' and push it to the stack from the object at the specified index. - * - * @param index the object index - * @param name the property name - * @note The stack contains the property value - */ - template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> - inline void getProperty(int index, const std::string &name) - { - duk_get_prop_string(m_handle.get(), index, name.c_str()); - } - - /** - * Get the property by index and push it to the stack from the object at the specified index. - * - * @param index the object index - * @param position the position in the object - * @note The stack contains the property value - */ - template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> - inline void getProperty(int index, int position) - { - duk_get_prop_index(m_handle.get(), index, position); - } - - /* -------------------------------------------------------- - * Put properties functions (for object) - * -------------------------------------------------------- */ - - /** - * Set a property to the object at the specified index. - * - * @param index the object index - * @param name the property name - * @param value the value to forward - * @note The stack is unchanged - */ - template <typename Type> - void putProperty(int index, const std::string &name, Type &&value) - { - index = duk_normalize_index(m_handle.get(), index); - - push(std::forward<Type>(value)); - duk_put_prop_string(m_handle.get(), index, name.c_str()); - } - - /** - * Set a property by index, for arrays. - * - * @param index the object index - * @param position the position in the object - * @param value the value to forward - * @note The stack is unchanged - */ - template <typename Type> - void putProperty(int index, int position, Type &&value) - { - index = duk_normalize_index(m_handle.get(), index); - - push(std::forward<Type>(value)); - duk_put_prop_index(m_handle.get(), index, position); - } - - /** - * Put the value that is at the top of the stack as property to the object. - * - * @param index the object index - * @param name the property name - */ - inline void putProperty(int index, const std::string &name) - { - duk_put_prop_string(m_handle.get(), index, name.c_str()); - } - - /** - * Put the value that is at the top of the stack to the object as index. - * - * @param index the object index - * @param position the position in the object - */ - inline void putProperty(int index, int position) - { - duk_put_prop_index(m_handle.get(), index, position); - } - - /* -------------------------------------------------------- - * Basic functions - * -------------------------------------------------------- */ - - /** - * Get the error object when a JavaScript error has been thrown (e.g. eval failure). - * - * @param index the index - * @return the information - */ - ErrorInfo error(int index); /** * Get the type of the value at the specified index. @@ -621,19 +451,6 @@ } /** - * Call in protected mode the object at the top of the stack. - * - * @param ctx the context - * @param nargs the number of arguments - * @throw ErrorInfo on errors - */ - void pcall(unsigned nargs = 0); - - /* ------------------------------------------------------------------ - * Eval functions - * ------------------------------------------------------------------ */ - - /** * Evaluate a non-protected chunk that is at the top of the stack. * * @param ctx @@ -643,6 +460,23 @@ duk_eval(m_handle.get()); } + /* + * Extended native functions + * ---------------------------------------------------------- + * + * The following functions have different behaviour than the original native Duktape C functions, see their + * descriptions for more information + */ + + /** + * Call in protected mode the object at the top of the stack. + * + * @param ctx the context + * @param nargs the number of arguments + * @throw ErrorInfo on errors + */ + void pcall(unsigned nargs = 0); + /** * Evaluate a non-protected source. * @@ -659,7 +493,6 @@ /** * Evaluate a protected chunk that is at the top of the stack. * - * @param ctx the context * @throw ErrorInfo the error */ void peval(); @@ -683,14 +516,270 @@ } } - /* ------------------------------------------------------------------ - * Extended functions - * ------------------------------------------------------------------ */ + /* + * Push / Get / Require / Is / Optional + * ---------------------------------------------------------- + * + * The following functions are used to push, get or check values from the stack. They use specialization + * of TypeInfo class. + */ + + /** + * Push a value into the stack. Calls TypeInfo<T>::push(*this, value); + * + * @param value the value to forward + */ + template <typename Type> + inline void push(Type &&value) + { + TypeInfo<std::decay_t<Type>>::push(*this, std::forward<Type>(value)); + } + + /** + * Generic template function to get a value from the stack. + * + * @param index the index + * @return the value + */ + template <typename Type> + inline auto get(int index) -> decltype(TypeInfo<Type>::get(*this, 0)) + { + return TypeInfo<Type>::get(*this, index); + } + + /** + * Require a type at the specified index. + * + * @param index the index + * @return the value + */ + template <typename Type> + inline auto require(int index) -> decltype(TypeInfo<Type>::require(*this, 0)) + { + return TypeInfo<Type>::require(*this, index); + } + + /** + * Check if a value is a type of T. + * + * The TypeInfo<T> must have `static bool is(ContextPtr ptr, int index)`. + * + * @param index the value index + * @return true if is the type + */ + template <typename T> + inline bool is(int index) + { + return TypeInfo<T>::is(*this, index); + } + + /** + * Get an optional value from the stack, if the value is not available of not the correct type, + * return defaultValue instead. + * + * The TypeInfo<T> must have `static T optional(Context &, int index, T &&defaultValue)`. + * + * @param index the value index + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename Type> + inline auto optional(int index, Type &&defaultValue) + { + return TypeInfo<std::decay_t<Type>>::optional(*this, index, std::forward<Type>(defaultValue)); + } + + /* + * Properties management + * ---------------------------------------------------------- + * + * The following functions are used to read or set properties on objects or globals also using TypeInfo. + */ + + /** + * Get the property `name' as value from the object at the specified index. + * + * @param index the object index + * @param name the property name + * @return the value + * @note The stack is unchanged + */ + template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> + inline auto getProperty(int index, const std::string &name) -> decltype(get<Type>(0)) + { + duk_get_prop_string(m_handle.get(), index, name.c_str()); + decltype(get<Type>(0)) value = get<Type>(-1); + duk_pop(m_handle.get()); + + return value; + } + + /** + * Get a property by index, for arrays. + * + * @param index the object index + * @param position the position int the object + * @return the value + * @note The stack is unchanged + */ + template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> + inline auto getProperty(int index, int position) -> decltype(get<Type>(0)) + { + duk_get_prop_index(m_handle.get(), index, position); + decltype(get<Type>(0)) value = get<Type>(-1); + duk_pop(m_handle.get()); + + return value; + } + + /** + * Get the property `name' and push it to the stack from the object at the specified index. + * + * @param index the object index + * @param name the property name + * @note The stack contains the property value + */ + template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> + inline void getProperty(int index, const std::string &name) + { + duk_get_prop_string(m_handle.get(), index, name.c_str()); + } + + /** + * Get the property by index and push it to the stack from the object at the specified index. + * + * @param index the object index + * @param position the position in the object + * @note The stack contains the property value + */ + template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> + inline void getProperty(int index, int position) + { + duk_get_prop_index(m_handle.get(), index, position); + } + + /** + * Set a property to the object at the specified index. + * + * @param index the object index + * @param name the property name + * @param value the value to forward + * @note The stack is unchanged + */ + template <typename Type> + void putProperty(int index, const std::string &name, Type &&value) + { + index = duk_normalize_index(m_handle.get(), index); + + push(std::forward<Type>(value)); + duk_put_prop_string(m_handle.get(), index, name.c_str()); + } + + /** + * Set a property by index, for arrays. + * + * @param index the object index + * @param position the position in the object + * @param value the value to forward + * @note The stack is unchanged + */ + template <typename Type> + void putProperty(int index, int position, Type &&value) + { + index = duk_normalize_index(m_handle.get(), index); + + push(std::forward<Type>(value)); + duk_put_prop_index(m_handle.get(), index, position); + } + + /** + * Put the value that is at the top of the stack as property to the object. + * + * @param index the object index + * @param name the property name + */ + inline void putProperty(int index, const std::string &name) + { + duk_put_prop_string(m_handle.get(), index, name.c_str()); + } + + /** + * Put the value that is at the top of the stack to the object as index. + * + * @param index the object index + * @param position the position in the object + */ + inline void putProperty(int index, int position) + { + duk_put_prop_index(m_handle.get(), index, position); + } + + /** + * Get a global value. + * + * @param name the name of the global variable + * @return the value + */ + template <typename Type> + inline auto getGlobal(const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(0)) + { + duk_get_global_string(m_handle.get(), name.c_str()); + decltype(get<Type>(0)) value = get<Type>(-1); + duk_pop(m_handle.get()); + + return value; + } + + /** + * Overload that push the value at the top of the stack instead of returning it. + */ + template <typename Type> + inline void getGlobal(const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept + { + duk_get_global_string(m_handle.get(), name.c_str()); + } + + /** + * Set a global variable. + * + * @param name the name of the global variable + * @param type the value to set + */ + template <typename Type> + inline void putGlobal(const std::string &name, Type&& type) + { + push(std::forward<Type>(type)); + duk_put_global_string(m_handle.get(), name.c_str()); + } + + /** + * Put the value at the top of the stack as global property. + * + * @param name the property name + */ + inline void putGlobal(const std::string &name) + { + duk_put_global_string(m_handle.get(), name.c_str()); + } + + /* + * Extra functions + * ---------------------------------------------------------- + * + * The following functions are implemented for convenience and do not exists in the native Duktape API. + */ + + /** + * Get the error object when a JavaScript error has been thrown (e.g. eval failure). + * + * @param index the index + * @return the information + */ + ErrorInfo error(int index); /** * Enumerate an object or an array at the specified index. * - * @param ctx the context * @param index the object or array index * @param flags the optional flags to pass to duk_enum * @param getvalue set to true if you want to extract the value @@ -727,7 +816,6 @@ /** * Throw an ECMAScript exception. * - * @param ctx the context * @param ex the exception */ template <typename Exception> @@ -755,60 +843,6 @@ { TypeInfo<std::decay_t<T>>::construct(*this, std::forward<T>(value)); } - - /* -------------------------------------------------------- - * Global functions - * -------------------------------------------------------- */ - - /** - * Get a global value. - * - * @param ctx the context - * @param name the name of the global variable - * @return the value - */ - template <typename Type> - inline auto getGlobal(const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(0)) - { - duk_get_global_string(m_handle.get(), name.c_str()); - decltype(get<Type>(0)) value = get<Type>(-1); - duk_pop(m_handle.get()); - - return value; - } - - /** - * Overload that push the value at the top of the stack instead of returning it. - */ - template <typename Type> - inline void getGlobal(const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept - { - duk_get_global_string(m_handle.get(), name.c_str()); - } - - /** - * Set a global variable. - * - * @param ctx the context - * @param name the name of the global variable - * @param type the value to set - */ - template <typename Type> - inline void putGlobal(const std::string &name, Type&& type) - { - push(std::forward<Type>(type)); - duk_put_global_string(m_handle.get(), name.c_str()); - } - - /** - * Put the value at the top of the stack as global property. - * - * @param name the property name - */ - inline void putGlobal(const std::string &name) - { - duk_put_global_string(m_handle.get(), name.c_str()); - } }; /* ------------------------------------------------------------------ @@ -868,6 +902,11 @@ */ class Error : public ExceptionAbstract { public: + /** + * Constructor with a message. + * + * @param message the message + */ inline Error(std::string message) noexcept : ExceptionAbstract{"Error", std::move(message)} { @@ -880,6 +919,9 @@ */ class EvalError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline EvalError(std::string message) noexcept : ExceptionAbstract{"EvalError", std::move(message)} { @@ -892,6 +934,9 @@ */ class RangeError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline RangeError(std::string message) noexcept : ExceptionAbstract{"RangeError", std::move(message)} { @@ -904,6 +949,9 @@ */ class ReferenceError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline ReferenceError(std::string message) noexcept : ExceptionAbstract{"ReferenceError", std::move(message)} { @@ -916,6 +964,9 @@ */ class SyntaxError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline SyntaxError(std::string message) noexcept : ExceptionAbstract{"SyntaxError", std::move(message)} { @@ -928,6 +979,9 @@ */ class TypeError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline TypeError(std::string message) noexcept : ExceptionAbstract{"TypeError", std::move(message)} { @@ -940,6 +994,9 @@ */ class URIError : public ExceptionAbstract { public: + /** + * @copydoc Error + */ inline URIError(std::string message) noexcept : ExceptionAbstract{"URIError", std::move(message)} { @@ -959,16 +1016,38 @@ template <> class TypeInfo<int> { public: + /** + * Get an integer, return 0 if not an integer. + * + * @param ctx the context + * @param index the index + * @return the integer + */ static inline int get(Context &ctx, int index) { return duk_get_int(ctx, index); } + /** + * Check if value is an integer. + * + * @param ctx the context + * @param index the index + * @return true if integer + */ static inline bool is(Context &ctx, int index) { return duk_is_number(ctx, index); } + /** + * Get an integer, return defaultValue if the value is not an integer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the integer or defaultValue + */ static inline int optional(Context &ctx, int index, int defaultValue) { if (!duk_is_number(ctx, index)) { @@ -978,11 +1057,24 @@ return duk_get_int(ctx, index); } + /** + * Push an integer. + * + * @param ctx the context + * @param value the value + */ static inline void push(Context &ctx, int value) { duk_push_int(ctx, value); } + /** + * Require an integer, throws a JavaScript exception if not an integer. + * + * @param ctx the context + * @param index the index + * @return the integer + */ static inline int require(Context &ctx, int index) { return duk_require_int(ctx, index); @@ -998,16 +1090,38 @@ template <> class TypeInfo<bool> { public: + /** + * Get a boolean, return 0 if not a boolean. + * + * @param ctx the context + * @param index the index + * @return the boolean + */ static inline bool get(Context &ctx, int index) { return duk_get_boolean(ctx, index); } + /** + * Check if value is a boolean. + * + * @param ctx the context + * @param index the index + * @return true if boolean + */ static inline bool is(Context &ctx, int index) { return duk_is_boolean(ctx, index); } + /** + * Get a bool, return defaultValue if the value is not a boolean. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the boolean or defaultValue + */ static inline bool optional(Context &ctx, int index, bool defaultValue) { if (!duk_is_boolean(ctx, index)) { @@ -1017,11 +1131,24 @@ return duk_get_boolean(ctx, index); } + /** + * Push a boolean. + * + * @param ctx the context + * @param value the value + */ static inline void push(Context &ctx, bool value) { duk_push_boolean(ctx, value); } + /** + * Require a boolean, throws a JavaScript exception if not a boolean. + * + * @param ctx the context + * @param index the index + * @return the boolean + */ static inline bool require(Context &ctx, int index) { return duk_require_boolean(ctx, index); @@ -1037,16 +1164,38 @@ template <> class TypeInfo<double> { public: + /** + * Get a double, return 0 if not a double. + * + * @param ctx the context + * @param index the index + * @return the double + */ static inline double get(Context &ctx, int index) { return duk_get_number(ctx, index); } + /** + * Check if value is a double. + * + * @param ctx the context + * @param index the index + * @return true if double + */ static inline bool is(Context &ctx, int index) { return duk_is_number(ctx, index); } + /** + * Get a double, return defaultValue if the value is not a double. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the double or defaultValue + */ static inline double optional(Context &ctx, int index, double defaultValue) { if (!duk_is_number(ctx, index)) { @@ -1056,11 +1205,24 @@ return duk_get_number(ctx, index); } + /** + * Push a double. + * + * @param ctx the context + * @param value the value + */ static inline void push(Context &ctx, double value) { duk_push_number(ctx, value); } + /** + * Require a double, throws a JavaScript exception if not a double. + * + * @param ctx the context + * @param index the index + * @return the double + */ static inline double require(Context &ctx, int index) { return duk_require_number(ctx, index); @@ -1078,6 +1240,13 @@ template <> class TypeInfo<std::string> { public: + /** + * Get a string, return 0 if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ static inline std::string get(Context &ctx, int index) { duk_size_t size; @@ -1086,11 +1255,26 @@ return std::string{text, size}; } + /** + * Check if value is a string. + * + * @param ctx the context + * @param index the index + * @return true if string + */ static inline bool is(Context &ctx, int index) { return duk_is_string(ctx, index); } + /** + * Get a string, return defaultValue if the value is not an string. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the string or defaultValue + */ static inline std::string optional(Context &ctx, int index, std::string defaultValue) { if (!duk_is_string(ctx, index)) { @@ -1100,11 +1284,24 @@ return get(ctx, index); } + /** + * Push a string. + * + * @param ctx the context + * @param value the value + */ static inline void push(Context &ctx, const std::string &value) { duk_push_lstring(ctx, value.c_str(), value.length()); } + /** + * Require a string, throws a JavaScript exception if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ static inline std::string require(Context &ctx, int index) { duk_size_t size; @@ -1123,16 +1320,38 @@ template <> class TypeInfo<const char *> { public: + /** + * Get a string, return 0 if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ static inline const char *get(Context &ctx, int index) { return duk_get_string(ctx, index); } + /** + * Check if value is a string. + * + * @param ctx the context + * @param index the index + * @return true if string + */ static inline bool is(Context &ctx, int index) { return duk_is_string(ctx, index); } + /** + * Get an integer, return defaultValue if the value is not an integer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the integer or defaultValue + */ static inline const char *optional(Context &ctx, int index, const char *defaultValue) { if (!duk_is_string(ctx, index)) { @@ -1142,11 +1361,24 @@ return duk_get_string(ctx, index); } + /** + * Push a string. + * + * @param ctx the context + * @param value the value + */ static inline void push(Context &ctx, const char *value) { duk_push_string(ctx, value); } + /** + * Require a string, throws a JavaScript exception if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ static inline const char *require(Context &ctx, int index) { return duk_require_string(ctx, index); @@ -1154,6 +1386,79 @@ }; /** + * @brief Implementation for non-managed pointers. + * + * Provides: get, is, optional, push, require. + */ +template <typename T> +class TypeInfo<Pointer<T>> { +public: + /** + * Get a pointer, return nullptr if not a pointer. + * + * @param ctx the context + * @param index the index + * @return the pointer + */ + static inline T *get(Context &ctx, int index) + { + return static_cast<T *>(duk_to_pointer(ctx, index)); + } + + /** + * Check if value is a pointer. + * + * @param ctx the context + * @param index the index + * @return true if pointer + */ + static inline bool is(Context &ctx, int index) + { + return duk_is_pointer(ctx, index); + } + + /** + * Get a pointer, return defaultValue if the value is not a pointer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the pointer or defaultValue + */ + static inline T *optional(Context &ctx, int index, Pointer<T> defaultValue) + { + if (!duk_is_pointer(ctx, index)) { + return defaultValue.object; + } + + return static_cast<T *>(duk_to_pointer(ctx, index)); + } + + /** + * Push a pointer. + * + * @param ctx the context + * @param value the value + */ + static inline void push(Context &ctx, const Pointer<T> &value) + { + duk_push_pointer(ctx, value.object); + } + + /** + * Require a pointer, throws a JavaScript exception if not a pointer. + * + * @param ctx the context + * @param index the index + * @return the pointer + */ + static inline T *require(Context &ctx, int index) + { + return static_cast<T *>(duk_require_pointer(ctx, index)); + } +}; + +/** * @class TypeInfo<Function> * @brief Push C++ function to the stack. * @@ -1164,6 +1469,13 @@ template <> class TypeInfo<Function> { public: + /** + * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the + * std::function. + * + * @param ctx the context + * @param fn the function + */ static void push(Context &ctx, Function fn); }; @@ -1176,6 +1488,12 @@ template <> class TypeInfo<FunctionMap> { public: + /** + * Push a map of function to the object at the top of the stack. + * + * @param ctx the context + * @param map the map of function + */ static inline void push(Context &ctx, const FunctionMap &map) { for (const auto &entry : map) { @@ -1193,11 +1511,23 @@ template <> class TypeInfo<Object> { public: + /** + * Check if value is an object. + * + * @param ctx the context + * @param index the index + * @return true if object + */ static inline bool is(Context &ctx, int index) { return duk_is_object(ctx, index); } + /** + * Create an empty object on the stack. + * + * @param ctx the context + */ static inline void push(Context &ctx, const Object &) { duk_push_object(ctx); @@ -1213,11 +1543,23 @@ template <> class TypeInfo<Array> { public: + /** + * Check if value is a array. + * + * @param ctx the context + * @param index the index + * @return true if array + */ static inline bool is(Context &ctx, int index) { return duk_is_array(ctx, index); } + /** + * Create an empty array on the stack. + * + * @param ctx the context + */ static inline void push(Context &ctx, const Array &) { duk_push_array(ctx); @@ -1233,11 +1575,23 @@ template <> class TypeInfo<Undefined> { public: + /** + * Check if value is undefined. + * + * @param ctx the context + * @param index the index + * @return true if undefined + */ static inline bool is(Context &ctx, int index) { return duk_is_undefined(ctx, index); } + /** + * Push undefined value on the stack. + * + * @param ctx the context + */ static inline void push(Context &ctx, const Undefined &) { duk_push_undefined(ctx); @@ -1253,11 +1607,23 @@ template <> class TypeInfo<Null> { public: + /** + * Check if value is null. + * + * @param ctx the context + * @param index the index + * @return true if null + */ static inline bool is(Context &ctx, int index) { return duk_is_null(ctx, index); } + /** + * Push null value on the stack. + * + * @param ctx the context + */ static inline void push(Context &ctx, const Null &) { duk_push_null(ctx); @@ -1265,44 +1631,6 @@ }; /** - * @brief Implementation for non-managed pointers. - * - * Provides: get, is, optional, push, require. - */ -template <typename T> -class TypeInfo<Pointer<T>> { -public: - static inline T *get(Context &ctx, int index) - { - return static_cast<T *>(duk_to_pointer(ctx, index)); - } - - static inline bool is(Context &ctx, int index) - { - return duk_is_pointer(ctx, index); - } - - static inline T *optional(Context &ctx, int index, Pointer<T> defaultValue) - { - if (!duk_is_pointer(ctx, index)) { - return defaultValue.object; - } - - return static_cast<T *>(duk_to_pointer(ctx, index)); - } - - static inline void push(Context &ctx, const Pointer<T> &p) - { - duk_push_pointer(ctx, p.object); - } - - static inline T *require(Context &ctx, int index) - { - return static_cast<T *>(duk_require_pointer(ctx, index)); - } -}; - -/** * @class TypeInfo<Global> * @brief Push the global object to the stack. * @@ -1311,6 +1639,11 @@ template <> class TypeInfo<Global> { public: + /** + * Push the global object into the stack. + * + * @param ctx the context + */ static inline void push(Context &ctx, const Global &) { duk_push_global_object(ctx); @@ -1325,9 +1658,16 @@ * This class is convenient for settings constants such as enums, string and such. */ template <typename T> -class TypeInfo<Map<T>> { +class TypeInfo<std::unordered_map<std::string, T>> { public: - static void push(Context &ctx, const Map<T> &map) + /** + * Put all values from the map as properties to the object at the top of the stack. + * + * @param ctx the context + * @param map the values + * @note You need an object at the top of the stack before calling this function + */ + static void push(Context &ctx, const std::unordered_map<std::string, T> &map) { for (const auto &pair : map) { TypeInfo<T>::push(ctx, pair.second); @@ -1344,6 +1684,13 @@ template <typename T> class TypeInfo<std::vector<T>> { public: + /** + * Get an array from the stack. + * + * @param ctx the context + * @param index the array index + * @return the array or empty array if the value is not an array + */ static std::vector<T> get(Context &ctx, int index) { std::vector<T> result; @@ -1360,6 +1707,12 @@ return result; } + /** + * Create an array with the specified values. + * + * @param ctx the context + * @param array the values + */ static void push(Context &ctx, const std::vector<T> &array) { duk_push_array(ctx); @@ -1380,7 +1733,7 @@ * @class TypeInfoShared * @brief Push objects as shared_ptr. * - * TODO: add better documentation when finalized. + * Overload TypeInfo<T *> and inherits from this class to implement constrct, push and get function automatically. */ template <typename T> class TypeInfoShared { @@ -1388,8 +1741,29 @@ static void apply(Context &ctx, std::shared_ptr<T> value); public: + /** + * Construct the shared_ptr as this. + * + * @param ctx the context + * @param value the value + */ static void construct(Context &ctx, std::shared_ptr<T> value); + + /** + * Push a managed shared_ptr as object. + * + * @param ctx the context + * @param value the value + */ static void push(Context &ctx, std::shared_ptr<T> value); + + /** + * Get a managed shared_ptr from the stack. + * + * @param ctx the context + * @param index the object index + * @return the shared_ptr + */ static std::shared_ptr<T> get(Context &ctx, int index); }; @@ -1451,9 +1825,12 @@ /** * @class TypeInfoPointer - * @brief Push pointers as objects. + * @brief Push managed pointers as objects. * - * TODO: add better documentation when finalized. + * Overload TypeInfo<T *> and inherits from this class to implement constrct, push and get function automatically, + * the pointer is constructed and managed into the Duktape context. It will be deleted when the Duktape garbage + * collectors collects the value. It is unsafe to keep a pointer to the object from the C++ side, if you need + * to share values, look at TypeInfoShared. */ template <typename T> class TypeInfoPointer { @@ -1461,8 +1838,30 @@ static void apply(Context &ctx, T *value); public: + /** + * Construct the pointer as this. + * + * @param ctx the context + * @param value the value + */ static void construct(Context &ctx, T *value); + + /** + * Push a managed pointer as object. + * + * @param ctx the context + * @param value the value + */ static void push(Context &ctx, T *value); + + /** + * Get a managed pointer from the stack. + * + * @param ctx the context + * @param index the object index + * @return the pointer + * @warning Do not store the pointer into the C++ side, the object can be deleted at any time + */ static T *get(Context &ctx, int index); };
--- a/C++/tests/Js/main.cpp Thu Oct 08 08:39:47 2015 +0200 +++ b/C++/tests/Js/main.cpp Thu Oct 08 10:02:37 2015 +0200 @@ -112,7 +112,7 @@ }; ASSERT_EQ(0, context.top()); - context.push(js::Object{}); + context.push(Object{}); context.push(map); ASSERT_EQ(DUK_TYPE_OBJECT, context.type(-1)); @@ -440,7 +440,7 @@ Context context; ASSERT_EQ(0, context.top()); - ASSERT_EQ(nullptr, context.optional<js::Pointer<int>>(0, js::Pointer<int>{nullptr})); + ASSERT_EQ(nullptr, context.optional<Pointer<int>>(0, Pointer<int>{nullptr})); ASSERT_EQ(0, context.top()); }