浏览代码

Use lazy path evaluation when accessing the fields of a table

Ole 9 年之前
父节点
当前提交
7d0b12795e
共有 1 个文件被更改,包括 101 次插入53 次删除
  1. 101 53
      lib/luwra/tables.hpp

+ 101 - 53
lib/luwra/tables.hpp

@@ -14,10 +14,104 @@
 LUWRA_NS_BEGIN
 
 namespace internal {
-	template <typename K>
-	struct TableAccessor;
+	// This represents a "path" which will be resolved lazily. It is useful for chained table
+	// access. An access like 'table.field1.field2' would be represented similiar to
+	// {{table, field1}, field}.
+	template <typename P, typename K>
+	struct Path {
+		P parent;
+		K key;
+
+		// Read the value to which this path points to.
+		template <typename V> inline
+		V read(State* state) {
+			luwra::push(state, *this);
+
+			V value = luwra::read<V>(state, -1);
+
+			lua_pop(state, 1);
+			return value;
+		}
+
+		// Change the value to which this path points to.
+		template <typename V> inline
+		void write(State* state, V&& value) {
+			size_t pushedParents = luwra::push(state, parent);
+			if (pushedParents > 1)
+				lua_pop(state, static_cast<int>(pushedParents - 1));
+
+			size_t pushedKeys = luwra::push(state, key);
+			if (pushedKeys > 1)
+				lua_pop(state, static_cast<int>(pushedKeys - 1));
+
+			size_t pushedValues = luwra::push(state, std::forward<V>(value));
+			if (pushedValues > 1)
+				lua_pop(state, static_cast<int>(pushedValues - 1));
+
+			lua_rawset(state, -3);
+			lua_pop(state, 1);
+		}
+	};
+
+	template <typename A>
+	struct TableAccessor2 {
+		State* state;
+		A accessor;
+
+		template <typename V> inline
+		V read() {
+			return accessor.template read<V>(state);
+		}
+
+		template <typename V> inline
+		operator V() {
+			return accessor.template read<V>(state);
+		}
+
+		template <typename V> inline
+		TableAccessor2<A>& write(V&& value) {
+			accessor.write(state, std::forward<V>(value));
+			return *this;
+		}
+
+		template <typename V> inline
+		TableAccessor2<A>& operator =(V&& value) {
+			accessor.write(state, std::forward<V>(value));
+			return *this;
+		}
+
+		template <typename K> inline
+		TableAccessor2<Path<A, K>> access(K&& subkey) {
+			return {state, {accessor, std::forward<K>(subkey)}};
+		}
+
+		template <typename K> inline
+		TableAccessor2<Path<A, K>> operator [](K&& subkey) {
+			return {state, {accessor, std::forward<K>(subkey)}};
+		}
+	};
 }
 
+template <typename P, typename K>
+struct Value<internal::Path<P, K>> {
+	// Push the value to which the path points onto the stack.
+	static inline
+	size_t push(State* state, const internal::Path<P, K>& accessor) {
+		size_t pushedParents = luwra::push(state, accessor.parent);
+		if (pushedParents > 1)
+			lua_pop(state, static_cast<int>(pushedParents - 1));
+
+		size_t pushedKeys = luwra::push(state, accessor.key);
+		if (pushedKeys > 1)
+			lua_pop(state, static_cast<int>(pushedKeys - 1));
+
+		lua_rawget(state, -2);
+		lua_remove(state, -2);
+
+		return 1;
+	}
+};
+
 struct Table {
 	Reference ref;
 
@@ -32,11 +126,13 @@ struct Table {
 	}
 
 	template <typename K> inline
-	internal::TableAccessor<K> access(K&& key);
+	internal::TableAccessor2<internal::Path<Reference, K>> access(K&& key)  {
+		return {ref.impl->state, {ref, std::forward<K>(key)}};
+	}
 
 	template <typename K> inline
-	internal::TableAccessor<K> operator [](K&& key) {
-		return access<K>(std::forward<K>(key));
+	internal::TableAccessor2<internal::Path<Reference, K>> operator [](K&& key) {
+		return {ref.impl->state, {ref, std::forward<K>(key)}};
 	}
 
 	inline
@@ -101,54 +197,6 @@ struct Table {
 	}
 };
 
-namespace internal {
-	template <typename K>
-	struct TableAccessor {
-		Table parent;
-		K key;
-
-		template <typename V> inline
-		V read() {
-			return parent.get<V>(key);
-		}
-
-		template <typename V> inline
-		operator V() {
-			return parent.get<V>(key);
-		}
-
-		template <typename V> inline
-		TableAccessor<K>& write(V&& value) {
-			parent.set(key, std::forward<V>(value));
-			return *this;
-		}
-
-		template <typename V> inline
-		TableAccessor<K>& operator =(V&& value) {
-			parent.set(key, std::forward<V>(value));
-			return *this;
-		}
-
-		template <typename T> inline
-		TableAccessor<T> access(T&& subkey) {
-			return {read<Table>(), std::forward<T>(subkey)};
-		}
-
-		template <typename T> inline
-		TableAccessor<T> operator [](T&& subkey) {
-			return {read<Table>(), std::forward<T>(subkey)};
-		}
-	};
-}
-
-/**
- * Table
- */
-template <typename K> inline
-internal::TableAccessor<K> Table::access(K&& key) {
-	return {*this, std::forward<K>(key)};
-}
-
 /**
  * See [Table](@ref Table).
  */