WIP: Move boilerplate application code to external lib.
Some checks reported errors
buildbot/darwin-macos-cmake-builder Build done.
buildbot/freebsd-jail-cmake-builder Build done.
buildbot/linux-podman-cmake-builder Build done.

Overview
---

- Added: External dependency on IOCore
- Removed:
  - Application.hpp, Application.cpp
  - debuginnfo.hpp,debuginfo.cpp
  - Exception.hpp,Exception.cpp
  - types/legible_ctypes.hpp
  - All references to Boost and execinfo/backtrace.

Additionally:
---

- .clang-format: Switch to modified WebKit code style
- .clang-tidy:   Tweak style for Constexpr  statements
- .clangd:  Re-enable IWYU include directory insertion & analysis

CMakeLists.txt:
  - Replace manual CMake conditionals with prepackaged functions from my
    custom cmake/BuildProperties.cmake CMake module.
  - Bump project version
  - Set project-wide dir variables
  - Add and use CPM Package Manager
  - Add reference to my IOCore application framework library using CPM
  - Remove references to backtrace generation. Now using IOCore
  - Comment out app and demo subdirectories for now.

cmake/BuildProperties.cmake:
  - Move in-source build detection, set project-wide environment
    variables, and other configuration tasks to specific CMake
    functions in a custom CMake module.

cmake/CPM.cmake:  Imported from the CPM Project under MIT License
  - Copyright (c) Lars Melchior and contributors

demo/Phong.hpp,demo/Phong.cpp:
  - Use  new method names. (untested, never compiled)

include/Component.hpp: Unused, Untested changes

Work #28
This commit is contained in:
S David 2024-04-13 16:06:24 -04:00
parent 89e90aaa5e
commit 42af043b3f
40 changed files with 438 additions and 1201 deletions

View File

@ -4,31 +4,23 @@ Language: Cpp
IndentWidth: 8
UseTab: AlignWithSpaces
ColumnLimit: 80
AccessModifierOffset: -6
AlwaysBreakAfterReturnType: None
BinPackArguments: true
ColumnLimit: 81
AccessModifierOffset: -4
BinPackParameters: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PenaltyReturnTypeOnItsOwnLine: 50
ContinuationIndentWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
PackConstructorInitializers: CurrentLine
AllowAllArgumentsOnNextLine: true
AlignAfterOpenBracket: Align
DerivePointerAlignment: False
PointerAlignment: Left
ReferenceAlignment: Pointer
AlwaysBreakTemplateDeclarations: Yes
FixNamespaceComments: Yes
NamespaceIndentation: Inner
AlignAfterOpenBracket: BlockIndent
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: true
#BreakBeforeBraces: Custom
BreakBeforeBraces: WebKit
#BraceWrapping:
# AfterCaseLabel: false
# AfterClass: true
# AfterControlStatement: Always
# AfterControlStatement: MultiLine
# AfterEnum: false
# AfterFunction: true
# AfterNamespace: false
@ -45,4 +37,5 @@ KeepEmptyLinesAtTheStartOfBlocks: true
# SplitEmptyFunction: true
# SplitEmptyRecord: false
# SplitEmptyNamespace: true
#
---

View File

@ -12,7 +12,7 @@ CheckOptions:
- { key: readability-function-cognitive-complexity.IgnoreMacros, value: true }
# Minimum Variable Length
- { key: readability-identifier-length.MinimumVariableLength, value: 3 }
- { key: readability-identifier-length.MinimumVariableNameLength, value: 3 }
- { key: readability-identifier-length.IgnoredVariableNames, value: "^(i|j|n|x|y|z|it)$" }
# Minimum Parameter Length
@ -46,10 +46,10 @@ CheckOptions:
value: '' }
- { key: readability-identifier-naming.TypeTemplateParameterCase,
value: CamelCase }
- { key: readability-identifier-naming.TypeTemplateParameterIgnoredRegexp, value: "^T$" }
# TypeAlias Rules
- { key: readability-identifier-naming.TypeAliasCase, value: CamelCase }
- { key: readability-identifier-naming.TypeAliasTemplateCase, value: CamelCase }
- { key: readability-identifier-naming.TypeAliasIgnoredRegexp,
value: '.*_t|string|.*_string' }
@ -71,7 +71,7 @@ CheckOptions:
# Constant Expression
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: 'k' }
- { key: readability-identifier-naming.ConstexprVariableCase, value: Camelcase }
- { key: readability-identifier-naming.ConstexprVariableCase, value: Camel_Snake_Case }
- { key: readability-identifier-naming.ConstexprFunctionCase, value: Camel_Snake_Case }
- { key: readability-identifier-naming.ConstexprMethodCase, value: Camel_Snake_Case }

View File

@ -1,3 +1,9 @@
#.clangd
CompileFlags:
Add: [-DCLANGD, -DVIM_LSP=1]
Diagnostics:
UnusedIncludes: Strict
MissingIncludes: Strict
Includes:
IgnoreHeader: types\.hpp

View File

@ -1,88 +1,122 @@
cmake_minimum_required(VERSION 3.26)
# Prevent in-source builds
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Source and build directories cannot be the same.")
endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif()
# Check if this CMakeFile is being built as part of a FetchContent CMake
# dependency download.
if (NOT DEFINED PROJECT_NAME)
# When this package is included as a subproject, save some time by skipping
# the unit test build and execution.
# To override this, set -DENABLE_TESTS=true when you call CMake
option(ENABLE_TESTS "Build and run unit tests" ON)
else()
option(ENABLE_TESTS "Build and run unit tests" OFF)
endif()
option(CI_BUILD "Defines a C preprocessor macro used to disable some code paths in CI servers" OFF)
# Additional paths to search for custom and third-party CMake modules
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(BuildProperties)
prevent_in_source_build()
disable_deprecated_features()
# When this package is included as a subproject, there's no need to
# build and run the unit-tests.
# Sets -DBUILD_TESTING to false by default if this is a third-party lib build
# This check must appear before project()
disable_tests_if_subproject()
project(Elemental
VERSION 0.0.1
VERSION 0.0.2
LANGUAGES C CXX
# Save this for later:
# HOMEPAGE_URL <URL>
DESCRIPTION "A simple top-down strategy game"
)
include(CPM)
# Custom CMake Defines / Command-line options
option(USE_SYSTEM_CATCH2
"Do not download & compile catch2 library for unit tests"
ON
)
SET(${PROJECT_NAME}_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET(${PROJECT_NAME}_INCLUDE_DIRS ${IOCore_CMAKE_SOURCE_DIR}/include)
if (CI_BUILD)
add_compile_definitions(-DCI_BUILD=1)
endif()
if( NOT CMAKE_BUILD_TYPE )
SET( CMAKE_BUILD_TYPE Debug )
endif()
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
# Disable non-portable GNU compiler extensions
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_EXTENSIONS OFF)
# Check if ccache is installed and enable CMake integration
# if found. This will speed up repeated builds.
find_program(CCACHE_PATH ccache)
if(ccache_path)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
endif(ccache_path)
if (USE_SYSTEM_CATCH2)
message(CHECK_START "Detecting System Catch2 ")
find_package(Catch2 3 QUIET)
if(TARGET Catch2::Catch2)
message(CHECK_PASS "found target Catch2::Catch2")
else()
message(CHECK_FAIL "not found")
set(USE_SYSTEM_CATCH2 OFF)
message(STATUS "USE_SYSTEM_CATCH2=OFF")
endif()
endif()
if (UNIX AND NOT(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"))
option(USE_BOOST_STACKTRACE "Use Boost::stacktrace for stack traces" OFF)
option(USE_EXECINFO_STACKTRACE "Use BSD/UNIX execinfo for stack traces" ON)
else()
option(USE_BOOST_STACKTRACE "Use Boost::stacktrace for stack traces" ON)
option(USE_EXECINFO_STACKTRACE "Use BSD/UNIX execinfo for stack traces" OFF)
endif()
option(USE_CCACHE
[=[Use ccache compiler cache to speed up builds.
Enabled by default if ccache is found]=]
ON
)
# enable compile_commands.json generation for clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
IF( NOT CMAKE_BUILD_TYPE )
SET( CMAKE_BUILD_TYPE Debug )
ENDIF()
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
# Disable GNU compiler extensions
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_EXTENSIONS OFF)
# Search for the code caching compiler wrapper, ccache and enable it
# if found. This will speed up repeated builds.
if (USE_CCACHE)
message(CHECK_START "Detecting cacche")
find_program(CCACHE_PATH ccache)
if(CCACHE_PATH)
message(CHECK_PASS("found"))
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
endif()
list(APPEND CMAKE_MESSAGE_INDENT " ")
message(STATUS "(set -DUSE_CCACHE=Off to disable)")
list(POP_BACK CMAKE_MESSAGE_INDENT)
endif()
if (BUILD_TESTING)
CPMFindPackage(NAME Catch2
GITHUB_REPOSITORY catchorg/Catch2
VERSION 3.4.0
OPTIONS
"CATCH_DEVELOPMENT_BUILD OFF"
"CATCH_BUILD_TESTING OFF"
)
CPMFindPackage(NAME FakeIt
GITHUB_REPOSITORY eranpeer/FakeIt
GIT_TAG 2.4.0
OPTIONS
"BUILD_TESTINGING OFF"
)
if (TARGET Catch2)
set_target_properties(Catch2 PROPERTIES
CXX_STANDARD 20
)
endif()
if (TARGET Catch2WithMain)
set_target_properties(Catch2WithMain PROPERTIES
CXX_STANDARD 20
)
endif()
if (Catch2_ADDED)
list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
else()
if (Catch2_DIR)
list(APPEND CMAKE_MODULE_PATH ${Catch2_DIR})
endif()
endif()
endif()
CPMAddPackage(NAME IOCore
GIT_REPOSITORY "file://${CMAKE_CURRENT_SOURCE_DIR}/../IOCore"
#GIT_TAG HEAD
#GIT_REPOSITORY "https://gitea.beniquez.me/sdaveb/IOCore.git"
GIT_TAG v0.2.10
OPTIONS
"BUILD_SHARED_LIBS OFF"
"BUILD_TESTING OFF"
)
# Set output directories for build targets
set_artifact_dir(${CMAKE_BINARY_DIR}/out)
# Initialize FetchContent
include(FetchContent)
include(CheckIncludeFile)
@ -96,12 +130,13 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
pkg_check_modules(SDL2_IMAGE REQUIRED IMPORTED_TARGET SDL2_image)
pkg_check_modules(SDL2_GFX REQUIRED IMPORTED_TARGET SDL2_gfx)
find_package(PkgConfig REQUIRED)
pkg_check_modules(NLOHMANN_JSON "nlohmann_json >= 3.11.2" REQUIRED)
SET(SDL2_COMBINED_INCLUDE_DIRS "")
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIRS})
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_GFX_INCLUDE_DIRS})
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIRS})
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_GFX_INCLUDE_DIRS})
list(REMOVE_DUPLICATES SDL2_COMBINED_INCLUDE_DIRS)
@ -111,98 +146,25 @@ set(SDL2_COMBINED_LINK_DEPS
PkgConfig::SDL2_GFX
)
if (USE_EXECINFO_STACKTRACE AND (NOT USE_BOOST_STACKTRACE))
CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H)
if (HAVE_EXECINFO_H)
add_definitions(-DHAVE_EXECINFO_H=1)
endif()
find_library(LIB_EXEC_INFO
NAMES execinfo # Specify the library name without the 'lib' prefix or file extension
HINTS /usr/lib /usr/local/lib # Optional hint for the library location
)
if (LIB_EXEC_INFO)
message(STATUS "Found libexecinfo: ${LIB_EXEC_INFO}")
set(STACKTRACE_DEP_LIBS ${LIB_EXEC_INFO})
endif()
elseif((NOT USE_EXECINFO_STACKTRACE) AND USE_BOOST_STACKTRACE)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_STATIC_RUNTIME OFF) # Do not require static C++ runtime
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.82.0 COMPONENTS system filesystem REQUIRED)
if (Boost_FOUND)
add_definitions(-DBOOST_STACKTRACER=1)
add_definitions(-DBOOST_STACKTRACE_USE_ADDR2LINE=1)
include_directories(${Boost_INCLUDE_DIRS})
endif()
endif()
if (ENABLE_TESTS)
if (NOT USE_SYSTEM_CATCH2)
FetchContent_Declare(
Catch2
URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.4.0.zip
URL_HASH MD5=c426e77d4ee0055410bc930182959ae5
)
FetchContent_MakeAvailable(Catch2)
endif()
FetchContent_Declare(
FakeIt
URL https://github.com/eranpeer/FakeIt/archive/refs/tags/2.4.0.zip
URL_HASH MD5=72e4ce7f1c0de97074d2d5b517753286
)
FetchContent_MakeAvailable(FakeIt)
if (TARGET Catch2::Catch2)
set_target_properties(Catch2::Catch2 PROPERTIES
CXX_STANDARD 17
)
endif()
if (TARGET Catch2::Catch2WithMain)
set_target_properties(Catch2::Catch2WithMain PROPERTIES
CXX_STANDARD 17
)
endif()
if (TARGET FakeIt::FakeIt-catch)
set(FakeIt_INCLUDE_DIRS "${FakeIt_SOURCE_DIR}/single_header/catch")
endif()
list(APPEND cmake_module_path ${Catch2_source_dir}/extras)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(-DDEBUG=1)
endif()
# Set output directories for build targets
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/out)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}/bin)
# Include directories
#include_directories(${CMAKE_SOURCE_DIR}/src)
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${Elemental_CMAKE_SOURCE_DIR}/include)
# Add a target to copy application resource files to the build dir
add_custom_target(copy_assets
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${OUTPUT_DIR}/share/data
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${Elemental_ARTIFACT_DIR}/share/data
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/tests/data
)
# Add subdirectories
add_subdirectory(src)
add_subdirectory(demo)
add_subdirectory(apps)
#add_subdirectory(demo)
#add_subdirectory(apps)
if(ENABLE_TESTS)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()

View File

@ -0,0 +1,46 @@
# BuildProperties.cmake
# Copyright (c) 2024 Saul D Beniquez
# License: MIT
#
# This module defines a function prevent_in_source_build() that prevents in-source builds
# and sets a policy for CMake version 3.24.0 and above.
function(prevent_in_source_build)
# Prevent in-source builds
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Source and build directories cannot be the same.")
endif()
endfunction()
function(set_artifact_dir path)
# Set local variable, not necessary to be parent scope since it's not used outside this function
set(ARTIFACT_DIR "${path}")
# Set project-specific artifact directory in parent scope
set(${PROJECT_NAME}_ARTIFACT_DIR "${path}" PARENT_SCOPE)
# Set output directories in parent scope using the provided path directly
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${path}/bin" PARENT_SCOPE)
endfunction()
function(disable_deprecated_features)
# Use new timestamp behavior when extracting files archives
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif()
endfunction()
function(disable_tests_if_subproject)
if (NOT DEFINED PROJECT_NAME)
option(BUILD_TESTING "Build and run unit tests" ON)
else()
option(BUILD_TESTING "Build and run unit tests" OFF)
endif()
endfunction()
# vim: ts=4 sts=4 sw=4 noet :

24
cmake/CPM.cmake Normal file
View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.38.7)
set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

View File

@ -59,23 +59,11 @@ Phong::run() -> int
{
this->is_running = true;
try {
LoopRegulator frame_regulator(60_Hz);
this->running_threads["simulation_thread"] =
std::thread([this]() { this->simulation_thread_loop(); });
while (this->is_running) {
frame_regulator.startUpdate();
this->video_renderer.clearScreen();
this->event_emitter.pollEvents();
auto cycle_delay_ms = frame_regulator.delay();
print_cycle_rate(cycle_delay_ms, "frame delay");
video_renderer.flip();
}
this->is_running = false;
this->event_and_rendering_loop();
/* threading clean-up:
* wait for all child threads to finish */
@ -142,6 +130,25 @@ Phong::Phong()
this->event_emitter.pollEvents();
}
void
Phong::event_and_rendering_loop()
{
LoopRegulator frame_regulator(60_Hz);
do {
frame_regulator.startUpdate();
this->video_renderer.clearScreen();
this->event_emitter.pollEvents();
auto cycle_delay_ms = frame_regulator.delay();
print_cycle_rate(cycle_delay_ms, "frame delay");
video_renderer.flip();
} while (this->is_running);
this->is_running = false;
}
void
Phong::simulation_thread_loop()
{
@ -150,7 +157,7 @@ Phong::simulation_thread_loop()
do {
loop_regulator.startUpdate();
this->event_emitter.transmitEvents();
this->event_emitter.sendEvents();
auto cycle_delay_ms = loop_regulator.delay();
print_cycle_rate(cycle_delay_ms);

View File

@ -65,6 +65,8 @@ class Phong
bool is_running{ false };
Dictionary<std::thread> running_threads;
void event_and_rendering_loop();
void simulation_thread_loop();
IRenderer& video_renderer;

View File

@ -1,58 +0,0 @@
/* Application.hpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <vector>
#include "IApplication.hpp"
#include "types.hpp"
#include <vector>
namespace elemental {
class Application : public IApplication // NOLINT
{
public:
~Application() override = default;
auto init(int argc, c::const_string argv[], c::const_string envp[])
-> void override;
auto run() -> int override = 0;
[[nodiscard]] inline auto getArguments() const
-> const std::vector<std::string>& override
{
return this->arguments;
}
[[nodiscard]] inline auto getEnvironment() const
-> const Dictionary<const std::string>& override
{
return this->environment_variables;
}
protected:
Application();
Application(const IApplication&) = delete;
Application(IApplication&&) = delete;
auto operator=(const IApplication&) -> Application& = delete;
auto operator=(IApplication&&) -> Application& = delete;
void read_arguments(int argc, c::const_string argv[]);
void create_env_dictionary(c::const_string envp[]);
std::vector<std::string> arguments;
Dictionary<const std::string> environment_variables;
};
} // namespace elemental
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -19,6 +19,7 @@ struct Component
{
public:
using TypeInfo = std::type_index;
// using EntityId = unsigned int;
using InstanceID = unsigned int;
@ -26,11 +27,11 @@ struct Component
virtual ~Component() = default;
inline auto getInstanceId() const -> InstanceID { return instance_id; }
auto getInstanceId() const -> InstanceID { return instance_id; }
virtual auto getTypeIndex() -> TypeInfo = 0;
template<typename T_>
inline static auto isChildClass() -> bool
static auto isChildClass() -> bool
{
static_assert(std::is_base_of_v<Component, T_>,
"T must be a derived class of Component");
@ -52,7 +53,7 @@ struct Component
static unsigned int next_instance_id;
};
inline unsigned int Component::next_instance_id = 0;
unsigned int Component::next_instance_id = 0;
} // namespace elemental
// clang-format off

View File

@ -1,84 +0,0 @@
/* exceptions.hpp
* Copyright © 2020 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
#include <algorithm>
#include <cstring>
#include <exception>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#define ASSERT(condition) \
if (condition == false) { \
elemental::assert_impl(#condition); \
}
#define ASSERT_MSG(condition, msg) \
if (condition == false) { \
elemental::assert_impl(#condition, msg); \
}
namespace elemental {
class Exception : public std::exception
{
public:
Exception(c::const_string message = kDEFAULT_ERROR);
Exception(std::string message);
Exception(const elemental::Exception& other) = default;
Exception(const std::exception& inner);
auto operator=(const Exception&) -> Exception& = delete;
auto what() const noexcept -> const char* override;
auto stacktrace() const noexcept -> const std::string&;
constexpr static auto kDEFAULT_ERROR = "An exception has ocurred!";
protected:
void build_what_message(c::const_string class_name = "",
c::const_string optional_data = "");
private:
std::string error_message;
std::string what_message;
std::string stack_trace;
std::exception_ptr inner_exception_ptr;
};
struct NotImplementedException : public Exception
{
NotImplementedException() : Exception("Method not implemented") {}
~NotImplementedException() override = default;
};
void inline assert_impl(c::const_string failed_condition,
c::const_string assert_reason = "")
{
std::stringstream assert_buffer;
assert_buffer << failed_condition << " is false!";
if (std::strlen(assert_reason) > 0) {
assert_buffer << std::endl
<< "\tassert_resion: " << assert_reason;
}
assert_buffer << std::flush;
throw Exception(assert_buffer.str());
}
} // namespace elemental
// clang-format off
// vim: set foldmethod=marker foldmarker=\{,\} textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -16,8 +16,7 @@
#include <fstream>
namespace elemental {
enum class CreateDirs : bool
{
enum class CreateDirs : bool {
Default = false,
Disable = false,
Disabled = false,
@ -25,29 +24,29 @@ enum class CreateDirs : bool
Enabled = true
};
class FileResource
{
public:
FileResource(const std::filesystem::path& file_path,
CreateDirs mode = CreateDirs::Default);
class FileResource {
public:
FileResource(
const std::filesystem::path& file_path,
CreateDirs mode = CreateDirs::Default
);
virtual ~FileResource() = default;
protected:
protected:
std::filesystem::path file_path;
};
struct UnreachablePathException : public Exception
{
inline UnreachablePathException(const std::filesystem::path& path)
: Exception("Unreachable path or directory")
, unreachable_path(path)
struct UnreachablePathException : public IOCore::Exception {
UnreachablePathException(const std::filesystem::path& path)
: Exception("Unreachable path or directory"), unreachable_path(path)
{
this->build_what_message("elemental::UnreachablePathException",
path.c_str());
this->build_what_message(
"elemental::UnreachablePathException", path.c_str()
);
}
auto inline what() const noexcept -> const char* override
auto what() const noexcept -> const char* override
{
return Exception::what();
}

View File

@ -1,43 +0,0 @@
/* IApplication.hpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
#include <functional>
#include <vector>
namespace elemental {
struct IApplication;
using IApplicationRef = std::reference_wrapper<IApplication>;
class IApplication
{
public:
virtual ~IApplication() = default;
virtual auto init(int argc, c::const_string argv[],
c::const_string envp[]) -> void = 0;
virtual auto run() -> int = 0;
[[nodiscard]] virtual auto getArguments() const
-> const std::vector<std::string>& = 0;
[[nodiscard]] virtual auto getEnvironment() const
-> const Dictionary<const std::string>& = 0;
protected:
IApplication() {}
};
} // namespace elemental
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -18,14 +18,12 @@ struct IDrawable
{
virtual ~IDrawable(){};
inline void Draw(Position& pos)
{
this->Draw(Area{ pos.x, pos.y, 0, 0 });
}
virtual void Draw(const Area& rect) = 0;
virtual void draw(const Rectangle& rect) = 0;
void draw(Position2D& pos) { this->draw(Rectangle{ pos.x, pos.y }); }
};
}
} // namespace elemental
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -24,8 +24,8 @@ struct IEventSource
, private INonCopyable
{
~IEventSource() override = default;
virtual auto pollEvents() -> void = 0;
virtual auto transmitEvents() -> void = 0;
virtual void pollEvents() = 0;
virtual void sendEvents() = 0;
protected:
explicit IEventSource(InputDevices device_flags) {}

View File

@ -41,10 +41,7 @@ class JsonConfigFile : public FileResource
config_json = value;
}
inline auto getJsonData() -> nlohmann::json&
{
return this->config_json;
};
auto getJsonData() -> nlohmann::json& { return this->config_json; };
protected:
nlohmann::json config_json;

View File

@ -52,23 +52,23 @@ namespace elemental {
* automatically manage resource SDL resources. */
struct SdlResourceDeleter
{
inline auto operator()(SDL_Window* window_ptr) -> void
auto operator()(SDL_Window* window_ptr) -> void
{
SDL_DestroyWindow(window_ptr);
}
inline auto operator()(SDL_Renderer* renderer_ptr) -> void
auto operator()(SDL_Renderer* renderer_ptr) -> void
{
SDL_DestroyRenderer(renderer_ptr);
}
inline auto operator()(SDL_Surface* surface_ptr) -> void
auto operator()(SDL_Surface* surface_ptr) -> void
{
SDL_FreeSurface(surface_ptr);
}
inline auto operator()(SDL_Texture* texture_ptr) -> void
auto operator()(SDL_Texture* texture_ptr) -> void
{
SDL_DestroyTexture(texture_ptr);
}
inline auto operator()(SDL_Joystick* joystick_ptr) -> void
auto operator()(SDL_Joystick* joystick_ptr) -> void
{
SDL_JoystickClose(joystick_ptr);
}

View File

@ -28,6 +28,7 @@ namespace elemental {
class SdlEventSource : public IEventSource
{
TEST_INSPECTABLE(SdlEventSource);
public:
using Mutex = std::mutex;
using MutexLock = std::lock_guard<Mutex>;
@ -39,8 +40,8 @@ class SdlEventSource : public IEventSource
~SdlEventSource() override = default;
auto pollEvents() -> void override;
auto transmitEvents() -> void override;
void pollEvents() override;
void sendEvents() override;
protected:
std::queue<SDL_Event> event_queue;

View File

@ -12,34 +12,33 @@ namespace elemental {
namespace platform {
enum platform_t
{ // NOLINTBEGIN
kUNKNOWN = 0b0000,
kWINDOWS = 0b0001,
kUNIX = 0b0100,
kLINUX = 0b0101,
kFREEBSD = 0b0110,
kMACOS = 0b0111
}; // NOLINTEND
enum platform_t { // NOLINTBEGIN
kUNKNOWN = 0b0000,
kWINDOWS = 0b0001,
kUNIX = 0b0100,
kLINUX = 0b0101,
kFREEBSD = 0b0110,
kMACOS = 0b0111
}; // NOLINTEND
#ifdef __linux__
static const platform_t kCurrentPlatform = kLINUX;
static const platform_t kCurrentPlatform = kLINUX;
#endif
#ifdef _WIN32
static const platform_t kCurrentPlatform = kWINDOWS;
static const platform_t kCurrentPlatform = kWINDOWS;
#endif
#ifdef __APPLE__
static const platform_t kCurrentPlatform = kMACOS;
static const platform_t kCurrentPlatform = kMACOS;
#endif
#ifdef __FreeBSD__
static const platform_t kCurrentPlatform = kFREEBSD;
static const platform_t kCurrentPlatform = kFREEBSD;
#endif
// I don't own any AIX, Solaris, HP-UX, or pure Darwin systems, sorry :)
// To be added at a later date.
// I don't own any AIX, Solaris, HP-UX, or pure Darwin systems, sorry :)
// To be added at a later date.
}; // namespace platform
} // namespace elemental

View File

@ -11,7 +11,7 @@
#include "types/containers.hpp"
#include "types/errors.hpp"
#include "types/legible_ctypes.hpp"
// #include "types/legible_ctypes.hpp"
#include "types/pointers.hpp"
// clang-format off

View File

@ -1,23 +0,0 @@
/* containers.hpp
* Copyright © 2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <string>
#include <unordered_map>
namespace elemental {
/// \brief Convenience for std::map objects where the key is always a string.
template<typename TValueT>
using Dictionary = std::unordered_map<std::string, TValueT>;
} // namespace elemental
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -1,24 +0,0 @@
/* legible_ctypes.hpp
* Copyright © 2023-2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <cstddef>
/*! \name Aliases for C-types that are unclear.
* The C type char* does not immediately scream "STRING", and
* socket libraries return `int`, rather than a typedef socket_fd_t. */
namespace elemental::c {
using string = char*;
using const_string = const char*;
using count_t = size_t;
} // namespace elemental::c
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -32,22 +32,15 @@ using Resolution = Area;
struct Rectangle
{
union
{
Point position;
struct
{
uint32_t x, y;
};
};
union
{
Area size;
struct
{
uint32_t width, height;
};
};
Point position;
Area size;
uint32_t& x = position.x;
uint32_t& y = position.y;
uint32_t& width = size.width;
uint32_t& height = size.height;
SERIALIZABLE(Rectangle, position, size);
};

View File

@ -1,75 +0,0 @@
/* Application.cpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "Application.hpp"
#include "Exception.hpp"
#include "types.hpp"
#include <string>
#include <string_view>
#include <vector>
using namespace elemental;
void
Application::init(int argc, c::const_string argv[], c::const_string envp[])
{
if (argv == nullptr || envp == nullptr) {
std::string problem = (argv == nullptr) ? "argv " : "envp ";
auto message = "Cannot instantiate the application class "
"with null " +
problem + "parameter";
auto fatal_exception = std::logic_error(message);
throw elemental::Exception(fatal_exception);
}
this->read_arguments(argc, argv);
this->create_env_dictionary(envp);
}
Application::Application()
: IApplication()
, arguments()
, environment_variables()
{
}
void
Application::read_arguments(int argc, c::const_string argv[])
{
for (c::count_t index = 0; index < argc; ++index) {
this->arguments.emplace_back(argv[index]);
}
}
void
Application::create_env_dictionary(c::const_string envp[])
{
for (c::count_t num = 0; envp[num] != nullptr; ++num) {
auto encoded_pair = std::string_view(envp[num]);
size_t equal_character_pos;
auto not_found = encoded_pair.npos;
equal_character_pos = encoded_pair.find('=');
if (equal_character_pos != not_found) {
auto key = std::string(
encoded_pair.substr(0, equal_character_pos));
auto val = std::string(
encoded_pair.substr(equal_character_pos + 1));
this->environment_variables.insert(
std::make_pair(key, val));
}
}
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -1,14 +1,11 @@
# Define the library 'engine'
set(ELEMENTAL_SOURCES
debuginfo.cpp
Exception.cpp
Application.cpp
SdlRenderer.cpp
LoopRegulator.cpp
Observable.cpp
SdlEventSource.cpp
FileResource.cpp
JsonConfigFile.cpp
LoopRegulator.cpp
Observable.cpp
SdlRenderer.cpp
SdlEventSource.cpp
paths.cpp
)
@ -21,14 +18,16 @@ target_include_directories(elemental SYSTEM BEFORE
# Add a target to copy this project's header files to the build dir
add_custom_target(include_files
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/include ${OUTPUT_DIR}/include
COMMAND ${CMAKE_COMMAND} -E copy_directory ${Elemental_CMAKE_SOURCE_DIR}/include ${Elemental_ARTIFACT_DIR}/include
)
add_dependencies(elemental include_files)
set(ELEMENTAL_LINK_DEPS
IOCore::IOCoreStatic
Threads::Threads
${SDL2_COMBINED_LINK_DEPS}
${STACKTRACE_DEP_LIBS}
${NLOHMANN_JSON_LIBS}
)
# Add additional link options for boost::stacktrace
@ -40,16 +39,4 @@ endif()
# Also get the same dependencies.
target_link_libraries(elemental PUBLIC ${ELEMENTAL_LINK_DEPS})
#if (ENABLE_TESTS)
# if (USE_BOOST_STACKTRACE)
# target_link_options(elemental-testing PUBLIC -rdynamic)
# endif()
# target_link_libraries(elemental-testing PUBLIC ${ELEMENTAL_LINK_DEPS})
#
# # Define a preprocessor flag to enable helper code for unit-testing
# # This flag will propagate to programs that link to this library (PUBLIC)
# #target_compile_definitions(elemental-testing PUBLIC -DUNIT_TEST=1)
#
#endif()
# vim: ts=4 sw=4 noet foldmethod=indent :

View File

@ -1,121 +0,0 @@
/* exceptions.hpp
* Copyright © 2020 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Exception.hpp"
#include "sys/debuginfo.hpp"
#include "types.hpp"
#include <algorithm>
#include <exception>
#include <iostream>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
using elemental::Exception;
constexpr unsigned kDEFAULT_STACKFRAMES_TO_STRIP = 3;
// Helper classes and functions. #region
Exception::Exception(c::const_string error_message)
: std::exception()
, error_message(error_message)
, what_message()
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
, inner_exception_ptr()
{
build_what_message();
}
Exception::Exception(std::string error_message)
: std::exception()
, error_message(std::move(error_message))
, what_message()
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
, inner_exception_ptr()
{
build_what_message();
}
Exception::Exception(const std::exception& inner)
: std::exception(inner)
, error_message(inner.what())
, what_message()
, inner_exception_ptr(std::make_exception_ptr(&inner))
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
{
build_what_message();
}
auto
Exception::what() const noexcept -> const char*
{
return this->what_message.c_str();
}
auto
Exception::stacktrace() const noexcept -> const std::string&
{
return this->stack_trace;
}
auto
prepend_tabs_to_lines(const std::string& input) -> std::string
{
std::ostringstream results_buffer;
std::istringstream input_buffer(input);
// Function to add a tab character before each line
auto add_tab_before_line = [&results_buffer](const std::string& line) {
results_buffer << '\t' << line << '\n';
};
// Process each line and add a tab character before it
std::string line;
while (std::getline(input_buffer, line)) {
add_tab_before_line(line);
}
return results_buffer.str();
}
void
Exception::build_what_message(c::const_string class_name,
c::const_string optional_data)
{
std::string my_name(class_name);
std::stringstream buffer;
if (my_name.empty()) {
my_name = "elemental::Exception";
};
std::string indented_stacktrace =
prepend_tabs_to_lines(this->stack_trace);
buffer << my_name << "::what(): { " << std::endl
<< "\terror: " << error_message.c_str() << std::endl;
if (std::strlen(optional_data) > 0) {
buffer << "\tdata: " << optional_data << std::endl;
}
buffer << "\tstack_trace: " << std::endl
<< indented_stacktrace << std::endl
<< "};" << std::endl;
this->what_message = buffer.str().c_str();
}
// clang-format off
// vim: set foldmethod=marker foldmarker=\{,\} textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -39,14 +39,15 @@ FileResource::FileResource(const fs::path& file_path, CreateDirs mode)
if (fs::exists(file_path) == false) {
std::ofstream file_stream(
file_path, std::ios::out | std::ios::trunc);
file_path, std::ios::out | std::ios::trunc
);
file_stream.flush();
file_stream.close();
}
} catch (elemental::Exception&) {
} catch (IOCore::Exception&) {
throw;
} catch (std::exception& exception) {
throw Exception(exception);
throw IOCore::Exception(exception);
}
};
// clang-format off

View File

@ -26,14 +26,12 @@ namespace fs = std::filesystem;
namespace {
static std::stringstream error_buffer;
enum IndentMode : int
{
enum IndentMode : int {
Compact = -1,
NewlinesOnly = 0,
Ident = 1,
};
enum AsciiMode : bool
{
enum AsciiMode : bool {
Default = false,
Raw = false,
IgnoreUnicode = false,
@ -50,8 +48,7 @@ JsonConfigFile::JsonConfigFile(const fs::path& file_path, CreateDirs mode)
JsonConfigFile::~JsonConfigFile() = default;
auto
JsonConfigFile::read() -> nlohmann::json&
auto JsonConfigFile::read() -> nlohmann::json&
{
try {
std::ifstream file_stream(file_path);
@ -61,27 +58,26 @@ JsonConfigFile::read() -> nlohmann::json&
error_buffer
<< "Error opening JsonConfigFile for reading: "
<< file_path << std::endl;
throw Exception(error_buffer.str());
throw IOCore::Exception(error_buffer.str());
}
// If the file is empty, do not try to open it and parse JSON
if (file_stream.peek() != std::ifstream::traits_type::eof()) {
file_stream >> config_json;
}
} catch (elemental::Exception& except) {
} catch (IOCore::Exception& except) {
throw;
} catch (const std::exception& e) {
error_buffer.str("");
error_buffer << "JsonConfigFile::Read() error" << std::endl
<< e.what() << std::flush;
throw Exception(error_buffer.str());
throw IOCore::Exception(error_buffer.str());
}
return this->config_json;
}
void
JsonConfigFile::write()
void JsonConfigFile::write()
{
try {
std::ofstream file_stream(file_path);
@ -90,24 +86,26 @@ JsonConfigFile::write()
error_buffer << "Error opening JsonConfigFile "
"for writing: "
<< file_path << std::endl;
throw Exception(error_buffer.str());
throw IOCore::Exception(error_buffer.str());
}
file_stream
<< config_json.dump(
IndentMode::Ident, '\t', AsciiMode::IgnoreUnicode,
nlohmann::json::error_handler_t::replace)
<< std::endl;
file_stream << config_json.dump(
IndentMode::Ident,
'\t',
AsciiMode::IgnoreUnicode,
nlohmann::json::error_handler_t::replace
)
<< std::endl;
return;
} catch (elemental::Exception& except) {
} catch (IOCore::Exception& except) {
throw;
} catch (const std::exception& e) {
error_buffer.str("");
error_buffer << "JSonConfigFile::Save() error: " << std::endl
<< e.what() << std::flush;
throw Exception(error_buffer.str());
throw IOCore::Exception(error_buffer.str());
}
}
} // namespace elemental::configuration

View File

@ -74,7 +74,7 @@ SdlEventSource::pollEvents() -> void
}
auto
SdlEventSource::transmitEvents() -> void
SdlEventSource::sendEvents() -> void
{
auto thread_lock = MutexLock(this->mutex);

View File

@ -16,6 +16,7 @@
#include "util/debug.hpp"
#include "types/input.hpp"
#include "types/rendering.hpp"
#include <nlohmann/json.hpp>
@ -30,11 +31,10 @@ namespace {
std::stringstream error_buffer;
} // namespace
#define HANDLE_SDL_ERROR(what) \
error_buffer.str(""); \
error_buffer << what << ", SDL Error:" << SDL_GetError() \
<< std::flush; \
throw elemental::Exception(error_buffer.str());
#define HANDLE_SDL_ERROR(what) \
error_buffer.str(""); \
error_buffer << what << ", SDL Error:" << SDL_GetError() << std::flush; \
throw IOCore::Exception(error_buffer.str());
SdlRenderer::~SdlRenderer()
{
@ -43,20 +43,20 @@ SdlRenderer::~SdlRenderer()
}
}
void
SdlRenderer::init(RendererSettings& settings)
void SdlRenderer::init(RendererSettings& settings)
{
if (SDL_InitSubSystem(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0) {
HANDLE_SDL_ERROR("Could not initialize video subsystem");
}
if (kError == IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF |
IMG_INIT_WEBP)) {
if (kError ==
IMG_Init(
IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP
)) {
error_buffer.str("");
error_buffer
<< "Could not initialize SDL_Image: IMG_INIT() == 0"
<< std::flush;
throw elemental::Exception(error_buffer.str());
error_buffer << "Could not initialize SDL_Image: IMG_INIT() == 0"
<< std::flush;
throw IOCore::Exception(error_buffer.str());
}
int window_xpos, window_ypos, window_width, window_height, res_width,
res_height;
@ -81,21 +81,28 @@ SdlRenderer::init(RendererSettings& settings)
sdl_flags |= SDL_WINDOW_FULLSCREEN;
}
this->sdl_window_ptr =
SDL_CreateWindow(window_title.c_str(), window_xpos, window_ypos,
window_width, window_height, sdl_flags);
this->sdl_window_ptr = SDL_CreateWindow(
window_title.c_str(),
window_xpos,
window_ypos,
window_width,
window_height,
sdl_flags
);
if (nullptr == this->sdl_window_ptr) {
HANDLE_SDL_ERROR("Could not create SDL_Window");
}
this->sdl_renderer_ptr = SDL_CreateRenderer(this->sdl_window_ptr, 0,
SDL_RENDERER_ACCELERATED);
this->sdl_renderer_ptr = SDL_CreateRenderer(
this->sdl_window_ptr, 0, SDL_RENDERER_ACCELERATED
);
if (nullptr == this->sdl_renderer_ptr) {
HANDLE_SDL_ERROR("Could not initialize SDL_Renderer");
}
if (SDL_RenderSetLogicalSize(this->sdl_renderer_ptr, res_width,
res_height)) {
if (SDL_RenderSetLogicalSize(
this->sdl_renderer_ptr, res_width, res_height
)) {
HANDLE_SDL_ERROR("Could not set SDL_Renderer LogicalSize");
}
@ -103,8 +110,7 @@ SdlRenderer::init(RendererSettings& settings)
this->is_initialized = true;
}
void
SdlRenderer::deactivate()
void SdlRenderer::deactivate()
{
DBG_PRINT("SdlRenderer::Deactivate called!");
if (this->sdl_window_ptr != nullptr) {
@ -117,30 +123,28 @@ SdlRenderer::deactivate()
SDL_QuitSubSystem(SDL_INIT_VIDEO);
this->is_initialized = false;
}
auto
SdlRenderer::isInitialized() -> bool
auto SdlRenderer::isInitialized() -> bool
{
return this->is_initialized;
};
auto
SdlRenderer::getResolution() -> Resolution
auto SdlRenderer::getResolution() -> Resolution
{
int width, height;
/* SDL does not seem to catch this condition sometimes */
ASSERT(this->sdl_renderer_ptr.get() != nullptr)
if (kError == SDL_GetRendererOutputSize(this->sdl_renderer_ptr.get(),
&width, &height)) {
if (kError == SDL_GetRendererOutputSize(
this->sdl_renderer_ptr.get(), &width, &height
)) {
HANDLE_SDL_ERROR("Could not get Renderer output size");
}
return { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
}
auto
SdlRenderer::getWindowSize() -> Area
auto SdlRenderer::getWindowSize() -> Area
{
int width, height;
@ -156,8 +160,7 @@ SdlRenderer::getWindowSize() -> Area
return { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
}
void
SdlRenderer::clearScreen()
void SdlRenderer::clearScreen()
{
ASSERT(this->sdl_renderer_ptr != nullptr);
@ -168,8 +171,7 @@ SdlRenderer::clearScreen()
HANDLE_SDL_ERROR("Call to SDL_RenderClear failed!");
}
}
void
SdlRenderer::flip()
void SdlRenderer::flip()
{
ASSERT(this->sdl_renderer_ptr != nullptr);
@ -178,33 +180,32 @@ SdlRenderer::flip()
}
/*! \todo convert this to a private method, used internally to wrap SDL_Blit */
void
SdlRenderer::blit(std::shared_ptr<void> image_data, Rectangle& placement)
void SdlRenderer::blit(std::shared_ptr<void> image_data, Rectangle& placement)
{
ASSERT(this->sdl_renderer_ptr != nullptr);
ASSERT(image_data.get() != nullptr);
try {
auto to_draw =
std::static_pointer_cast<SDL_Texture>(image_data);
auto to_draw = std::static_pointer_cast<SDL_Texture>(image_data);
auto position = fromRectangle<SDL_Rect>(placement);
if (kError == SDL_RenderCopy(this->sdl_renderer_ptr.get(),
to_draw.get(), nullptr,
&position)) {
if (kError == SDL_RenderCopy(
this->sdl_renderer_ptr.get(),
to_draw.get(),
nullptr,
&position
)) {
HANDLE_SDL_ERROR("SDL_RenderCopy failed.");
}
} catch (Exception& thrown_exception) {
} catch (IOCore::Exception& thrown_exception) {
throw;
} catch (std::exception& thrown_exception) {
throw Exception(thrown_exception);
throw IOCore::Exception(thrown_exception);
}
}
SdlRenderer::SdlRenderer()
: IRenderer()
, sdl_window_ptr(nullptr)
, sdl_renderer_ptr(nullptr)
: IRenderer(), sdl_window_ptr(nullptr), sdl_renderer_ptr(nullptr)
{
}

View File

@ -1,146 +0,0 @@
/* debuginfo.h
* Copyright © 2020-2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "sys/debuginfo.hpp"
#include "sys/platform.hpp"
#if !defined(BOOST_STACKTRACER)
#if defined(HAVE_EXECINFO_H)
#include <execinfo.h>
#endif
#include <cxxabi.h>
#else
#include <boost/stacktrace.hpp>
#endif
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
namespace elemental {
namespace {
// Extracts the mangled symbol from a string like <func_name+0x34>
auto extract_mangled_symbol(const std::string& input) -> std::string
{
std::string result;
bool inside_angle_brackets = false;
for (char c : input) {
if (c == '<') {
inside_angle_brackets = true;
continue;
}
if (c == '>') {
inside_angle_brackets = false;
continue;
}
if (c == '+') {
break;
}
if (inside_angle_brackets) {
result += c;
}
}
return result;
}
} // namespace
// There are a lot of C and platform-specific hacks contained within
// I am sorry. 🤡
auto
generate_stacktrace(unsigned short framesToRemove) -> std::string
{
using namespace elemental::platform;
std::stringstream buffer;
#ifndef BOOST_STACKTRACER
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
size_t columns_to_print = 0;
// preconfigure column length for certain platforms
if (platform::kCurrentPlatform == kFREEBSD) {
columns_to_print = 2;
} else if (platform::kCurrentPlatform == kMACOS) {
columns_to_print = 4;
}
if (framesToRemove == frames) {
framesToRemove = 0;
}
for (i = framesToRemove; i < frames; ++i) {
std::string word;
std::stringstream line_stream(strs[i]);
std::vector<std::string> wordlist;
// Create a list of words for this stack trace line
while (line_stream >> word) {
if (columns_to_print != 0 &&
(word.find('<') != word.npos &&
word.find('>') != word.npos)) {
auto extracted_symbol =
extract_mangled_symbol(word);
word = extracted_symbol;
}
wordlist.push_back(word);
}
// if columns_to_print is still 0, assign it to the list length
// It is only pre-configured for certain platforms, see above
if (!columns_to_print) {
columns_to_print = wordlist.size();
}
// Process the extracted words one at a time and format the
// stack trace string
for (unsigned pos = 0; pos < columns_to_print; ++pos) {
auto word = wordlist[pos];
int status;
char* demangled_symbol = abi::__cxa_demangle(
word.c_str(), nullptr, nullptr, &status);
if (status == 0) {
buffer << demangled_symbol << '\t';
std::free(demangled_symbol);
} else {
buffer << word << '\t';
}
}
buffer << std::endl;
}
std::free(strs);
#else
buffer << boost::stacktrace::stacktrace() << std::flush;
#endif
return buffer.str();
}
void
print_cmdline(int argc, const char* argv[])
{
int i;
std::cout << "Command-line received" << std::endl;
for (i = 0; i < argc; ++i)
std::cout << argv[i] << " ";
std::cout << std::endl;
}
} // namespace elemental
// clang-format off
// vim: set foldmethod=syntax foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -7,10 +7,8 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "types/legible_ctypes.hpp"
#include "Exception.hpp"
#include "sys/paths.hpp"
#include "Exception.hpp"
#include "sys/platform.hpp"
#include <cstdlib>
@ -25,8 +23,7 @@
namespace fs = std::filesystem;
namespace elemental::paths {
auto
get_home() -> fs::path
auto get_home() -> fs::path
{
c::string result;
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
@ -37,8 +34,7 @@ get_home() -> fs::path
return result;
}
auto
get_app_config_root() -> fs::path
auto get_app_config_root() -> fs::path
{
fs::path result;
@ -55,44 +51,41 @@ get_app_config_root() -> fs::path
result = getenv("APPDATA");
break;
default:
throw NotImplementedException();
throw IOCore::NotImplementedException();
break;
}
return result;
}
auto
expand_path(const fs::path& location) -> fs::path
auto expand_path(const fs::path& location) -> fs::path
{
try {
fs::path result(location.root_path());
for (auto path_iter = location.begin();
path_iter != location.end(); ++path_iter) {
path_iter != location.end();
++path_iter) {
std::string token(path_iter->string());
c::string env_val;
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
if (token == "~" || token == "$HOME") {
env_val = getenv("HOME");
result =
result / (env_val ? std::string(env_val)
: std::string(""));
result = result / (env_val ? std::string(env_val)
: std::string(""));
} else if (token[0] == '$') {
// remove the $ from the varaible
token = token.substr(1, token.length());
env_val = getenv(token.c_str());
result =
result / (env_val ? std::string(env_val)
: std::string(""));
result = result / (env_val ? std::string(env_val)
: std::string(""));
} else {
#elif defined(__WIN32__)
if (token[0] == '%' && token[token.length()] == '%') {
// Remove the % around the varaible
token = token.substr(1, token.length() - 1);
env_val = getenv(token.c_str());
result =
result / (env_val ? std::string(env_val)
: std::string(""));
result = result / (env_val ? std::string(env_val)
: std::string(""));
} else {
#endif
@ -100,10 +93,10 @@ expand_path(const fs::path& location) -> fs::path
}
}
return fs::canonical(result);
} catch (elemental::Exception& e) {
} catch (IOCore::Exception& e) {
throw e;
} catch (std::exception& e) {
throw Exception(e);
throw IOCore::Exception(e);
}
}
} // namespace elemental::paths

View File

@ -1,61 +0,0 @@
/* Application.test.cpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "Application.hpp"
#include "Exception.hpp"
#include "test-utils/common.hpp"
#include <catch2/matchers/catch_matchers_string.hpp>
namespace {
struct SimulatedLaunch
{
static const char* argv[];
static const char* env[];
};
inline const char* SimulatedLaunch::argv[] = { "param1", "param2", "param3" };
inline const char* SimulatedLaunch::env[] = {
"PATH=/usr/bin", "VAR2=TWO", "REQUEST_URI=markdown?msg=hello-world",
nullptr
};
} // namespace
BEGIN_TEST_SUITE("elemental::Application")
{
using namespace elemental;
struct IDerivedApplication : public Application
{
auto run() -> int override { return 0; }
};
struct TestFixture
{
TestFixture() : derived_app(), app(derived_app) {}
IDerivedApplication derived_app;
IApplication& app;
};
FIXTURE_TEST("elemental::Application - Init method populates "
"Arguments list and Environment dictionary")
{
app.init(3, SimulatedLaunch::argv, SimulatedLaunch::env);
CHECK(app.getArguments().size() == 3);
CHECK(app.getArguments()[0] == "param1");
CHECK(app.getArguments()[1] == "param2");
CHECK(app.getArguments()[2] == "param3");
CHECK(app.getEnvironment().at("PATH") == "/usr/bin");
CHECK(app.getEnvironment().at("VAR2") == "TWO");
CHECK(app.getEnvironment().at("REQUEST_URI") ==
"markdown?msg=hello-world");
};
}
// clang-format off
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -1,9 +1,7 @@
# Define the executable 'test-runner'
set(test-runner_SOURCES
runtime.test.cpp
Exception.test.cpp
Singleton.template.test.cpp
Application.test.cpp
IRenderer.test.cpp
LoopRegulator.test.cpp
sdl/SdlRenderer.test.cpp
@ -19,7 +17,7 @@ add_executable(test-runner
${test-runner_SOURCES}
)
set_target_properties(test-runner PROPERTIES EXCLUDE_FROM_ALL 0)
set_target_properties(test-runner PROPERTIES EXCLUDE_FROM_ALL 1)
target_compile_definitions(test-runner PRIVATE
-DUNIT_TEST=1
@ -56,7 +54,7 @@ PRIVATE
# Set output directories for build targets
set_target_properties(test-runner PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/tests"
RUNTIME_OUTPUT_DIRECTORY "${Elemental_ARTIFACT_DIR}/tests"
)
# extras: catch2 ctest integration.
# add catch2's ctest cmake module and register the tests defined by mdml-tests

View File

@ -1,135 +0,0 @@
/* exceptions-test.cpp
* Copyright © 2023 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "Exception.hpp"
#include "test-utils/common.hpp"
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <exception>
#include <iostream>
#include <optional>
#include <stdexcept>
namespace Match = Catch::Matchers;
using Catch::CaseSensitive;
void
throw_wrapped_stl_exception()
{
auto local = std::logic_error("This is a stack variable");
throw elemental::Exception(local);
}
BEGIN_TEST_SUITE("elemental::Exception")
{
auto throw_an_exception = []() {
throw elemental::Exception("An error occurred!!");
};
TEST("elemental::Exception - Can throw new exception type")
{
REQUIRE_THROWS(throw_an_exception());
}
TEST("elemental::Exception - Can construct exception various ways")
{
SECTION("1. Blank constructor")
{
elemental::Exception obj;
}
SECTION("2a. With cstring parameter")
{
elemental::Exception obj("Sample Error");
}
SECTION("2b. With std::string parameter")
{
elemental::Exception obj(std::string("Sample Error"));
}
SECTION("3. With STL exception")
{
elemental::Exception obj(
std::runtime_error("Sample Error"));
}
SECTION("4. With destroyed stack")
{
auto nested_function_call = []() {
throw_wrapped_stl_exception();
};
try {
nested_function_call();
} catch (std::exception& e) {
REQUIRE_THAT(e.what(),
Match::ContainsSubstring(
"This is a stack variable"));
}
}
}
TEST("elemental::Exception::what() - message reflects error")
{
SECTION("1. Unspecified error or exception")
{
elemental::Exception obj;
REQUIRE_THAT(obj.what(),
Match::ContainsSubstring(
elemental::Exception::kDEFAULT_ERROR,
CaseSensitive::Yes));
}
SECTION("2. custom error or exception")
{
constexpr auto kTEST_MESSAGE = "This is a test.";
elemental::Exception test_object_one(kTEST_MESSAGE);
elemental::Exception test_object_two(
std::logic_error("Makes no sense"));
SECTION(" a: what() does not contain default message")
{
REQUIRE_THAT(
test_object_one.what(),
!Match::ContainsSubstring(
elemental::Exception::kDEFAULT_ERROR));
}
SECTION(" b: what() displays custom message")
{
REQUIRE_THAT(
test_object_one.what(),
Match::ContainsSubstring(kTEST_MESSAGE));
}
SECTION(" c: what() contains inner exception message")
{
REQUIRE_THAT(
test_object_two.what(),
Match::ContainsSubstring("Makes no sense"));
}
}
}
TEST("elemental::Exception::what() - contains stacktrace with Catch2 "
"runtime method names")
{
elemental::Exception test_object("Test");
SECTION(" a: what() does not contain default message")
{
REQUIRE_THAT(
test_object.what(),
Match::ContainsSubstring("Catch::RunContext"));
SUCCEED(test_object.what());
}
}
}
// clang-format off
// vim: set foldmethod=syntax textwidth=80 ts=4 sts=0 sw=4 noexpandtab ft=cpp.doxygen :

View File

@ -12,7 +12,6 @@
#include "Exception.hpp"
#include "sys/debuginfo.hpp"
#include "types/legible_ctypes.hpp"
#include "util/debug.hpp"
#include "test-utils/common.hpp"
@ -36,37 +35,37 @@ constexpr c::const_string kNON_EXISTENT_PATH = "/hades/tmp/dne/file.json";
BEGIN_TEST_SUITE("elemental::JsonConfigFile")
{
namespace { // Test fixtures
struct SampleFileGenerator
struct SampleFileGenerator {
SampleFileGenerator()
{
SampleFileGenerator()
{
if (!fs::exists(kINPUT_FILE_PATH)) {
std::ofstream f(kINPUT_FILE_PATH,
std::ios::out |
std::ios::trunc);
f << R"({"key1": "value1", "key2": "value2"})"
<< std::endl;
f.close();
}
if (!fs::exists(kINPUT_FILE_PATH)) {
std::ofstream f(
kINPUT_FILE_PATH,
std::ios::out | std::ios::trunc
);
f << R"({"key1": "value1", "key2": "value2"})"
<< std::endl;
f.close();
}
~SampleFileGenerator()
{
try {
if (fs::exists(kINPUT_FILE_PATH)) {
fs::remove(kINPUT_FILE_PATH);
}
} catch (std::exception& e) {
DBG_PRINT(e.what());
}
~SampleFileGenerator()
{
try {
if (fs::exists(kINPUT_FILE_PATH)) {
fs::remove(kINPUT_FILE_PATH);
}
} catch (std::exception& e) {
DBG_PRINT(e.what());
}
};
using TestFixture = SampleFileGenerator;
}
};
using TestFixture = SampleFileGenerator;
} // namespace
TEST("elemental::nlohmann::json is serializablable like "
"std::map<std::string,std::string>")
{
elemental::Dictionary<std::string> test_data;
IOCore::Dictionary<std::string> test_data;
nlohmann::json jsonified;
test_data["one"] = "1";
@ -92,8 +91,10 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
SECTION("JsonConfigFile w/ invalid path throws exception")
{
REQUIRE_THROWS_AS(JsonConfigFile(kNON_EXISTENT_PATH),
elemental::UnreachablePathException);
REQUIRE_THROWS_AS(
JsonConfigFile(kNON_EXISTENT_PATH),
elemental::UnreachablePathException
);
}
}
FIXTURE_TEST("JsonConfigFile::Read")
@ -113,9 +114,9 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
SECTION("JsonConfigFile::Read w/ bad file throws exception")
{
if (!fs::exists(kBADFILE_PATH)) {
std::ofstream f(kBADFILE_PATH);
f << R"({"Hello World"})" << std::endl;
f.close();
std::ofstream fileout(kBADFILE_PATH);
fileout << R"({"Hello World"})" << std::endl;
fileout.close();
}
REQUIRE_THROWS_AS(
[&]() {
@ -124,7 +125,8 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
bad_config.read();
}(),
Exception);
IOCore::Exception
);
}
if (fs::exists(kBADFILE_PATH)) {
fs::remove(kBADFILE_PATH);
@ -148,34 +150,37 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
resulting_file >> jobject;
auto written_data =
jobject.get<elemental::Dictionary<std::string>>();
jobject.get<IOCore::Dictionary<std::string>>();
REQUIRE(written_data["one"] == test_data["one"]);
REQUIRE(written_data["resolution"] ==
test_data["resolution"]);
REQUIRE(
written_data["resolution"] == test_data["resolution"]
);
REQUIRE(written_data["Hello"] == test_data["Hello"]);
}
fs::remove(kINPUT_FILE_PATH);
}
FIXTURE_TEST(
"JsonConfigFile::Get<T>() basically wraps nlohmann::json::get<T>()")
"JsonConfigFile::Get<T>() basically wraps nlohmann::json::get<T>()"
)
{
auto config_file = JsonConfigFile(kINPUT_FILE_PATH);
auto& json_data = config_file.getJsonData();
config_file.read();
auto obtained_data =
config_file.get<elemental::Dictionary<std::string>>();
config_file.get<IOCore::Dictionary<std::string>>();
REQUIRE(obtained_data["key1"] == "value1");
REQUIRE(obtained_data["key2"] == "value2");
}
FIXTURE_TEST(
"JsonConfigFile::Set() basically wraps nlohmann::json::operator=()")
"JsonConfigFile::Set() basically wraps nlohmann::json::operator=()"
)
{
auto config_file = JsonConfigFile(kINPUT_FILE_PATH);
elemental::Dictionary<std::string> test_data;
IOCore::Dictionary<std::string> test_data;
test_data["one"] = "1";
test_data["resolution"] = "1280x720";

View File

@ -7,10 +7,8 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "types/legible_ctypes.hpp"
#include "Exception.hpp"
#include "sys/paths.hpp"
#include "Exception.hpp"
#include "sys/platform.hpp"
#include "test-utils/common.hpp"
@ -39,8 +37,10 @@ BEGIN_TEST_SUITE("elemental::paths")
{
#if (defined(__APPLE__) && defined(__MACH__))
fs::path app_config_root = get_app_config_root();
REQUIRE(app_config_root ==
(get_home() / "Library" / "Application Support"));
REQUIRE(
app_config_root ==
(get_home() / "Library" / "Application Support")
);
#elif defined(__unix__)
fs::path appConfigRoot = get_app_config_root();
@ -56,24 +56,29 @@ BEGIN_TEST_SUITE("elemental::paths")
using namespace elemental::paths;
elemental::c::string home_var = getenv("HOME");
elemental::c::string user_name = getenv("USER");
c::string home_var = getenv("HOME");
c::string user_name = getenv("USER");
SECTION("resolves home directory")
{
if (home_var) {
REQUIRE(expand_path("~") ==
fs::canonical(home_var));
REQUIRE(expand_path("$HOME") ==
fs::canonical(home_var));
REQUIRE(
expand_path("~") == fs::canonical(home_var)
);
REQUIRE(
expand_path("$HOME") ==
fs::canonical(home_var)
);
}
}
SECTION("substitutes other variables")
{
if ((home_var && user_name) &&
(std::string(home_var) != "/")) {
REQUIRE(expand_path("~/../$USER") ==
fs::canonical(home_var));
REQUIRE(
expand_path("~/../$USER") ==
fs::canonical(home_var)
);
}
}
#if !defined(__unix__) && !(defined(__APPLE__) && defined(__MACH__))

View File

@ -36,7 +36,7 @@ PRIVATE
# Set output directories for build targetsk
set_target_properties(SDL_test-runner PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/tests"
RUNTIME_OUTPUT_DIRECTORY "${Elemental_ARTIFACT_DIR}/tests"
)
add_dependencies(ctest

View File

@ -121,7 +121,7 @@ BEGIN_TEST_SUITE("elemental::SdlEventSource")
event_queue_ref.push(input);
}
test_object.transmitEvents();
test_object.sendEvents();
REQUIRE(recorder.received.size() > 0);

View File

@ -22,21 +22,13 @@
namespace elemental {
struct SdlEventSimulator
{
enum KeyDir
{
Up = 0,
Right,
Down,
Left
};
struct SdlEventSimulator {
enum KeyDir { Up = 0, Right, Down, Left };
static inline auto eventFromScancode(SDL_Scancode scancode) -> SDL_Event
{
SDL_Event event{ .key = {
.type = SDL_KEYDOWN,
.keysym = { .scancode = scancode } } };
SDL_Event event{ .key = { .type = SDL_KEYDOWN,
.keysym = { .scancode = scancode } } };
return event;
}
@ -104,18 +96,17 @@ struct SdlEventSimulator
}
}; // #endregion
struct SdlTestFixture
{
struct SdlTestFixture {
std::stringstream buffer;
SdlTestFixture() : buffer()
{
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
if (SDL_InitSubSystem(SDL_INIT_EVENTS) != kSuccess) {
if (SDL_InitSubSystem(SDL_INIT_EVENTS) != IOCore::kSuccess) {
buffer << "SDL Could not initialize; SDL_Error: "
<< SDL_GetError();
throw elemental::Exception(buffer.str());
throw IOCore::Exception(buffer.str());
}
SDL_PumpEvents();
}