File array.hpp

File List > include > simplesquirrel > array.hpp

Go to the documentation of this file.

#pragma once
#ifndef SSQ_ARRAY_HEADER_H
#define SSQ_ARRAY_HEADER_H

#include "object.hpp"
#include "args.hpp"
#include <squirrel.h>
#include <vector>

namespace ssq {
    class SSQ_API Array: public Object {
    public:
        Array(HSQUIRRELVM vm, size_t len = 0);
        virtual ~Array() = default;
        template<typename T>
        Array(HSQUIRRELVM vm, const std::vector<T>& vector):Object(vm) {
            sq_newarray(vm, 0);
            sq_getstackobj(vm, -1, &obj);
            sq_addref(vm, &obj);

            for(const auto& val : vector) {
                detail::push(vm, val);
                if(SQ_FAILED(sq_arrayappend(vm, -2))) {
                    sq_pop(vm, 2);
                    throw TypeException("Failed to push value to back of the array");
                }
            }

            sq_pop(vm, 1); // Pop array
        }
        explicit Array(const Object& object);
        Array(const Array& other);
        Array(Array&& other) NOEXCEPT;
        size_t size();
        template<typename T>
        void push(const T& value) {
            sq_pushobject(vm, obj);
            detail::push(vm, value);
            if(SQ_FAILED(sq_arrayappend(vm, -2))) {
                sq_pop(vm, 2);
                throw TypeException("Failed to push value to back of the array");
            }
            sq_pop(vm, 1);
        }
        template<typename T>
        T popAndGet() {
            sq_pushobject(vm, obj);
            auto s = sq_getsize(vm, -1);
            if(s == 0) {
                sq_pop(vm, 1);
                throw TypeException("Out of bounds");
            }

            try {
                if(SQ_FAILED(sq_arraypop(vm, -1, true))) {
                    sq_pop(vm, 1);
                    throw TypeException("Failed to pop value from back of the array");
                }
                T ret(detail::pop<T>(vm, -1));
                sq_pop(vm, 1);
                return std::move(ret);
            } catch (...) {
                sq_pop(vm, 1);
                std::rethrow_exception(std::current_exception());
            }
        }
        void pop();
        template<typename T>
        T get(size_t index) {
            sq_pushobject(vm, obj);
            auto s = static_cast<size_t>(sq_getsize(vm, -1));
            if(index >= s) {
                sq_pop(vm, 1);
                throw TypeException("Out of bounds");
            }
            detail::push(vm, index);
            if(SQ_FAILED(sq_get(vm, -2))) {
                sq_pop(vm, 1);
                throw TypeException("Failed to get value from the array");
            }
            try {
                T ret(detail::pop<T>(vm, -1));
                sq_pop(vm, 2);
                return std::move(ret);
            } catch (...) {
                sq_pop(vm, 2);
                std::rethrow_exception(std::current_exception());
            }
        }
        template<typename T>
        T begin() {
            return get<T>(0);
        }
        template<typename T>
        T back() {
            auto s = size();
            if (s == 0) throw TypeException("Out of bounds");
            return get<T>(s - 1);
        }
        template<typename T>
        void set(size_t index, const T& value) {
            sq_pushobject(vm, obj);
            auto s = static_cast<size_t>(sq_getsize(vm, -1));
            if(index >= s) {
                sq_pop(vm, 1);
                throw TypeException("Out of bounds");
            }
            detail::push(vm, index);
            detail::push(vm, value);
            if(SQ_FAILED(sq_set(vm, -3))) {
                sq_pop(vm, 1);
                throw TypeException("Failed to set value in the array");
            }
            sq_pop(vm, 1);
        }
        std::vector<Object> convertRaw();
        template<typename T>
        std::vector<T> convert() {
            sq_pushobject(vm, obj);
            auto s = static_cast<size_t>(sq_getsize(vm, -1));
            std::vector<T> ret;
            ret.reserve(s);
            while(s--) {
                sq_arraypop(vm, -1, true);
                ret.push_back(detail::pop<T>(vm, -1));
            }
            sq_pop(vm, 1);
            return ret;
        }
        Array& operator = (const Array& other);
        Array& operator = (Array&& other) NOEXCEPT;
    };
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    namespace detail {
        template<>
        inline Array popValue(HSQUIRRELVM vm, SQInteger index){
            checkType(vm, index, OT_ARRAY);
            Array val(vm);
            if (SQ_FAILED(sq_getstackobj(vm, index, &val.getRaw()))) throw TypeException("Could not get Array from squirrel stack");
            sq_addref(vm, &val.getRaw());
            return val;
        }
    }
#endif
}

#endif