changeset 415:ac4573b9bb4b

Js: add js::Pointer for non-managed pointers
author David Demelier <markand@malikania.fr>
date Thu, 08 Oct 2015 08:29:48 +0200
parents 0b6f7f7c8a6c
children a93dfbb65648
files C++/modules/Js/Js.h C++/tests/Js/main.cpp
diffstat 2 files changed, 102 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Js/Js.h	Wed Oct 07 15:06:10 2015 +0200
+++ b/C++/modules/Js/Js.h	Thu Oct 08 08:29:48 2015 +0200
@@ -84,6 +84,20 @@
 };
 
 /**
+ * @class Pointer
+ * @brief Push a non-managed pointer to Duktape, the pointer will never be deleted.
+ * @note For a managed pointer with prototype, see TypeInfoPointer
+ */
+template <typename T>
+class Pointer {
+public:
+	/**
+	 * The pointer to push.
+	 */
+	T *object;
+};
+
+/**
  * @class Function
  * @brief Duktape/C function definition.
  */
@@ -1183,6 +1197,44 @@
 };
 
 /**
+ * @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.
  *
--- a/C++/tests/Js/main.cpp	Wed Oct 07 15:06:10 2015 +0200
+++ b/C++/tests/Js/main.cpp	Thu Oct 08 08:29:48 2015 +0200
@@ -137,6 +137,16 @@
 	ASSERT_EQ(3, array[2]);
 }
 
+TEST(PushAndGet, pointer)
+{
+	Context context;
+
+	ASSERT_EQ(0, context.top());
+	context.push(Pointer<int>{new int(1)});
+	ASSERT_EQ(1, *context.get<Pointer<int>>(-1));
+	ASSERT_EQ(1, context.top());
+}
+
 /* --------------------------------------------------------
  * Require
  * -------------------------------------------------------- */
@@ -246,6 +256,27 @@
 	ASSERT_EQ(0, context.top());
 }
 
+TEST(Require, pointer)
+{
+	Context context;
+
+	ASSERT_EQ(0, context.top());
+
+	try {
+		context.push(Function{[] (Context &ctx) -> int {
+			ctx.require<Pointer<int>>(0);
+
+			return 0;
+		}});
+		context.peval();
+
+		FAIL() << "exception expected";
+	} catch (...) {
+	}
+
+	ASSERT_EQ(0, context.top());
+}
+
 /* --------------------------------------------------------
  * Is
  * -------------------------------------------------------- */
@@ -340,6 +371,16 @@
 	ASSERT_EQ(1, context.top());
 }
 
+TEST(Is, pointer)
+{
+	Context context;
+
+	ASSERT_EQ(0, context.top());
+	context.push(Pointer<int>{new int(1)});
+	ASSERT_TRUE(context.is<Pointer<int>>(-1));
+	ASSERT_EQ(1, context.top());
+}
+
 /* --------------------------------------------------------
  * Optional
  * -------------------------------------------------------- */
@@ -394,6 +435,15 @@
 	ASSERT_EQ(0, context.top());
 }
 
+TEST(Optional, pointer)
+{
+	Context context;
+
+	ASSERT_EQ(0, context.top());
+	ASSERT_EQ(nullptr, context.optional<js::Pointer<int>>(0, js::Pointer<int>{nullptr}));
+	ASSERT_EQ(0, context.top());
+}
+
 /* --------------------------------------------------------
  * Basics
  * -------------------------------------------------------- */