table

a representation of a Lua (meta)table

template <bool global>
class table_core;

typedef table_core<false> table;
typedef table_core<true> global_table;

class lua_table;

sol::table is an extremely efficient manipulator of state that brings most of the magic of the sol abstraction. Capable of doing multiple sets at once, multiple gets into a std::tuple, being indexed into using [key] syntax and setting keys with a similar syntax (see: here), sol::table is the corner of the interaction between Lua and C++.

There are two kinds of tables: the global table and non-global tables: however, both have the exact same interface and all sol::global_table s are convertible to regular sol::table s.

Tables are the core of Lua, and they are very much the core of sol.

sol::lua_table is specifically useful for specifying you want exactly a Lua table, and not something that can masquerade like a table (e.g., a userdata with a metatable that has overriden __index and __new_index fields).

members

constructor: table
table(lua_State* L, int index = -1);
table(lua_State* L, sol::new_table nt)

The first takes a table from the Lua stack at the specified index and allows a person to use all of the abstractions therein. The second creates a new table using the capacity hints specified in sol::new_table’s structure (sequence_hint and map_hint). If you don’t care exactly about the capacity, create a table using sol::table my_table(my_lua_state, sol::create);. Otherwise, specify the table creation size hints by initializing it manually through sol::new_table’s simple constructor.

function: get / traversing get
template<typename... Args, typename... Keys>
decltype(auto) get(Keys&&... keys) const;

template<typename T, typename... Keys>
decltype(auto) traverse_get(Keys&&... keys) const;

template<typename T, typename Key>
decltype(auto) get_or(Key&& key, T&& otherwise) const;

template<typename T, typename Key, typename D>
decltype(auto) get_or(Key&& key, D&& otherwise) const;

These functions retrieve items from the table. The first one (get) can pull out multiple values, 1 for each key value passed into the function. In the case of multiple return values, it is returned in a std::tuple<Args...>. It is similar to doing return table["a"], table["b"], table["c"]. Because it returns a std::tuple, you can use std::tie/std::make_tuple on a multi-get to retrieve all of the necessary variables. The second one (traverse_get) pulls out a single value, using each successive key provided to do another lookup into the last. It is similar to doing x = table["a"]["b"]["c"][...].

If the keys within nested queries try to traverse into a table that doesn’t exist, it will first pull out a nil value. If there are further lookups past a key that do not exist, the additional lookups into the nil-returned variable will cause a panic to be fired by the lua C API. If you need to check for keys, check with auto x = table.get<sol::optional<int>>( std::tie("a", "b", "c" ) );, and then use the optional interface to check for errors. As a short-hand, easy method for returning a default if a value doesn’t exist, you can use get_or instead.

This function does not create tables where they do not exist.

function: raw get / traversing raw get
template<typename... Args, typename... Keys>
decltype(auto) raw_get(Keys&&... keys) const;

template<typename T, typename... Keys>
decltype(auto) traverse_raw_get(Keys&&... keys) const;

template<typename T, typename Key>
decltype(auto) raw_get_or(Key&& key, T&& otherwise) const;

template<typename T, typename Key, typename D>
decltype(auto) raw_get_or(Key&& key, D&& otherwise) const;

Similar to get, but it does so “raw” (ignoring metamethods on the table’s metatable).

function: set / traversing set
template<typename... Args>
table& set(Args&&... args);

template<typename... Args>
table& traverse_set(Args&&... args);

These functions set items into the table. The first one (set) can set multiple values, in the form key_a, value_a, key_b, value_b, .... It is similar to table[key_a] = value_a; table[key_b] = value_b, .... The second one (traverse_set) sets a single value, using all but the last argument as keys to do another lookup into the value retrieved prior to it. It is equivalent to table[key_a][key_b][...] = value;.

If the keys within nested queries try to traverse into a table that doesn’t exist, it will first pull out a nil value. If there are further lookups past a key that do not exist, the additional lookups into the nil-returned variable will cause a panic to be fired by the lua C API.

Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this note here.

This function does not create tables where they do not exist.

function: raw set / traversing raw set
template<typename... Args>
table& raw_set(Args&&... args);

template<typename... Args>
table& traverse_raw_set(Args&&... args);

Similar to set, but it does so “raw” (ignoring metamethods on the table’s metatable).

Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this note here.

Note

Value semantics are applied to all set operations. If you do not std::ref( obj ) or specifically make a pointer with std::addressof( obj ) or &obj, it will copy / move. This is different from how sol::function behaves with its call operator. Also note that this does not detect callables by default: see the note here.

function: set a function with the specified key into lua
template<typename Key, typename Fx>
state_view& set_function(Key&& key, Fx&& fx, [...]);

Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua. Also note that this will allow Lua to understand that a callable object (such as a lambda) should be serialized as a function and not as a userdata: see the note here for more details.

function: add
template<typename... Args>
table& add(Args&&... args);

This function appends a value to a table. The definition of appends here is only well-defined for a table which has a perfectly sequential (and integral) ordering of numeric keys with associated non-null values (the same requirement for the size function). Otherwise, this falls to the implementation-defined behavior of your Lua VM, whereupon is may add keys into empty ‘holes’ in the array (e.g., the first empty non-sequential integer key it gets to from size) or perhaps at the very “end” of the “array”. Do yourself the favor of making sure your keys are sequential.

Each argument is appended to the list one at a time.

function: size
std::size_t size() const;

This function returns the size of a table. It is only well-defined in the case of a Lua table which has a perfectly sequential (and integral) ordering of numeric keys with associated non-null values.

function: setting a usertype
template<typename Class, typename... Args>
table& new_usertype(const std::string& name, Args&&... args);
template<typename Class, typename CTor0, typename... CTor, typename... Args>
table& new_usertype(const std::string& name, Args&&... args);
template<typename Class, typename... CArgs, typename... Args>
table& new_usertype(const std::string& name, constructors<CArgs...> ctor, Args&&... args);

This class of functions creates a new usertype with the specified arguments, providing a few extra details for constructors. After creating a usertype with the specified argument, it passes it to set_usertype.

function: creating an enum
template<bool read_only = true, typename... Args>
basic_table_core& new_enum(const std::string& name, Args&&... args);
template<typename T, bool read_only = true>
basic_table_core& new_enum(const std::string& name, std::initializer_list<std::pair<string_view, T>> items);

Use this function to create an enumeration type in Lua. By default, the enum will be made read-only, which creates a tiny performance hit to make the values stored in this table behave exactly like a read-only enumeration in C++. If you plan on changing the enum values in Lua, set the read_only template parameter in your new_enum call to false. The arguments are expected to come in key, value, key, value, ... list.

If you use the second overload, you will create a (runtime) std::initializer_list. This will avoid compiler overhead for excessively large enumerations. For this overload, hoever, you must pass the enumeration name as a template parameter first, and then the read_only parameter, like lua.new_enum<my_enum>( "my_enum", { {"a", my_enum:: a}, { "b", my_enum::b } } );.

function: setting a pre-created usertype
template<typename T>
table& set_usertype(usertype<T>& user);
template<typename Key, typename T>
table& set_usertype(Key&& key, usertype<T>& user);

Sets a previously created usertype with the specified key into the table. Note that if you do not specify a key, the implementation falls back to setting the usertype with a key of usertype_traits<T>::name, which is an implementation-defined name that tends to be of the form {namespace_name 1}_[{namespace_name 2 ...}_{class name}.

function: begin / end for iteration
table_iterator begin () const;
table_iterator end() const;
table_iterator cbegin() const;
table_iterator cend() const;

Provides (what can barely be called) input iterators for a table. This allows tables to work with single-pass, input-only algorithms (like std::for_each). Note that manually getting an iterator from .begin() without a .end() or using postfix incrementation (++mytable.begin()) will lead to poor results. The Lua stack is manipulated by an iterator and thusly not performing the full iteration once you start is liable to ruin either the next iteration or break other things subtly. Use a C++11 ranged for loop, std::for_each, or other algorithims which pass over the entire collection at least once and let the iterators fall out of scope.

Warning

The iterators you use to walk through a sol::table are NOT guaranteed to iterate in numeric order, or ANY kind of order. They may iterate backwards, forwards, in the style of cuckoo-hashing, by accumulating a visited list while calling rand() to find the next target, or some other crazy scheme. Now, no implementation would be crazy, but it is behavior specifically left undefined because there are many ways that your Lua package can implement the table type.

Iteration order is NOT something you should rely on. If you want to figure out the length of a table, call the length operation (int count = mytable.size(); using the sol API) and then iterate from 1 to count (inclusive of the value of count, because Lua expects iteration to work in the range of [1, count]). This will save you some headaches in the future when the implementation decides not to iterate in numeric order.

function: iteration with a function
template <typename Fx>
void for_each(Fx&& fx);

A functional for_each loop that calls the desired function. The passed in function must take either sol::object key, sol::object value or take a std::pair<sol::object, sol::object> key_value_pair. This version can be a bit safer as allows the implementation to definitively pop the key/value off the Lua stack after each call of the function.

function: operator[] access
template<typename T>
proxy<table&, T> operator[](T&& key);
template<typename T>
proxy<const table&, T> operator[](T&& key) const;

Generates a proxy that is templated on the table type and the key type. Enables lookup of items and their implicit conversion to a desired type. Lookup is done lazily.

Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this note here.

function: create a table with defaults
table create(int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args);

static table create(lua_State* L, int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
static table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args);

Creates a table, optionally with the specified values pre-set into the table. If narr or nrec are 0, then compile-time shenanigans are used to guess the amount of array entries (e.g., integer keys) and the amount of hashable entries (e.g., all other entries).

function: create a table with compile-time defaults assumed
template <typename... Args>
table create_with(Args&&... args);
template <typename... Args>
static table create_with(lua_State* L, Args&&... args);

Creates a table, optionally with the specified values pre-set into the table. It checks every 2nd argument (the keys) and generates hints for how many array or map-style entries will be placed into the table. Applies the same rules as table.set when putting the argument values into the table, including how it handles callable objects.

function: create a named table with compile-time defaults assumed
template <typename Name, typename... Args>
table create_named(Name&& name, Args&&... args);

Creates a table, optionally with the specified values pre-set into the table, and sets it as the key name in the table. Applies the same rules as table.set when putting the argument values into the table, including how it handles callable objects.