PrevUpHomeNext

concept L_Reg_sequence

An L_Reg_sequence is a sequence of named functions.

It is quite common in lua C API programming to need to create lists of functions paired with names. lua has a standard idiom for this. The following structure is defined in the lua headers:

struct luaL_Reg {
  const char * name;
  lua_CFunction func;
};

Many lua api calls (e.g. lua_register) take as a parameter a pointer const luaL_Reg *, which is expected to point into an array, terminated by a luaL_Reg holding two null pointers.

It is common to need to make such lists when creating APIs, or specifying userdata.

In primer, we respect this idiom, but we extend it as follows:

In total we call this concept "L_Reg_sequence".

Examples

This code pushes a collection of functions to lua and gives them names in the global environment.

Synopsis

The concept is used by an internal function detail::iterate_L_Reg_sequence:

// Iterate over an L_Reg_sequence
template <typename T, typename F>
void
iterate_L_Reg_sequence(T && t, F && f) {
  static_assert(is_L_Reg_sequence<decay_t<T>>::value,
                "Expected an L_Reg_sequence");

  for (const auto & reg :
       is_L_Reg_sequence<decay_t<T>>::adapt(std::forward<T>(t))) {
    if (reg.name || reg.func) { std::forward<F>(f)(reg.name, reg.func); }
  }
}

which calls a functor using each name, func pair from the sequence.

primer::set_funcs and a few variations are as follows:

There are a few variations of primer::set_funcs.

template <typename T>
void
set_funcs(lua_State * L, T && seq) {
  PRIMER_ASSERT_STACK_NEUTRAL(L);
  PRIMER_ASSERT_TABLE(L);

  detail::iterate_L_Reg_sequence(std::forward<T>(seq),
                                 [&](const char * name, lua_CFunction func) {
                                   if (name && func) {
                                     lua_pushcfunction(L, func);
                                     lua_setfield(L, -2, name);
                                   }
                                 });
}

template <typename T>
void
set_funcs_reverse(lua_State * L, T && seq) {
  PRIMER_ASSERT_STACK_NEUTRAL(L);
  PRIMER_ASSERT_TABLE(L);

  detail::iterate_L_Reg_sequence(std::forward<T>(seq),
                                 [&](const char * name, lua_CFunction func) {
                                   if (name && func) {
                                     lua_pushcfunction(L, func);
                                     lua_pushstring(L, name);
                                     lua_settable(L, -3);
                                   }
                                 });
}

template <typename T>
void
set_funcs_prefix(lua_State * L, const std::string & prefix, T && seq) {
  PRIMER_ASSERT_STACK_NEUTRAL(L);
  PRIMER_ASSERT_TABLE(L);

  detail::iterate_L_Reg_sequence(
    std::forward<T>(seq), [&](const char * name, lua_CFunction func) {
      if (name && func) {
        lua_pushcfunction(L, func);
        lua_setfield(L, -2, (prefix + name).c_str());
      }
    });
}

template <typename T>
void
set_funcs_prefix_reverse(lua_State * L, const std::string & prefix, T && seq) {
  PRIMER_ASSERT_STACK_NEUTRAL(L);
  PRIMER_ASSERT_TABLE(L);

  detail::iterate_L_Reg_sequence(std::forward<T>(seq),
                                 [&](const char * name, lua_CFunction func) {
                                   if (name && func) {
                                     lua_pushcfunction(L, func);
                                     lua_pushstring(L, (prefix + name).c_str());
                                     lua_settable(L, -3);
                                   }
                                 });
}

PrevUpHomeNext