Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Hash Library

This library contains functionality common to both tables and namespaces, which are two similar kinds of hash tables. It also defines the metatables for tables and namespaces.

Members

  1. Iteration Over Hashes
  2. hash.dup(t: table)
  3. hash.keys(t: table|namespace)
  4. hash.values(t: table|namespace)
  5. hash.apply(t: table|namespace, mode: string|null)
  6. hash.each(t: table|namespace, body: function)
  7. hash.take(t: table|namespace)
  8. hash.clear(t: table|namespace)
  9. hash.remove(t: table|namespace, key)
  10. hash.get(t: table|namespace, key)
  11. hash.set(t: table|namespace, key, value)
  12. table Metatable
  13. namespace Metatable

Iteration Over Hashes

Both tables and namespaces define opApply metamethods which you can use to iterate over them. Alternatively you can use hash.apply(); both ways have the same effect.

When you iterate over a hash, the behavior of iteration if you add or remove keys during iteration is undefined. No errors will be thrown and no data will be corrupted or anything like that, but it has a chance of messing up the iteration. Updating an existing key-value pair with a new value is, however, legal.

If you want to be able to add or remove keys during iteration, the hash.apply and opApply methods take an iteration mode, "modify", which will allow you to add or remove keys during iteration with defined behavior, at the cost of allocating an array. The iteration works by iterating over the keys of the hash at the time iteration began, so removing keys will have no effect and new keys will not appear in the iteration.

If you foreach over a hash directly (without using hash.apply), you pass the "modify" string as the second value in the container:

foreach(k, v; t, "modify")
	// modify t here

hash.dup(t: table)

Duplicates the given table. The returned table has the same key-value pairs as the source table. This is only a "shallow" copy; the keys and values themselves are not copied.

hash.keys(t: table|namespace)

Returns an array of all the keys in the given table or namespace. This is a nontrivial function, so don't call this often in performance-intensive code. The order of the elements is arbitrary.

hash.values(t: table|namespace)

Returns an array of all the values in the given table or namespace. This is a nontrivial function, so don't call this often in performance-intensive code. The order of the elements is arbitrary.

hash.apply(t: table|namespace, mode: string|null)

An external version of the built-in opApply functions defined for tables and namespaces. You can use this to use the "real" table opApply in case a table decides to define its own. It returns an iterator that can be looped over using foreach, that is:

foreach(k, v; hash.apply(t))
	// ...

If the mode parameter is "modify", you will be able to add or remove key-value pairs in the hash during iteration without messing up the foreach loop.

foreach(k, v; hash.apply(t, "modify"))
	// add or remove keys in t here

hash.each(t: table|namespace, body: function)

This function provides an alternative way of iterating through a table or namespace. You can sacrifice a little bit of flexibility for a bit more performance with this function. Rather than writing a foreach loop, you can pass this function a callback, or the "body" of the loop. The hash will be iterated over, calling the callback function for each key-value pair.

The callback function takes two parameters: the key and the value. The 'this' parameter of the callback function is also set to be the hash. If the function wishes to leave the loop early (i.e. where you'd usually use a break statement), the function should return false. Just like a foreach loop, it's illegal to add or remove key-value pairs from the hash during iteration. Well, nothing will stop you from doing so, but the iteration will get messed up.

Here is some example usage:

local t =
{
	x = 5,
	y = 10,
	z = 15,
	foo = "hi",
	bar = "bye"
}

// Print out the key-value pairs
t.each(function(k, v)
	writefln("table[", k, "] = ", v))

// Looks for v in t, and returns the index where the value is found, or null if not found.
local function findValue(t, v)
{
	local index

	t.each(function(k, val)
	{
		if(val is v)
		{
			index = k

			// Return false to break out of the loop early
			return false
		}
	})
	
	return index;
}

writefln(findValue(t, 15))
writefln(findValue(t, 1325908))

hash.take(t: table|namespace)

If the given table or namespace is empty, throws an error. Otherwise, returns an arbitrary key-value pair as two return values (first the key, then the value). The key-value pair is not removed from the hash. This is useful when using a table or namespace as a set.

hash.clear(t: table|namespace)

Removes all key-value pairs from the given hash.

hash.remove(t: table|namespace, key)

Removes a key-value pair from the given hash. If the hash is a namespace, the key must be a string. You can also remove key-value pairs from tables by assigning a null value to the key, but for namespaces, this function is the only way to remove a key-value pair.

hash.get(t: table|namespace, key)

Gets the value at the given key without calling any metamethods. For namespaces, the key must be a string.

hash.set(t: table|namespace, key, value)

Sets the given key-value pair in the given hash without calling any metamethods. For namespaces, the key must be a string.

table Metatable

Tables have a metatable set that allows you to call some methods on them by default. They are t.dup(), t.keys(), t.values(), t.opApply(), t.each(), t.clear(), and t.take(). They correspond exactly to the hash functions of the same name, except the first parameter is skipped as the table is used as the object upon which to operate instead.

namespace Metatable

The only method in the namespace metatable is opApply, which allows you to iterate over a namespace using a foreach loop.