Tester Stable
This commit is contained in:
parent
f25d3cc8da
commit
2fba0b1d53
17 changed files with 769 additions and 113 deletions
|
@ -2,17 +2,15 @@
|
||||||
# CMake Configuration for the Sortiva Project
|
# CMake Configuration for the Sortiva Project
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|
||||||
# Specify the minimum CMake version required
|
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
# Project name, languages, and version
|
|
||||||
project(sortiva
|
project(sortiva
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
VERSION 1.0.0
|
VERSION 1.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# C++ Standard and General Settings
|
# Global Settings
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20) # Use C++20
|
set(CMAKE_CXX_STANDARD 20) # Use C++20
|
||||||
|
@ -22,11 +20,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile commands (useful
|
||||||
set(USE_FOLDERS ON) # Organize targets into folders (for IDEs)
|
set(USE_FOLDERS ON) # Organize targets into folders (for IDEs)
|
||||||
set(BUILD_SHARED_LIBS OFF) # Build static libraries by default
|
set(BUILD_SHARED_LIBS OFF) # Build static libraries by default
|
||||||
|
|
||||||
# =======================================================
|
# ========================================================
|
||||||
# Helper Functions:
|
# Helper Functions:
|
||||||
# Puts Targets into a Folder
|
# Puts Targets into a Folder
|
||||||
# Finds all files in a dir wich are defined file-types
|
# Finds all files in a dir wich are defined file-types
|
||||||
# =======================================================
|
# ========================================================
|
||||||
# This function puts targets into a specified folder.
|
# This function puts targets into a specified folder.
|
||||||
# It checks if the target exists and gets the actual target (if it is aliased).
|
# It checks if the target exists and gets the actual target (if it is aliased).
|
||||||
# It then sets the folder property for the target.
|
# It then sets the folder property for the target.
|
||||||
|
@ -93,6 +91,17 @@ FetchContent_Declare(
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(sol2)
|
FetchContent_MakeAvailable(sol2)
|
||||||
|
|
||||||
|
# --- Add Lua
|
||||||
|
FetchContent_Declare(
|
||||||
|
lua
|
||||||
|
GIT_REPOSITORY "https://github.com/marovira/lua"
|
||||||
|
GIT_TAG "5.4.4"
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(lua)
|
||||||
|
|
||||||
|
set(LUA_BUILD_INTERPRETER ON)
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# Helper Function: Set Common Target Properties
|
# Helper Function: Set Common Target Properties
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
@ -101,8 +110,10 @@ FetchContent_MakeAvailable(sol2)
|
||||||
|
|
||||||
function(set_common_properties target)
|
function(set_common_properties target)
|
||||||
target_link_libraries(${target} PRIVATE sol2::sol2) # Link with Sol2
|
target_link_libraries(${target} PRIVATE sol2::sol2) # Link with Sol2
|
||||||
|
target_compile_definitions(${target} PRIVATE SOL_ALL_SAFETIES_ON=1)
|
||||||
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Include project headers
|
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Include project headers
|
||||||
target_sources(${target} PRIVATE ${SVA_COMMON_FILES}) # Include common files
|
target_sources(${target} PRIVATE ${SVA_COMMON_FILES}) # Include common files
|
||||||
|
target_link_libraries(${target} PRIVATE lua::lua)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
@ -111,14 +122,11 @@ endfunction()
|
||||||
|
|
||||||
set(GUI_TARGET_NAME "${PROJECT_NAME}")
|
set(GUI_TARGET_NAME "${PROJECT_NAME}")
|
||||||
# --- Create GUI Executable
|
# --- Create GUI Executable
|
||||||
|
find_files(SVA_GUI_FILES "./src/" hpp cpp h c hxx cxx)
|
||||||
find_files(SVA_GUI_FILES "./src/gui/" hpp cpp h c hxx cxx)
|
|
||||||
add_executable(${GUI_TARGET_NAME}
|
add_executable(${GUI_TARGET_NAME}
|
||||||
src/main.cpp # Entry point for the GUI application
|
|
||||||
src/sva.hpp # Header file for the console
|
|
||||||
${SVA_GUI_FILES}
|
${SVA_GUI_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
# RAYLIB
|
# RAYLIB
|
||||||
# ---------------
|
# ---------------
|
||||||
|
@ -200,21 +208,22 @@ if(${SVA_BUILD_TEST})
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
# --- Create Test Executable
|
# --- Create Test Executable
|
||||||
|
set(TEST_TARGET_NAME "${GUI_TARGET_NAME}_test")
|
||||||
add_executable(
|
add_executable(
|
||||||
sortiva_test
|
${TEST_TARGET_NAME}
|
||||||
tests/test_main.cpp # Test entry point
|
tests/test_main.cpp # Test entry point
|
||||||
tests/test_sorting_functions.cpp
|
tests/test_sorting_functions.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
sortiva_test
|
${TEST_TARGET_NAME}
|
||||||
PRIVATE GTest::gtest_main # Link Google Test framework
|
PRIVATE GTest::gtest_main # Link Google Test framework
|
||||||
)
|
)
|
||||||
set_common_properties(sortiva_test)
|
set_common_properties(${TEST_TARGET_NAME})
|
||||||
|
|
||||||
# --- Enable Google Test's test discovery feature
|
# --- Enable Google Test's test discovery feature
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(sortiva_test)
|
gtest_discover_tests(${TEST_TARGET_NAME})
|
||||||
|
|
||||||
# put google test targets into a folder
|
# put google test targets into a folder
|
||||||
put_targets_into_folder(
|
put_targets_into_folder(
|
||||||
|
@ -227,3 +236,28 @@ if(${SVA_BUILD_TEST})
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Option to create an includes target
|
||||||
|
set(SVA_CREATE_INCLUDES_TARGET ON CACHE BOOL "Create an includes target")
|
||||||
|
|
||||||
|
if(${SVA_CREATE_INCLUDES_TARGET})
|
||||||
|
set(INCLUDES_TARGET_NAME "${GUI_TARGET_NAME}_includes")
|
||||||
|
set(INCLUDE_FILES)
|
||||||
|
find_files(
|
||||||
|
INCLUDE_FILES
|
||||||
|
"include/"
|
||||||
|
hpp h hxx
|
||||||
|
)
|
||||||
|
message(STATUS "Include files: ${INCLUDE_FILES}")
|
||||||
|
add_custom_target(${INCLUDES_TARGET_NAME}
|
||||||
|
SOURCES
|
||||||
|
${INCLUDE_FILES}
|
||||||
|
)
|
||||||
|
set_target_properties(${INCLUDES_TARGET_NAME} PROPERTIES FOLDER "sva")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
put_targets_into_folder(
|
||||||
|
FOLDER "sva"
|
||||||
|
TARGETS
|
||||||
|
${GUI_TARGET_NAME}
|
||||||
|
${TEST_TARGET_NAME}
|
||||||
|
)
|
||||||
|
|
106
include/Profiling/Timer.hpp
Normal file
106
include/Profiling/Timer.hpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#pragma once
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
struct timer_result
|
||||||
|
{
|
||||||
|
double seconds = 0;
|
||||||
|
double difftime = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Timer {
|
||||||
|
enum State : u8
|
||||||
|
{
|
||||||
|
running = 0,
|
||||||
|
paused = 1
|
||||||
|
};
|
||||||
|
State state = paused;
|
||||||
|
|
||||||
|
std::clock_t begin;
|
||||||
|
std::clock_t elapsed = 0;
|
||||||
|
std::optional<std::ostream*> out;
|
||||||
|
std::optional<timer_result*> result;
|
||||||
|
|
||||||
|
Timer() : begin(std::clock()) {}
|
||||||
|
Timer(std::ostream& o) : begin(std::clock()), out(&o) {}
|
||||||
|
Timer(timer_result& r) : begin(std::clock()), result(&r) {}
|
||||||
|
Timer(std::ostream& o, timer_result& r) : begin(std::clock()), out(&o), result(&r) {}
|
||||||
|
Timer(State initial_state) : state(initial_state), begin(std::clock())
|
||||||
|
{
|
||||||
|
if (state == paused)
|
||||||
|
begin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer(std::ostream& o, State initial_state) : state(initial_state), begin(std::clock()), out(&o)
|
||||||
|
{
|
||||||
|
if (state == paused)
|
||||||
|
begin = 0;
|
||||||
|
}
|
||||||
|
Timer(timer_result& r, State initial_state) : state(initial_state), begin(std::clock()), result(&r)
|
||||||
|
{
|
||||||
|
if (state == paused)
|
||||||
|
begin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer(std::ostream& o, timer_result& r, State initial_state) : state(initial_state), begin(std::clock()), out(&o), result(&r)
|
||||||
|
{
|
||||||
|
if (state == paused)
|
||||||
|
begin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(State init_state) {
|
||||||
|
if (state == paused)
|
||||||
|
begin = 0;
|
||||||
|
else
|
||||||
|
begin = std::clock();
|
||||||
|
elapsed = 0;
|
||||||
|
state = init_state;
|
||||||
|
lap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_state(State new_state)
|
||||||
|
{
|
||||||
|
if (this->state == new_state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (new_state == running)
|
||||||
|
{
|
||||||
|
begin = std::clock();
|
||||||
|
}
|
||||||
|
else // pausing
|
||||||
|
{
|
||||||
|
assert(begin != 0);
|
||||||
|
elapsed += std::clock() - begin;
|
||||||
|
begin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lap();
|
||||||
|
this->state = new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lap()
|
||||||
|
{
|
||||||
|
std::clock_t total_time = elapsed;
|
||||||
|
if (state == running)
|
||||||
|
{
|
||||||
|
total_time += std::clock() - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
result.value()->seconds = static_cast<double>(total_time) / CLOCKS_PER_SEC;
|
||||||
|
result.value()->difftime = static_cast<double>(total_time) / CLOCKS_PER_SEC;
|
||||||
|
}
|
||||||
|
if (out)
|
||||||
|
{
|
||||||
|
*out.value() << static_cast<double>(total_time) / CLOCKS_PER_SEC << " seconds.\n";
|
||||||
|
*out.value() << "Total time = " << static_cast<double>(total_time) / CLOCKS_PER_SEC << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Timer() {
|
||||||
|
lap();
|
||||||
|
}
|
||||||
|
};
|
167
include/list.hpp
Normal file
167
include/list.hpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#pragma once
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A thread-safe dynamic array container class
|
||||||
|
*
|
||||||
|
* List provides a fixed-size array container with thread-safe access through mutex protection.
|
||||||
|
* It supports construction with a size or initializer list, as well as copy/move operations.
|
||||||
|
* All operations that access or modify the internal data are protected by a mutex.
|
||||||
|
*
|
||||||
|
* @tparam T The type of elements stored in the list
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class List {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Type alias for the element type stored in the list
|
||||||
|
*
|
||||||
|
* This type represents the template parameter T that defines
|
||||||
|
* the type of elements contained in the List container.
|
||||||
|
*/
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a List with specified size
|
||||||
|
* @param size The number of elements to allocate
|
||||||
|
*/
|
||||||
|
explicit List(std::size_t size)
|
||||||
|
: data_(std::make_unique<T[]>(size))
|
||||||
|
, size_(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a List from an initializer list
|
||||||
|
* @param init The initializer list containing initial values
|
||||||
|
*/
|
||||||
|
List(std::initializer_list<T> init)
|
||||||
|
: data_(std::make_unique<T[]>(init.size()))
|
||||||
|
, size_(init.size()) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
std::copy(init.begin(), init.end(), data_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor
|
||||||
|
* @param other The List to copy from
|
||||||
|
* @thread_safety Both this and other List's mutexes are locked during copy
|
||||||
|
*/
|
||||||
|
List(const List& other) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
std::lock_guard<std::mutex> other_lock(other.mutex_);
|
||||||
|
data_ = std::make_unique<T[]>(other.size_);
|
||||||
|
std::copy(other.data_.get(), other.data_.get() + other.size_, data_.get());
|
||||||
|
size_ = other.size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
* @param other The List to move from
|
||||||
|
* @thread_safety Both this and other List's mutexes are locked during move
|
||||||
|
*/
|
||||||
|
List(List&& other) noexcept {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
std::lock_guard<std::mutex> other_lock(other.mutex_);
|
||||||
|
data_ = std::move(other.data_);
|
||||||
|
size_ = other.size_;
|
||||||
|
other.size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy assignment operator
|
||||||
|
* @param other The List to copy from
|
||||||
|
* @return Reference to this List
|
||||||
|
* @thread_safety Both this and other List's mutexes are locked during assignment
|
||||||
|
*/
|
||||||
|
List& operator=(const List& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
std::lock_guard<std::mutex> other_lock(other.mutex_);
|
||||||
|
data_ = std::make_unique<T[]>(other.size_);
|
||||||
|
std::copy(other.data_.get(), other.data_.get() + other.size_, data_.get());
|
||||||
|
size_ = other.size_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment operator
|
||||||
|
* @param other The List to move from
|
||||||
|
* @return Reference to this List
|
||||||
|
* @thread_safety Both this and other List's mutexes are locked during move
|
||||||
|
*/
|
||||||
|
List& operator=(List&& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
std::lock_guard<std::mutex> other_lock(other.mutex_);
|
||||||
|
data_ = std::move(other.data_);
|
||||||
|
size_ = other.size_;
|
||||||
|
other.size_ = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access element at specified index with bounds wrapping
|
||||||
|
* @param index The index of the element to access
|
||||||
|
* @return Reference to the element at the wrapped index
|
||||||
|
* @thread_safety Protected by mutex
|
||||||
|
*/
|
||||||
|
T& operator[](std::size_t index) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return data_[index % size_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access const element at specified index with bounds wrapping
|
||||||
|
* @param index The index of the element to access
|
||||||
|
* @return Const reference to the element at the wrapped index
|
||||||
|
* @thread_safety Protected by mutex
|
||||||
|
*/
|
||||||
|
const T& operator[](std::size_t index) const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return data_[index % size_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get const element at specified index with bounds wrapping
|
||||||
|
* @param index The index of the element to access
|
||||||
|
* @return Const reference to the element at the wrapped index
|
||||||
|
* @thread_safety Protected by mutex
|
||||||
|
*/
|
||||||
|
const T& get(std::size_t index) const
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return data_[index % size_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set element at specified index with bounds wrapping
|
||||||
|
* @param index The index of the element to set
|
||||||
|
* @param value The value to set at the specified index
|
||||||
|
* @thread_safety Protected by mutex
|
||||||
|
*/
|
||||||
|
void set(std::size_t index, const T& value) {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
data_[index % size_] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the size of the List
|
||||||
|
* @return The number of elements in the List
|
||||||
|
* @thread_safety Protected by mutex
|
||||||
|
*/
|
||||||
|
std::size_t size() const {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<T[]> data_; ///< Underlying array storage
|
||||||
|
std::size_t size_; ///< Number of elements in the array
|
||||||
|
mutable std::mutex mutex_; ///< Mutex for thread-safe access
|
||||||
|
};
|
22
include/std.hpp
Normal file
22
include/std.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SHOW(variable) std::cout << #variable << " = " << (variable) << std::endl;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define DEBUG
|
||||||
|
#define ASSERT(condition, message) while(!(condition)) { std::cerr << "Assertion failed: " << #condition << "\n\t" << (message); exit(1); }
|
||||||
|
#define FATAL_ASSERT(condition, message) ASSERT(condition, message)
|
||||||
|
#else
|
||||||
|
#define RELEASE
|
||||||
|
#define FATAL_ASSERT(condition, message) ASSERT(condition, message) exit(1);
|
||||||
|
#define ASSERT(condition, message) if(!(condition)) { std::cerr << "Assertion failed: " << #condition << "\nIn File: " << __FILE__ << "\nOn line: " << __LINE__ << "\n\t" << (message); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "list.hpp"
|
||||||
|
#include "flagman.hpp"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include "Profiling/Timer.hpp"
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,4 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
@ -84,3 +84,4 @@ typedef TRect<double> rectd;
|
||||||
typedef TRect<uintmax_t> rectu;
|
typedef TRect<uintmax_t> rectu;
|
||||||
typedef TRect<intmax_t> recti;
|
typedef TRect<intmax_t> recti;
|
||||||
|
|
||||||
|
#include "list.hpp"
|
1
src/Renderer.cpp
Normal file
1
src/Renderer.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "Renderer.h"
|
7
src/Renderer.h
Normal file
7
src/Renderer.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Renderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
42
src/SortingTester.cpp
Normal file
42
src/SortingTester.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "SortingTester.h"
|
||||||
|
|
||||||
|
|
||||||
|
SortingTester::SortingTester() : list(10)
|
||||||
|
{
|
||||||
|
lua.lua.open_libraries(sol::lib::coroutine, sol::lib::table);
|
||||||
|
lua.lua.new_usertype<SortingTester>("List",
|
||||||
|
"size", &SortingTester::list_size,
|
||||||
|
"swap", &SortingTester::list_swap,
|
||||||
|
"greater", &SortingTester::list_greater,
|
||||||
|
"less", &SortingTester::list_less,
|
||||||
|
"equal", &SortingTester::list_equal
|
||||||
|
);
|
||||||
|
|
||||||
|
lua.lua["list"] = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortingTester::load(const std::string& script)
|
||||||
|
{
|
||||||
|
if(lua.load(script) != safesol::LuaResultType::SUCCESS)
|
||||||
|
{
|
||||||
|
std::cerr << "Error loading file" << std::endl;
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "internal_script.hpp"
|
||||||
|
|
||||||
|
void SortingTester::load_internal()
|
||||||
|
{
|
||||||
|
if (lua.script(std_intern_sorting_script) != safesol::LuaResultType::SUCCESS)
|
||||||
|
{
|
||||||
|
std::cerr << "Error loading internal script" << std::endl;
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortingTester::populate(const populate_function& f)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < list.size(); i++)
|
||||||
|
f(i, list[i]);
|
||||||
|
}
|
152
src/SortingTester.h
Normal file
152
src/SortingTester.h
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#pragma once
|
||||||
|
#define SVA_LIST_CALLBACKS
|
||||||
|
#include <std.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include "lua/safesol.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
class SortingTester
|
||||||
|
{
|
||||||
|
List<u64> list;
|
||||||
|
|
||||||
|
safesol lua;
|
||||||
|
|
||||||
|
Timer timer = Timer(Timer::State::paused);
|
||||||
|
|
||||||
|
using populate_function = std::function<void(size_t, u64&)>;
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
sol::protected_function_result run_function(const sol::protected_function& function, Args&&... args)
|
||||||
|
{
|
||||||
|
timer.set_state(Timer::State::running);
|
||||||
|
sol::protected_function_result result = function(std::forward<Args>(args)...);
|
||||||
|
timer.set_state(Timer::State::paused);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool list_greater(size_t index1, size_t index2)
|
||||||
|
{
|
||||||
|
if (active_result)
|
||||||
|
++active_result->count_greater;
|
||||||
|
return list[index1] > list[index2];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool list_less(size_t index1, size_t index2)
|
||||||
|
{
|
||||||
|
if (active_result)
|
||||||
|
++active_result->count_less;
|
||||||
|
return list[index1] < list[index2];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool list_equal(size_t index1, size_t index2)
|
||||||
|
{
|
||||||
|
if (active_result)
|
||||||
|
++active_result->count_equal;
|
||||||
|
return list[index1] == list[index2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_swap(size_t index1, size_t index2)
|
||||||
|
{
|
||||||
|
if (active_result)
|
||||||
|
++active_result->count_swaps;
|
||||||
|
// list[index1] ^= list[index2];
|
||||||
|
// list[index2] ^= list[index1];
|
||||||
|
// list[index1] ^= list[index2];
|
||||||
|
auto tmp = list[index1];
|
||||||
|
list[index1] = list[index2];
|
||||||
|
list[index2] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t list_size() const
|
||||||
|
{
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_sorted()
|
||||||
|
{
|
||||||
|
if (list.size() <= 1)
|
||||||
|
return true;
|
||||||
|
for (size_t i = 1; i < list.size(); ++i)
|
||||||
|
{
|
||||||
|
if (list[i - 1] > list[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct run_result
|
||||||
|
{
|
||||||
|
timer_result timer;
|
||||||
|
// counts
|
||||||
|
u64 count_swaps = 0;
|
||||||
|
u64 count_greater = 0;
|
||||||
|
u64 count_less = 0;
|
||||||
|
u64 count_equal = 0;
|
||||||
|
// counts for comparisons
|
||||||
|
u64 count_comparisons = 0;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
run_result* active_result = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SortingTester();
|
||||||
|
|
||||||
|
void load(const std::string& script);
|
||||||
|
void load_internal();
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
run_result run(const std::string& function_name, Args&&... args)
|
||||||
|
{
|
||||||
|
run_result result;
|
||||||
|
timer.result.emplace(&result.timer);
|
||||||
|
timer.reset(Timer::State::paused);
|
||||||
|
active_result = &result;
|
||||||
|
|
||||||
|
// Create a bound member function using std::bind
|
||||||
|
auto bound_run_function = std::bind(&SortingTester::run_function<Args...>,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
safesol::LuaResultType runstate = lua.run_on_caller(function_name, bound_run_function);
|
||||||
|
|
||||||
|
if (runstate != safesol::LuaResultType::SUCCESS)
|
||||||
|
{
|
||||||
|
std::cerr << "Error running function \"" << function_name << "\": " << static_cast<u16>(runstate) << std::endl;
|
||||||
|
exit(static_cast<int>(runstate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_sorted())
|
||||||
|
{
|
||||||
|
std::cerr << "[ERROR] The algorithm \"" << function_name << "\" did not sort the list" << std::endl;
|
||||||
|
std::cerr << "[List] [ ";
|
||||||
|
for (size_t i = 0; i < list.size(); i++)
|
||||||
|
{
|
||||||
|
if(i == list.size()-1)
|
||||||
|
{
|
||||||
|
std::cerr << list[i] << " ]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::cerr << list[i] << ", ";
|
||||||
|
}
|
||||||
|
std::flush(std::cerr);
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.count_comparisons = result.count_equal + result.count_greater + result.count_less;
|
||||||
|
|
||||||
|
active_result = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void populate(const populate_function& f);
|
||||||
|
};
|
|
@ -1,13 +0,0 @@
|
||||||
#include "View.h"
|
|
||||||
#include <raylibs/raygui.h>
|
|
||||||
|
|
||||||
void View::draw()
|
|
||||||
{
|
|
||||||
BeginDrawing();
|
|
||||||
ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
|
|
||||||
EndDrawing();
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::update()
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "raylib.h"
|
|
||||||
#include <types.hpp>
|
|
||||||
|
|
||||||
class View
|
|
||||||
{
|
|
||||||
friend class ViewManager;
|
|
||||||
public:
|
|
||||||
View(rectu rect) : m_rect(rect) {}
|
|
||||||
virtual ~View() = default;
|
|
||||||
virtual void draw();
|
|
||||||
virtual void update();
|
|
||||||
virtual void onMouseDown(vec2d mousePos) {}
|
|
||||||
virtual void onMouseUp(vec2d mousePos) {}
|
|
||||||
virtual void onMouseMove(vec2d mousePos) {}
|
|
||||||
virtual void onKeyDown(int key) {}
|
|
||||||
virtual void onKeyUp(int key) {}
|
|
||||||
virtual void onKeyPress(int key) {}
|
|
||||||
virtual void onFocus() {}
|
|
||||||
virtual void onBlur() {}
|
|
||||||
|
|
||||||
virtual void onResize(vec2d factor)
|
|
||||||
{
|
|
||||||
m_rect.width = static_cast<rectu::type>(static_cast<float>(m_rect.width) * factor.x);
|
|
||||||
m_rect.height = static_cast<rectu::type>(static_cast<float>(m_rect.height) * factor.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec2u getPosition() const { return {m_rect.x, m_rect.y}; }
|
|
||||||
vec2u getSize() const { return {m_rect.width, m_rect.height}; }
|
|
||||||
const rectu& getRect() const { return m_rect; }
|
|
||||||
void setPosition(vec2u pos) { m_rect.x = pos.x; m_rect.y = pos.y; }
|
|
||||||
void setSize(vec2u size) { m_rect.width = size.x; m_rect.height = size.y; }
|
|
||||||
void setRect(rectu &rect) { m_rect = rect; }
|
|
||||||
virtual void Resize(float multiplier)
|
|
||||||
{
|
|
||||||
m_rect.width = static_cast<rectu::type>(static_cast<float>(m_rect.width) * multiplier);
|
|
||||||
m_rect.height = static_cast<rectu::type>(static_cast<float>(m_rect.height) * multiplier);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
rectu m_rect;
|
|
||||||
};
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include "ViewManager.h"
|
|
||||||
|
|
||||||
ViewManager::ViewManager()
|
|
||||||
{
|
|
||||||
m_viewportSize = { GetScreenWidth(), GetScreenHeight() };
|
|
||||||
m_mainView = new View({ 0, 0, m_viewportSize.x, m_viewportSize.y });
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewManager::update()
|
|
||||||
{
|
|
||||||
if (IsWindowResized())
|
|
||||||
{
|
|
||||||
m_viewportSize = { GetScreenWidth(), GetScreenHeight() };
|
|
||||||
m_mainView->onResize({ static_cast<float>(m_viewportSize.x), static_cast<float>(m_viewportSize.y) });
|
|
||||||
}
|
|
||||||
m_mainView->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewManager::draw()
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "View.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <types.hpp>
|
|
||||||
|
|
||||||
class ViewManager
|
|
||||||
{
|
|
||||||
vec2u m_viewportSize;
|
|
||||||
public:
|
|
||||||
ViewManager();
|
|
||||||
~ViewManager();
|
|
||||||
void update();
|
|
||||||
void draw();
|
|
||||||
private:
|
|
||||||
View* m_mainView;
|
|
||||||
};
|
|
27
src/internal_script.hpp
Normal file
27
src/internal_script.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
inline const char* std_intern_sorting_script = R"(
|
||||||
|
-- bubble sort
|
||||||
|
function bubble_sort()
|
||||||
|
isSorted = false
|
||||||
|
while isSorted == false do
|
||||||
|
movedElements = 0
|
||||||
|
for x=1, list:size(), 1 do
|
||||||
|
if list:greater(x, x+1) then
|
||||||
|
movedElements = movedElements + 1
|
||||||
|
list:swap(x, x+1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if movedElements == 0 then
|
||||||
|
isSorted = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function do_nothing()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- other functions
|
||||||
|
|
||||||
|
|
||||||
|
)";
|
61
src/lua/safesol.cpp
Normal file
61
src/lua/safesol.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#include "safesol.h"
|
||||||
|
|
||||||
|
safesol::LuaResultType safesol::script(const std::string& script)
|
||||||
|
{
|
||||||
|
sol::load_result result = lua.load(script);
|
||||||
|
if (!result.valid()) {
|
||||||
|
sol::error err = result;
|
||||||
|
std::cout << "Error loading script: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::protected_function_result script_result = result();
|
||||||
|
|
||||||
|
if (!script_result.valid()) {
|
||||||
|
sol::error err = script_result;
|
||||||
|
std::cout << "Error running script: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::SCRIPT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaResultType::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
safesol::LuaResultType safesol::script(const char* script)
|
||||||
|
{
|
||||||
|
sol::load_result result = lua.load(script);
|
||||||
|
if (!result.valid()) {
|
||||||
|
sol::error err = result;
|
||||||
|
std::cout << "Error loading script: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::protected_function_result script_result = result();
|
||||||
|
|
||||||
|
if (!script_result.valid()) {
|
||||||
|
sol::error err = script_result;
|
||||||
|
std::cout << "Error running script: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::SCRIPT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaResultType::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
safesol::LuaResultType safesol::load(const std::string& file)
|
||||||
|
{
|
||||||
|
sol::load_result result = lua.load_file(file);
|
||||||
|
if (!result.valid()) {
|
||||||
|
sol::error err = result;
|
||||||
|
std::cout << "Error loading file: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::protected_function_result script_result = result();
|
||||||
|
|
||||||
|
if (!script_result.valid()) {
|
||||||
|
sol::error err = script_result;
|
||||||
|
std::cout << "Error running script: " << err.what() << std::endl;
|
||||||
|
return LuaResultType::SCRIPT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaResultType::SUCCESS;
|
||||||
|
}
|
55
src/lua/safesol.h
Normal file
55
src/lua/safesol.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
#include <std.hpp>
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
class safesol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class LuaResultType : u8
|
||||||
|
{
|
||||||
|
SUCCESS = 0,
|
||||||
|
LOAD_ERROR = 1,
|
||||||
|
SCRIPT_ERROR,
|
||||||
|
RUN_ERROR,
|
||||||
|
UNKNOWN_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
|
||||||
|
|
||||||
|
LuaResultType script(const std::string& script);
|
||||||
|
LuaResultType script(const char* script);
|
||||||
|
|
||||||
|
LuaResultType load(const std::string& file);
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
sol::protected_function_result default_caller(const sol::protected_function& function, Args&&... args)
|
||||||
|
{
|
||||||
|
return function(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
LuaResultType run(const std::string& function_name, Args&&... args)
|
||||||
|
{
|
||||||
|
return run_on_caller(function_name, default_caller, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...Args, typename Caller = std::function<sol::protected_function_result(const sol::protected_function&, Args&&...)>>
|
||||||
|
LuaResultType run_on_caller(const std::string& function_name, const Caller& caller, Args&&... args)
|
||||||
|
{
|
||||||
|
auto function = lua[function_name];
|
||||||
|
if (!function.valid()) {
|
||||||
|
std::cout << "Error: function " << function_name << " not found" << std::endl;
|
||||||
|
return LuaResultType::RUN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = caller(function, std::forward<Args>(args)...);
|
||||||
|
if (!result.valid()) {
|
||||||
|
sol::error err = result;
|
||||||
|
std::cout << "Error running function " << function_name << ": " << err.what() << std::endl;
|
||||||
|
return LuaResultType::RUN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LuaResultType::SUCCESS;
|
||||||
|
}
|
||||||
|
};
|
80
src/main.cpp
80
src/main.cpp
|
@ -6,8 +6,14 @@
|
||||||
|
|
||||||
#include "gui/drawing_helper.hpp"
|
#include "gui/drawing_helper.hpp"
|
||||||
|
|
||||||
#define RESOURCES_PATH "G:\\School\\Belegarbeit\\sortiva\\res\\"
|
#define RESOURCES_PATH "G:/School/Belegarbeit/sortiva/res/"
|
||||||
|
|
||||||
|
#define SETTINGS_PATH "./.config.cfg"
|
||||||
|
|
||||||
|
#define NO_GUI
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NO_GUI
|
||||||
|
|
||||||
int screenWidth = 1280;
|
int screenWidth = 1280;
|
||||||
int screenHeight = 720;
|
int screenHeight = 720;
|
||||||
|
@ -23,13 +29,77 @@ GAME_STATES gameState = SVA_STATE_TITLE;
|
||||||
void UpdateDrawFrame(); // Update and Draw one frame
|
void UpdateDrawFrame(); // Update and Draw one frame
|
||||||
|
|
||||||
#include "gui/themes/dark.h"
|
#include "gui/themes/dark.h"
|
||||||
#include <filesystem>
|
|
||||||
#include "gui/Views/ViewManager.h"
|
#include "gui/Views/ViewManager.h"
|
||||||
|
#endif
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NO_GUI
|
||||||
|
#include "SortingTester.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_int_distribution<u64> dis(0, 10);
|
||||||
|
|
||||||
|
void populate(size_t index, u64& value)
|
||||||
|
{
|
||||||
|
value = dis(gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
sva_console_init();
|
sva_console_init();
|
||||||
|
|
||||||
|
#ifdef NO_GUI
|
||||||
|
|
||||||
|
std::cout << "Sortiva - Sorting Algorithm Visualizer" << std::endl;
|
||||||
|
std::cout << "No GUI mode" << std::endl;
|
||||||
|
|
||||||
|
SortingTester tester;
|
||||||
|
tester.populate( populate );
|
||||||
|
|
||||||
|
tester.load_internal();
|
||||||
|
|
||||||
|
SortingTester::run_result result = tester.run("bubble_sort");
|
||||||
|
|
||||||
|
std::cout << "Time: " << result.timer.seconds << " seconds" << std::endl;
|
||||||
|
std::cout << "Difftime: " << result.timer.difftime << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "Count swaps: " << result.count_swaps << std::endl;
|
||||||
|
std::cout << "Count comparisons: " << result.count_comparisons << std::endl;
|
||||||
|
std::cout << "\tCount greater: " << result.count_greater << std::endl;
|
||||||
|
std::cout << "\tCount less: " << result.count_less << std::endl;
|
||||||
|
std::cout << "\tCount equal: " << result.count_equal << std::endl;
|
||||||
|
|
||||||
|
std::cout << "\n\n";
|
||||||
|
|
||||||
|
|
||||||
|
result = tester.run("do_nothing");
|
||||||
|
|
||||||
|
std::cout << "Time: " << result.timer.seconds << " seconds" << std::endl;
|
||||||
|
std::cout << "Difftime: " << result.timer.difftime << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "Count swaps: " << result.count_swaps << std::endl;
|
||||||
|
std::cout << "Count comparisons: " << result.count_comparisons << std::endl;
|
||||||
|
std::cout << "\tCount greater: " << result.count_greater << std::endl;
|
||||||
|
std::cout << "\tCount less: " << result.count_less << std::endl;
|
||||||
|
std::cout << "\tCount equal: " << result.count_equal << "\n\n";
|
||||||
|
|
||||||
|
std::cout << "\nPress any key to exit..." << std::endl;
|
||||||
|
getchar();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_GUI
|
||||||
if(!DirectoryExists(RESOURCES_PATH))
|
if(!DirectoryExists(RESOURCES_PATH))
|
||||||
{
|
{
|
||||||
std::cerr << "Resources folder not found!" << std::endl;
|
std::cerr << "Resources folder not found!" << std::endl;
|
||||||
|
@ -62,9 +132,11 @@ int main(int argc, char** argv)
|
||||||
UpdateDrawFrame();
|
UpdateDrawFrame();
|
||||||
}
|
}
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_GUI
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Render Functions
|
// Render Functions
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -149,4 +221,6 @@ void RenderGameplayState()
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue