PrevUpHomeNext

class lua_ref_seq

A primer::lua_ref_seq is a dynamically-sized sequence of lua_ref objects.

The intended usage is to allow handling lua functions with multiple return values. Given a stack full of return values, they can all be popped at once into a lua_ref_seq using a call to pop_stack or pop_n.

1inline lua_ref_seq pop_n(lua_State * L, int n);

2inline lua_ref_seq pop_stack(lua_State * L);

1

Pop n elements form the stack. Throws std::bad_alloc. Can cause lua memory alloc failure.

2

Pop the entire stack. Throws std::bad_alloc. Can cause lua memory alloc failure

They can be restored in the same order using lua_ref_seq member function push_each.

(Lack of) Push semantics

Because a lua_ref_seq represents multiple values and not just one, it can't be used with primer::push. (primer::push is required to push exactly one item.)

However, lua_ref_seq is essentially just a std::vector<lua_ref>, as you'll see from it's synopsis.

To prevent it from being used accidentally as a std::vector<lua_ref> with push or read, which could cause bugs, it is implemented as a struct containing a std::vector<lua_ref> member, which forwards most of the member functions of std::vector.

Instead of lua_ref_seq you could simply use std::vector<lua_ref> and push and read that instead. But when you push it for instance, it's going to push a single table which contains the sequence of values, due to the semantics we give to std::vector (see the containers section), which is different from simply pushing all of those values onto the stack.

Synopsis
struct lua_ref_seq {
  using refs_t = std::vector<lua_ref>;
  refs_t refs_;

  1bool push_each(lua_State * L) const noexcept {
    bool result = true;
    for (const auto & r : refs_) {
      bool temp = r.push(L);
      result = result && temp;
    }
    return result;
  }

  //
  // Forward MANY methods from std::vector...
  //

  std::size_t size() const { return refs_.size(); }

  using value_type = refs_t::value_type;
  using reference = refs_t::reference;
  using const_reference = refs_t::const_reference;

  // Index
  reference operator[](std::size_t i) { return refs_[i]; }
  const_reference operator[](std::size_t i) const { return refs_[i]; }

  reference at(std::size_t i) { return refs_.at(i); }
  const_reference at(std::size_t i) const { return refs_.at(i); }

  reference front() { return refs_.front(); }
  const_reference front() const { return refs_.front(); }

  reference back() { return refs_.back(); }
  const_reference back() const { return refs_.back(); }

  // Support iteration
  using iterator = refs_t::iterator;
  using const_iterator = refs_t::const_iterator;

  iterator begin() { return refs_.begin(); }
  const_iterator begin() const { return refs_.begin(); }

  iterator end() { return refs_.end(); }
  const_iterator end() const { return refs_.end(); }

  // Manipulation

  void reserve(std::size_t s) { refs_.reserve(s); }
  void clear() { refs_.clear(); }
  void resize(std::size_t s) { refs_.resize(s); }
  void pop_back() { refs_.pop_back(); }
  template <typename... Args>
  void emplace_back(Args &&... args) {
    refs_.emplace_back(std::forward<Args>(args)...);
  }

  template <typename... Args>
  void emplace(const_iterator pos, Args &&... args) {
    refs_.emplace(pos, std::forward<Args>(args)...);
  }

  template <typename InputIt>
  iterator insert(const_iterator pos, InputIt first, InputIt last) {
    return refs_.insert(pos, first, last);
  }
};

1

Push all the refs onto the stack in succession. Return of true means every push succeeded. You can usually ignore the result, it only fails if some of the refs in the lua_ref_seq are actually in an empty state. If not all of the refs are in the same VM as the argument lua_State *, then you get UB. See lua_ref.


PrevUpHomeNext