Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
- "**/ThirdParty/**"
- "**/CMakeLists.txt"
- "**/.gitmodules"
- "!**/*.md"
- "!**/*.txt"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -37,7 +39,7 @@ jobs:
- name: Install Ninja
run: |
sudo apt-get update
sudo apt-get -y install ninja-build
sudo apt-get -y install ninja-build libreadline-dev

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
Expand Down
19 changes: 16 additions & 3 deletions Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,18 @@ v [3] = v [2]; // v[2] and v[3] reference the same table
v [2] = luabridge::LuaNil (); // Removes the value with key = 2. The table is still referenced by v[3].
```

To append one or more values to a sequence table, use `append`. It is equivalent to assigning to `#t + 1`, `#t + 2`, etc., and uses `lua_rawseti` internally:

```cpp
luabridge::LuaRef t = luabridge::newTable (L);

t.append (1); // t = {1}
t.append (2, 3); // t = {1, 2, 3}
t.append ("hello", true); // t = {1, 2, 3, "hello", true}
```

`append` returns `true` if all values were successfully pushed and stored, and stops early (returning `false`) if any value fails to push onto the Lua stack.

4.3 - Calling Lua
-----------------

Expand Down Expand Up @@ -1903,9 +1915,10 @@ bool operator>= (T rhs) const;
template <class T>
bool rawequal (T v) const;

/// Append a value to a referred table. If the table is a sequence this will add another element to it.
template <class T>
void append (T v) const;
/// Append one or more values to a referred table. If the table is a sequence this will add more elements to it.
/// Uses lua_rawseti internally. Returns true if all values were successfully appended.
template <class... Ts>
bool append (const Ts&... vs) const;

/// Return the length of a referred array. This is identical to applying the Lua # operator.
int length () const;
Expand Down
33 changes: 33 additions & 0 deletions Source/LuaBridge/detail/LuaRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,39 @@ class LuaRefBase
return get_length(m_L, -1);
}

//=============================================================================================
/**
* @brief Append one or more values to a referred table.
*
* If the table is a sequence this will add more elements to it.
*
* @param vs Values to append.
*
* @returns True if all values were successfully appended.
*/
template <class... Ts>
bool append(const Ts&... vs) const
{
static_assert(sizeof...(vs) > 0);

const StackRestore stackRestore(m_L);

impl().push(m_L);

int index = get_length(m_L, -1) + 1;

auto appendOne = [&](const auto& v) -> bool
{
if (! Stack<std::decay_t<decltype(v)>>::push(m_L, v))
return false;

lua_rawseti(m_L, -2, index++);
return true;
};

return (appendOne(vs) && ...);
}

//=============================================================================================
/**
* @brief Call Lua code.
Expand Down
54 changes: 54 additions & 0 deletions Tests/Source/LuaRefTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,3 +766,57 @@ TEST_F(LuaRefTests, HookTesting)
func.second(0, "x");
}
}

TEST_F(LuaRefTests, AppendSingleValue)
{
runLua("result = {}");

EXPECT_TRUE(result().append(1));
EXPECT_TRUE(result().append(2));
EXPECT_TRUE(result().append(3));

ASSERT_EQ(3, result().length());
ASSERT_EQ(1, result()[1].unsafe_cast<int>());
ASSERT_EQ(2, result()[2].unsafe_cast<int>());
ASSERT_EQ(3, result()[3].unsafe_cast<int>());
}

TEST_F(LuaRefTests, AppendMultipleValues)
{
runLua("result = {}");

EXPECT_TRUE(result().append(10, 20, 30));

ASSERT_EQ(3, result().length());
ASSERT_EQ(10, result()[1].unsafe_cast<int>());
ASSERT_EQ(20, result()[2].unsafe_cast<int>());
ASSERT_EQ(30, result()[3].unsafe_cast<int>());
}

TEST_F(LuaRefTests, AppendMixedTypes)
{
runLua("result = {}");

EXPECT_TRUE(result().append(42, std::string("hello"), true, 3.14));

ASSERT_EQ(4, result().length());
ASSERT_EQ(42, result()[1].unsafe_cast<int>());
ASSERT_EQ("hello", result()[2].unsafe_cast<std::string>());
ASSERT_TRUE(result()[3].unsafe_cast<bool>());
ASSERT_DOUBLE_EQ(3.14, result()[4].unsafe_cast<double>());
}

TEST_F(LuaRefTests, AppendToExistingSequence)
{
runLua("result = {10, 20}");

ASSERT_EQ(2, result().length());

EXPECT_TRUE(result().append(30, 40));

ASSERT_EQ(4, result().length());
ASSERT_EQ(10, result()[1].unsafe_cast<int>());
ASSERT_EQ(20, result()[2].unsafe_cast<int>());
ASSERT_EQ(30, result()[3].unsafe_cast<int>());
ASSERT_EQ(40, result()[4].unsafe_cast<int>());
}