Initial release commit
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
|
||||
/.vs
|
||||
/build/lbs.exe
|
||||
/build/lbs.pdb
|
||||
/obj/src/lua_dependency_tree.cpp.o
|
||||
/obj/src/lua_filesystem.cpp.o
|
||||
/obj/src/lua_platform.cpp.o
|
||||
/obj/src/main.cpp.o
|
||||
/obj/src/simple_string.cpp.o
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "thirdparty/luajit"]
|
||||
path = thirdparty/luajit
|
||||
url = https://luajit.org/git/luajit.git
|
||||
12
include/includes.h
Normal file
12
include/includes.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <lua.hpp>
|
||||
#include <luajit.h>
|
||||
#include <lauxlib.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
// Any function marked with this means that the exposed lua API is not sandboxed
|
||||
#define LUA_UNSAFE
|
||||
9
include/lua_datetime.h
Normal file
9
include/lua_datetime.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "includes.h"
|
||||
|
||||
int luaopen_datetime(lua_State* L);
|
||||
|
||||
int lua_datetime_unix_time(lua_State* L);
|
||||
|
||||
int lua_datetime_tostring(lua_State* L);
|
||||
int lua_datetime_tounix(lua_State* L);
|
||||
101
include/lua_dependency_tree.h
Normal file
101
include/lua_dependency_tree.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
#include "includes.h"
|
||||
#include "dynarray.hpp"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
struct dependency_tree
|
||||
{
|
||||
typedef uint32_t ref_t;
|
||||
typedef ref_t state_t;
|
||||
typedef ref_t state_cmp_t;
|
||||
|
||||
enum STATE : state_t
|
||||
{
|
||||
FULFILLED = 0,
|
||||
FAILED = 1,
|
||||
WAITING = 2,
|
||||
WORKING = 3
|
||||
};
|
||||
enum STATE_CMP : state_cmp_t
|
||||
{
|
||||
CMP_FULFILED = 1,
|
||||
CMP_FAILED = 2,
|
||||
CMP_WAITING = 4,
|
||||
CMP_WORKING = 8
|
||||
};
|
||||
|
||||
struct node
|
||||
{
|
||||
node(const node&) = delete;
|
||||
node& operator =(const node&) = delete;
|
||||
node(node&& other) noexcept;
|
||||
node& operator =(node&& other) noexcept;
|
||||
node();
|
||||
// What depends on this node
|
||||
std::set<ref_t> m_dependents = {};
|
||||
// Name of the node
|
||||
const char* m_name = nullptr;
|
||||
// How many other nodes does this node depend on
|
||||
ref_t m_num_pending_dependencies = 0;
|
||||
// A user-controlled u30
|
||||
ref_t m_userdata : (sizeof(ref_t)-2) = -1;
|
||||
// State of the node
|
||||
state_t m_state : 2;
|
||||
|
||||
~node();
|
||||
};
|
||||
|
||||
~dependency_tree();
|
||||
|
||||
// A list that maps a nodes name to its index
|
||||
std::map<std::string, ref_t> m_node_name_mapping;
|
||||
// A list of all nodes in the dependency tree
|
||||
dynarray<node> m_nodes;
|
||||
|
||||
node& operator[](const ref_t idx) noexcept;
|
||||
const node& operator[](const ref_t idx) const noexcept;
|
||||
|
||||
dynarray<ref_t> get_leaf_nodes(const bool ignore_fulfilled=false) const;
|
||||
dynarray<const char*> get_leaf_node_names(const bool ignore_fulfilled=false) const;
|
||||
dynarray<ref_t> filter_nodes(const state_cmp_t state_cmp, const ref_t num_dependencies_gt, const bool invert_num_deps) const;
|
||||
void set_node_state(const ref_t node, const state_t new_state);
|
||||
void set_node_state(const char* node, const state_t new_state);
|
||||
|
||||
ref_t add_node(const char* node_name, const dynarray<ref_t>& dependents);
|
||||
ref_t add_node(const char* node_name, const dynarray<const char*>& dependents);
|
||||
ref_t add_node(const char* node_name, const std::initializer_list<ref_t>& dependents);
|
||||
ref_t add_node(const char* node_name, const std::initializer_list<const char*>& dependents);
|
||||
ref_t add_node(const char* node_name);
|
||||
|
||||
void add_node_dependency(const ref_t node, const ref_t dependency);
|
||||
void add_node_dependency(const ref_t node, const char* dependency);
|
||||
void add_node_dependency(const char* node, const ref_t dependency);
|
||||
void add_node_dependency(const char* node, const char* dependency);
|
||||
|
||||
void add_node_dependencies(const ref_t node, const std::initializer_list<ref_t>& dependencies);
|
||||
void add_node_dependencies(const ref_t node, const dynarray<ref_t>& dependencies);
|
||||
void add_node_dependencies(const ref_t node, const std::initializer_list<const char*>& dependencies);
|
||||
void add_node_dependencies(const ref_t node, const dynarray<const char*>& dependencies);
|
||||
};
|
||||
|
||||
|
||||
int luaopen_dependency_tree(lua_State* L);
|
||||
|
||||
int lua_dependency_create(lua_State* L);
|
||||
int lua_dependency_destroy(lua_State* L);
|
||||
int lua_dependency_add_node(lua_State* L);
|
||||
int lua_dependency_add_dependency(lua_State* L);
|
||||
int lua_dependency_remove_dependency(lua_State* L);
|
||||
int lua_dependency_add_dependencies(lua_State* L);
|
||||
int lua_dependency_remove_dependencies(lua_State* L);
|
||||
int lua_dependency_get_leafs(lua_State* L);
|
||||
int lua_dependency_match_nodes(lua_State* L);
|
||||
int lua_dependency_get_node_state(lua_State* L);
|
||||
int lua_dependency_set_node_state(lua_State* L);
|
||||
int lua_dependency_get_node_userval(lua_State* L);
|
||||
int lua_dependency_set_node_userval(lua_State* L);
|
||||
int lua_dependency_get_node_name(lua_State* L);
|
||||
int lua_dependency_get_node(lua_State* L);
|
||||
int lua_dependency_index(lua_State* L);
|
||||
59
include/lua_filesystem.h
Normal file
59
include/lua_filesystem.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include "includes.h"
|
||||
|
||||
// Provides variables;
|
||||
// fs.work_dir: string
|
||||
int luaopen_filesystem(lua_State* L);
|
||||
|
||||
// x = list_dir(path)
|
||||
int lua_fs_list_dir(lua_State* L);
|
||||
|
||||
// x = list_all_dirs(path)
|
||||
int lua_fs_list_alldirs(lua_State* L);
|
||||
|
||||
int lua_fs_foreach_dir(lua_State* L);
|
||||
int lua_fs_forall_dir(lua_State* L);
|
||||
|
||||
int lua_fs_foreach_dir_next(lua_State* L);
|
||||
int lua_fs_forall_dir_next(lua_State* L);
|
||||
|
||||
int lua_fs_foreach_dir_dtor(lua_State* L);
|
||||
int lua_fs_forall_dir_dtor(lua_State* L);
|
||||
|
||||
|
||||
// number | nil function fs.last_modified(path: string)
|
||||
int lua_fs_last_modified(lua_State* L);
|
||||
// boolean function fs.exists(path: string)
|
||||
int lua_fs_exists(lua_State* L);
|
||||
// boolean function fs.is_dir(path: string)
|
||||
int lua_fs_is_dir(lua_State* L);
|
||||
// boolean function fs.is_file(path: string)
|
||||
int lua_fs_is_file(lua_State* L);
|
||||
// boolean function create_dir(path: string)
|
||||
int lua_fs_create_dir(lua_State* L);
|
||||
// userdata<file_hdl> | nil function fs.open_file(path: string)
|
||||
int lua_fs_open_file(lua_State* L);
|
||||
// nil function fs.close_file(userdata<file_hdl>)
|
||||
// file dtor
|
||||
int lua_fs_close_file(lua_State* L);
|
||||
// string | nil function fs.read_file(userdata<file_hdl>, num_bytes: number)
|
||||
int lua_fs_read_file(lua_State* L);
|
||||
// nil function fs.seek(userdata<file_hdl>, num_bytes: number, [opt] boolean: seek_backward=false)
|
||||
int lua_fs_seek_file(lua_State* L);
|
||||
// nil function fs.getpos(userdata<file_hdl>)
|
||||
int lua_fs_getpos_file(lua_State* L);
|
||||
// nil function fs.write(userdata<file_hdl>, string)
|
||||
int lua_fs_write_file(lua_State* L);
|
||||
// nil function fs.append(userdata<file_hdl>, string)
|
||||
int lua_fs_append_file(lua_State* L);
|
||||
|
||||
// string function fs.relative(string base, string path)
|
||||
int lua_fs_relative(lua_State* L);
|
||||
// string function fs.absolute(string path)
|
||||
int lua_fs_absolute(lua_State* L);
|
||||
// string function fs.file_name(string path)
|
||||
int lua_fs_file_name(lua_State* L);
|
||||
// string function fs.file_extension(string path)
|
||||
int lua_fs_file_extension(lua_State* L);
|
||||
// string function fs.file_directory(string path)
|
||||
int lua_fs_file_directory(lua_State* L);
|
||||
0
include/lua_git.h
Normal file
0
include/lua_git.h
Normal file
48
include/lua_parallel.h
Normal file
48
include/lua_parallel.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// A lua module that provides multithreadding utilities to lua
|
||||
#pragma once
|
||||
#include "lua_stack.h"
|
||||
|
||||
// All functions are sandboxed
|
||||
int luaopen_parallel_safe(lua_State* L);
|
||||
// Some functions are not sandboxed
|
||||
int luaopen_parallel_unsafe(lua_State* L);
|
||||
|
||||
int lua_parallel_create_mutex(lua_State* L);
|
||||
int lua_parallel_destroy_mutex(lua_State* L);
|
||||
int lua_parallel_lock_mutex(lua_State* L);
|
||||
int lua_parallel_unlock_mutex(lua_State* L);
|
||||
|
||||
int lua_parallel_create_promise(lua_State* L);
|
||||
int lua_parallel_destroy_promise(lua_State* L);
|
||||
int lua_parallel_await_promise(lua_State* L);
|
||||
int lua_parallel_fullfilled_promise(lua_State* L);
|
||||
int lua_parallel_fullfilled_all_promises(lua_State* L);
|
||||
|
||||
struct lua_parallel_thread
|
||||
{
|
||||
// A list of all messages recieved from other threads
|
||||
lua_stack stack;
|
||||
// Coroutine lua state pointer
|
||||
lua_State* L;
|
||||
// underlying thread object
|
||||
std::jthread thread;
|
||||
};
|
||||
|
||||
// userdata<thread> function parallel.create_thread(function fn, ...)
|
||||
int lua_parallel_create_thread(lua_State* L);
|
||||
// N/A
|
||||
int lua_parallel_destroy_thread(lua_State* L);
|
||||
// nil function parallel.join(userdata<thread> thread)
|
||||
int lua_parallel_join_thread(lua_State* L);
|
||||
// nil function parallel.request_stop(userdata<thread> thread)
|
||||
int lua_parallel_request_stop(lua_State* L);
|
||||
// boolean function parallel.stop_requested()
|
||||
int lua_parallel_stop_requested(lua_State* L);
|
||||
// nil function parallel.sendmsg(userdata<thread> thread, ...)
|
||||
int lua_parallel_sendmsg_thread(lua_State* L);
|
||||
// table function parallel.recvmsg(userdata<thread>[] | nil filter)
|
||||
int lua_parallel_recvmsg_thread(lua_State* L);
|
||||
// number function parallel.recvsize(userdata<thread>[] | nil filter)
|
||||
int lua_parallel_recvsize_thread(lua_State* L);
|
||||
|
||||
|
||||
34
include/lua_platform.h
Normal file
34
include/lua_platform.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "lua_parallel.h"
|
||||
// Platform-related code
|
||||
|
||||
// Provided variables;
|
||||
// platform.os: string
|
||||
// platform.arch: string
|
||||
// platform.call_convention: string
|
||||
// platform.isa_exts: table<string, boolean>
|
||||
int luaopen_platform(lua_State* L);
|
||||
|
||||
// Returns the exit code of the command as well as a string of its stdout
|
||||
// int, string function platform.exec(cmd: string, args: array<string>)
|
||||
int lua_platform_exec(lua_State* L);
|
||||
|
||||
// Executes a command asynchronosly, returning a promise to the functions return values
|
||||
// promise<int>, promise<string> function platform.exec_async(cmd: string, args: array<string>)
|
||||
int lua_platform_exec_async(lua_State* L);
|
||||
|
||||
// Executes a command asynchronosly, calling a callback on its completion with its error code and
|
||||
// overall stdout and another callback on each token read from its stdout
|
||||
// function platform.exec_async_cb(cmd: string,
|
||||
// function on_complete(cmd: string, exit_code: int, overall_output: string),
|
||||
// function on_stdout(cmd: string, overall_output: string, delta_output: string)
|
||||
// )
|
||||
int lua_platform_exec_async_cb(lua_State* L);
|
||||
|
||||
|
||||
// Executes the same command up to N times in parallel, iterating through the args provided until all arguments have been used
|
||||
// array[promise<int>, promise<string>] function platform.exec_parallel_async(cmd: string, N: int, args: array<array<string>>)
|
||||
int lua_platform_exec_parallel_async(lua_State* L);
|
||||
|
||||
// array<int>, array<string> function platform.exec_parallel(cmd: string, N: int, args: array<array<string>>)
|
||||
int lua_platform_exec_parallel(lua_State* L);
|
||||
43
include/lua_stack.h
Normal file
43
include/lua_stack.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
struct lua_stack
|
||||
{
|
||||
typedef uint8_t type_t;
|
||||
enum TYPES : type_t
|
||||
{
|
||||
NIL,
|
||||
NUMBER,
|
||||
BOOLEAN,
|
||||
INTEGER,
|
||||
LSTRING,
|
||||
STRING,
|
||||
USERDATA,
|
||||
THREAD,
|
||||
CFUNCTION,
|
||||
CCLOSURE,
|
||||
TABLE
|
||||
};
|
||||
void push_nil (void);
|
||||
void push_boolean (const bool val);
|
||||
void push_integer (const lua_Integer val);
|
||||
void push_number (const lua_Number val);
|
||||
void push_lstring (const char* beg, const char* end);
|
||||
void push_lstring (const std::string::iterator& beg, const std::string::iterator& end);
|
||||
void push_lstring (const char* val, const size_t slen);
|
||||
void push_string (const char* val);
|
||||
void push_string (const std::string& val);
|
||||
void push_lightuserdata (void* p);
|
||||
void push_thread (lua_State* L);
|
||||
void push_cfunction (const lua_CFunction f);
|
||||
void push_cclosure (const lua_CFunction fn, const int num_upvalues);
|
||||
void push_table (lua_State* L, const int tbl_idx);
|
||||
|
||||
void value_type(const size_t idx);
|
||||
|
||||
uint8_t* m_data;
|
||||
uint8_t* m_types;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
};
|
||||
8
include/platform_agnostic.h
Normal file
8
include/platform_agnostic.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#if defined (WIN32) || defined (_WIN32)
|
||||
FILE* popen(const char* cmd, const char* mode) { return _popen(cmd, mode); }
|
||||
int pclose(FILE* stream) { return _pclose(stream); };
|
||||
#else
|
||||
|
||||
#endif
|
||||
47
include/simple_string.h
Normal file
47
include/simple_string.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <malloc.h>
|
||||
#include <string>
|
||||
|
||||
class simple_string
|
||||
{
|
||||
public:
|
||||
simple_string(const simple_string& src);
|
||||
simple_string& operator =(const simple_string& src);
|
||||
simple_string(simple_string&& src) noexcept;
|
||||
simple_string& operator =(simple_string&& src) noexcept;
|
||||
|
||||
simple_string(const char* beg, const char* end);
|
||||
simple_string(const char* str, const size_t slen);
|
||||
simple_string(const char* str);
|
||||
simple_string(const size_t initial_capacity, const char fill_value='\0');
|
||||
simple_string(const std::string& str);
|
||||
simple_string();
|
||||
|
||||
~simple_string(void);
|
||||
|
||||
simple_string& append(const char* other);
|
||||
simple_string& append(const char* beg, const char* end);
|
||||
simple_string& append(const char* other, const size_t slen);
|
||||
simple_string& append(const std::string& other);
|
||||
simple_string& append(const simple_string& other);
|
||||
simple_string& append(const char x);
|
||||
|
||||
void resize(const size_t new_size);
|
||||
void expand(const size_t extra_capacity);
|
||||
void reserve(const size_t new_capacity);
|
||||
|
||||
const char* c_str(void) const noexcept;
|
||||
char* data(void) noexcept;
|
||||
size_t size(void) const noexcept;
|
||||
|
||||
char* begin(void) noexcept;
|
||||
char* end(void) noexcept;
|
||||
const char* cbegin(void) const noexcept;
|
||||
const char* cend(void) const noexcept;
|
||||
|
||||
char& operator [](const size_t idx) noexcept;
|
||||
const char& operator [](const size_t idx) const noexcept;
|
||||
private:
|
||||
char* m_data = nullptr;
|
||||
size_t m_size = 0;
|
||||
size_t m_capacity = 0;
|
||||
};
|
||||
59
makefile
Normal file
59
makefile
Normal file
@@ -0,0 +1,59 @@
|
||||
CXX := clang++
|
||||
|
||||
INCLUDES := include src thirdparty/luajit/src
|
||||
LIBRARY_DIRECTORIES := thirdparty/luajit/src
|
||||
LINKER_INPUTS := lua51 luajit
|
||||
|
||||
DEBUG_DEFINES :=
|
||||
DEFINES :=
|
||||
|
||||
CXX_FLAGS := -std=c++20 -g -O0
|
||||
CXX_DEBUG_FLAGS :=
|
||||
LNK_FLAGS := -g -O0
|
||||
LNK_DEBUG_FLAGS :=
|
||||
|
||||
LUAJUT_BUILD_CMD := call msvcbuild.bat
|
||||
|
||||
.PHONY: all clean
|
||||
all: build_deps link_lbs
|
||||
|
||||
# From https://stackoverflow.com/a/18258352/8617429
|
||||
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
|
||||
define \n
|
||||
|
||||
endef
|
||||
ifeq ($(OS), Windows_NT)
|
||||
PLATFORM_SEPERATOR := &
|
||||
touch = type nul > $(1)
|
||||
rm = rmdir /S /Q $(1) > nul || (exit 0)
|
||||
RM = del
|
||||
mkdir = mkdir $(subst /,\,$(1)) > nul 2>&1 || (exit 0)
|
||||
OUTPUT_NAME := lbs.exe
|
||||
else
|
||||
PLATFORM_SEPERATOR := &&
|
||||
touch = touch $(1)
|
||||
rm = rm -rf $(1)
|
||||
RM = rm -f
|
||||
mkdir = mkdir -p $(1)
|
||||
OUTPUT_NAME := lbs
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(call RM,$(call rwildcard, obj,*.o) build/$(OUTPUT_NAME))
|
||||
|
||||
SOURCE_FILES := $(call rwildcard,src,*.cpp,*.hpp)
|
||||
OBJECT_FILES := $(foreach d,$(addsuffix .o,$(SOURCE_FILES)), obj/$(d))
|
||||
|
||||
obj/src/%.cpp.o: src/%.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(foreach inc,$(INCLUDES),-I$(inc)) $(foreach def,$(DEFINES),-D$(def)) $< -o $@
|
||||
obj/src/%.hpp.o: src/%.hpp
|
||||
|
||||
link_lbs: $(OBJECT_FILES)
|
||||
$(CXX) $(LNK_FLAGS) $(LNK_FLAGS) $(foreach lib,$(LIBRARY_DIRECTORIES),-L$(lib)) $(foreach lnk,$(LINKER_INPUTS),-l$(lnk)) $^ -o build/$(OUTPUT_NAME)
|
||||
|
||||
build_deps: .make/thirdparty_luajit
|
||||
|
||||
.make/thirdparty_luajit:
|
||||
git submodule update --init --recursive
|
||||
cd thirdparty/luajit/src $(PLATFORM_SEPERATOR) $(LUAJUT_BUILD_CMD)
|
||||
$(call touch,".make/thirdparty_luajit")
|
||||
365
src/dynarray.hpp
Normal file
365
src/dynarray.hpp
Normal file
@@ -0,0 +1,365 @@
|
||||
#pragma once
|
||||
#include <utility>
|
||||
#include <string.h>
|
||||
|
||||
template <typename T>
|
||||
class dynarray
|
||||
{
|
||||
public:
|
||||
dynarray(const dynarray& src);
|
||||
dynarray& operator =(const dynarray& src);
|
||||
dynarray(dynarray&& other) noexcept;
|
||||
dynarray& operator =(dynarray&& other) noexcept;
|
||||
|
||||
dynarray(void);
|
||||
dynarray(const std::initializer_list<T>& src);
|
||||
dynarray(const size_t initial_capacity);
|
||||
|
||||
~dynarray(void);
|
||||
|
||||
T& operator [](const size_t idx) noexcept;
|
||||
const T& operator [](const size_t idx) const noexcept;
|
||||
|
||||
T* begin(void) noexcept;
|
||||
const T* begin(void) const noexcept;
|
||||
const T* cbegin(void) const noexcept;
|
||||
T* end(void) noexcept;
|
||||
const T* end(void) const noexcept;
|
||||
const T* cend(void) const noexcept;
|
||||
|
||||
T* c_str(void) const noexcept;
|
||||
T* c_array(void) const noexcept;
|
||||
T* data(void) const noexcept;
|
||||
size_t size(void) const noexcept;
|
||||
size_t capacity(void) const noexcept;
|
||||
|
||||
bool is_empty(void) const noexcept;
|
||||
bool is_nullptr(void) const noexcept;
|
||||
|
||||
void push_back(const T& val);
|
||||
void push_back(T&& val);
|
||||
void push_back(const std::initializer_list<T>& vals);
|
||||
void push_back(const dynarray<T>& vals);
|
||||
void push_back(const T* vals, const size_t num_vals);
|
||||
|
||||
T&& pop_back(void) noexcept;
|
||||
|
||||
T& front(void) noexcept;
|
||||
const T& front(void) const noexcept;
|
||||
T& back(void) noexcept;
|
||||
const T& back(void) const noexcept;
|
||||
|
||||
void resize(const size_t new_size);
|
||||
void expand(const size_t extra_capacity);
|
||||
void reserve(const size_t new_capacity);
|
||||
void shrink_to_fit(void);
|
||||
private:
|
||||
T* m_data = nullptr;
|
||||
size_t m_capacity = 0;
|
||||
size_t m_size = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::dynarray(const dynarray& src)
|
||||
{
|
||||
if (m_data == src.m_data) return;
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
m_data = (T*)malloc(src.m_size*sizeof(T));
|
||||
if (src.m_data != nullptr)
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_data[i] = src.m_data[i];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>& dynarray<T>::operator=(const dynarray& src)
|
||||
{
|
||||
if (m_data == src.m_data) return;
|
||||
if (m_data != nullptr) delete[] m_data;
|
||||
m_data = nullptr;
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
m_data = (T*)malloc(src.m_size*sizeof(T));
|
||||
if (src.m_data != nullptr)
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_data[i] = src.m_data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::dynarray(dynarray&& other) noexcept
|
||||
{
|
||||
if (this == &other) return;
|
||||
m_data = other.m_data;
|
||||
m_size = other.m_size;
|
||||
m_capacity = other.m_capacity;
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
other.m_data = nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>& dynarray<T>::operator=(dynarray&& other) noexcept
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
if (m_data != nullptr) delete[] m_data;
|
||||
m_data = other.m_data;
|
||||
m_size = other.m_size;
|
||||
m_capacity = other.m_capacity;
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
other.m_data = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::dynarray(void)
|
||||
{
|
||||
m_data = nullptr;
|
||||
m_size = 0;
|
||||
m_capacity = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::dynarray(const std::initializer_list<T>& src)
|
||||
{
|
||||
m_data = (T*)malloc(src.size()*sizeof(T));
|
||||
m_size = src.size();
|
||||
m_capacity = src.size();
|
||||
if (std::is_trivially_copyable<T>::value)
|
||||
memcpy(m_data, src.begin(), sizeof(T) * m_size);
|
||||
else
|
||||
for (size_t i = 0; i < src.size(); ++i)
|
||||
m_data[i++] = src.begin()[i];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::dynarray(const size_t initial_capacity)
|
||||
{
|
||||
m_data = (initial_capacity == 0) ? nullptr : (T*)malloc(initial_capacity*sizeof(T));
|
||||
m_size = 0;
|
||||
m_capacity = initial_capacity;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline dynarray<T>::~dynarray(void)
|
||||
{
|
||||
if (m_data != nullptr)
|
||||
{
|
||||
if (!std::is_trivially_destructible<T>::value)
|
||||
{
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_data[i].~T();
|
||||
}
|
||||
free(m_data);
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T& dynarray<T>::operator[](const size_t idx) noexcept
|
||||
{ return m_data[idx]; }
|
||||
|
||||
template<typename T>
|
||||
inline const T& dynarray<T>::operator[](const size_t idx) const noexcept
|
||||
{ return m_data[idx]; }
|
||||
|
||||
template<typename T>
|
||||
inline T* dynarray<T>::begin(void) noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline const T* dynarray<T>::begin(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline const T* dynarray<T>::cbegin(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline T* dynarray<T>::end(void) noexcept
|
||||
{ return m_data == nullptr ? nullptr : (m_data + m_size); }
|
||||
|
||||
template<typename T>
|
||||
inline const T* dynarray<T>::end(void) const noexcept
|
||||
{ return m_data == nullptr ? nullptr : (m_data + m_size); }
|
||||
|
||||
template<typename T>
|
||||
inline const T* dynarray<T>::cend(void) const noexcept
|
||||
{ return m_data == nullptr ? nullptr : (m_data + m_size); }
|
||||
|
||||
template<typename T>
|
||||
inline T* dynarray<T>::c_str(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline T* dynarray<T>::c_array(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline T* dynarray<T>::data(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline size_t dynarray<T>::size(void) const noexcept
|
||||
{ return m_size; }
|
||||
|
||||
template<typename T>
|
||||
inline size_t dynarray<T>::capacity(void) const noexcept
|
||||
{ return m_capacity; }
|
||||
|
||||
template<typename T>
|
||||
inline bool dynarray<T>::is_empty(void) const noexcept
|
||||
{ return m_size == 0; }
|
||||
|
||||
template<typename T>
|
||||
inline bool dynarray<T>::is_nullptr(void) const noexcept
|
||||
{
|
||||
return m_data == nullptr || m_capacity == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::push_back(const T& val)
|
||||
{
|
||||
// Double capacity if we can not fit an extra value
|
||||
if (m_size + 1 > m_capacity) this->expand(m_capacity == 0 ? 32 : m_capacity);
|
||||
m_data[m_size++] = val;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::push_back(T&& val)
|
||||
{
|
||||
// Double capacity if we can not fit an extra value
|
||||
if (m_size + 1 > m_capacity) this->expand(m_capacity == 0 ? 32 : m_capacity);
|
||||
new (m_data + m_size) T(std::move(val));
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::push_back(const std::initializer_list<T>& vals)
|
||||
{
|
||||
const size_t prev_size = m_size;
|
||||
this->resize(m_size + vals.size());
|
||||
if (std::is_trivially_copyable<T>::value)
|
||||
memcpy(m_data + prev_size, vals.begin(), sizeof(T) * vals.size());
|
||||
else
|
||||
for (size_t i = 0; i < vals.size(); ++i)
|
||||
m_data[prev_size + i] = vals.begin()[i];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::push_back(const dynarray<T>& vals)
|
||||
{
|
||||
const size_t prev_size = m_size;
|
||||
this->resize(m_size + vals.m_size);
|
||||
if (std::is_trivially_copyable<T>::value)
|
||||
memcpy(m_data + prev_size, vals.m_data, sizeof(T) * vals.m_size);
|
||||
else
|
||||
for (size_t i = 0; i < vals.m_size; ++i)
|
||||
m_data[prev_size + i] = vals.m_data[i];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::push_back(const T* vals, const size_t num_vals)
|
||||
{
|
||||
const size_t prev_size = m_size;
|
||||
this->resize(m_size + num_vals);
|
||||
if (std::is_trivially_copyable<T>::value)
|
||||
memcpy(m_data + prev_size, vals, sizeof(T) * num_vals);
|
||||
else
|
||||
for (size_t i = 0; i < num_vals; ++i)
|
||||
m_data[prev_size + i] = vals[i];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T&& dynarray<T>::pop_back(void) noexcept
|
||||
{
|
||||
m_size--;
|
||||
return std::move(m_data[m_size]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T& dynarray<T>::front(void) noexcept
|
||||
{ return *m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline const T& dynarray<T>::front(void) const noexcept
|
||||
{ return *m_data; }
|
||||
|
||||
template<typename T>
|
||||
inline T& dynarray<T>::back(void) noexcept
|
||||
{ return m_data[m_size - 1]; }
|
||||
|
||||
template<typename T>
|
||||
inline const T& dynarray<T>::back(void) const noexcept
|
||||
{ return m_data[m_size-1]; }
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::resize(const size_t new_size)
|
||||
{
|
||||
if (new_size > m_capacity)
|
||||
this->expand(new_size);
|
||||
else if (new_size < m_size && std::is_trivially_destructible<T>::value)
|
||||
for (size_t i = new_size; i < m_size; ++i)
|
||||
m_data[i].~T();
|
||||
m_size = new_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::expand(const size_t extra_capacity)
|
||||
{ this->reserve(m_capacity + extra_capacity); }
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::reserve(const size_t new_capacity)
|
||||
{
|
||||
if (new_capacity <= m_capacity) return;
|
||||
T* new_data = (T*)malloc(new_capacity*sizeof(T));
|
||||
if (new_data == nullptr) return;
|
||||
if constexpr (std::is_trivially_copyable<T>::value)
|
||||
memcpy(new_data, m_data, m_size * sizeof(T));
|
||||
else if constexpr (std::is_move_assignable<T>::value)
|
||||
{
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
new (new_data + i) T(std::move(m_data[i]));
|
||||
}
|
||||
else if constexpr (std::is_copy_assignable<T>::value)
|
||||
{
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
new (new_data+i) T(m_data[i]);
|
||||
}
|
||||
|
||||
if (!std::is_trivially_destructible<T>::value)
|
||||
{
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_data[i].~T();
|
||||
}
|
||||
free(m_data);
|
||||
|
||||
m_data = new_data;
|
||||
m_capacity = new_capacity;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void dynarray<T>::shrink_to_fit(void)
|
||||
{
|
||||
if (m_capacity == m_size) return;
|
||||
if (m_size == 0)
|
||||
{
|
||||
delete[] m_data;
|
||||
m_capacity = 0;
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
T* new_data = (T*)malloc(m_size*sizeof(T));
|
||||
if (std::is_trivially_copyable<T>::value)
|
||||
memcpy(new_data, m_data, m_size * sizeof(T));
|
||||
else if (std::is_move_assignable<T>::value)
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
new (new_data+i) T(std::move(m_data[i]));
|
||||
else if (std::is_copy_assignable<T>::value)
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
new (new_data+i) T(m_data[i]);
|
||||
delete[] m_data;
|
||||
m_data = new_data;
|
||||
m_capacity = m_size;
|
||||
}
|
||||
667
src/lua_dependency_tree.cpp
Normal file
667
src/lua_dependency_tree.cpp
Normal file
@@ -0,0 +1,667 @@
|
||||
#include "lua_dependency_tree.h"
|
||||
#include <string.h>
|
||||
|
||||
dependency_tree::node& dependency_tree::operator[](const ref_t idx) noexcept
|
||||
{ return m_nodes[idx]; }
|
||||
|
||||
const dependency_tree::node& dependency_tree::operator[](const ref_t idx) const noexcept
|
||||
{ return m_nodes[idx]; }
|
||||
|
||||
dynarray<dependency_tree::ref_t> dependency_tree::get_leaf_nodes(const bool ignore_fulfilled) const
|
||||
{
|
||||
dynarray<ref_t> result;
|
||||
for (size_t i = 0; i < m_nodes.size(); ++i)
|
||||
{
|
||||
if (m_nodes[i].m_num_pending_dependencies == 0 &&
|
||||
(!ignore_fulfilled || m_nodes[i].m_state != FULFILLED))
|
||||
result.push_back(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
dynarray<const char*> dependency_tree::get_leaf_node_names(const bool ignore_fulfilled) const
|
||||
{
|
||||
dynarray<ref_t> refs = this->get_leaf_nodes(ignore_fulfilled);
|
||||
dynarray<const char*> names;
|
||||
for (const ref_t ref : refs)
|
||||
names.push_back(m_nodes[ref].m_name);
|
||||
return names;
|
||||
}
|
||||
|
||||
dynarray<dependency_tree::ref_t> dependency_tree::filter_nodes(const state_cmp_t state_cmp, const ref_t num_dependencies_gt, const bool invert_num_deps) const
|
||||
{
|
||||
dynarray<ref_t> res;
|
||||
|
||||
for (ref_t i = 0; i < m_nodes.size(); ++i)
|
||||
{
|
||||
const node& n = m_nodes[i];
|
||||
// Ignore nodes that do not match the num_dependencies requirement
|
||||
if (!((n.m_num_pending_dependencies > num_dependencies_gt) ^ invert_num_deps)) continue;
|
||||
|
||||
bool inc = false;
|
||||
inc |= (state_cmp & CMP_FULFILED) > 0 && n.m_state == FULFILLED;
|
||||
inc |= (state_cmp & CMP_FAILED ) > 0 && n.m_state == FAILED;
|
||||
inc |= (state_cmp & CMP_WORKING ) > 0 && n.m_state == WORKING;
|
||||
inc |= (state_cmp & CMP_WAITING ) > 0 && n.m_state == WAITING;
|
||||
if (!inc) continue;
|
||||
|
||||
res.push_back(i);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Sets the state of a node
|
||||
// If the node transitions from a fulfilled state it will recursively update its parents
|
||||
void dependency_tree::set_node_state(const ref_t ref_node, const state_t new_state)
|
||||
{
|
||||
node& n = m_nodes[ref_node];
|
||||
if (n.m_state == new_state) return;
|
||||
if (new_state == WORKING && n.m_num_pending_dependencies != 0) return;
|
||||
if (new_state == FULFILLED && n.m_num_pending_dependencies != 0) return;
|
||||
|
||||
|
||||
|
||||
else if (n.m_state == FULFILLED && new_state != FULFILLED)
|
||||
{
|
||||
for (const ref_t ref_p : n.m_dependents)
|
||||
{
|
||||
node& p = m_nodes[ref_p];
|
||||
p.m_num_pending_dependencies++;
|
||||
if (p.m_state == FULFILLED)
|
||||
this->set_node_state(ref_p, WAITING);
|
||||
}
|
||||
}
|
||||
// If changing from a non-resolved state to a resolved state,
|
||||
// Decrement the node and update its parents
|
||||
else if (new_state == FULFILLED)
|
||||
{
|
||||
for (const ref_t ref_p : n.m_dependents)
|
||||
{
|
||||
node& p = m_nodes[ref_p];
|
||||
p.m_num_pending_dependencies--;
|
||||
if (p.m_num_pending_dependencies == 0)
|
||||
this->set_node_state(ref_p, WORKING);
|
||||
}
|
||||
}
|
||||
|
||||
n.m_state = new_state;
|
||||
}
|
||||
|
||||
void dependency_tree::set_node_state(const char* node, const state_t new_state)
|
||||
{ this->set_node_state(m_node_name_mapping[node], new_state); }
|
||||
|
||||
dependency_tree::ref_t dependency_tree::add_node(const char* node_name, const dynarray<ref_t>& dependents)
|
||||
{
|
||||
ref_t ret = -1;
|
||||
// The node already exists, so just add non-duplicating dependents to it
|
||||
if (m_node_name_mapping.contains(node_name))
|
||||
{
|
||||
ret = m_node_name_mapping[node_name];
|
||||
for (const ref_t dep : dependents)
|
||||
{
|
||||
if (m_nodes[ret].m_dependents.insert(dep).second)
|
||||
m_nodes[dep].m_num_pending_dependencies += m_nodes[ret].m_state != FULFILLED;
|
||||
}
|
||||
}
|
||||
// Otherwise create the node and add the dependencies to it
|
||||
else
|
||||
{
|
||||
ret = (ref_t)m_nodes.size();
|
||||
node n;
|
||||
n.m_dependents = std::set<ref_t>(dependents.cbegin(), dependents.cend());
|
||||
size_t sl = strlen(node_name);
|
||||
char* local_name = new char[sl + 1];
|
||||
local_name[sl] = '\0';
|
||||
memcpy(local_name, node_name, sl);
|
||||
n.m_name = local_name;
|
||||
n.m_num_pending_dependencies = 0;
|
||||
n.m_state = WAITING;
|
||||
n.m_userdata = 0;
|
||||
m_nodes.push_back(std::move(n));
|
||||
m_node_name_mapping[local_name] = ret;
|
||||
for (const ref_t dep : dependents)
|
||||
m_nodes[dep].m_num_pending_dependencies += m_nodes.back().m_state != FULFILLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
dependency_tree::ref_t dependency_tree::add_node(const char* node_name, const dynarray<const char*>& dependents)
|
||||
{
|
||||
dynarray<ref_t> ref_dependents;
|
||||
for (const char* dep : dependents)
|
||||
ref_dependents.push_back(m_node_name_mapping[dep]);
|
||||
return this->add_node(node_name, ref_dependents);
|
||||
}
|
||||
|
||||
dependency_tree::ref_t dependency_tree::add_node(const char* node_name, const std::initializer_list<ref_t>& dependents)
|
||||
{ return this->add_node(node_name, dynarray<ref_t>(dependents)); }
|
||||
|
||||
dependency_tree::ref_t dependency_tree::add_node(const char* node_name, const std::initializer_list<const char*>& dependents)
|
||||
{
|
||||
dynarray<ref_t> ref_dependents;
|
||||
for (const char* dep : dependents)
|
||||
ref_dependents.push_back(m_node_name_mapping[dep]);
|
||||
return this->add_node(node_name, ref_dependents);
|
||||
}
|
||||
|
||||
dependency_tree::ref_t dependency_tree::add_node(const char* node_name)
|
||||
{
|
||||
if (!m_node_name_mapping.contains(node_name))
|
||||
{
|
||||
ref_t ret = (ref_t)m_nodes.size();
|
||||
node n;
|
||||
n.m_dependents = std::set<ref_t>();
|
||||
size_t sl = strlen(node_name);
|
||||
char* local_name = new char[sl + 1];
|
||||
local_name[sl] = '\0';
|
||||
memcpy(local_name, node_name, sl);
|
||||
n.m_name = local_name;
|
||||
n.m_num_pending_dependencies = 0;
|
||||
n.m_state = WAITING;
|
||||
n.m_userdata = 0;
|
||||
m_nodes.push_back(std::move(n));
|
||||
m_node_name_mapping[local_name] = ret;
|
||||
return ret;
|
||||
}
|
||||
return m_node_name_mapping[node_name];
|
||||
}
|
||||
|
||||
void dependency_tree::add_node_dependency(const ref_t node, const ref_t dependency)
|
||||
{
|
||||
if (m_nodes[dependency].m_dependents.insert(node).second)
|
||||
m_nodes[node].m_num_pending_dependencies++;
|
||||
}
|
||||
|
||||
void dependency_tree::add_node_dependency(const ref_t node, const char* dependency)
|
||||
{ this->add_node_dependency(node, m_node_name_mapping[dependency]); }
|
||||
|
||||
void dependency_tree::add_node_dependency(const char* node, const ref_t dependency)
|
||||
{ this->add_node_dependency(m_node_name_mapping[node], dependency); }
|
||||
|
||||
void dependency_tree::add_node_dependency(const char* node, const char* dependency)
|
||||
{ this->add_node_dependency(m_node_name_mapping[node], m_node_name_mapping[dependency]); }
|
||||
|
||||
void dependency_tree::add_node_dependencies(const ref_t node, const std::initializer_list<ref_t>& dependencies)
|
||||
{
|
||||
for (const ref_t& dep : dependencies)
|
||||
this->add_node_dependency(node, dep);
|
||||
}
|
||||
|
||||
void dependency_tree::add_node_dependencies(const ref_t node, const dynarray<ref_t>& dependencies)
|
||||
{
|
||||
for (const ref_t& dep : dependencies)
|
||||
this->add_node_dependency(node, dep);
|
||||
}
|
||||
void dependency_tree::add_node_dependencies(const ref_t node, const std::initializer_list<const char*>& dependencies)
|
||||
{
|
||||
for (const char* dep : dependencies)
|
||||
this->add_node_dependency(node, dep);
|
||||
}
|
||||
|
||||
void dependency_tree::add_node_dependencies(const ref_t node, const dynarray<const char*>& dependencies)
|
||||
{
|
||||
for (const char* dep : dependencies)
|
||||
this->add_node_dependency(node, dep);
|
||||
}
|
||||
|
||||
dependency_tree::~dependency_tree() {}
|
||||
|
||||
dependency_tree::node::node(node&& other) noexcept
|
||||
{
|
||||
this->m_dependents = std::move(other.m_dependents);
|
||||
this->m_name = other.m_name;
|
||||
this->m_num_pending_dependencies = other.m_num_pending_dependencies;
|
||||
this->m_state = other.m_state;
|
||||
this->m_userdata = other.m_userdata;
|
||||
other.m_name = nullptr;
|
||||
other.m_num_pending_dependencies = -1;
|
||||
other.m_state = -1;
|
||||
other.m_userdata = -1;
|
||||
}
|
||||
|
||||
dependency_tree::node& dependency_tree::node::operator=(node&& other) noexcept
|
||||
{
|
||||
if (this == &other) return *this;
|
||||
|
||||
if (this->m_name != nullptr) delete[] m_name;
|
||||
|
||||
this->m_dependents = std::move(other.m_dependents);
|
||||
this->m_name = other.m_name;
|
||||
this->m_num_pending_dependencies = other.m_num_pending_dependencies;
|
||||
this->m_state = other.m_state;
|
||||
this->m_userdata = other.m_userdata;
|
||||
other.m_name = nullptr;
|
||||
other.m_num_pending_dependencies = -1;
|
||||
other.m_state = -1;
|
||||
other.m_userdata = -1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dependency_tree::node::node()
|
||||
{
|
||||
this->m_name = nullptr;
|
||||
this->m_num_pending_dependencies = -1;
|
||||
this->m_state = -1;
|
||||
this->m_userdata = -1;
|
||||
}
|
||||
|
||||
dependency_tree::node::~node()
|
||||
{
|
||||
if (m_name == nullptr) return;
|
||||
delete[] m_name;
|
||||
}
|
||||
|
||||
|
||||
int luaopen_dependency_tree(lua_State* L)
|
||||
{
|
||||
luaL_newmetatable(L, "lbs.dependency_tree");
|
||||
|
||||
lua_pushcfunction(L, lua_dependency_destroy);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
lua_pushcfunction(L, lua_dependency_add_node);
|
||||
lua_setfield(L, -2, "add_node");
|
||||
lua_pushcfunction(L, lua_dependency_add_dependency);
|
||||
lua_setfield(L, -2, "add_dependency");
|
||||
lua_pushcfunction(L, lua_dependency_add_dependencies);
|
||||
lua_setfield(L, -2, "add_dependencies");
|
||||
lua_pushcfunction(L, lua_dependency_remove_dependency);
|
||||
lua_setfield(L, -2, "remove_dependency");
|
||||
lua_pushcfunction(L, lua_dependency_remove_dependencies);
|
||||
lua_setfield(L, -2, "remove_dependencies");
|
||||
lua_pushcfunction(L, lua_dependency_get_leafs);
|
||||
lua_setfield(L, -2, "get_leafs");
|
||||
lua_pushcfunction(L, lua_dependency_match_nodes);
|
||||
lua_setfield(L, -2, "match");
|
||||
lua_pushcfunction(L, lua_dependency_set_node_state);
|
||||
lua_setfield(L, -2, "set_state");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_state);
|
||||
lua_setfield(L, -2, "get_state");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_userval);
|
||||
lua_setfield(L, -2, "get_userval");
|
||||
lua_pushcfunction(L, lua_dependency_set_node_userval);
|
||||
lua_setfield(L, -2, "set_userval");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_name);
|
||||
lua_setfield(L, -2, "get_name");
|
||||
lua_pushcfunction(L, lua_dependency_get_node);
|
||||
lua_setfield(L, -2, "get_node");
|
||||
|
||||
//lua_pushcfunction(L, lua_dependency_index);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushcfunction(L, lua_dependency_create);
|
||||
lua_setfield(L, -2, "create");
|
||||
lua_pushcfunction(L, lua_dependency_add_node);
|
||||
lua_setfield(L, -2, "add_node");
|
||||
lua_pushcfunction(L, lua_dependency_add_dependency);
|
||||
lua_setfield(L, -2, "add_dependency");
|
||||
lua_pushcfunction(L, lua_dependency_add_dependencies);
|
||||
lua_setfield(L, -2, "add_dependencies");
|
||||
lua_pushcfunction(L, lua_dependency_remove_dependency);
|
||||
lua_setfield(L, -2, "remove_dependency");
|
||||
lua_pushcfunction(L, lua_dependency_remove_dependencies);
|
||||
lua_setfield(L, -2, "remove_dependencies");
|
||||
lua_pushcfunction(L, lua_dependency_get_leafs);
|
||||
lua_setfield(L, -2, "get_leafs");
|
||||
lua_pushcfunction(L, lua_dependency_match_nodes);
|
||||
lua_setfield(L, -2, "match");
|
||||
lua_pushcfunction(L, lua_dependency_set_node_state);
|
||||
lua_setfield(L, -2, "set_state");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_state);
|
||||
lua_setfield(L, -2, "get_state");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_userval);
|
||||
lua_setfield(L, -2, "get_userval");
|
||||
lua_pushcfunction(L, lua_dependency_set_node_userval);
|
||||
lua_setfield(L, -2, "set_userval");
|
||||
lua_pushcfunction(L, lua_dependency_get_node_name);
|
||||
lua_setfield(L, -2, "get_name");
|
||||
lua_pushcfunction(L, lua_dependency_get_node);
|
||||
lua_setfield(L, -2, "get_node");
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, "dependency_tree");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dependency_tree* get_lua_dependency_tree(lua_State* L, int idx)
|
||||
{ return (dependency_tree*)luaL_checkudata(L, idx, "lbs.dependency_tree"); }
|
||||
|
||||
dependency_tree::ref_t get_lua_dependency_ref(dependency_tree* tree, lua_State* L, int idx)
|
||||
{
|
||||
if (lua_isnumber(L, idx))
|
||||
{
|
||||
if (lua_tonumber(L, idx) >= tree->m_nodes.size()) return -1;
|
||||
return lua_tonumber(L, idx);
|
||||
}
|
||||
else if (lua_isstring(L, idx))
|
||||
{
|
||||
const char* name = lua_tostring(L, idx);
|
||||
if (tree->m_node_name_mapping.contains(name)) return tree->m_node_name_mapping[name];
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lua_dependency_create(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = (dependency_tree*)lua_newuserdata(L, sizeof(dependency_tree));
|
||||
new (tree) dependency_tree();
|
||||
luaL_getmetatable(L, "lbs.dependency_tree");
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_destroy(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, -1);
|
||||
if (tree == nullptr) return 0;
|
||||
tree->~dependency_tree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_add_node(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "Expected first argument to be a string of the dependency nodes name");
|
||||
int t = lua_type(L, 3);
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TTABLE || lua_type(L, 3) <= LUA_TNIL, 3, "Expected second argument to be a table of the names or references of the dependents or nil");
|
||||
|
||||
const char* node_name = lua_tostring(L, 2);
|
||||
|
||||
if (lua_type(L, 3) == LUA_TTABLE)
|
||||
{
|
||||
static dynarray<dependency_tree::ref_t> dependent_nodes;
|
||||
dependent_nodes.resize(0);
|
||||
dependent_nodes.reserve(lua_objlen(L, 3));
|
||||
for (size_t i = 1; i < lua_objlen(L, 3); ++i)
|
||||
{
|
||||
lua_rawgeti(L, 3, i);
|
||||
if (lua_type(L, -1) != LUA_TSTRING && lua_type(L, -1) != LUA_TNUMBER)
|
||||
return luaL_error(L, "Expected value %d in second argument to be a string or reference, not %s", i, lua_typename(L, lua_type(L, -1)));
|
||||
dependency_tree::ref_t n = get_lua_dependency_ref(tree, L, -1);
|
||||
if (n == -1)
|
||||
return luaL_error(L, "Expected value %d in second argument to be a valid node name or reference", i);
|
||||
dependent_nodes.push_back(n);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pushinteger(L, tree->add_node(node_name, dependent_nodes));
|
||||
}
|
||||
else
|
||||
lua_pushinteger(L, tree->add_node(node_name));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_add_dependency(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING || lua_type(L, 2) == LUA_TNUMBER, 2, "Expected first argument to be a string of the dependency nodes name or a reference to it");
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TSTRING || lua_type(L, 3) == LUA_TNUMBER, 3, "Expected second argument to be a string of the dependent node's name or a reference to it");
|
||||
dependency_tree::ref_t dependency = get_lua_dependency_ref(tree, L, 2);
|
||||
if (dependency == -1)
|
||||
return luaL_error(L, "Expected first argument to be a valid name or reference to a node");
|
||||
dependency_tree::ref_t dependent = get_lua_dependency_ref(tree, L, 3);
|
||||
if (dependent == -1)
|
||||
return luaL_error(L, "Expected second argument to be a valid name or reference to a node");
|
||||
tree->add_node_dependency(dependency, dependent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_remove_dependency(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t dependency = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, dependency != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
dependency_tree::ref_t dependent = get_lua_dependency_ref(tree, L, 3);
|
||||
luaL_argcheck(L, dependent != -1, 3, "Expected second argument to be a valid node name or reference");
|
||||
tree->m_nodes[dependent].m_dependents.erase(dependency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_add_dependencies(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t dependency = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, dependency != -1, 1, "Expected first argument to be a valid name or reference to a node");
|
||||
|
||||
static dynarray<dependency_tree::ref_t> dependents;
|
||||
dependents.resize(0); // Clear prior values
|
||||
dependents.reserve(lua_gettop(L)); // This is approx. equal to top-2
|
||||
for (size_t idx = 3; idx < lua_gettop(L); ++idx)
|
||||
{
|
||||
if (lua_type(L, idx) == LUA_TTABLE)
|
||||
{
|
||||
int tbl_len = lua_objlen(L, idx);
|
||||
for (size_t i = 1; i < tbl_len; ++i)
|
||||
{
|
||||
lua_rawgeti(L, idx, i);
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, idx);
|
||||
if (ref == -1)
|
||||
return luaL_error(L, "Expected argument %d[%d] to be a valid name or reference of a node", idx - 2, i);
|
||||
dependents.push_back(ref);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, idx);
|
||||
if (ref == -1)
|
||||
return luaL_error(L, "Expected argument %d to be a valid name or reference of a node", idx-2);
|
||||
dependents.push_back(ref);
|
||||
}
|
||||
}
|
||||
|
||||
tree->add_node_dependencies(dependency, dependents);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_remove_dependencies(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t dependency = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, dependency != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
|
||||
for (size_t idx = 3; idx < lua_gettop(L); ++idx)
|
||||
{
|
||||
if (lua_type(L, idx) == LUA_TTABLE)
|
||||
{
|
||||
int tbl_len = lua_objlen(L, 3);
|
||||
for (int i = 1; i < tbl_len; ++i)
|
||||
{
|
||||
lua_rawgeti(L, idx, i);
|
||||
dependency_tree::ref_t dependent = get_lua_dependency_ref(tree, L, -1);
|
||||
if (dependent != -1)
|
||||
return luaL_error(L, "Expected argument %d[%d] to be a valid name or reference to a node", idx-2,i);
|
||||
tree->m_nodes[dependent].m_dependents.erase(dependency);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const dependency_tree::ref_t dependent = get_lua_dependency_ref(tree, L, idx);
|
||||
if (dependent != -1)
|
||||
return luaL_error(L, "Expected argument %d to be a valid name or reference to a node", idx - 2);
|
||||
tree->m_nodes[dependent].m_dependents.erase(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_get_leafs(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dynarray<dependency_tree::ref_t> leafs;
|
||||
if (lua_isboolean(L, 2) && (lua_toboolean(L, 2) > 0))
|
||||
leafs = tree->get_leaf_nodes();
|
||||
else
|
||||
leafs = tree->get_leaf_nodes(false);
|
||||
|
||||
lua_newtable(L);
|
||||
for (const dependency_tree::ref_t leaf : leafs)
|
||||
{
|
||||
lua_pushinteger(L, leaf);
|
||||
lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_match_nodes(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
luaL_argcheck(L, lua_type(L, 2) == LUA_TNUMBER || lua_type(L, 2) <= LUA_TNIL, 2, "Expected first argument to be a number or nil. This is what states need to be true\n\tFulfiled = 1\n\tFailed = 2\n\tWorking = 4\n\tWaiting = 8");
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TNUMBER || lua_type(L, 3) <= LUA_TNIL, 3, "Expected second argument to be a number or nil. This is the least number of pending dependencies a node needs to have to pass");
|
||||
luaL_argcheck(L, lua_type(L, 4) == LUA_TBOOLEAN || lua_type(L, 4) <= LUA_TNIL, 4, "Expected third argument to be a boolean or nil. This controls whether the number of pending dependencies is greater or less-equal");
|
||||
|
||||
dynarray<dependency_tree::ref_t> matches = tree->filter_nodes(
|
||||
lua_tointeger(L, 2) & 0b1111,
|
||||
lua_tointeger(L, 3),
|
||||
lua_toboolean(L, 3) > 0
|
||||
);
|
||||
|
||||
lua_newtable(L);
|
||||
for (const dependency_tree::ref_t match : matches)
|
||||
{
|
||||
lua_pushinteger(L, match);
|
||||
lua_rawseti(L, -2, lua_objlen(L, -2)+1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_set_node_state(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t node = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, node != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TNUMBER || lua_type(L, 3) == LUA_TSTRING, 3, "Expected second argument to be a number or string of the state\n\t0 = FULFILLED\n\t1 = FAILED\n\t2 = WAITING\n\t3 = WORKING");
|
||||
|
||||
uint8_t new_state;
|
||||
if (lua_type(L, 3) == LUA_TNUMBER)
|
||||
new_state = lua_tointeger(L, 3) & 0b11;
|
||||
else
|
||||
{
|
||||
const char* state_name = lua_tostring(L, 3);
|
||||
if (strcmp(state_name, "FULFILLED") == 0 || strcmp(state_name, "fulfilled") == 0)
|
||||
new_state = dependency_tree::FULFILLED;
|
||||
else if (strcmp(state_name, "FAILED") == 0 || strcmp(state_name, "failed") == 0)
|
||||
new_state = dependency_tree::FAILED;
|
||||
else if (strcmp(state_name, "WAITING") == 0 || strcmp(state_name, "waiting") == 0)
|
||||
new_state = dependency_tree::WAITING;
|
||||
else if (strcmp(state_name, "WORKING") == 0 || strcmp(state_name, "working") == 0)
|
||||
new_state = dependency_tree::WORKING;
|
||||
else return luaL_error(L, "Expected seconda argument to be fulfilled, failed, waiting or working not %s", state_name);
|
||||
}
|
||||
|
||||
tree->set_node_state(node, new_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_get_node_userval(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, ref != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
|
||||
lua_pushinteger(L, tree->m_nodes[ref].m_userdata);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_set_node_userval(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, ref != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TNUMBER, 3, "Expected second argument to be a 30-bit number");
|
||||
|
||||
tree->m_nodes[ref].m_userdata = lua_tointeger(L, 3) & 0x3FFFFFFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_dependency_get_node_state(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, ref != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
|
||||
const dependency_tree::node& node = tree->m_nodes[ref];
|
||||
if (node.m_state == dependency_tree::FULFILLED) lua_pushstring(L, "fulfilled");
|
||||
else if (node.m_state == dependency_tree::FAILED) lua_pushstring(L, "failed");
|
||||
else if (node.m_state == dependency_tree::WAITING) lua_pushstring(L, "waiting");
|
||||
else if (node.m_state == dependency_tree::WORKING) lua_pushstring(L, "working");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_get_node_name(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, ref != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
|
||||
lua_pushstring(L, tree->m_nodes[ref].m_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dependency_get_node(lua_State* L)
|
||||
{
|
||||
dependency_tree* tree = get_lua_dependency_tree(L, 1);
|
||||
luaL_argcheck(L, tree != nullptr, 1, "Expected implicit argument to be userdata<dependency_tree>");
|
||||
const dependency_tree::ref_t ref = get_lua_dependency_ref(tree, L, 2);
|
||||
luaL_argcheck(L, ref != -1, 2, "Expected first argument to be a valid node name or reference");
|
||||
|
||||
const dependency_tree::node& node = tree->m_nodes[ref];
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "name");
|
||||
lua_pushstring(L, node.m_name);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "pending_dependencies");
|
||||
lua_pushinteger(L, node.m_num_pending_dependencies);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "state");
|
||||
if (node.m_state == dependency_tree::FULFILLED) lua_pushstring(L, "fulfilled");
|
||||
else if (node.m_state == dependency_tree::FAILED) lua_pushstring(L, "failed");
|
||||
else if (node.m_state == dependency_tree::WAITING) lua_pushstring(L, "waiting");
|
||||
else if (node.m_state == dependency_tree::WORKING) lua_pushstring(L, "working");
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "userdata");
|
||||
lua_pushinteger(L, node.m_userdata);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "dependents");
|
||||
lua_newtable(L);
|
||||
for (const dependency_tree::ref_t dependent : node.m_dependents)
|
||||
{
|
||||
lua_pushinteger(L, dependent);
|
||||
lua_rawseti(L, -2, lua_objlen(L, -2));
|
||||
}
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
331
src/lua_filesystem.cpp
Normal file
331
src/lua_filesystem.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
#include "lua_filesystem.h"
|
||||
#include <filesystem>
|
||||
|
||||
int luaopen_filesystem(lua_State* L)
|
||||
{
|
||||
luaL_newmetatable(L, "fs.file_handle");
|
||||
|
||||
// Push iterator state metatables
|
||||
luaL_newmetatable(L, "fs.stdlibcpp.filesystem.directory_iterator");
|
||||
lua_pushcfunction(L, lua_fs_foreach_dir_dtor);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
luaL_newmetatable(L, "fs.stdlibcpp.filesystem.recursive_directory_iterator");
|
||||
lua_pushcfunction(L, lua_fs_forall_dir_dtor);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
|
||||
|
||||
// Push functions
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushcfunction(L, lua_fs_absolute);
|
||||
lua_setfield(L, -2, "absolute");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_create_dir);
|
||||
lua_setfield(L, -2, "create_dir");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_exists);
|
||||
lua_setfield(L, -2, "exists");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_file_directory);
|
||||
lua_setfield(L, -2, "dir");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_file_extension);
|
||||
lua_setfield(L, -2, "extension");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_file_name);
|
||||
lua_setfield(L, -2, "file_name");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_forall_dir);
|
||||
lua_setfield(L, -2, "forall");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_foreach_dir);
|
||||
lua_setfield(L, -2, "foreach");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_is_dir);
|
||||
lua_setfield(L, -2, "is_dir");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_is_file);
|
||||
lua_setfield(L, -2, "is_file");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_last_modified);
|
||||
lua_setfield(L, -2, "last_modified");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_list_dir);
|
||||
lua_setfield(L, -2, "list_dir");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_list_alldirs);
|
||||
lua_setfield(L, -2, "list_alldirs");
|
||||
|
||||
lua_pushcfunction(L, lua_fs_relative);
|
||||
lua_setfield(L, -2, "relative_to");
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, "fs");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_list_dir(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a path to make the second argument relative to");
|
||||
const char* fpath = lua_tostring(L, 1);
|
||||
lua_newtable(L);
|
||||
uint32_t i = 1;
|
||||
for (const std::filesystem::path& p : std::filesystem::directory_iterator(fpath))
|
||||
{
|
||||
const std::string x = p.string();
|
||||
lua_pushlstring(L, x.c_str(), x.size());
|
||||
lua_rawseti(L, -2, i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_list_alldirs(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a path to make the second argument relative to");
|
||||
const char* fpath = lua_tostring(L, 1);
|
||||
lua_newtable(L);
|
||||
uint32_t i = 1;
|
||||
for (const std::filesystem::path& p : std::filesystem::directory_iterator(fpath))
|
||||
{
|
||||
const std::string x = p.string();
|
||||
lua_pushlstring(L, x.c_str(), x.size());
|
||||
lua_rawseti(L, -2, i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_foreach_dir(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a path");
|
||||
const char* path = lua_tostring(L, 1);
|
||||
|
||||
void* ud = lua_newuserdata(L, sizeof(std::filesystem::directory_iterator));
|
||||
new (ud) std::filesystem::directory_iterator(path);
|
||||
|
||||
luaL_getmetatable(L, "fs.stdlibcpp.filesystem.directory_iterator");
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushcclosure(L, lua_fs_foreach_dir_next, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_forall_dir(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a path");
|
||||
const char* path = lua_tostring(L, 1);
|
||||
|
||||
void* ud = lua_newuserdata(L, sizeof(std::filesystem::recursive_directory_iterator));
|
||||
new (ud) std::filesystem::recursive_directory_iterator(path);
|
||||
|
||||
luaL_getmetatable(L, "fs.stdlibcpp.filesystem.recursive_directory_iterator");
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushcclosure(L, lua_fs_forall_dir_next, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_foreach_dir_next(lua_State* L)
|
||||
{
|
||||
int idx = lua_upvalueindex(1);
|
||||
luaL_argcheck(L, lua_type(L, idx) == LUA_TUSERDATA, 1, "Expected first argument to fs.foreach_dir_next to be userdata<std::filesystem::directory_iterator>");
|
||||
void* ud = luaL_checkudata(L, idx, "fs.stdlibcpp.filesystem.directory_iterator");
|
||||
luaL_argcheck(L, ud != nullptr, 1, "Expected first argument's userdata type to be a std::filesystem::directory_iterator");
|
||||
std::filesystem::directory_iterator& x = *(std::filesystem::directory_iterator*)ud;
|
||||
if (x._At_end())
|
||||
return 0;
|
||||
std::string p = (*x).path().string();
|
||||
lua_pushlstring(L, p.c_str(), p.size());
|
||||
x++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_forall_dir_next(lua_State* L)
|
||||
{
|
||||
int idx = lua_upvalueindex(1);
|
||||
luaL_argcheck(L, lua_type(L, idx) == LUA_TUSERDATA, 1, "Expected first argument to fs.forall_dir_next to be userdata<std::filesystem::recursive_directory_iterator>");
|
||||
void* ud = luaL_checkudata(L, idx, "fs.stdlibcpp.filesystem.recursive_directory_iterator");
|
||||
luaL_argcheck(L, ud != nullptr, 1, "Expected first argument's userdata type to be a std::filesystem::recursive_directory_iterator");
|
||||
std::filesystem::recursive_directory_iterator& x = *(std::filesystem::recursive_directory_iterator*)ud;
|
||||
if (x == std::filesystem::recursive_directory_iterator{})
|
||||
return 0;
|
||||
std::string p = (*x).path().string();
|
||||
lua_pushlstring(L, p.c_str(), p.size());
|
||||
x++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_foreach_dir_dtor(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TUSERDATA, 1, "Expected first argument to fs.foreach_dir_next to be userdata<std::filesystem::directory_iterator>");
|
||||
void* ud = luaL_checkudata(L, 1, "fs.stdlibcpp.filesystem.directory_iterator");
|
||||
luaL_argcheck(L, ud != nullptr, 1, "Expected first argument's userdata type to be a std::filesystem::directory_iterator");
|
||||
std::filesystem::directory_iterator& x = *(std::filesystem::directory_iterator*)ud;
|
||||
x.~directory_iterator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_forall_dir_dtor(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TUSERDATA, 1, "Expected first argument to fs.forall_dir_next to be userdata<std::filesystem::recursive_directory_iterator>");
|
||||
void* ud = luaL_checkudata(L, 1, "fs.stdlibcpp.filesystem.recursive_directory_iterator");
|
||||
luaL_argcheck(L, ud != nullptr, 1, "Expected first argument's userdata type to be a std::filesystem::recursive_directory_iterator");
|
||||
std::filesystem::recursive_directory_iterator& x = *(std::filesystem::recursive_directory_iterator*)ud;
|
||||
x.~recursive_directory_iterator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_relative(lua_State* L)
|
||||
{
|
||||
try {
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a path to make the second argument relative to");
|
||||
luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "Expected second argument to be a string representing a full file path");
|
||||
const std::string f = std::filesystem::relative(std::filesystem::path(lua_tostring(L, 1)), std::filesystem::path(lua_tostring(L, 2))).string();
|
||||
lua_pushlstring(L, f.c_str(), f.size());
|
||||
return 1;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int lua_fs_absolute(lua_State* L)
|
||||
{
|
||||
try {
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
const std::string f = std::filesystem::absolute(std::filesystem::path(lua_tostring(L, 1))).string();
|
||||
lua_pushlstring(L, f.c_str(), f.size());
|
||||
return 1;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int lua_fs_file_name(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
const std::string f = std::filesystem::path(lua_tostring(L, 1)).filename().string();
|
||||
lua_pushlstring(L, f.c_str(), f.size());
|
||||
return 1;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int lua_fs_file_extension(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
const std::string f = std::filesystem::path(lua_tostring(L, 1)).extension().string();
|
||||
lua_pushlstring(L, f.c_str(), f.size());
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_fs_file_directory(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
const std::string f = std::filesystem::path(lua_tostring(L, 1)).remove_filename().string();
|
||||
lua_pushlstring(L, f.c_str(), f.size());
|
||||
return 1;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_last_modified(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
lua_pushinteger(L, std::filesystem::last_write_time(std::filesystem::path(lua_tostring(L, 1))).time_since_epoch().count());
|
||||
return 1;
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_exists(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
lua_pushboolean(L, std::filesystem::exists(lua_tostring(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_is_dir(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
lua_pushboolean(L, std::filesystem::is_directory(lua_tostring(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_is_file(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
lua_pushboolean(L, std::filesystem::is_regular_file(lua_tostring(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_fs_create_dir(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a full file path");
|
||||
try {
|
||||
lua_pushboolean(L, std::filesystem::create_directories(lua_tostring(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, e.what());
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
191
src/lua_platform.cpp
Normal file
191
src/lua_platform.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "lua_platform.h"
|
||||
#include "platform_agnostic.h"
|
||||
#include "dynarray.hpp"
|
||||
#include "mutex"
|
||||
#include <chrono>
|
||||
#include "simple_string.h"
|
||||
|
||||
int luaopen_platform(lua_State* L)
|
||||
{
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushcfunction(L, lua_platform_exec);
|
||||
lua_setfield(L, -2, "exec");
|
||||
lua_pushcfunction(L, lua_platform_exec_parallel);
|
||||
lua_setfield(L, -2, "exec_parallel");
|
||||
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, "platform");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_platform_exec(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_isstring(L, 1), 1, "Expected first argument to be a string");
|
||||
luaL_argcheck(L, lua_istable(L, 2), 2, "Expected second argument to be a table of strings");
|
||||
std::string cmd(lua_tostring(L, 1));
|
||||
size_t nargs = lua_objlen(L, 2);
|
||||
for (size_t i = 0; i < nargs; ++i)
|
||||
{
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
if (!lua_isstring(L, -1))
|
||||
return luaL_error(L, "Expected all values in argument table to be a string. Index %d was a %s", i, lua_typename(L, lua_type(L, -1)));
|
||||
cmd.append(" ").append(lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
FILE* f = popen(cmd.c_str(), "r");
|
||||
char buf[64];
|
||||
std::string result;
|
||||
while (fgets(buf, sizeof(buf), f) != NULL)
|
||||
result.append(buf);
|
||||
|
||||
lua_pushinteger(L, pclose(f));
|
||||
lua_pushlstring(L, result.c_str(), result.size());
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
struct command_stack
|
||||
{
|
||||
std::string base_cmd;
|
||||
dynarray<dynarray<std::string>> commands;
|
||||
std::recursive_mutex mux;
|
||||
|
||||
size_t num_cmds(void) const noexcept
|
||||
{ return commands.size(); }
|
||||
bool is_empty(void) const noexcept
|
||||
{ return commands.size() == 0; }
|
||||
std::pair<dynarray<std::string>, size_t> get_command(void) noexcept
|
||||
{
|
||||
std::scoped_lock lock(mux);
|
||||
const size_t sz = commands.size();
|
||||
return std::make_pair(std::move(commands.pop_back()),sz-1);
|
||||
}
|
||||
};
|
||||
struct result_stack
|
||||
{
|
||||
struct result
|
||||
{
|
||||
std::string program_output;
|
||||
int program_ret;
|
||||
};
|
||||
|
||||
std::recursive_mutex mux;
|
||||
dynarray<result> results;
|
||||
|
||||
void add_result(const size_t idx, const std::string& out, const int ret)
|
||||
{
|
||||
std::scoped_lock lock(mux);
|
||||
new (results.data() + idx) result(out, ret);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void worker_thread(std::stop_token token, const std::string& base_cmd, command_stack& in, result_stack& out)
|
||||
{
|
||||
char buf[64];
|
||||
while (!token.stop_requested())
|
||||
{
|
||||
std::string cmd = base_cmd;
|
||||
if (in.is_empty()) return;
|
||||
auto [arg, idx] = in.get_command();
|
||||
// Get a command
|
||||
|
||||
for (const std::string& a : arg)
|
||||
cmd.append(" ").append(a);
|
||||
|
||||
// Run the command
|
||||
FILE* f = popen(cmd.c_str(), "r");
|
||||
|
||||
// Capture the commands stdout
|
||||
std::string pout = "";
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
while (fgets(buf, sizeof(buf), f) != NULL)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(10us);
|
||||
pout.append(buf);
|
||||
}
|
||||
|
||||
// Await the program to exit
|
||||
int rc = pclose(f);
|
||||
out.add_result(idx, pout, rc);
|
||||
}
|
||||
}
|
||||
|
||||
int lua_platform_exec_parallel(lua_State* L)
|
||||
{
|
||||
luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "Expected first argument to be a string representing a command");
|
||||
luaL_argcheck(L, lua_type(L, 2) == LUA_TNUMBER, 2, "Expected second argument to be an integer representing the maximum number of parallel jobs to start");
|
||||
luaL_argcheck(L, lua_type(L, 3) == LUA_TTABLE, 3, "Expected third argument to be a table of table of strings representing the arguments");
|
||||
std::string base_cmd(lua_tostring(L, 1));
|
||||
const size_t max_parallel = lua_tointeger(L, 2);
|
||||
const size_t num_cmds = lua_objlen(L, 3);
|
||||
|
||||
command_stack in;
|
||||
in.base_cmd = base_cmd;
|
||||
result_stack out;
|
||||
for (size_t i = 0; i < num_cmds; ++i)
|
||||
out.results.push_back(result_stack::result{"Not Executed",-1});
|
||||
|
||||
// Generate the command stack from lua arguments
|
||||
for (size_t i = 0; i < num_cmds; ++i)
|
||||
{
|
||||
lua_rawgeti(L, 3, i + 1);
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
const size_t num_args = lua_objlen(L, -1);
|
||||
in.commands.push_back(dynarray<std::string>());
|
||||
dynarray<std::string>& back = in.commands.back();
|
||||
for (size_t j = 0; j < num_args; ++j)
|
||||
{
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
if (!lua_isstring(L, -1))
|
||||
return luaL_error(L, "Expected program argument to be a string. args[%d][%d] was a %s, not a string!\n", i, j, lua_typename(L, lua_type(L, -1)));
|
||||
std::string str(lua_tostring(L, -1), lua_objlen(L, -1));
|
||||
back.push_back(std::move(str));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else if (lua_type(L, -1) == LUA_TSTRING)
|
||||
{
|
||||
in.commands.push_back(dynarray<std::string>());
|
||||
in.commands.back().push_back(lua_tostring(L, -1));
|
||||
}
|
||||
else
|
||||
return luaL_error(L, "Expected a table of program arguments. args[%d] was a %s, not a table!\n", i, lua_typename(L, lua_type(L, -1)));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
// Dispatch worker threads
|
||||
std::vector<std::jthread> workers;
|
||||
for (size_t i = 0; i < max_parallel; ++i)
|
||||
workers.push_back(std::jthread(worker_thread,
|
||||
std::ref(base_cmd),
|
||||
std::ref(in),
|
||||
std::ref(out)
|
||||
));
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
while (!in.is_empty())
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
for (size_t i = 0; i < workers.size(); ++i)
|
||||
workers[i].request_stop();
|
||||
for (size_t i = 0; i < workers.size(); ++i)
|
||||
workers[i].join();
|
||||
|
||||
// Join thread results together and push them to lua stack
|
||||
lua_newtable(L); // rc
|
||||
lua_newtable(L); // stdout
|
||||
for (size_t i = 0; i < out.results.size(); ++i)
|
||||
{
|
||||
const result_stack::result& x = out.results[i];
|
||||
lua_pushinteger(L, x.program_ret);
|
||||
lua_rawseti(L, -3, i+1);
|
||||
lua_pushlstring(L, x.program_output.c_str(), x.program_output.size());
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
116
src/main.cpp
Normal file
116
src/main.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "lua_dependency_tree.h"
|
||||
#include "lua_platform.h"
|
||||
#include "lua_filesystem.h"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
// From lua
|
||||
static int msghandler(lua_State* L) {
|
||||
if (!lua_isstring(L, 1)) /* 'message' not a string? */
|
||||
return 1; /* keep it intact */
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushvalue(L, 1); /* pass error message */
|
||||
lua_pushinteger(L, 2); /* skip this function and traceback */
|
||||
lua_call(L, 2, 1); /* call debug.traceback */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* exec_file = "lbs.lua";
|
||||
int argstart = 1;
|
||||
if (argc > 2 && (
|
||||
strcmp(argv[1], "--buildscript") == 0 ||
|
||||
strcmp(argv[1], "-s") == 0))
|
||||
{
|
||||
exec_file = argv[2];
|
||||
argstart += 2;
|
||||
}
|
||||
if (!std::filesystem::exists(exec_file))
|
||||
{
|
||||
fprintf(stderr, "Failed to find buildscript %s to execute\n", exec_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
luaopen_dependency_tree(L);
|
||||
luaopen_platform(L);
|
||||
luaopen_filesystem(L);
|
||||
|
||||
|
||||
luaL_loadfile(L, exec_file);
|
||||
for (int i = (argstart+1); i < argc; ++i)
|
||||
lua_pushstring(L, argv[i]);
|
||||
int err = LUA_OK;
|
||||
int msg_base = lua_gettop(L) - argc - argstart - 1;
|
||||
lua_pushcfunction(L, msghandler);
|
||||
lua_insert(L, msg_base);
|
||||
if ( (err = lua_pcall(L, argc - argstart - 1, LUA_MULTRET, msg_base)) != LUA_OK)
|
||||
{
|
||||
if (err == LUA_ERRRUN)
|
||||
fprintf(stderr, "A runtime error when running the script %s has occured\n%s\n", exec_file, lua_tostring(L, -1));
|
||||
else if (err == LUA_ERRMEM)
|
||||
fprintf(stderr, "A memory allocation error when running the script %s has occured\n%s\n", exec_file, lua_tostring(L, -1));
|
||||
else if (err == LUA_ERRERR)
|
||||
fprintf(stderr, "A error handling function has errored when running the script %s\n%s\n", exec_file, lua_tostring(L, -1));
|
||||
else
|
||||
fprintf(stderr, "An unknown error has occured when running the script %s\n%s\n", exec_file, lua_tostring(L, -1));
|
||||
lua_close(L);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
lua_remove(L, msg_base);
|
||||
|
||||
|
||||
const char* lbs_cmd = argv[argstart];
|
||||
if (argstart >= argc)
|
||||
lbs_cmd = "main";
|
||||
lua_getglobal(L, lbs_cmd);
|
||||
if (lua_isnil(L, -1))
|
||||
{
|
||||
fprintf(stderr, "Failed to find command %s in buildscript %s to execute\n", lbs_cmd, exec_file);
|
||||
lua_close(L);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (int i = (argstart + 1); i < argc; ++i)
|
||||
lua_pushstring(L, argv[i]);
|
||||
|
||||
msg_base = lua_gettop(L) - argc - argstart - 1;
|
||||
lua_pushcfunction(L, msghandler);
|
||||
lua_insert(L, msg_base);
|
||||
if ( (err = lua_pcall(L, argc - argstart - 1, LUA_MULTRET, msg_base)) != LUA_OK)
|
||||
{
|
||||
if (err == LUA_ERRRUN)
|
||||
fprintf(stderr, "A runtime error when running the command %s in the script %s has occured\n%s\n", lbs_cmd, exec_file, lua_tostring(L, -1));
|
||||
else if (err == LUA_ERRMEM)
|
||||
fprintf(stderr, "A memory allocation error when running the command %s in the script %s has occured\n%s\n", lbs_cmd, exec_file, lua_tostring(L, -1));
|
||||
else if (err == LUA_ERRERR)
|
||||
fprintf(stderr, "A error handling function has errored when running the command %s in the script %s\n%s\n", lbs_cmd, exec_file, lua_tostring(L, -1));
|
||||
else
|
||||
fprintf(stderr, "An unknown error has occured when running the command %s in the script %s\n%s\n", lbs_cmd, exec_file, lua_tostring(L, -1));
|
||||
lua_close(L);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
lua_remove(L, msg_base);
|
||||
|
||||
// If a return value was provided, return it
|
||||
if (lua_isnumber(L, -1))
|
||||
{
|
||||
int rc = lua_tointeger(L, -1);
|
||||
lua_close(L);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Otherwise return success
|
||||
lua_close(L);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
216
src/simple_string.cpp
Normal file
216
src/simple_string.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "simple_string.h"
|
||||
|
||||
simple_string::simple_string(const simple_string& src)
|
||||
{
|
||||
m_data = (char*)malloc(src.m_size * sizeof(char));
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
memcpy(m_data, src.m_data, src.m_size * sizeof(char));
|
||||
}
|
||||
|
||||
simple_string& simple_string::operator=(const simple_string& src)
|
||||
{
|
||||
if (this == &src) return *this;
|
||||
this->~simple_string();
|
||||
m_data = (char*)malloc(src.m_size * sizeof(char));
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
memcpy(m_data, src.m_data, src.m_size * sizeof(char));
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string::simple_string(simple_string&& src) noexcept
|
||||
{
|
||||
m_data = src.m_data;
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
src.m_data = nullptr;
|
||||
src.m_size = 0;
|
||||
src.m_capacity = 0;
|
||||
}
|
||||
|
||||
simple_string& simple_string::operator=(simple_string&& src) noexcept
|
||||
{
|
||||
if (this == &src) return *this;
|
||||
this->~simple_string();
|
||||
m_data = src.m_data;
|
||||
m_size = src.m_size;
|
||||
m_capacity = src.m_capacity;
|
||||
src.m_data = nullptr;
|
||||
src.m_size = 0;
|
||||
src.m_capacity = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string::simple_string(const char* beg, const char* end)
|
||||
{
|
||||
const ptrdiff_t slen = (ptrdiff_t)(end - beg);
|
||||
m_size = slen;
|
||||
m_capacity = slen;
|
||||
m_data = (char*)malloc(slen*sizeof(char)+1);
|
||||
memcpy(m_data, beg, slen * sizeof(char));
|
||||
m_data[slen - 1] = '\0';
|
||||
}
|
||||
|
||||
simple_string::simple_string(const char* str, const size_t slen)
|
||||
{
|
||||
m_size = slen;
|
||||
m_capacity = slen;
|
||||
m_data = (char*)malloc(slen * sizeof(char)+1);
|
||||
memcpy(m_data, str, slen * sizeof(char));
|
||||
m_data[slen - 1] = '\0';
|
||||
}
|
||||
|
||||
simple_string::simple_string(const char* str)
|
||||
{
|
||||
size_t slen = strlen(str);
|
||||
m_size = slen;
|
||||
m_capacity = slen;
|
||||
m_data = (char*)malloc(slen * sizeof(char)+1);
|
||||
memcpy(m_data, str, slen * sizeof(char));
|
||||
m_data[slen - 1] = '\0';
|
||||
}
|
||||
|
||||
simple_string::simple_string(const size_t initial_capacity, const char fill_value)
|
||||
{
|
||||
m_size = 0;
|
||||
m_capacity = initial_capacity;
|
||||
m_data = (char*)malloc(initial_capacity * sizeof(char));
|
||||
memset(m_data, fill_value, m_capacity);
|
||||
}
|
||||
|
||||
simple_string::simple_string(const std::string& str)
|
||||
{
|
||||
m_capacity = str.size();
|
||||
m_size = str.size();
|
||||
m_data = (char*)malloc(m_size*sizeof(char)+1);
|
||||
memcpy(m_data, str.data(), m_size*sizeof(char));
|
||||
m_data[m_size - 1] = '\0';
|
||||
}
|
||||
|
||||
simple_string::simple_string()
|
||||
{
|
||||
m_data = nullptr;
|
||||
m_capacity = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
simple_string::~simple_string(void)
|
||||
{
|
||||
if (m_data != nullptr)
|
||||
free(m_data);
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const char* other)
|
||||
{
|
||||
const size_t slen = strlen(other);
|
||||
if (slen == 0) return *this;
|
||||
if (m_size + slen + 1 > m_capacity)
|
||||
this->resize(m_size + slen);
|
||||
memcpy(m_data + m_size, other, slen * sizeof(char));
|
||||
m_size += slen;
|
||||
m_data[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const char* beg, const char* end)
|
||||
{
|
||||
const ptrdiff_t slen = (ptrdiff_t)(end - beg);
|
||||
if (slen == 0) return *this;
|
||||
if (m_size + slen + 1 > m_capacity)
|
||||
this->resize(m_size + slen);
|
||||
memcpy(m_data + m_size, beg, slen * sizeof(char));
|
||||
m_size += slen;
|
||||
m_data[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const char* other, const size_t slen)
|
||||
{
|
||||
if (slen == 0) return *this;
|
||||
if (m_size + slen + 1> m_capacity)
|
||||
this->resize(m_size + slen);
|
||||
memcpy(m_data + m_size, other, slen * sizeof(char));
|
||||
m_size += slen;
|
||||
m_data[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const std::string& other)
|
||||
{
|
||||
if (other.size() == 0) return *this;
|
||||
if (m_size + other.size() > m_capacity)
|
||||
this->resize(m_size + other.size());
|
||||
memcpy(m_data + m_size, other.data(), other.size() * sizeof(char));
|
||||
m_size += other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const simple_string& other)
|
||||
{
|
||||
if (other.m_size == 0) return *this;
|
||||
if (m_size + other.m_size > m_capacity)
|
||||
this->resize(m_size + other.m_size);
|
||||
memcpy(m_data + m_size, other.m_data, other.m_size * sizeof(char));
|
||||
m_size += other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
simple_string& simple_string::append(const char x)
|
||||
{
|
||||
if (m_size + 1 > m_capacity)
|
||||
this->expand(std::max(m_capacity, 1ULL));
|
||||
m_data[m_size] = x;
|
||||
++m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void simple_string::resize(const size_t new_size)
|
||||
{
|
||||
if (new_size >= m_capacity)
|
||||
this->expand(std::max(new_size, m_capacity));
|
||||
m_size = new_size;
|
||||
}
|
||||
|
||||
void simple_string::expand(const size_t extra_capacity)
|
||||
{ this->reserve(m_capacity + extra_capacity); }
|
||||
|
||||
void simple_string::reserve(const size_t new_capacity)
|
||||
{
|
||||
if (new_capacity <= m_capacity) return;
|
||||
char* new_data = (char*)malloc(new_capacity*sizeof(char));
|
||||
if (m_capacity != 0 && m_data != nullptr)
|
||||
{
|
||||
memcpy(new_data, m_data, m_size * sizeof(char));
|
||||
free(m_data);
|
||||
}
|
||||
m_data = new_data;
|
||||
m_capacity = new_capacity;
|
||||
}
|
||||
|
||||
const char* simple_string::c_str(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
char* simple_string::data(void) noexcept
|
||||
{ return m_data; }
|
||||
|
||||
size_t simple_string::size(void) const noexcept
|
||||
{ return m_size; }
|
||||
|
||||
char* simple_string::begin(void) noexcept
|
||||
{ return m_data; }
|
||||
|
||||
char* simple_string::end(void) noexcept
|
||||
{ return m_data + m_size; }
|
||||
|
||||
const char* simple_string::cbegin(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
const char* simple_string::cend(void) const noexcept
|
||||
{ return m_data; }
|
||||
|
||||
char& simple_string::operator[](const size_t idx) noexcept
|
||||
{ return m_data[idx]; }
|
||||
|
||||
const char& simple_string::operator[](const size_t idx) const noexcept
|
||||
{ return m_data[idx]; }
|
||||
1
thirdparty/luajit
vendored
Submodule
1
thirdparty/luajit
vendored
Submodule
Submodule thirdparty/luajit added at a4f56a459a
Reference in New Issue
Block a user