Compare commits
41 Commits
7aafa4c9aa
...
custom_pla
| Author | SHA1 | Date | |
|---|---|---|---|
| 086c73f058 | |||
| 339f5c8cd8 | |||
| 18c0a7099d | |||
| 540c7fbce8 | |||
| cbcd699ab0 | |||
| ff27caab4f | |||
| fe4c49d092 | |||
| 037c62bf12 | |||
| 494d766741 | |||
| 83f0c01e29 | |||
| 4ff739d625 | |||
| 7cd38604a7 | |||
| 733fca41ef | |||
| 55a8c54119 | |||
| 27754a56d7 | |||
| fcf9c6adcb | |||
| e6c0a60ea9 | |||
| 5252ba84c9 | |||
| 73041e994d | |||
| 3ddc2b3d97 | |||
| e91c2aa9f1 | |||
| 38b7221fa0 | |||
| 8bfb59cd20 | |||
| 2535e1ac4b | |||
| f173c3e7cd | |||
| cc4d85c393 | |||
| d6e31a89b0 | |||
| 74fb525453 | |||
| b9de039a10 | |||
| 9f96155856 | |||
| d2be083a8f | |||
| efe56b3699 | |||
| b7d8426e86 | |||
| 2cb41e1437 | |||
| 0f721f57ea | |||
| 4a3639ecb4 | |||
| ff4d6efedc | |||
| 9dc9ed4ed1 | |||
| 5e04eb0ca6 | |||
| 3d42dea9eb | |||
| 3d4ea4398a |
7
.gdbinit
Normal file
7
.gdbinit
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
python
|
||||||
|
import sys, os.path
|
||||||
|
print(os.path.abspath("./gdb"))
|
||||||
|
sys.path.insert(0, os.path.abspath("./gdb"))
|
||||||
|
import fennec
|
||||||
|
fennec.register_printers(gdb.current_objfile())
|
||||||
|
end
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
|||||||
/docs/
|
/docs/
|
||||||
/bin/
|
/bin/
|
||||||
/lib/
|
/lib/
|
||||||
|
/doxy/README.md
|
||||||
|
|||||||
@@ -20,20 +20,38 @@ cmake_minimum_required(VERSION 3.30)
|
|||||||
project(fennec)
|
project(fennec)
|
||||||
|
|
||||||
# External dependencies should be loaded here
|
# External dependencies should be loaded here
|
||||||
|
|
||||||
# CppTrace is a dependency of the project, added as a git submodule
|
|
||||||
add_subdirectory(external/cpptrace)
|
add_subdirectory(external/cpptrace)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_C_STANDARD 23)
|
set(CMAKE_C_STANDARD 23)
|
||||||
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
add_custom_target(fennec-dependencies
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
|
||||||
|
COMMENT "Running dependencies."
|
||||||
|
)
|
||||||
|
|
||||||
|
macro(fennec_add_sources)
|
||||||
|
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(fennec_add_definitions)
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(fennec_add_link_libraries)
|
||||||
|
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
# include scripts
|
# include scripts
|
||||||
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
|
||||||
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
|
||||||
include("${FENNEC_SOURCE_DIR}/cmake/build.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/build.cmake")
|
||||||
include("${FENNEC_SOURCE_DIR}/cmake/compiler.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/compiler.cmake")
|
||||||
|
|
||||||
|
# common defines
|
||||||
|
list(APPEND FENNEC_COMPILE_DEFINITIONS "NULL=0")
|
||||||
|
|
||||||
# find dependencies
|
# find dependencies
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
fennec_check_platform()
|
fennec_check_platform()
|
||||||
@@ -58,16 +76,32 @@ add_library(fennec STATIC
|
|||||||
include/fennec/core/engine.h source/core/engine.cpp
|
include/fennec/core/engine.h source/core/engine.cpp
|
||||||
include/fennec/core/event.h source/core/event.cpp
|
include/fennec/core/event.h source/core/event.cpp
|
||||||
|
|
||||||
|
include/fennec/core/system.h
|
||||||
|
|
||||||
|
|
||||||
|
# SCENE ================================================================================================================
|
||||||
|
include/fennec/scene/scene.h
|
||||||
|
include/fennec/scene/component.h
|
||||||
|
|
||||||
|
|
||||||
# CONTAINERS ===========================================================================================================
|
# CONTAINERS ===========================================================================================================
|
||||||
|
include/fennec/containers/containers.h
|
||||||
|
|
||||||
include/fennec/containers/array.h
|
include/fennec/containers/array.h
|
||||||
|
include/fennec/containers/deque.h
|
||||||
include/fennec/containers/dynarray.h
|
include/fennec/containers/dynarray.h
|
||||||
|
include/fennec/containers/graph.h
|
||||||
include/fennec/containers/list.h
|
include/fennec/containers/list.h
|
||||||
include/fennec/containers/map.h
|
include/fennec/containers/map.h
|
||||||
|
include/fennec/containers/object_pool.h
|
||||||
include/fennec/containers/optional.h
|
include/fennec/containers/optional.h
|
||||||
include/fennec/containers/pair.h
|
include/fennec/containers/pair.h
|
||||||
|
include/fennec/containers/rdtree.h
|
||||||
include/fennec/containers/set.h
|
include/fennec/containers/set.h
|
||||||
|
include/fennec/containers/traversal.h
|
||||||
include/fennec/containers/tuple.h
|
include/fennec/containers/tuple.h
|
||||||
|
include/fennec/containers/variant.h
|
||||||
|
|
||||||
|
|
||||||
include/fennec/containers/detail/_tuple.h
|
include/fennec/containers/detail/_tuple.h
|
||||||
|
|
||||||
@@ -83,7 +117,7 @@ add_library(fennec STATIC
|
|||||||
include/fennec/lang/intrinsics.h
|
include/fennec/lang/intrinsics.h
|
||||||
include/fennec/lang/limits.h
|
include/fennec/lang/limits.h
|
||||||
include/fennec/lang/numeric_transforms.h
|
include/fennec/lang/numeric_transforms.h
|
||||||
include/fennec/lang/sequences.h
|
include/fennec/lang/const_sequences.h
|
||||||
include/fennec/lang/startup.h
|
include/fennec/lang/startup.h
|
||||||
include/fennec/lang/type_identity.h
|
include/fennec/lang/type_identity.h
|
||||||
include/fennec/lang/type_operators.h
|
include/fennec/lang/type_operators.h
|
||||||
@@ -95,6 +129,9 @@ add_library(fennec STATIC
|
|||||||
include/fennec/lang/utility.h
|
include/fennec/lang/utility.h
|
||||||
include/fennec/lang/integer.h
|
include/fennec/lang/integer.h
|
||||||
|
|
||||||
|
include/fennec/lang/assert.h source/lang/assert.cpp
|
||||||
|
|
||||||
|
|
||||||
include/fennec/lang/detail/_bits.h
|
include/fennec/lang/detail/_bits.h
|
||||||
include/fennec/lang/detail/_int.h
|
include/fennec/lang/detail/_int.h
|
||||||
include/fennec/lang/detail/_numeric_transforms.h
|
include/fennec/lang/detail/_numeric_transforms.h
|
||||||
@@ -104,8 +141,6 @@ add_library(fennec STATIC
|
|||||||
include/fennec/lang/detail/_type_sequences.h
|
include/fennec/lang/detail/_type_sequences.h
|
||||||
include/fennec/lang/detail/_typeuuid.h
|
include/fennec/lang/detail/_typeuuid.h
|
||||||
|
|
||||||
include/fennec/lang/assert.h source/lang/assert.cpp
|
|
||||||
|
|
||||||
|
|
||||||
# MEMORY ===============================================================================================================
|
# MEMORY ===============================================================================================================
|
||||||
include/fennec/memory/new.h source/memory/new.cpp
|
include/fennec/memory/new.h source/memory/new.cpp
|
||||||
@@ -115,15 +150,10 @@ add_library(fennec STATIC
|
|||||||
include/fennec/memory/common.h
|
include/fennec/memory/common.h
|
||||||
include/fennec/memory/memory.h
|
include/fennec/memory/memory.h
|
||||||
include/fennec/memory/pointers.h
|
include/fennec/memory/pointers.h
|
||||||
include/fennec/memory/ptr_traits.h
|
include/fennec/memory/pointer_traits.h
|
||||||
|
|
||||||
include/fennec/memory/detail/_ptr_traits.h
|
include/fennec/memory/detail/_ptr_traits.h
|
||||||
|
|
||||||
# CONCURRENCY ==========================================================================================================
|
|
||||||
include/fennec/concurrency/thread.h
|
|
||||||
include/fennec/concurrency/mutex.h
|
|
||||||
include/fennec/concurrency/atomic.h
|
|
||||||
|
|
||||||
# DEBUG ================================================================================================================
|
# DEBUG ================================================================================================================
|
||||||
source/debug/assert_impl.cpp
|
source/debug/assert_impl.cpp
|
||||||
|
|
||||||
@@ -164,18 +194,18 @@ add_library(fennec STATIC
|
|||||||
include/fennec/math/detail/_vector_traits.h
|
include/fennec/math/detail/_vector_traits.h
|
||||||
|
|
||||||
|
|
||||||
# FPROC ================================================================================================================
|
# langproc ================================================================================================================
|
||||||
|
|
||||||
# Strings
|
# Strings
|
||||||
include/fennec/fproc/strings/cstring.h
|
include/fennec/langproc/strings/cstring.h
|
||||||
include/fennec/fproc/strings/locale.h
|
include/fennec/langproc/strings/locale.h
|
||||||
include/fennec/fproc/strings/string.h
|
include/fennec/langproc/strings/string.h
|
||||||
|
|
||||||
include/fennec/fproc/strings/detail/_ctype.h
|
include/fennec/langproc/strings/detail/_ctype.h
|
||||||
|
|
||||||
# Filesystem
|
# Filesystem
|
||||||
include/fennec/fproc/filesystem/file.h source/fproc/filesystem/file.cpp
|
include/fennec/langproc/filesystem/file.h source/langproc/filesystem/file.cpp
|
||||||
include/fennec/fproc/filesystem/path.h source/fproc/filesystem/path.cpp
|
include/fennec/langproc/filesystem/path.h source/langproc/filesystem/path.cpp
|
||||||
|
|
||||||
|
|
||||||
# PLATFORM =============================================================================================================
|
# PLATFORM =============================================================================================================
|
||||||
@@ -184,6 +214,7 @@ add_library(fennec STATIC
|
|||||||
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
|
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
|
||||||
include/fennec/platform/interface/display.h source/platform/interface/display.cpp
|
include/fennec/platform/interface/display.h source/platform/interface/display.cpp
|
||||||
include/fennec/platform/interface/gfxcontext.h
|
include/fennec/platform/interface/gfxcontext.h
|
||||||
|
include/fennec/platform/interface/gfxsurface.h
|
||||||
|
|
||||||
|
|
||||||
# EXTRA SOURCES ========================================================================================================
|
# EXTRA SOURCES ========================================================================================================
|
||||||
@@ -191,7 +222,7 @@ add_library(fennec STATIC
|
|||||||
${FENNEC_EXTRA_SOURCES}
|
${FENNEC_EXTRA_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(fennec metaprogramming)
|
add_dependencies(fennec metaprogramming fennec-dependencies)
|
||||||
|
|
||||||
target_compile_definitions(fennec PUBLIC
|
target_compile_definitions(fennec PUBLIC
|
||||||
${FENNEC_COMPILE_DEFINITIONS}
|
${FENNEC_COMPILE_DEFINITIONS}
|
||||||
@@ -203,8 +234,9 @@ target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not comp
|
|||||||
# This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated
|
# This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated
|
||||||
|
|
||||||
target_link_libraries(fennec PRIVATE
|
target_link_libraries(fennec PRIVATE
|
||||||
cpptrace::cpptrace
|
|
||||||
${FENNEC_LINK_LIBRARIES}
|
${FENNEC_LINK_LIBRARIES}
|
||||||
|
|
||||||
|
cpptrace::cpptrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -217,6 +249,7 @@ file(COPY logo DESTINATION docs/logo)
|
|||||||
if(DOXYGEN_FOUND)
|
if(DOXYGEN_FOUND)
|
||||||
add_dependencies(fennec fennecdocs)
|
add_dependencies(fennec fennecdocs)
|
||||||
set(DOXY_OUTPUT_DIR "${FENNEC_SOURCE_DIR}/docs")
|
set(DOXY_OUTPUT_DIR "${FENNEC_SOURCE_DIR}/docs")
|
||||||
|
set(DOXY_EXAMPLES_DIR "${FENNEC_SOURCE_DIR}/examples")
|
||||||
get_filename_component(DOXYGEN_PROJECT_NAME ${FENNEC_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir
|
get_filename_component(DOXYGEN_PROJECT_NAME ${FENNEC_SOURCE_DIR} NAME) # Set Doxy Project name to the name of the root dir
|
||||||
set(DOXYGEN_CONFIG_IN "${FENNEC_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments
|
set(DOXYGEN_CONFIG_IN "${FENNEC_SOURCE_DIR}/doxy/Doxyfile.in") # Input config file with preprocessor arguments
|
||||||
set(DOXYGEN_CONFIG_OUT "${FENNEC_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input
|
set(DOXYGEN_CONFIG_OUT "${FENNEC_SOURCE_DIR}/doxy/Doxyfile") # Generated config file from input
|
||||||
|
|||||||
657
PLANNING.md
657
PLANNING.md
@@ -1,657 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# Planning Documentation for fennec
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
2. [TODO](#todo)
|
|
||||||
1. [Security Ramblings](#file-security-ramblings)
|
|
||||||
2. [Platform Support](#platform--api-support)
|
|
||||||
3. [C++ Language](#c-language-library-lang)
|
|
||||||
4. [Math Library](#math-library-math)
|
|
||||||
5. [Memory Library](#memory-library-memory)
|
|
||||||
6. [Containers Library](#containers-library-containers)
|
|
||||||
7. [Format Processing](#format-processing-fproc)
|
|
||||||
8. [Core](#core-core)
|
|
||||||
1. [Tick](#tick)
|
|
||||||
2. [Frame](#frame)
|
|
||||||
9. [Platform Support Layer](#platform-support-layer-platform)
|
|
||||||
10. [Scene](#scene-scene)
|
|
||||||
11. [2D Graphics](#2d-graphics-gfx2d)
|
|
||||||
12. [3D Graphics](#3d-graphics-gfx3d)
|
|
||||||
1. [Structures](#structures-gfx3d)
|
|
||||||
2. [Stages](#stages-gfx3d)
|
|
||||||
13. [3D Physics](#3d-physics-physics3d)
|
|
||||||
14. [Artificial Intelligence](#artificial-intelligence-ai)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
This file serves as a general planning document for engine structure, systems, pipelines, and implementation.
|
|
||||||
|
|
||||||
|
|
||||||
Implementations of core engine systems should strive to be `O(1)` in implementations,
|
|
||||||
both in terms of runtime and memory performance. This is obviously not a realistic goal,
|
|
||||||
so rather than the goal requiring the entire engine to be `O(1)`, we should more specifically look
|
|
||||||
at achieving `O(1)` performance on hot paths. I distinctly use 'strive' and 'goal' as different concepts, where designs
|
|
||||||
should *strive* to accommodate function implementations for `O(1)`, however the specifics of the implementation might not always
|
|
||||||
be able to achieve that, so the end *goal* is that hot paths should be `O(1)`.
|
|
||||||
|
|
||||||
Functions should be highly verbose and any bugprone or erroneous behaviour should throw
|
|
||||||
assertions. **DO NOT USE EXCEPTIONS**.
|
|
||||||
|
|
||||||
System implementations should be independent of architecture or platforms. i.e. the code of the graphics system should
|
|
||||||
not care if OpenGL or Vulkan is used and should not use any direct calls to OpenGL or Vulkan.
|
|
||||||
|
|
||||||
The engine should not care about the types of objects loaded from a so/dll. In fact, most of the code should
|
|
||||||
be type independent. Any shared information among a collection of objects should be held either implicitly or explicitly
|
|
||||||
in the super-class. It will be the responsibility of the linked code to initialize and cleanup the objects related to it.
|
|
||||||
This principle should extend to the submodules of the engine.
|
|
||||||
|
|
||||||
It is also best to avoid objects having behaviour that is not defined by the system they are in. There are some exceptions
|
|
||||||
in extensions or mods and should be given configurability and programmability within those systems and their stages.
|
|
||||||
This however can be achieved using events at different stages of those engines that are on-demand.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- 2D Graphics (`gfx2d`)
|
|
||||||
- 2D Physics (`physics2d`)
|
|
||||||
- 2D & 3D Audio (`audio`)
|
|
||||||
|
|
||||||
|
|
||||||
### File Security Ramblings:
|
|
||||||
|
|
||||||
Windows is starting to piss me off, so I am considering dropping official support for MSVC. MinGW and Cygwin
|
|
||||||
will still work for compiling on Windows if this ends up being the case. The reason for this is that there are
|
|
||||||
*a lot* of platform dependent security issues. MinGW and Cygwin wrap Linux and glibc headers for Windows, which would
|
|
||||||
push the security onus onto the compiler and end-user.
|
|
||||||
|
|
||||||
The biggest blocker at the moment in terms of this is the filesystem. If we want to implement a filesystem that
|
|
||||||
is safe across platforms, stdc++ *and* iso libc have no guarantees about the safety of their functions.
|
|
||||||
|
|
||||||
The crux of this issue falls at the following specific behaviour:
|
|
||||||
- User selects an existing file to write to
|
|
||||||
- Application interface confirms overwrite action
|
|
||||||
- Application writes to the file after confirmation
|
|
||||||
|
|
||||||
A threat actor can introduce a malicious file or symlink to the file that was attempted access between the check and
|
|
||||||
usage of the file. This is called TOCTOU (time of check, time of use).
|
|
||||||
|
|
||||||
This issue can be solved using `fopen("<file>", "a+")` and `ftell`, however this specific behaviour is not intuitive to
|
|
||||||
those first learning how to work with file systems. We can attempt to abstract this away with another wrapper, or simply
|
|
||||||
write the file structure to handle this behaviour properly. The downside to this method overall is that it will break
|
|
||||||
common conventions of how humans interpret filesystems and the related control flow logic. What we can do is force the
|
|
||||||
`'+'` flag to always be present for write operations, and raise an error when desired, if the file is not empty. This
|
|
||||||
unfortunately would have the downside of being unable to open a file as write only.
|
|
||||||
|
|
||||||
Using `"wx"` in this instance would not be sufficient since it would require a second call to fopen, which would
|
|
||||||
create the conditions for the TOCTOU error described above.
|
|
||||||
|
|
||||||
Another issue arises when we are parsing a directory tree. The best we can do is take ownership of the directory that
|
|
||||||
is opened as the root. However, this requires `dirent.h` which is not implemented in MSVC. A custom implementation of
|
|
||||||
`dirent.h` may be written for MSVC, however this is one of the few things I am not willing to outsource to another
|
|
||||||
library. Developing our own implementation would take a non-insignificant amount of time, between writing the library,
|
|
||||||
debugging it, and testing for vulnerabilities. As stated above, this implementation is native to MinGW and Cygwin,
|
|
||||||
so we would not have to entirely drop support for Windows. However, MSVC is the most widely used compiler for Windows
|
|
||||||
applications and is native to Visual Studio and VSCode.
|
|
||||||
|
|
||||||
What is probably the best solution is to wrap everything in a file interface that does not allow the direct setting of
|
|
||||||
these flags. Then we set our own usage type for the file that informs which flags should be used.
|
|
||||||
|
|
||||||
We need to be able to handle the following types of files:
|
|
||||||
- Assets, such as scenes, audio, textures, metadata, meshes, etc.
|
|
||||||
- Save files, setting files, etc.
|
|
||||||
|
|
||||||
One of the nice things about the assets is that they are guaranteed to be read-only once an application is installed
|
|
||||||
on the computer of the end-user. Therefore, this issue only arises with save files and custom file formats.
|
|
||||||
|
|
||||||
When the editor is run, all these files should be opened in read/write mode.
|
|
||||||
|
|
||||||
Naming conventions should exist for the types of files and how they are read. For example, in release mode,
|
|
||||||
most assets should be opened once, and then closed immediately. However, this does not make sense for formats
|
|
||||||
that are continuous and too large to be kept around in memory, such as video formats.
|
|
||||||
|
|
||||||
Perhaps the following conventions:
|
|
||||||
- Static Asset
|
|
||||||
- Stream Asset
|
|
||||||
- Resource
|
|
||||||
|
|
||||||
We can turn this into an object-oriented approach by having different formats inherit these base types. We may still
|
|
||||||
have a base file type that wraps C functionality, but discourage developers from using the interface.
|
|
||||||
|
|
||||||
We could also declare the file interface extern so that only internal files know the implementation. However, I would
|
|
||||||
not be satisfied by doing this since it would prevent developers from implementing custom file type implementations.
|
|
||||||
|
|
||||||
Conserving memory is not really an issue here as long as we are smart about our implementation. Files should only be
|
|
||||||
open when necessary and be closed when it is no longer necessary to have them open. Data should be streamed unless the
|
|
||||||
all the data in the file is required.
|
|
||||||
|
|
||||||
When built in release mode, we also need to pack static assets into some sort of archive that is mountable to reduce
|
|
||||||
disk space consumption of a program.
|
|
||||||
|
|
||||||
I was considering encryption for archives, however it does not make much sense. Assuming someone intends to pirate the
|
|
||||||
game, there is not much stopping them from running the files. I will add Steam support at some point which would allow
|
|
||||||
you to use Steam's DRM to prevent the executable from being run. Otherwise, there is no point in attempting to encrypt
|
|
||||||
game files. Even Unreal PAK files can be cracked in seconds, and even if I managed to write something that cannot be
|
|
||||||
trivially cracked locally, you can scrape most assets from the GPU and Audio Card.
|
|
||||||
|
|
||||||
I have managed to solve the specific case provided at the top of this section, which was done by wrapping C I/O calls
|
|
||||||
into a file wrapper. This wrapper can handle a few different mode flags and has specific conditions for the flags. See
|
|
||||||
the documentation for `fennec/fproc/io/file.h` for more info.
|
|
||||||
|
|
||||||
One question remains unanswered on this front; should a read/write file open as `r+` or `a+`. `rewind` is slightly faster
|
|
||||||
than `fseek(SEEK_END)`, however for the case of save files and editor assets, `r+` makes more sense from a usage perspective
|
|
||||||
|
|
||||||
Directories remain an issue, with `dirent.h` being the only sensible option at time of writing. The issue with using
|
|
||||||
`dirent.h` boils back down to security issues on Windows. However, the only option is to write a custom implementation
|
|
||||||
for MSVC.
|
|
||||||
|
|
||||||
|
|
||||||
### Platform & API Support
|
|
||||||
|
|
||||||
I have decided to forgo SDL, this is so the engine can provide specific support for specific platforms.
|
|
||||||
Also, SDL implements a lot of things that will need to be implemented specifically for the engine, so only the window
|
|
||||||
management would be used.
|
|
||||||
|
|
||||||
Platform support will be implemented in the following order:
|
|
||||||
- Linux/BSD
|
|
||||||
- Wayland
|
|
||||||
- OpenGL (EGL)
|
|
||||||
- PulseAudio
|
|
||||||
- Vulkan
|
|
||||||
- X11
|
|
||||||
- OpenGL (EGL)
|
|
||||||
- ALSA
|
|
||||||
- Vulkan
|
|
||||||
- Microsoft Windows
|
|
||||||
- XInput
|
|
||||||
- OpenGL
|
|
||||||
- DirectSound
|
|
||||||
- Vulkan
|
|
||||||
- Android
|
|
||||||
- OpenGL ES
|
|
||||||
- macOS
|
|
||||||
- iOS
|
|
||||||
|
|
||||||
Most consoles will never get official platform support due to NDAs which conflict with the principles of this engine.
|
|
||||||
fennec will avoid using proprietary libraries except when strictly necessary, such as support for Windows and MacOS.
|
|
||||||
fennec will interact with any drivers required for the listed operating systems above, even if proprietary.
|
|
||||||
|
|
||||||
|
|
||||||
## C++ Language Library (`lang`)
|
|
||||||
|
|
||||||
Implement header files for standard functions relating to the C++ Language.
|
|
||||||
|
|
||||||
So far this is implemented on an as-needed basis. A full implementation should be worked on continuously.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Math Library (`math`)
|
|
||||||
|
|
||||||
Implement math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf).
|
|
||||||
|
|
||||||
"Extensions" has a different meaning here. Extensions for the math library are any functions that are not defined within
|
|
||||||
the Specification.
|
|
||||||
|
|
||||||
Additional extensions should be implemented to provide standard definitions for functions predominantly related
|
|
||||||
to Linear Algebra, Mathematical Analysis, and more specifically Discrete Analysis. Additional extensions will be
|
|
||||||
implemented on an as-needed basis.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Memory Library (`memory`)
|
|
||||||
|
|
||||||
Implement headers related to memory allocation in C++.
|
|
||||||
|
|
||||||
* Smart Pointers
|
|
||||||
* Unique Pointer
|
|
||||||
* Shared Pointer
|
|
||||||
|
|
||||||
- Memory Allocation
|
|
||||||
- Allocation
|
|
||||||
-
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Containers Library (`containers`)
|
|
||||||
|
|
||||||
All containers of the [C++ Standard Library](https://cppreference.com/w/cpp/container.html) should be implemented.
|
|
||||||
|
|
||||||
Here are essential data-structures not specified in the C++ stdlib:
|
|
||||||
- Graph → AI `graph`
|
|
||||||
- Necessary for 2D and 3D navigation.
|
|
||||||
- Rooted Directed Tree → Scene `rd_tree`
|
|
||||||
- Defines the scene structure.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Format Processing (`fproc`)
|
|
||||||
|
|
||||||
This library contains information for any data that is formatted. This includes basic string formats, file formats,
|
|
||||||
and eventually programming languages
|
|
||||||
|
|
||||||
fennec should be able to use Doxygen and LaTeX externally. Consider including binaries with releases.
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
|
|
||||||
* String Analysis (`fproc/strings`)
|
|
||||||
* Search
|
|
||||||
* Manipulation
|
|
||||||
* Delimiting
|
|
||||||
* Regex
|
|
||||||
|
|
||||||
- File Formats (`fproc/formats`)
|
|
||||||
- Serialization
|
|
||||||
- JSON
|
|
||||||
- HTML
|
|
||||||
- XML
|
|
||||||
- YAML
|
|
||||||
- Configuration
|
|
||||||
- INI
|
|
||||||
- TOML
|
|
||||||
- Documents
|
|
||||||
- ODF
|
|
||||||
- Markdown
|
|
||||||
- PDF
|
|
||||||
- Spreadsheets & Tables
|
|
||||||
- ODS
|
|
||||||
- CSV
|
|
||||||
- Audio Formats
|
|
||||||
- MP3
|
|
||||||
- WAV
|
|
||||||
- AAC
|
|
||||||
- Graphics Formats
|
|
||||||
- Textures
|
|
||||||
- BMP
|
|
||||||
- DDS
|
|
||||||
- JPG
|
|
||||||
- PNG
|
|
||||||
- TIFF
|
|
||||||
- Vectors
|
|
||||||
- OTF
|
|
||||||
- SVG
|
|
||||||
- TTF
|
|
||||||
- Models
|
|
||||||
- FBX
|
|
||||||
- Wavefront OBJ
|
|
||||||
- Video Formats
|
|
||||||
- MP4
|
|
||||||
- AVI
|
|
||||||
- MPG
|
|
||||||
- MOV
|
|
||||||
|
|
||||||
**TODO LATER**
|
|
||||||
* Compilation (`fproc/code`)
|
|
||||||
* Lexical Analysis
|
|
||||||
* Syntax Analysis
|
|
||||||
* Semantic Analysis
|
|
||||||
* Intermediate Code Generation
|
|
||||||
* Optimization
|
|
||||||
* Target Code Generation
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Core (`core`)
|
|
||||||
|
|
||||||
This will be the core of the engine.
|
|
||||||
|
|
||||||
- Event System
|
|
||||||
- Most events will fire at the start of the next tick, especially those related to physics and input.
|
|
||||||
- Events for graphics or audio should propagate immediately.
|
|
||||||
- Events for stages should also propagate immediately, this is to support extensions and mods.
|
|
||||||
- Core Engine Loop
|
|
||||||
- System Manager
|
|
||||||
- Ticks vs. Frames
|
|
||||||
|
|
||||||
The following systems are not essential to the core engine, but are instead major systems that should be defined
|
|
||||||
in their operation order:
|
|
||||||
|
|
||||||
### Tick
|
|
||||||
- **Update**
|
|
||||||
- Events
|
|
||||||
- Scripts
|
|
||||||
- AI
|
|
||||||
- **Physics**
|
|
||||||
- Newtonian Commit
|
|
||||||
- Apply Forces (Updates Acceleration and Torque)
|
|
||||||
- Apply Torque & Acceleration (Updates Velocities)
|
|
||||||
- Apply Velocities (Updates Position and Rotation)
|
|
||||||
- Constraint Resolution
|
|
||||||
- Collision Detection
|
|
||||||
- Collision Resolution
|
|
||||||
- Collision Response
|
|
||||||
- Calculate Forces & Velocities
|
|
||||||
- Queue events for next tick
|
|
||||||
|
|
||||||
|
|
||||||
### Frame
|
|
||||||
- **Physics**
|
|
||||||
- Physics Interpolation
|
|
||||||
- **Graphics**
|
|
||||||
- [2D Graphics](#2d-graphics-gfx2d)
|
|
||||||
- Generate 3D Mask
|
|
||||||
- [3D Graphics](#3d-graphics-gfx3d)
|
|
||||||
- **Audio**
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Platform Support Layer (`platform`)
|
|
||||||
|
|
||||||
This is the core part of platform support for fennec. All necessary drivers
|
|
||||||
and OS specific functionality will be wrapped up nicely into these interfaces.
|
|
||||||
|
|
||||||
See implementation order [here](#platform--api-support)
|
|
||||||
|
|
||||||
|
|
||||||
## Scene (`scene`)
|
|
||||||
|
|
||||||
* In-Array Directed Tree
|
|
||||||
* Elegant method for providing `O(1)` insertions and `O(log(n))` deletions.
|
|
||||||
* Bounding Volume Hierarchy
|
|
||||||
* Octree
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 2D Graphics (`gfx2d`)
|
|
||||||
|
|
||||||
Links:
|
|
||||||
- https://en.wikipedia.org/wiki/Quadtree
|
|
||||||
- https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-25-rendering-vector-art-gpu
|
|
||||||
|
|
||||||
Object Structure. The mesh is implicit data.
|
|
||||||
|
|
||||||
|
|
||||||
### Structures (`gfx2d`)
|
|
||||||
|
|
||||||
For the 2d rendering framework, Materials need to be rendered independently because we have
|
|
||||||
no size constraints for images. This disallows us from using a meta-shader like in
|
|
||||||
the 3d rendering framework.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
struct Object
|
|
||||||
{
|
|
||||||
vec2 location, scale; // A matrix would be 36 bytes, this is instead 20 bytes
|
|
||||||
float rotation;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- BVH
|
|
||||||
- Quadtree
|
|
||||||
- Leaf Size and Tree Depth should be calculated by the scene, constraints are as follows:
|
|
||||||
- Min Object Size
|
|
||||||
- Max Object Size
|
|
||||||
- Scene Center
|
|
||||||
- Scene Edge
|
|
||||||
- Insertions and Updates are done on the CPU
|
|
||||||
- Nodes
|
|
||||||
- Start Index 32-bits
|
|
||||||
- Object Count 32-bits
|
|
||||||
- Objects
|
|
||||||
- Buffer of Object IDs grouped by Octree Node
|
|
||||||
- Culling
|
|
||||||
- Starting at each Octree Leaf, traverse upwards.
|
|
||||||
- Insert Visible Leaf IDs
|
|
||||||
- Track using atomic buffer
|
|
||||||
- Generate the Command Buffer for Culled Meshes from the Visible Leaf Buffer
|
|
||||||
- Count Materials
|
|
||||||
- Count Meshes per Material
|
|
||||||
- Generate the Culled Object Buffer by copying objects from the Object Buffer
|
|
||||||
- Adjust Buffer Size using the counts
|
|
||||||
- Insert using another atomic buffer
|
|
||||||
|
|
||||||
- Translucent objects will be sorted. We can cheat by using a z-index instead of a z-coordinate.
|
|
||||||
This will allow us to sort objects as they are created. We can still bulk render each z-index,
|
|
||||||
with meshes and objects being grouped by material.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 3D Graphics (`gfx3d`)
|
|
||||||
|
|
||||||
Links:
|
|
||||||
- https://en.wikipedia.org/wiki/Octree
|
|
||||||
- https://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/
|
|
||||||
- https://learnopengl.com/PBR/Lighting
|
|
||||||
- https://learnopengl.com/PBR/IBL/Diffuse-irradiance
|
|
||||||
- https://en.wikipedia.org/wiki/Schlick%27s_approximation
|
|
||||||
- https://pixelandpoly.com/ior.html
|
|
||||||
- https://developer.download.nvidia.com/SDK/10/opengl/screenshots/samples/dual_depth_peeling.html
|
|
||||||
|
|
||||||
**DirectX will never have official support.**
|
|
||||||
If you would like to make a fork, have at it, but know that I will hold a deep disdain for you.
|
|
||||||
|
|
||||||
The graphics pipeline will have a buffer with a list of objects and their rendering data.
|
|
||||||
This will be referred to as the Object Buffer. There will be two, for both the Deferred and Forward Passes.
|
|
||||||
|
|
||||||
The buffers will be optimized by scene prediction.
|
|
||||||
This involves tracking the meshes and textures directly and indirectly used by a scene.
|
|
||||||
A callback function in the graphics system for scene loading can do this.
|
|
||||||
|
|
||||||
|
|
||||||
Materials and Lighting models will be run via a shader metaprogram to make the pipeline independent of this aspect.
|
|
||||||
This allows the GPU to draw every single deferred rendered mesh in a single draw call for each stage of the renderer.
|
|
||||||
|
|
||||||
Specifications for debugging views via early breaks are included in the stages.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Structures (`gfx3d`)
|
|
||||||
|
|
||||||
Object Structure. The mesh is implicit data.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
struct Object
|
|
||||||
{
|
|
||||||
vec3 location, scale; // A matrix would be 64 bytes, this is instead 28 bytes
|
|
||||||
quat rotation;
|
|
||||||
int material;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Textures for 3D rendering are stored in various buffers with sizes of powers of 2.
|
|
||||||
Ratios of `1:1` and `2:1` are allowed. The `2:1` ratio is specifically for spherical and cylindrical projection.
|
|
||||||
UVs may be transformed to use a `2:1` as if it were `1:2`.
|
|
||||||
Cubemaps may only be `1:1`, I would be concerned if you are using any other ratio.
|
|
||||||
|
|
||||||
- 8-Bit R Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
- 8-Bit RG Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
- 8-Bit RGB Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
- 8-Bit RGBA Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
- 8-Bit RGB Cubemap `1024, 512, 256, 128` (4)
|
|
||||||
|
|
||||||
* 16-Bit HDR RGB Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
* 16-Bit HDR RGBA Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
* 16-Bit HDR RGB Cubemap `1024, 512, 256, 128` (4)
|
|
||||||
|
|
||||||
- 16-Bit Shadow Texture `4096, 2048, 1024, 512` (8)
|
|
||||||
- 16-Bit Shadow Cubemap `2048, 1024, 512, 256` (4)
|
|
||||||
|
|
||||||
Documentation should provide guidelines on categories of Art Assets and the resolution of textures to use.
|
|
||||||
|
|
||||||
Textures are identified by an 8-bit integer and 16-bit integer.
|
|
||||||
- `int8` → the texture buffer
|
|
||||||
- `int16` → the layer in the buffer
|
|
||||||
|
|
||||||
Artists should be informed on the texture structure of the engine and its limitations.
|
|
||||||
However, these principles should be followed in other game engines as these are
|
|
||||||
guided by what is most efficient for typical GPU hardware.
|
|
||||||
|
|
||||||
|
|
||||||
Materials are, for the most part, user-defined. Documentation should make the user aware of this.
|
|
||||||
Material buffers will be a sequence of the Material Struct instances.
|
|
||||||
They will at the very least contain the id of their shader.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Stages (`gfx3d`)
|
|
||||||
|
|
||||||
This is the set of stages for the graphics pipeline that runs every frame:
|
|
||||||
Unless otherwise specified, each stage will be run on the GPU.
|
|
||||||
|
|
||||||
- BVH
|
|
||||||
- Octree `(8 Bpn, 64 bpn) [6-Layers ≈ 2.1MB]`
|
|
||||||
- Leaf Size and Tree Depth should be calculated by the scene, constraints are as follows:
|
|
||||||
- Min Object Size
|
|
||||||
- Max Object Size
|
|
||||||
- Scene Center
|
|
||||||
- Scene Edge
|
|
||||||
- Buffer has implicit locations due to the tree having 8 children.
|
|
||||||
- Insertions and Updates are done on the CPU
|
|
||||||
- Nodes
|
|
||||||
- Start Index `int32`
|
|
||||||
- Object Count `int32`
|
|
||||||
- Objects
|
|
||||||
- Buffer of Object IDs grouped by Octree Node
|
|
||||||
- Leaf Culling
|
|
||||||
- Starting at each Octree Leaf, traverse upwards.
|
|
||||||
- Insert Visible Leaf IDs
|
|
||||||
- Track using atomic buffer
|
|
||||||
- Generate the Command Buffer for Culled Mesh LODs from the Visible Leaf Buffer
|
|
||||||
- Track counts using atomic buffers
|
|
||||||
- To avoid double counting due to the construction of the Octree output, we have some options
|
|
||||||
- Ignore Leaf Instances based on occurrences of the mesh in the surrounding 8 Quadtree Leaves. This would require
|
|
||||||
a bias towards a specific corner of the filter.
|
|
||||||
- Perform a preprocessing step on the CPU to erase duplicate elements and fix the buffer continuity.
|
|
||||||
- Let the duplicates be rendered.
|
|
||||||
- Generate the Culled Object Buffer with the respective object IDs
|
|
||||||
- Adjust Buffer Size using the counts
|
|
||||||
- Insert by reusing the count buffer, clipped to only contain used meshes
|
|
||||||
|
|
||||||
Debug View: Object ID, Mesh ID, LOD
|
|
||||||
|
|
||||||
- Visibility
|
|
||||||
- Buffer `(15 Bpp, 120 bpp) [1920x1080] ≈ 39.4MB`
|
|
||||||
- Depth Buffer → `D24`
|
|
||||||
- Visibility Info → `RGB32I`
|
|
||||||
- R = Object ID
|
|
||||||
- G = Mesh ID
|
|
||||||
- B = Material ID
|
|
||||||
- Regenerate the Command Buffer for Visible Mesh LODs
|
|
||||||
- Regenerate the Culled Object Buffer
|
|
||||||
|
|
||||||
Debug View: Visibility Buffer
|
|
||||||
|
|
||||||
* G-Buffer Pass `(17 Bpp, 136 bpp) [1920x1080] ≈ 35.3MB`
|
|
||||||
* Depth - Stencil → `D24_S8`
|
|
||||||
* S → used to represent the lighting model.
|
|
||||||
* Diffuse → `RGBA8`
|
|
||||||
* A → Ambient Occlusion
|
|
||||||
* Emission → `RGB8`
|
|
||||||
* Normal → `RGB8`
|
|
||||||
* Specular → `RGB8`
|
|
||||||
* R → Roughness
|
|
||||||
* G → Specularity (sometimes called the Metallicness)
|
|
||||||
* B → Index of Refraction (IOR)
|
|
||||||
|
|
||||||
Debug View: Depth, Stencil, Diffuse, Emission, Normal, Specularity
|
|
||||||
|
|
||||||
- Deferred Lighting Pass `(10 Bpp, 80 bpp) [1920x1080] ≈ 2 x 16.3MB + 8.3MB ≈ 24.6MB`
|
|
||||||
- Depth Buffer → `D24`
|
|
||||||
- Lighting Buffer → `RGB16` (w/ Mipmapping when Bloom or DoF are enabled)
|
|
||||||
- Stencil Buffer $rarr; `S8`
|
|
||||||
- Generate Dynamic Shadows
|
|
||||||
- Generate Dynamic Reflections (Optional)
|
|
||||||
- SSAO (Optional)
|
|
||||||
- Apply Lighting Model
|
|
||||||
|
|
||||||
Debug View: Shadows, Reflections, SSAO, Deferred Lighting
|
|
||||||
|
|
||||||
* Forward Pass
|
|
||||||
* BVH, Same as Above
|
|
||||||
* LOD Selection, Same as Above
|
|
||||||
* Translucent Materials
|
|
||||||
* Dual Depth Peeling
|
|
||||||
|
|
||||||
Debug View: Forward Mask
|
|
||||||
|
|
||||||
- Post Processing
|
|
||||||
- Depth of Field (Optional)
|
|
||||||
- When enabled, the Visiblity Buffer, G-Buffer, and Deferred Lighting Pass will be double layered.
|
|
||||||
- At this point the Lighting Buffers will be Flattened
|
|
||||||
- Bloom (Optional) → Mipmap Blurring `(6Bpp, 48bpp) [1920x1080] ≈ 16.3MB`
|
|
||||||
- Tonemapping (Optional)
|
|
||||||
- HDR Correction
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 3D Physics `(physics3d)`
|
|
||||||
|
|
||||||
Links:
|
|
||||||
- https://www.researchgate.net/publication/264839743_Simulating_Ocean_Water
|
|
||||||
- https://arxiv.org/pdf/2109.00104
|
|
||||||
- https://www.youtube.com/watch?v=rSKMYc1CQHE
|
|
||||||
- https://tflsguoyu.github.io/webpage/pdf/2013ICIA.pdf
|
|
||||||
- https://animation.rwth-aachen.de/publication/0557/
|
|
||||||
- https://github.com/InteractiveComputerGraphics/PositionBasedDynamics?tab=readme-ov-file
|
|
||||||
- https://www.cs.umd.edu/class/fall2019/cmsc828X/LEC/PBD.pdf
|
|
||||||
|
|
||||||
Systems
|
|
||||||
|
|
||||||
* Rigid Body Physics
|
|
||||||
* Newtonian Physics and Collision Resolution
|
|
||||||
* Articulated Skeletal Systems
|
|
||||||
* Inverse Kinematics
|
|
||||||
* Stiff Rods
|
|
||||||
- Particle Physics
|
|
||||||
* Soft Body Physics
|
|
||||||
* Elastics → Finite Element Simulation
|
|
||||||
* Cloth → Position-Based Dynamics
|
|
||||||
* Water
|
|
||||||
* Oceans → iWave
|
|
||||||
* Reasoning: iWave provides interactive lightweight fluid dynamics suitable for flat planes of water.
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
* 3D Fluid Dynamics → Smoothed-Particle Hydrodynamics
|
|
||||||
* Reasoning: This is the simplest method for simulating 3D bodies of water. This should exclusively be
|
|
||||||
used for small scale simulations where self-interactive fluids are necessary. I.E. pouring water into
|
|
||||||
a glass.
|
|
||||||
<br><br>
|
|
||||||
|
|
||||||
* 2D Fluid Dynamics → Force-Based Dynamics
|
|
||||||
* Reasoning: This model, like iWave, provides lightweight interactive fluid dynamics, but is more easily
|
|
||||||
adapted to flowing surfaces such as streams and rivers.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Artificial Intelligence (`ai`)
|
|
||||||
|
|
||||||
This artificial intelligence method only differs in static generation between 2D and 3D.
|
|
||||||
The solvers are dimension independent since they work on a graph.
|
|
||||||
|
|
||||||
The general process is;
|
|
||||||
|
|
||||||
Static:
|
|
||||||
- generate a static navigation graph (sometimes called a NavMesh)
|
|
||||||
|
|
||||||
Update:
|
|
||||||
* resolve dynamic blockers
|
|
||||||
* update paths using dijkstra's algorithm
|
|
||||||
* apply rigid-body forces with constraints
|
|
||||||
|
|
||||||
The update loop for artificial intelligence should only update every `n` ticks. Where `n <= k`, with `k` being the
|
|
||||||
tick rate of the physics engine.
|
|
||||||
90
README.md
90
README.md
@@ -8,17 +8,23 @@
|
|||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## Table of Contents
|
<a id="table-of-contents"></a>
|
||||||
|
<h2>Table of Contents</h2>
|
||||||
|
|
||||||
|
* [Table of Contents](#table-of-contents)
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Coding Standards](#coding-standards)
|
||||||
|
* [Building from Source](#building-from-source)
|
||||||
|
* [Building from Terminal](#building-from-terminal)
|
||||||
|
* [Debian](#debian) → `apt`
|
||||||
|
* [Arch](#arch) → `pacman`
|
||||||
|
* [Fedora](#fedora) → `dnf`
|
||||||
|
* [Building on Windows](#building-on-windows)
|
||||||
|
* [Running the Test Suite](#running-the-test-suite)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [Licensing](#licensing)
|
||||||
|
* [Contribution](#contribution)
|
||||||
|
|
||||||
1. [Introduction](#introduction)
|
|
||||||
1. [Coding Standards](#coding-standards)
|
|
||||||
2. [Building from Source](#building-from-source)
|
|
||||||
1. [Building from Terminal](#building-from-terminal)
|
|
||||||
2. [Building on Windows](#building-on-windows)
|
|
||||||
3. [Running the Test Suite](#running-the-test-suite)
|
|
||||||
4. [Usage](#usage)
|
|
||||||
5. [Contribution](#contribution)
|
|
||||||
6. [Documentation](./documentation.html)
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -125,6 +131,7 @@ is also a viable IDE but involves some extra setup.
|
|||||||
|-------------------|----------------------------------------------------------------------------------------------------------|
|
|-------------------|----------------------------------------------------------------------------------------------------------|
|
||||||
| C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used |
|
| C/C++ Compiler | GCC/G++ is the compiler that fennec is designed around, however, Clang, MSVC, and MinGW may also be used |
|
||||||
| CMake | The build manager used by the engine |
|
| CMake | The build manager used by the engine |
|
||||||
|
| glew | OpenGL Extension Wrangler, necessary for modern OpenGL |
|
||||||
| A build system | Any build system will work, however, `build.sh` uses Ninja by default. |
|
| A build system | Any build system will work, however, `build.sh` uses Ninja by default. |
|
||||||
| A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. |
|
| A memory debugger | Any memory debugger will work, however, `test.sh` uses Valgrind by default. |
|
||||||
| Doxygen | Doxygen is required for building the documentation for fennec. This is an optional dependency |
|
| Doxygen | Doxygen is required for building the documentation for fennec. This is an optional dependency |
|
||||||
@@ -141,11 +148,53 @@ for more info.
|
|||||||
  By default, the CMake generator used is Ninja, which requires Ninja to be installed. You can modify the
|
  By default, the CMake generator used is Ninja, which requires Ninja to be installed. You can modify the
|
||||||
build scripts to use another build manager, see the [CMake documentation for available generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
|
build scripts to use another build manager, see the [CMake documentation for available generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html).
|
||||||
|
|
||||||
|
|
||||||
  I will at no point provide official cross-compilation toolchains for fennec. However, I will provide tools for
|
  I will at no point provide official cross-compilation toolchains for fennec. However, I will provide tools for
|
||||||
using specific toolchains for specific platforms that necessitate this. The primary examples would be Android and iOS.
|
using specific toolchains for specific platforms that necessitate this. The primary examples would be Android and iOS.
|
||||||
If you wish to build for Windows *and* Linux, your options are WSL or Dual Boot. I recommend Dual Boot over WSL.
|
If you wish to build for Windows *and* Linux, your options are WSL or Dual Boot. I recommend Dual Boot over WSL.
|
||||||
|
|
||||||
|
|
||||||
|
<a id="debian"></a>
|
||||||
|
#### Debian
|
||||||
|
|
||||||
|
On Debian-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo apt install build-essential cmake ninja-build libglew-dev valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo apt install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="arch"></a>
|
||||||
|
#### Arch
|
||||||
|
|
||||||
|
On Arch-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo pacman -S base-devel cmake ninja glew valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo pacman -S doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="fedora"></a>
|
||||||
|
#### Fedora
|
||||||
|
|
||||||
|
On Fedora-based distributions, you can install dependencies using the following command:
|
||||||
|
```shell
|
||||||
|
sudo dnf install build-essential g++ cmake ninja-build glew-devel valgrind
|
||||||
|
git submodule update --force --init --recursive --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
for Doxygen run:
|
||||||
|
```shell
|
||||||
|
sudo dnf install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<a id="building-on-windows"></a>
|
<a id="building-on-windows"></a>
|
||||||
@@ -155,7 +204,7 @@ If you wish to build for Windows *and* Linux, your options are WSL or Dual Boot.
|
|||||||
script in WSL, simply use the "bash" command in Command Prompt or PowerShell. The script will require
|
script in WSL, simply use the "bash" command in Command Prompt or PowerShell. The script will require
|
||||||
the build [dependencies](#dependencies) installed and configured to be available on the `PATH` environment variable.
|
the build [dependencies](#dependencies) installed and configured to be available on the `PATH` environment variable.
|
||||||
|
|
||||||
Fore more details, [see this blog post](https://blogs.windows.com/windows-insider/2016/04/06/announcing-windows-10-insider-preview-build-14316/) for Windows Build 14316.
|
For more details, [see this blog post](https://blogs.windows.com/windows-insider/2016/04/06/announcing-windows-10-insider-preview-build-14316/) for Windows Build 14316.
|
||||||
|
|
||||||
Otherwise, follow the sequence of commands provided in the bash script.
|
Otherwise, follow the sequence of commands provided in the bash script.
|
||||||
|
|
||||||
@@ -206,23 +255,26 @@ information displayed is correct.
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
||||||
|
<a id="licensing"></a>
|
||||||
### Licensing
|
### Licensing
|
||||||
|
|
||||||
The following content of this section is not legal advice, nor is it legally binding, and nor does it change the terms
|
The following content of this section is not legal advice, nor is it legally binding, and nor does it change the terms
|
||||||
of the license. Please seek legal council if you have any concerns.
|
of the license. Please seek legal council if you have any concerns.
|
||||||
|
|
||||||
  fennec is licensed under GPLv3. The primary reason for the choice of license is to dissuade corporations from modifying
|
TLDR; You may license your game under whichever license you please. Any C++ code that is by definition a derivative work
|
||||||
fennec and using it in a commercial manner. This of course does not bar them from using fennec commercially, however
|
must be licensed under GPLv3 and freely available, everything else; assets, scripts, design documents, etc. may be under
|
||||||
it will prevent them from being able to make the derivative work proprietary. You are free to use and redistribute
|
the license of your choosing and remain proprietary.
|
||||||
fennec however you wish according to the terms of the license, which does not bar you from commercializing software
|
|
||||||
based on fennec.
|
  fennec is licensed under GPLv3. The primary reason for the choice of license is to dissuade corporations from
|
||||||
|
modifying fennec and using it in a commercial manner. This of course does not bar them from using fennec commercially,
|
||||||
|
however it will prevent them from being able to make the derivative work proprietary. You are free to use and redistribute
|
||||||
|
fennec however you wish according to the terms of the license, which does not bar you from commercializing software based
|
||||||
|
on fennec.
|
||||||
|
|
||||||
  If you wish to protect your game files, assets and generated content do not constitute a covered work and may be
|
  If you wish to protect your game files, assets and generated content do not constitute a covered work and may be
|
||||||
copyrighted under a non-compliant license. Think of it in terms of using Blender to create a mesh for a game, then
|
copyrighted under a non-compliant license. Think of it in terms of using Blender to create a mesh for a game, then
|
||||||
licensing that mesh under another license.
|
licensing that mesh under another license.
|
||||||
|
|
||||||
Any code that is linked against fennec or uses any part is by definition a covered work must be licensed under GPLv3.
|
|
||||||
|
|
||||||
  Later down the line, I plan on implementing scripts in a manner that allows the script itself to remain proprietary.
|
  Later down the line, I plan on implementing scripts in a manner that allows the script itself to remain proprietary.
|
||||||
The scripts will likely be trans-compiled to another language before being compiled to binary, but this is only an
|
The scripts will likely be trans-compiled to another language before being compiled to binary, but this is only an
|
||||||
intermediate step and will be erased when no longer needed.
|
intermediate step and will be erased when no longer needed.
|
||||||
|
|||||||
8
build.sh
8
build.sh
@@ -38,7 +38,7 @@ Help()
|
|||||||
Debug()
|
Debug()
|
||||||
{
|
{
|
||||||
mkdir -p build/debug
|
mkdir -p build/debug
|
||||||
cd ./build/debug
|
cd ./build/debug || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -47,7 +47,7 @@ Debug()
|
|||||||
Release()
|
Release()
|
||||||
{
|
{
|
||||||
mkdir -p build/release
|
mkdir -p build/release
|
||||||
cd ./build/release
|
cd ./build/release || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -56,7 +56,7 @@ Release()
|
|||||||
RelWithDebInfo()
|
RelWithDebInfo()
|
||||||
{
|
{
|
||||||
mkdir -p build/relwithdebinfo
|
mkdir -p build/relwithdebinfo
|
||||||
cd ./build/relwithdebinfo
|
cd ./build/relwithdebinfo || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -65,7 +65,7 @@ RelWithDebInfo()
|
|||||||
MinSizeRel()
|
MinSizeRel()
|
||||||
{
|
{
|
||||||
mkdir -p build/minsizerel
|
mkdir -p build/minsizerel
|
||||||
cd ./build/minsizerel
|
cd ./build/minsizerel || exit
|
||||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel -S ../.. -B .
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel -S ../.. -B .
|
||||||
cmake --build . --target fennec
|
cmake --build . --target fennec
|
||||||
cd ../..
|
cd ../..
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ add_compile_options("-mxsave" "-Wall" "-Wextra" "-pedantic" "-Werror")
|
|||||||
|
|
||||||
set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
|
set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
|
||||||
|
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]])
|
list(APPEND FENNEC_COMPILE_DEFINITIONS _GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]])
|
||||||
@@ -23,13 +23,13 @@ macro(fennec_check_platform)
|
|||||||
include("${FENNEC_SOURCE_DIR}/cmake/unix.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/unix.cmake")
|
||||||
|
|
||||||
# compile definitions
|
# compile definitions
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
fennec_add_definitions(
|
||||||
FENNEC_PLATFORM_NAME="Linux"
|
FENNEC_PLATFORM_NAME="Linux"
|
||||||
FENNEC_PLATFORM_LINUX=1
|
FENNEC_PLATFORM_LINUX=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# extra source files
|
# extra source files
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
fennec_add_sources(
|
||||||
include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp
|
include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -18,23 +18,17 @@
|
|||||||
|
|
||||||
if(FENNEC_GRAPHICS_WANT_EGL)
|
if(FENNEC_GRAPHICS_WANT_EGL)
|
||||||
find_package(OpenGL REQUIRED COMPONENTS EGL)
|
find_package(OpenGL REQUIRED COMPONENTS EGL)
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
message(STATUS "EGL Requested")
|
message(STATUS "EGL Requested")
|
||||||
else()
|
else()
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET OpenGL::GL) # Core OpenGL Desktop Profile
|
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
|
||||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::OpenGL)
|
message(STATUS "Found OpenGL: ${OPENGL_gl_LIBRARY}")
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_OPENGL=1)
|
fennec_add_link_libraries(OpenGL::GL GLEW::GLEW)
|
||||||
|
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
|
||||||
elseif(TARGET OpenGL::GLES3) # OpenGL for Embedded Systems 3
|
|
||||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::GLES3)
|
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_GLES3=1)
|
|
||||||
|
|
||||||
elseif (TARGET OpenGL::GLES2) # OpenGL for Embedded Systems 2
|
|
||||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::GLES2)
|
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_GLES2=1)
|
|
||||||
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No Suitable OpenGL implementation found.")
|
message(FATAL_ERROR "No Suitable OpenGL implementation found.")
|
||||||
endif()
|
endif()
|
||||||
@@ -44,9 +38,20 @@ if(FENNEC_GRAPHICS_WANT_EGL)
|
|||||||
message(FATAL_ERROR "EGL Library not found.")
|
message(FATAL_ERROR "EGL Library not found.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::EGL)
|
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_EGL=1)
|
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
fennec_add_link_libraries(OpenGL::EGL)
|
||||||
|
fennec_add_definitions(FENNEC_GRAPHICS_EGL=1)
|
||||||
|
|
||||||
|
fennec_add_sources(
|
||||||
|
include/fennec/platform/opengl/lib/fwd.h
|
||||||
|
include/fennec/platform/opengl/lib/enum.h
|
||||||
|
include/fennec/platform/opengl/lib/buffer.h
|
||||||
|
include/fennec/platform/opengl/lib/texture.h
|
||||||
|
include/fennec/platform/opengl/lib/vertex_array.h
|
||||||
|
|
||||||
|
include/fennec/platform/opengl/egl/fwd.h
|
||||||
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
|
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
|
||||||
|
include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
# generic unix functionality
|
# generic unix functionality
|
||||||
|
|
||||||
# compile definitions
|
# compile definitions
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
fennec_add_definitions(
|
||||||
FENNEC_PLATFORM_UNIX=1
|
FENNEC_PLATFORM_UNIX=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# extra source files
|
# extra source files
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
fennec_add_sources(
|
||||||
include/fennec/platform/unix/platform.h source/platform/unix/platform.cpp
|
include/fennec/platform/unix/platform.h source/platform/unix/platform.cpp
|
||||||
)
|
)
|
||||||
@@ -19,6 +19,23 @@
|
|||||||
# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a
|
# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a
|
||||||
# this script finds libwayland and dependencies
|
# this script finds libwayland and dependencies
|
||||||
|
|
||||||
|
# some of this code is based on SDL3's use of wayland-scanner
|
||||||
|
|
||||||
|
macro(fennec_wayland_get_header _SCANNER _XML _FILE)
|
||||||
|
set(_WAYLAND_PROT_H_CODE "${WAYLAND_HEADERS_DIR}/${_FILE}-client-protocols.h")
|
||||||
|
set(_WAYLAND_PROT_C_CODE "${WAYLAND_SOURCES_DIR}/${_FILE}-client.c")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_SCANNER} client-header "${_XML}" "${_WAYLAND_PROT_H_CODE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_SCANNER} private-code "${_XML}" "${_WAYLAND_PROT_C_CODE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
fennec_add_sources(${_WAYLAND_PROT_C_CODE} ${_WAYLAND_PROT_H_CODE})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
macro(fennec_check_wayland)
|
macro(fennec_check_wayland)
|
||||||
set(WAYLAND_CLIENT_FOUND 0)
|
set(WAYLAND_CLIENT_FOUND 0)
|
||||||
|
|
||||||
@@ -30,6 +47,7 @@ macro(fennec_check_wayland)
|
|||||||
WAYLAND_CLIENT_LIBRARY
|
WAYLAND_CLIENT_LIBRARY
|
||||||
NAMES wayland-client libwayland-client
|
NAMES wayland-client libwayland-client
|
||||||
)
|
)
|
||||||
|
find_program(WAYLAND_SCANNER NAMES wayland-scanner)
|
||||||
|
|
||||||
# EGL is required
|
# EGL is required
|
||||||
find_path(
|
find_path(
|
||||||
@@ -41,13 +59,34 @@ macro(fennec_check_wayland)
|
|||||||
NAMES wayland-egl libwayland-egl
|
NAMES wayland-egl libwayland-egl
|
||||||
)
|
)
|
||||||
|
|
||||||
if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY)
|
if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY AND WAYLAND_SCANNER)
|
||||||
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY))
|
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY))
|
||||||
message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}")
|
message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}")
|
||||||
|
|
||||||
|
set(WAYLAND_PROTOCOLS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/protocols)
|
||||||
|
set(WAYLAND_HEADERS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/headers)
|
||||||
|
set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/sources)
|
||||||
|
|
||||||
|
# Search for base protocol xml
|
||||||
|
find_file(WAYLAND_PROTOCOL NAMES wayland.xml PATHS /usr/share/wayland /usr/share/wayland-protocols)
|
||||||
|
file(COPY ${WAYLAND_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
|
||||||
|
|
||||||
|
# search for xdg protocols
|
||||||
|
find_file(XDG_SHELL_PROTOCOL NAMES xdg-shell.xml PATHS /usr/share/wayland-protocols/stable/xdg-shell)
|
||||||
|
file(COPY ${XDG_SHELL_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
|
||||||
|
|
||||||
|
# include sub-dependencies
|
||||||
include("${FENNEC_SOURCE_DIR}/cmake/xkb.cmake")
|
include("${FENNEC_SOURCE_DIR}/cmake/xkb.cmake")
|
||||||
fennec_check_xkb()
|
fennec_check_xkb()
|
||||||
|
|
||||||
|
# generate protocols, based on SDL3
|
||||||
|
file(GLOB WAYLAND_PROTOCOLS_XML RELATIVE "${WAYLAND_PROTOCOLS_DIR}" "${WAYLAND_PROTOCOLS_DIR}/*.xml")
|
||||||
|
foreach(_XML IN LISTS WAYLAND_PROTOCOLS_XML)
|
||||||
|
get_filename_component(_FILE ${_XML} NAME_WLE)
|
||||||
|
fennec_wayland_get_header("${WAYLAND_SCANNER}" "${WAYLAND_PROTOCOLS_DIR}/${_XML}" "${_FILE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add sources and libraries
|
||||||
get_filename_component(
|
get_filename_component(
|
||||||
WAYLAND_CLIENT_LIBRARY
|
WAYLAND_CLIENT_LIBRARY
|
||||||
${WAYLAND_CLIENT_LIBRARY}
|
${WAYLAND_CLIENT_LIBRARY}
|
||||||
@@ -63,19 +102,18 @@ macro(fennec_check_wayland)
|
|||||||
set(WAYLAND_EGL_FOUND 1)
|
set(WAYLAND_EGL_FOUND 1)
|
||||||
set(FENNEC_GRAPHICS_WANT_EGL 1)
|
set(FENNEC_GRAPHICS_WANT_EGL 1)
|
||||||
|
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
fennec_add_sources(
|
||||||
# Dynamic Library Files
|
# Dynamic Library Files
|
||||||
include/fennec/platform/linux/wayland/lib/fwd.h
|
|
||||||
include/fennec/platform/linux/wayland/lib/sym.h
|
include/fennec/platform/linux/wayland/lib/sym.h
|
||||||
include/fennec/platform/linux/wayland/lib/wayland-client.h
|
include/fennec/platform/linux/wayland/lib/wayland.h
|
||||||
include/fennec/platform/linux/wayland/lib/wayland-util.h
|
|
||||||
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
|
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
|
||||||
|
|
||||||
# Fennec Files
|
# Fennec Files
|
||||||
include/fennec/platform/linux/wayland/display.h source/platform/linux/wayland/display.cpp
|
include/fennec/platform/linux/wayland/display.h source/platform/linux/wayland/display.cpp
|
||||||
|
include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
fennec_add_definitions(
|
||||||
FENNEC_HAS_WAYLAND=1
|
FENNEC_HAS_WAYLAND=1
|
||||||
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
|
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
|
||||||
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
|
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
|
||||||
|
|||||||
@@ -41,17 +41,16 @@ macro(fennec_check_xkb)
|
|||||||
|
|
||||||
set(XKB_FOUND 1)
|
set(XKB_FOUND 1)
|
||||||
|
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
fennec_add_sources(
|
||||||
# Dynamic Library Files
|
# Dynamic Library Files
|
||||||
include/fennec/platform/linux/xkb/lib/fwd.h
|
|
||||||
include/fennec/platform/linux/xkb/lib/sym.h
|
include/fennec/platform/linux/xkb/lib/sym.h
|
||||||
include/fennec/platform/linux/xkb/lib/xkbcommon.h
|
include/fennec/platform/linux/xkb/lib/xkb.h
|
||||||
include/fennec/platform/linux/xkb/lib/loader.h source/platform/linux/xkb/lib/loader.cpp
|
include/fennec/platform/linux/xkb/lib/loader.h source/platform/linux/xkb/lib/loader.cpp
|
||||||
|
|
||||||
# Fennec files
|
# Fennec files
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
fennec_add_definitions(
|
||||||
FENNEC_HAS_XKB=1
|
FENNEC_HAS_XKB=1
|
||||||
FENNEC_LIB_XKB="${XKB_LIBRARY}"
|
FENNEC_LIB_XKB="${XKB_LIBRARY}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
<includes visible="$SHOW_HEADERFILE"/>
|
<includes visible="$SHOW_HEADERFILE"/>
|
||||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||||
<collaborationgraph visible="yes"/>
|
<collaborationgraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<nestedclasses visible="yes" title=""/>
|
<nestedclasses visible="yes" title=""/>
|
||||||
<publictypes title=""/>
|
<publictypes title=""/>
|
||||||
@@ -83,7 +84,6 @@
|
|||||||
<related title="" subtitle=""/>
|
<related title="" subtitle=""/>
|
||||||
<membergroups visible="yes"/>
|
<membergroups visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
<memberdef>
|
<memberdef>
|
||||||
<inlineclasses title=""/>
|
<inlineclasses title=""/>
|
||||||
<typedefs title=""/>
|
<typedefs title=""/>
|
||||||
@@ -105,6 +105,7 @@
|
|||||||
<!-- Layout definition for a namespace page -->
|
<!-- Layout definition for a namespace page -->
|
||||||
<namespace>
|
<namespace>
|
||||||
<briefdescription visible="yes"/>
|
<briefdescription visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<nestednamespaces visible="yes" title=""/>
|
<nestednamespaces visible="yes" title=""/>
|
||||||
<constantgroups visible="yes" title=""/>
|
<constantgroups visible="yes" title=""/>
|
||||||
@@ -121,7 +122,6 @@
|
|||||||
<variables title=""/>
|
<variables title=""/>
|
||||||
<membergroups visible="yes"/>
|
<membergroups visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
<memberdef>
|
<memberdef>
|
||||||
<inlineclasses title=""/>
|
<inlineclasses title=""/>
|
||||||
<typedefs title=""/>
|
<typedefs title=""/>
|
||||||
@@ -150,6 +150,7 @@
|
|||||||
<includegraph visible="yes"/>
|
<includegraph visible="yes"/>
|
||||||
<includedbygraph visible="yes"/>
|
<includedbygraph visible="yes"/>
|
||||||
<sourcelink visible="yes"/>
|
<sourcelink visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<interfaces visible="yes" title=""/>
|
<interfaces visible="yes" title=""/>
|
||||||
<classes visible="yes" title=""/>
|
<classes visible="yes" title=""/>
|
||||||
@@ -167,7 +168,6 @@
|
|||||||
<variables title=""/>
|
<variables title=""/>
|
||||||
<membergroups visible="yes"/>
|
<membergroups visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
<memberdef>
|
<memberdef>
|
||||||
<inlineclasses title=""/>
|
<inlineclasses title=""/>
|
||||||
<defines title=""/>
|
<defines title=""/>
|
||||||
@@ -185,6 +185,7 @@
|
|||||||
<group>
|
<group>
|
||||||
<briefdescription visible="yes"/>
|
<briefdescription visible="yes"/>
|
||||||
<groupgraph visible="yes"/>
|
<groupgraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<nestedgroups visible="yes" title=""/>
|
<nestedgroups visible="yes" title=""/>
|
||||||
<modules visible="yes" title=""/>
|
<modules visible="yes" title=""/>
|
||||||
@@ -210,7 +211,6 @@
|
|||||||
<friends title=""/>
|
<friends title=""/>
|
||||||
<membergroups visible="yes"/>
|
<membergroups visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
<memberdef>
|
<memberdef>
|
||||||
<pagedocs/>
|
<pagedocs/>
|
||||||
<inlineclasses title=""/>
|
<inlineclasses title=""/>
|
||||||
@@ -237,6 +237,7 @@
|
|||||||
<module>
|
<module>
|
||||||
<briefdescription visible="yes"/>
|
<briefdescription visible="yes"/>
|
||||||
<exportedmodules visible="yes"/>
|
<exportedmodules visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<concepts visible="yes" title=""/>
|
<concepts visible="yes" title=""/>
|
||||||
<classes visible="yes" title=""/>
|
<classes visible="yes" title=""/>
|
||||||
@@ -246,7 +247,6 @@
|
|||||||
<variables title=""/>
|
<variables title=""/>
|
||||||
<membergroups title=""/>
|
<membergroups title=""/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<files visible="yes"/>
|
<files visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
@@ -256,10 +256,10 @@
|
|||||||
<directory>
|
<directory>
|
||||||
<briefdescription visible="yes"/>
|
<briefdescription visible="yes"/>
|
||||||
<directorygraph visible="yes"/>
|
<directorygraph visible="yes"/>
|
||||||
|
<detaileddescription title=""/>
|
||||||
<memberdecl>
|
<memberdecl>
|
||||||
<dirs visible="yes"/>
|
<dirs visible="yes"/>
|
||||||
<files visible="yes"/>
|
<files visible="yes"/>
|
||||||
</memberdecl>
|
</memberdecl>
|
||||||
<detaileddescription title=""/>
|
|
||||||
</directory>
|
</directory>
|
||||||
</doxygenlayout>
|
</doxygenlayout>
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH =
|
IMAGE_PATH = "/home/medusa/Documents/Work/Personal/fennec/doxy/static"
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
@@ -1981,7 +1981,7 @@ GENERATE_LATEX = NO
|
|||||||
# The default directory is: latex.
|
# The default directory is: latex.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
LATEX_OUTPUT = latex
|
LATEX_OUTPUT = ./latex
|
||||||
|
|
||||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||||
# invoked.
|
# invoked.
|
||||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
@@ -2676,7 +2676,7 @@ INCLUDE_GRAPH = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDED_BY_GRAPH = YES
|
INCLUDED_BY_GRAPH = NO
|
||||||
|
|
||||||
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
||||||
# dependency graph for every global function or class method.
|
# dependency graph for every global function or class method.
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH =
|
IMAGE_PATH = "@PROJECT_SOURCE_DIR@/doxy/static"
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
@@ -1981,7 +1981,7 @@ GENERATE_LATEX = NO
|
|||||||
# The default directory is: latex.
|
# The default directory is: latex.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
LATEX_OUTPUT = latex
|
LATEX_OUTPUT = ./latex
|
||||||
|
|
||||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||||
# invoked.
|
# invoked.
|
||||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
@@ -2676,7 +2676,7 @@ INCLUDE_GRAPH = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INCLUDED_BY_GRAPH = YES
|
INCLUDED_BY_GRAPH = NO
|
||||||
|
|
||||||
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
|
||||||
# dependency graph for every global function or class method.
|
# dependency graph for every global function or class method.
|
||||||
|
|||||||
@@ -287,3 +287,8 @@ html.dark-mode {
|
|||||||
td.odd_c {
|
td.odd_c {
|
||||||
background-color: var(--odd-color)
|
background-color: var(--odd-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a + h2.groupheader {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
71
doxy/retrieve-emojis.py
Normal file
71
doxy/retrieve-emojis.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# script to download the emoticons from GitHub and to produce a table for
|
||||||
|
# inclusion in Doxygen. Works with python 2.7+ and python 3.x
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
import urllib.request as urlrequest
|
||||||
|
except ImportError:
|
||||||
|
import urllib as urlrequest
|
||||||
|
|
||||||
|
unicode_re = re.compile(r'.*?/unicode/(.*?).png\?.*')
|
||||||
|
|
||||||
|
def get_emojis():
|
||||||
|
response = urlrequest.urlopen('https://api.github.com/emojis')
|
||||||
|
raw_data = response.read()
|
||||||
|
return json.loads(raw_data)
|
||||||
|
|
||||||
|
def download_images(dir_name, silent):
|
||||||
|
if not os.path.exists(dir_name):
|
||||||
|
os.makedirs(dir_name)
|
||||||
|
json_data = get_emojis()
|
||||||
|
num_items = len(json_data)
|
||||||
|
cur_item=0
|
||||||
|
for image,url in sorted(json_data.items()):
|
||||||
|
image_name = image+'.png'
|
||||||
|
cur_item=cur_item+1
|
||||||
|
if url.find('/unicode/')==-1 or not os.path.isfile(dir_name+'/'+image_name):
|
||||||
|
success = True
|
||||||
|
with open(dir_name+'/'+image_name,'wb') as file:
|
||||||
|
if not silent:
|
||||||
|
print('%s/%s: fetching %s' % (cur_item,num_items,image_name))
|
||||||
|
try:
|
||||||
|
file.write(urlrequest.urlopen(url).read())
|
||||||
|
except:
|
||||||
|
print('Unable to fetch %s' % (image_name))
|
||||||
|
success = False
|
||||||
|
if not success:
|
||||||
|
os.remove(dir_name+'/'+image_name)
|
||||||
|
else:
|
||||||
|
if not silent:
|
||||||
|
print('%s/%s: skipping %s' % (cur_item,num_items,image_name))
|
||||||
|
|
||||||
|
def produce_table():
|
||||||
|
json_data = get_emojis()
|
||||||
|
lines = []
|
||||||
|
for image,url in sorted(json_data.items()):
|
||||||
|
match = unicode_re.match(url)
|
||||||
|
if match:
|
||||||
|
unicodes = match.group(1).split('-')
|
||||||
|
unicodes_html = ''.join(["&#x"+x+";" for x in unicodes])
|
||||||
|
image_str = "\":"+image+":\","
|
||||||
|
unicode_str = "\""+unicodes_html+"\""
|
||||||
|
lines.append(' { %-42s %-38s }' % (image_str,unicode_str))
|
||||||
|
out_str = ',\n'.join(lines)
|
||||||
|
print("{")
|
||||||
|
print(out_str)
|
||||||
|
print("};")
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument('-d','--dir',help='directory to place images in')
|
||||||
|
parser.add_argument('-t','--table',help='generate code fragment',action='store_true')
|
||||||
|
parser.add_argument('-s','--silent',help='silent mode',action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.table:
|
||||||
|
produce_table()
|
||||||
|
if args.dir:
|
||||||
|
download_images(args.dir, args.silent)
|
||||||
4
doxy/static/graphs/containers/rdtree.svg
Normal file
4
doxy/static/graphs/containers/rdtree.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 60 KiB |
2
external/cpptrace
vendored
2
external/cpptrace
vendored
Submodule external/cpptrace updated: 9133b90a99...787d8af6f6
36
gdb/fennec/__init__.py
Normal file
36
gdb/fennec/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# GDB CODE =============================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
from . import containers
|
||||||
|
from . import strings
|
||||||
|
from . import memory
|
||||||
|
from . import utility
|
||||||
|
from . import filesystem
|
||||||
|
from . import math
|
||||||
|
|
||||||
|
def register_printers(obj):
|
||||||
|
gdb.printing.register_pretty_printer(obj, containers.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, strings.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, memory.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, filesystem.printer)
|
||||||
|
gdb.printing.register_pretty_printer(obj, math.printer)
|
||||||
481
gdb/fennec/containers.py
Normal file
481
gdb/fennec/containers.py
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
# OPTIONAL =============================================================================================================
|
||||||
|
class OptionalPrinter:
|
||||||
|
"""Print a fennec::optional"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
is_initialized = self.val['_set']
|
||||||
|
if is_initialized:
|
||||||
|
return "{{ value = {} }}".format(self.val['_val'])
|
||||||
|
else:
|
||||||
|
return "{ empty }"
|
||||||
|
|
||||||
|
# PAIR =================================================================================================================
|
||||||
|
class PairPrinter:
|
||||||
|
"""Print a fennec::optional"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ first = " + str(self.val['first']) + ", second = " + str(self.val['second']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return ("first", self.val['first']), ("second", self.val['second'])
|
||||||
|
|
||||||
|
|
||||||
|
# TUPLE ================================================================================================================
|
||||||
|
|
||||||
|
class TuplePrinter:
|
||||||
|
"""Print a fennec::tuple"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.fields = val.type.fields()[0].type.fields()
|
||||||
|
self.elems = val
|
||||||
|
self.count = len(self.fields)
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return " { size = " + str(len(self.fields)) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.elems.cast(self.fields[i].type)['value']) for i in range(self.count))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ARRAY ================================================================================================================
|
||||||
|
class ArrayPrinter:
|
||||||
|
"""Print a fennec::array"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length = " + str(self.val['elements'].type.range()[1] + 1) + " }"
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
start = self.val['elements']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(0, self.val['elements'].type.range()[1] + 1))
|
||||||
|
|
||||||
|
|
||||||
|
# DYNARRAY =============================================================================================================
|
||||||
|
class DynArrayPrinter:
|
||||||
|
"""Print a fennec::dynarray"""
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_alloc']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
size = int(self.val['_size'])
|
||||||
|
start = self.val['_alloc']['_data']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(size))
|
||||||
|
|
||||||
|
|
||||||
|
# LIST =================================================================================================================
|
||||||
|
class ListPrinter:
|
||||||
|
"""Print a fennec::list"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.list = val
|
||||||
|
self.node = self.list['_root']
|
||||||
|
self.index = 0
|
||||||
|
self.table = self.list['_table']['_data']
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.node == 18446744073709551615:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
value = self.table[self.node]['value']['_val']
|
||||||
|
self.node = self.table[self.node]['next']
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_table']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# DEQUE ================================================================================================================
|
||||||
|
|
||||||
|
class DequePrinter:
|
||||||
|
"""Print a fennec::deque"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, start):
|
||||||
|
self.node = start
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.node is None:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
value = self.node.dereference()['value']
|
||||||
|
|
||||||
|
self.node = self.node.dereference()['next']
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.first = val['_first']
|
||||||
|
self.last = val['_last']
|
||||||
|
self.size = val['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.first is None:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ length " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.first)
|
||||||
|
|
||||||
|
|
||||||
|
# SET ==================================================================================================================
|
||||||
|
|
||||||
|
class SetPrinter:
|
||||||
|
"""Print a fennec::set"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, table, capacity):
|
||||||
|
self.table = table
|
||||||
|
self.capacity = capacity
|
||||||
|
self.node = 0
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
while self.node < self.capacity:
|
||||||
|
if self.table[self.node]['value']['_set']:
|
||||||
|
break
|
||||||
|
self.node = self.node + 1
|
||||||
|
|
||||||
|
if self.node >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
value = self.table[self.node]['value']['_val']
|
||||||
|
self.node = self.node + 1
|
||||||
|
self.index = self.index + 1
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.table = val['_alloc']['_data']
|
||||||
|
self.capacity = val['_alloc']['_capacity']
|
||||||
|
self.size = val['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.table, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
# MAP ==================================================================================================================
|
||||||
|
|
||||||
|
class MapPrinter:
|
||||||
|
"""Print a fennec::map"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, table, capacity):
|
||||||
|
self.table = table
|
||||||
|
self.capacity = capacity
|
||||||
|
self.node = 0
|
||||||
|
self.index = 0
|
||||||
|
self.move = False
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
while self.node < self.capacity:
|
||||||
|
if self.table[self.node]['value']['_set']:
|
||||||
|
break
|
||||||
|
self.node = self.node + 1
|
||||||
|
|
||||||
|
if self.node >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
pair = self.table[self.node]['value']['_val']
|
||||||
|
key = pair['first']
|
||||||
|
val = pair['second']
|
||||||
|
|
||||||
|
if not self.move:
|
||||||
|
self.move = True
|
||||||
|
return 'key' + str(i), key
|
||||||
|
else:
|
||||||
|
self.move = False
|
||||||
|
self.index = self.index + 1
|
||||||
|
self.node = self.node + 1
|
||||||
|
return 'value' + str(i), val
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.table = val['_set']['_alloc']['_data']
|
||||||
|
self.capacity = val['_set']['_alloc']['_capacity']
|
||||||
|
self.size = val['_set']['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.table, self.capacity)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'map'
|
||||||
|
|
||||||
|
|
||||||
|
# OBJECT_POOL ==========================================================================================================
|
||||||
|
class ObjectPoolPrinter:
|
||||||
|
"""Print a fennec::object_pool"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.list = val
|
||||||
|
self.index = 0
|
||||||
|
self.capacity = self.list['_table']['_alloc']['_capacity']
|
||||||
|
self.table = self.list['_table']['_alloc']['_data']
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
while True:
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
if self.index >= self.capacity:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
if bool(self.table[i]['_set']):
|
||||||
|
value = self.table[i]['_val']
|
||||||
|
break
|
||||||
|
|
||||||
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_table']['_alloc']['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# RDTREE ===============================================================================================================
|
||||||
|
|
||||||
|
class RDTreePrinter:
|
||||||
|
"""Print a fennec::rdtree"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, tree, node, capacity):
|
||||||
|
self.tree = tree
|
||||||
|
self.capacity = capacity
|
||||||
|
self.visit = deque()
|
||||||
|
|
||||||
|
self.visit.append((node, 0, 0))
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if len(self.visit) == 0:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
node = self.visit[0][0]
|
||||||
|
i = self.visit[0][1]
|
||||||
|
depth = self.visit[0][2]
|
||||||
|
self.visit.popleft()
|
||||||
|
|
||||||
|
value = self.tree[node]['value']
|
||||||
|
|
||||||
|
nnext = self.tree[node]['next']
|
||||||
|
nprev = self.tree[node]['prev']
|
||||||
|
nprevc = self.tree[nprev]['child'] if nprev != 18446744073709551615 else 18446744073709551615
|
||||||
|
child = self.tree[node]['child']
|
||||||
|
n_chld = self.tree[node]['num_children']
|
||||||
|
|
||||||
|
index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
|
||||||
|
|
||||||
|
if nnext < self.capacity:
|
||||||
|
self.visit.appendleft((nnext, i + 1, depth))
|
||||||
|
|
||||||
|
if child < self.capacity:
|
||||||
|
self.visit.appendleft((child, 0, depth + 1))
|
||||||
|
|
||||||
|
# ┌ ─ ├ └
|
||||||
|
|
||||||
|
if nnext != 18446744073709551615:
|
||||||
|
index += '├'
|
||||||
|
else:
|
||||||
|
index += '└'
|
||||||
|
|
||||||
|
index += '─'
|
||||||
|
index += '[{}, {}]'.format(node, i)
|
||||||
|
return index, value
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.tree = val['_table']['_data']
|
||||||
|
self.size = val['_size']
|
||||||
|
self.capacity = val['_table']['_capacity']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.tree, 0, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
# Graph ================================================================================================================
|
||||||
|
|
||||||
|
class GraphPrinter:
|
||||||
|
"""Print a fennec::graph"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.node_pool = val['_vertex_pool']['_table']['_alloc']['_data']
|
||||||
|
self.max_nodes = val['_vertex_pool']['_table']['_alloc']['_capacity']
|
||||||
|
self.conn_map = val['_edge_map']['_alloc']['_data']
|
||||||
|
self.max_conn = val['_edge_map']['_size']
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self.index >= self.max_nodes:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
while not bool(self.node_pool[i]['_set']):
|
||||||
|
i = self.index
|
||||||
|
self.index = self.index + 1
|
||||||
|
|
||||||
|
conns = self.get_conns(i)
|
||||||
|
value = self.node_pool[i]['_val']
|
||||||
|
|
||||||
|
return '[{} -> {{{}}}]'.format(i, str(conns)), value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_conns(self, index):
|
||||||
|
indices = []
|
||||||
|
|
||||||
|
if index >= self.max_conn:
|
||||||
|
return indices
|
||||||
|
|
||||||
|
map = self.conn_map[index]['_set']
|
||||||
|
max_conns = map['_alloc']['_capacity']
|
||||||
|
conns = map['_alloc']['_data']
|
||||||
|
|
||||||
|
print(max_conns)
|
||||||
|
|
||||||
|
if max_conns == 0:
|
||||||
|
return indices
|
||||||
|
|
||||||
|
for i in range(0, max_conns):
|
||||||
|
if bool(conns[i]['value']['_set']):
|
||||||
|
conn = conns[i]['value']['_val']
|
||||||
|
indices.append(str(int(conn['first'])))
|
||||||
|
|
||||||
|
return indices
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.size = val['_vertex_pool']['_size']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.Iterator(self.val)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering containers")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers")
|
||||||
|
pp.add_printer('fennec::array', '^fennec::array<.*>$', ArrayPrinter)
|
||||||
|
pp.add_printer('fennec::deque', '^fennec::deque<.*>$', DequePrinter)
|
||||||
|
pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
|
||||||
|
pp.add_printer('fennec::graph', '^fennec::graph<.*>$', GraphPrinter)
|
||||||
|
pp.add_printer('fennec::list', '^fennec::list<.*>$', ListPrinter)
|
||||||
|
pp.add_printer('fennec::map', '^fennec::map<.*>$', MapPrinter)
|
||||||
|
pp.add_printer('fennec::object_pool', '^fennec::object_pool<.*>$', ObjectPoolPrinter)
|
||||||
|
pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter)
|
||||||
|
pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter)
|
||||||
|
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
||||||
|
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
||||||
|
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
60
gdb/fennec/filesystem.py
Normal file
60
gdb/fennec/filesystem.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class PathPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val['_str']['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_data'].string('', 'replace', self.val['_capacity'] - 1) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class FilePrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.path = val['_path']['_str']['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.val['_handle']:
|
||||||
|
value = "{ path = \"" + self.path['_data'].string('', 'replace', self.path['_capacity'] - 1) + "\" }"
|
||||||
|
return value
|
||||||
|
return "{ closed }"
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering filesystem")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::filesystem")
|
||||||
|
pp.add_printer('fennec::path', '^fennec::path$', PathPrinter)
|
||||||
|
pp.add_printer('fennec::file', '^fennec::file$', FilePrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
99
gdb/fennec/math.py
Normal file
99
gdb/fennec/math.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
import os
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
from . import utility
|
||||||
|
|
||||||
|
# VECTOR =================================================================================================================
|
||||||
|
class VectorPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.base = val['data']['elements']
|
||||||
|
self.len = self.base.type.range()[1] + 1
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
res = "< "
|
||||||
|
if self.len > 0:
|
||||||
|
res += "x = " + str(self.val['x'])
|
||||||
|
if self.len > 1:
|
||||||
|
res += ", y = " + str(self.val['y'])
|
||||||
|
if self.len > 2:
|
||||||
|
res += ", z = " + str(self.val['z'])
|
||||||
|
if self.len > 3:
|
||||||
|
res += ", w = " + str(self.val['w'])
|
||||||
|
res += " >"
|
||||||
|
return res
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.base[i]) for i in range(self.len))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# PATH =================================================================================================================
|
||||||
|
class QuaternionPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
self.base = val['data']['elements']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
res = ("< "
|
||||||
|
+ str(self.val['x']) + " i + "
|
||||||
|
+ str(self.val['y']) + " j + "
|
||||||
|
+ str(self.val['z']) + " k + "
|
||||||
|
+ str(self.val['w']))
|
||||||
|
res += " >"
|
||||||
|
return res
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.base[i]) for i in range(4))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# VECTOR =================================================================================================================
|
||||||
|
class MatrixPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.columns = val['data']['elements']
|
||||||
|
self.num_columns = self.columns.type.range()[1] + 1
|
||||||
|
self.num_rows = val.type.template_argument(1)
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ rows = " + str(self.num_rows) + ", columns = " + str(self.num_columns) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return (('[{}]'.format(i), self.columns[i]) for i in range(self.num_columns))
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering filesystem")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::math")
|
||||||
|
pp.add_printer('fennec::vector', '^fennec::vector<.*>$', VectorPrinter)
|
||||||
|
pp.add_printer('fennec::quaternion', '^fennec::quaternion<.*>$', QuaternionPrinter)
|
||||||
|
pp.add_printer('fennec::matrix', '^fennec::matrix<.*>$', MatrixPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
43
gdb/fennec/memory.py
Normal file
43
gdb/fennec/memory.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# ALLOCATION ===========================================================================================================
|
||||||
|
class AllocationPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return "{ capacity = " + str(self.val['_capacity']) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
size = int(self.val['_capacity'])
|
||||||
|
start = self.val['_data']
|
||||||
|
return (('[{}]'.format(i), start[i]) for i in range(size))
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering memory")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::memory")
|
||||||
|
pp.add_printer('fennec::allocation', '^fennec::allocation<.*>$', AllocationPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
61
gdb/fennec/strings.py
Normal file
61
gdb/fennec/strings.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
|
||||||
|
# CSTRING ==============================================================================================================
|
||||||
|
class CStringPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_str'].string('', 'replace', self.val['_size']) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# STRING ===============================================================================================================
|
||||||
|
class StringPrinter:
|
||||||
|
def __init__(self, val):
|
||||||
|
self.val = val['_str']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
value = "\"" + self.val['_data'].string('', 'replace', self.val['_capacity'] - 1) + "\""
|
||||||
|
return value
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
|
def register_printers():
|
||||||
|
print("registering strings")
|
||||||
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::strings")
|
||||||
|
pp.add_printer('fennec::cstring', '^fennec::cstring$', CStringPrinter)
|
||||||
|
pp.add_printer('fennec::wcstring', '^fennec::wcstring$', CStringPrinter)
|
||||||
|
pp.add_printer('fennec::string', '^fennec::_string<.*>$', StringPrinter)
|
||||||
|
pp.add_printer('fennec::wstring', '^fennec::_wstring<.*>$', StringPrinter)
|
||||||
|
return pp
|
||||||
|
|
||||||
|
printer = register_printers()
|
||||||
20
gdb/fennec/utility.py
Normal file
20
gdb/fennec/utility.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ======================================================================================================================
|
||||||
|
# fennec, a free and open source game engine
|
||||||
|
# Copyright © 2025 Medusa Slockbower
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
# ======================================================================================================================
|
||||||
|
|
||||||
|
def printMembers(obj):
|
||||||
|
print(str(dir(obj)))
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file array.h
|
/// \file array.h
|
||||||
/// \brief statically allocated array wrapper
|
/// \brief A header containing the definition for a static/stack allocated array
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -40,61 +40,48 @@ namespace fennec
|
|||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \brief wrapper for fixed size arrays
|
/// \brief Data Structure that defines a compile-time allocated array
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
/// | Property | Value |
|
/// | Property | Value |
|
||||||
/// |----------|-------------------------|
|
/// |:----------:|:----------:|
|
||||||
/// | stable | \emoji heavy_check_mark |
|
/// | stable | ✅ |
|
||||||
/// | access | \f$O(1)\f$ |
|
/// | dynamic | ⛔ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
/// | space | \f$O(N)\f$ |
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | ⛔ |
|
||||||
|
/// | deletion | ⛔ |
|
||||||
///
|
///
|
||||||
/// \tparam ValueT value type
|
/// \tparam ValueT value type
|
||||||
/// \tparam ElemV number of elements
|
/// \tparam ElemV number of elements
|
||||||
template<typename ValueT, size_t ElemV>
|
template<typename ValueT, size_t ElemV>
|
||||||
struct array
|
struct array {
|
||||||
{
|
|
||||||
///
|
|
||||||
/// \brief backing c-style array handle
|
|
||||||
ValueT elements[ElemV];
|
|
||||||
|
|
||||||
/// \name Element Access
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = ValueT; ///< Alias for `ValueT`
|
||||||
|
|
||||||
|
// Public Members ======================================================================================================
|
||||||
|
|
||||||
|
/// \name Public Members
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \copydetails array::operator[](size_t) const
|
/// \brief backing c-style array handle
|
||||||
constexpr ValueT& operator[](size_t i) {
|
value_t data[ElemV];
|
||||||
assertd(i < ElemV, "Array Out of Bounds");
|
|
||||||
return elements[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief access specified element
|
|
||||||
/// \details Returns a reference to the element at \c i
|
|
||||||
/// \param i index of the element to return
|
|
||||||
/// \return reference to the requested element
|
|
||||||
///
|
|
||||||
/// \par Time-Complexity
|
|
||||||
/// Constant
|
|
||||||
///
|
|
||||||
/// \par Space-Complexity
|
|
||||||
/// Constant
|
|
||||||
constexpr const ValueT& operator[](size_t i) const {
|
|
||||||
assertd(i < ElemV, "Array Out of Bounds");
|
|
||||||
return elements[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ValueT* begin() { return elements; }
|
|
||||||
constexpr ValueT* end() { return elements + ElemV; }
|
|
||||||
|
|
||||||
constexpr const ValueT* begin() const { return elements; }
|
|
||||||
constexpr const ValueT* end() const { return elements + ElemV; }
|
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \name Capacity
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -111,24 +98,126 @@ struct array
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Element Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \copydetails array::operator[](size_t) const
|
||||||
|
constexpr value_t& operator[](size_t i) {
|
||||||
|
assertd(i < ElemV, "Array Out of Bounds");
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief access specified element
|
||||||
|
/// \details Returns a reference to the element at \c i
|
||||||
|
/// \param i index of the element to return
|
||||||
|
/// \return reference to the requested element
|
||||||
|
///
|
||||||
|
/// \par Time-Complexity
|
||||||
|
/// Constant
|
||||||
|
///
|
||||||
|
/// \par Space-Complexity
|
||||||
|
/// Constant
|
||||||
|
constexpr const value_t& operator[](size_t i) const {
|
||||||
|
assertd(i < ElemV, "Array Out of Bounds");
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access the first element
|
||||||
|
/// \returns A reference to the element at `elements[0]`
|
||||||
|
constexpr value_t& front() {
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access the first element
|
||||||
|
/// \returns A const-qualified reference to the element at `elements[0]`
|
||||||
|
constexpr const value_t& front() const {
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access the first element
|
||||||
|
/// \returns A reference to the element at `elements[ElemV - 1]`
|
||||||
|
constexpr value_t& back() {
|
||||||
|
return data[ElemV - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access the first element
|
||||||
|
/// \returns A const-qualified reference to the element at `elements[ElemV - 1]`
|
||||||
|
constexpr const value_t& back() const {
|
||||||
|
return data[ElemV - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Comparison ==========================================================================================================
|
||||||
|
|
||||||
/// \name Comparison Operators
|
/// \name Comparison Operators
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief
|
/// \brief Checks if all elements in the arrays are equal
|
||||||
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
|
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
|
||||||
return array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
return array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if any element in the arrays is not equal
|
||||||
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
|
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
|
||||||
return not array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
return not array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A pointer to the first element of the array
|
||||||
|
constexpr value_t* begin() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns A pointer to one after the end of the array
|
||||||
|
constexpr value_t* end() {
|
||||||
|
return data + ElemV;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A const-qualified pointer to the first element of the array
|
||||||
|
constexpr const value_t* begin() const {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `end()`
|
||||||
|
/// \returns A const-qualified pointer to one after the end of the array
|
||||||
|
constexpr const value_t* end() const {
|
||||||
|
return data + ElemV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<size_t...i>
|
template<size_t...i>
|
||||||
static bool _compare(const array& lhs, const array& rhs, index_sequence<i...>) {
|
static bool _compare(const array& lhs, const array& rhs, const_index_sequence<i...>) {
|
||||||
return ((lhs[i] == rhs[i]) && ...);
|
return ((lhs[i] == rhs[i]) && ...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
94
include/fennec/containers/containers.h
Normal file
94
include/fennec/containers/containers.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file containers.h
|
||||||
|
/// \brief fennec containers library main header
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
|
#define FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \page fennec_containers Containers Library
|
||||||
|
///
|
||||||
|
/// \brief The fennec Containers Library.
|
||||||
|
/// Includes various data structures, those specified in the C++ Standard Library, and custom data structures
|
||||||
|
/// that fennec uses.
|
||||||
|
///
|
||||||
|
/// \code #include <fennec/containers/containers.h> \endcode
|
||||||
|
///
|
||||||
|
/// \section fennec_containers_cppstdlib C++ Standard Template Library
|
||||||
|
///
|
||||||
|
/// | Symbol | Implemented | Passed |
|
||||||
|
/// |:----------------------------------------------------------------------------|:-----------:|:------:|
|
||||||
|
/// | \ref fennec::any "fennec::any" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::array "fennec::array" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::bitset "fennec::bitset" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::deque "fennec::deque" | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::dynarray "fennec::dynarray" `std::vector` | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::list "fennec::list" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::map "fennec::map" `std::unordered_map` | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::map_sequence "fennec::map_sequence" `std::map` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multiset "fennec::multiset" `std::unordered_multiset` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multisequence "fennec::multisequence" `std::multiset` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multimap "fennec::multimap" `std::unordered_multimap` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::multimap_sequence "fennec::multimap_sequence" `std::multimap` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::optional "fennec::optional" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::pair "fennec::pair" | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::sequence "fennec::sequence" `std::set` | ⛔ | ⛔ |
|
||||||
|
/// | \ref fennec::set "fennec::set" `std::unordered_set` | ✅ | ✅ |
|
||||||
|
/// | \ref fennec::tuple "fennec::tuple" | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::variant "fennec::variant" | ⛔ | ⛔ |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \section fennec_containers_fennec fennec
|
||||||
|
///
|
||||||
|
/// | Symbol | Implemented | Passed |
|
||||||
|
/// |:-------------------------|:-----------:|:------:|
|
||||||
|
/// | \ref fennec::graph | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::object_pool | 🚧 | 🚧 |
|
||||||
|
/// | \ref fennec::rdtree | ✅ | ✅ |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
|
||||||
|
#include <fennec/containers/traversal.h>
|
||||||
|
|
||||||
|
#include <fennec/containers/array.h>
|
||||||
|
#include <fennec/containers/deque.h>
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/graph.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/map.h>
|
||||||
|
#include <fennec/containers/object_pool.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/pair.h>
|
||||||
|
#include <fennec/containers/rdtree.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
#include <fennec/containers/tuple.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_CONTAINERS_H
|
||||||
345
include/fennec/containers/deque.h
Normal file
345
include/fennec/containers/deque.h
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file deque.h
|
||||||
|
/// \brief A header containing the definition for a double-ended queue
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_DEQUE_H
|
||||||
|
#define FENNEC_CONTAINERS_DEQUE_H
|
||||||
|
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief Data structure defining a double-ended queue.
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// This behaves the similar to fennec::list, however it does not allow arbitrary access, insertion, or deletion.
|
||||||
|
/// It is one of the few data structures in this library that is stable, i.e. pointers to elements do not change.
|
||||||
|
///
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ✅ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ⛔ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT value type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct deque {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
class iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
value_t value;
|
||||||
|
node *prev, *next;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
node(node* prev, node* next, ArgsT&&...args)
|
||||||
|
: value(fennec::forward<ArgsT>(args)...)
|
||||||
|
, prev(prev), next(next) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
|
||||||
|
using elem_t = node*;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty deque
|
||||||
|
deque()
|
||||||
|
: _alloc()
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Constructor, initializes an empty deque with the specified allocator
|
||||||
|
/// \param alloc the allocator to copy
|
||||||
|
deque(const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor
|
||||||
|
/// \param deque the deque to copy
|
||||||
|
deque(const deque& deque)
|
||||||
|
: _alloc(deque._alloc)
|
||||||
|
, _first(nullptr)
|
||||||
|
, _last(nullptr)
|
||||||
|
, _size(0) {
|
||||||
|
const elem_t node = deque._first;
|
||||||
|
while (node) {
|
||||||
|
this->push_back(node->value);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Deque Move Constructor
|
||||||
|
/// \param deque the deque to move
|
||||||
|
deque(deque&& deque) noexcept
|
||||||
|
: _alloc(deque._alloc)
|
||||||
|
, _first(deque._first)
|
||||||
|
, _last(deque._last)
|
||||||
|
, _size(deque._size) {
|
||||||
|
deque._first = nullptr;
|
||||||
|
deque._last = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, calls deque::clear
|
||||||
|
~deque() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the deque is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the number of elements in size()
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a reference to the first element in the deque
|
||||||
|
value_t& front() {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _first->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a const-qualified reference to the first element in the deque
|
||||||
|
const value_t& front() const {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _first->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a reference to the last element in the deque
|
||||||
|
value_t& back() {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _last->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns a const-qualified reference to the last element in the deque
|
||||||
|
const value_t& back() const {
|
||||||
|
assert(not empty(), "Attempted to access an empty deque.");
|
||||||
|
return _last->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Move, moves a value to the front of the deque
|
||||||
|
/// \param elem the value to move
|
||||||
|
void push_front(value_t&& elem) {
|
||||||
|
this->_push_front(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Copy, copies a value to the front of the deque
|
||||||
|
/// \param elem the value to copy
|
||||||
|
void push_front(const value_t& elem) {
|
||||||
|
this->_push_front(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Front, constructs a new value at the front of the deque
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments used to construct the value
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void emplace_front(ArgsT&&...args) {
|
||||||
|
this->_push_front(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Move, moves a value to the back of the deque
|
||||||
|
/// \param elem the value to move
|
||||||
|
void push_back(value_t&& elem) {
|
||||||
|
this->_push_back(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Copy, copies a value to the back of the deque
|
||||||
|
/// \param elem the value to copy
|
||||||
|
void push_back(const value_t& elem) {
|
||||||
|
this->_push_back(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Back, constructs a new value at the back of the deque
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments used to construct the value
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void emplace_back(ArgsT&&...args) {
|
||||||
|
this->_push_back(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the contents of the deque
|
||||||
|
void clear() {
|
||||||
|
elem_t it = _first;
|
||||||
|
while (it) {
|
||||||
|
elem_t next = it->next;
|
||||||
|
fennec::destruct(it);
|
||||||
|
_alloc.deallocate(it);
|
||||||
|
it = next;
|
||||||
|
}
|
||||||
|
_first = nullptr;
|
||||||
|
_last = nullptr;
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase the First Element
|
||||||
|
void pop_front() {
|
||||||
|
if (_first == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem_t next = _first->next;
|
||||||
|
fennec::destruct(_first);
|
||||||
|
_alloc.deallocate(_first);
|
||||||
|
_first = next;
|
||||||
|
_last = next ? _last : nullptr;
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase the Last Element
|
||||||
|
void pop_back() {
|
||||||
|
if (_last == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem_t prev = _last->prev;
|
||||||
|
fennec::destruct(_last);
|
||||||
|
_alloc.deallocate(_last);
|
||||||
|
_last = prev;
|
||||||
|
_first = prev ? _first : nullptr;
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Decide whether you should be able to iterate over a deque
|
||||||
|
*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
alloc_t _alloc;
|
||||||
|
node *_first, *_last;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void _push_front(ArgsT&&...args) {
|
||||||
|
elem_t next = _first;
|
||||||
|
_first = _alloc.allocate(1);
|
||||||
|
fennec::construct(_first, nullptr, next, fennec::forward<ArgsT>(args)...);
|
||||||
|
if (next) {
|
||||||
|
next->prev = _first;
|
||||||
|
} else {
|
||||||
|
_last = _first;
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
void _push_back(ArgsT&&...args) {
|
||||||
|
elem_t prev = _last;
|
||||||
|
_last = _alloc.allocate(1);
|
||||||
|
fennec::construct(_last, prev, nullptr, fennec::forward<ArgsT>(args)...);
|
||||||
|
if (prev) {
|
||||||
|
prev->next = _last;
|
||||||
|
} else {
|
||||||
|
_first = _last;
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_DEQUE_H
|
||||||
@@ -18,40 +18,42 @@
|
|||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
#include <fennec/lang/sequences.h>
|
#include <fennec/lang/const_sequences.h>
|
||||||
#include <fennec/lang/utility.h>
|
#include <fennec/lang/utility.h>
|
||||||
|
|
||||||
namespace fennec::detail
|
namespace fennec::detail
|
||||||
{
|
{
|
||||||
|
|
||||||
// leaves
|
|
||||||
template<size_t i, typename T>
|
template <std::size_t I, typename T>
|
||||||
struct _tuple_leaf {
|
struct _tuple_leaf
|
||||||
|
{
|
||||||
|
template <typename ArgT>
|
||||||
|
constexpr _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {}
|
||||||
|
|
||||||
|
constexpr ~_tuple_leaf() = default;
|
||||||
|
|
||||||
|
constexpr _tuple_leaf& operator=(const _tuple_leaf&) = default;
|
||||||
|
constexpr _tuple_leaf& operator=(_tuple_leaf&&) noexcept = default;
|
||||||
|
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
template<typename...ArgsT>
|
|
||||||
_tuple_leaf(ArgsT&&...args) : value(args...) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator T&() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator const T&() const {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// proxy
|
template <typename, typename...>
|
||||||
template<typename, typename...TypesT>
|
|
||||||
struct _tuple;
|
struct _tuple;
|
||||||
|
|
||||||
template<size_t...i, typename...TypesT>
|
template <size_t...IndicesV, typename...TypesT>
|
||||||
struct _tuple<index_sequence<i...>, TypesT...> : _tuple_leaf<i, TypesT>... {
|
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
|
||||||
|
{
|
||||||
template <typename...ArgsT>
|
template <typename...ArgsT>
|
||||||
_tuple(ArgsT&&...args) : _tuple_leaf<i, TypesT>(args)... {
|
constexpr _tuple(ArgsT&&... args)
|
||||||
|
: _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr _tuple& operator=(const _tuple&) = default;
|
||||||
|
constexpr _tuple& operator=(_tuple&&) noexcept = default;
|
||||||
|
|
||||||
|
constexpr ~_tuple() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file dynarray.h
|
/// \file dynarray.h
|
||||||
/// \brief dynamically allocated array wrapper
|
/// \brief A header containing the definition for a dynamically allocated array
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -40,126 +40,287 @@ namespace fennec
|
|||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \brief wrapper for dynamically sized arrays
|
/// \brief Wrapper for dynamically sized and allocated arrays
|
||||||
/// \details
|
/// \details
|
||||||
/// | Property | Value |
|
/// | Property | Value |
|
||||||
/// |-----------|--------------|
|
/// |:----------:|:----------:|
|
||||||
/// | stable | \emoji anger |
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
/// | access | \f$O(1)\f$ |
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
/// | insertion | \f$O(N)\f$ |
|
/// | insertion | \f$O(N)\f$ |
|
||||||
/// | deletion | \f$O(N)\f$ |
|
/// | deletion | \f$O(N)\f$ |
|
||||||
/// | space | \f$O(N)\f$ |
|
///
|
||||||
|
/// This structure prefers shallow moves and deep copies.
|
||||||
///
|
///
|
||||||
/// \tparam TypeT value type
|
/// \tparam TypeT value type
|
||||||
template<class TypeT, class Alloc = allocator<TypeT>>
|
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||||
class dynarray {
|
class dynarray {
|
||||||
public:
|
public:
|
||||||
using element_t = TypeT;
|
|
||||||
using alloc_t = Alloc;
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
using alloc_t = Alloc; ///< Alias for the allocator type
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Default Constructor, initializes an empty allocation.
|
/// \brief Default Constructor, initializes an empty allocation.
|
||||||
constexpr dynarray() : _alloc(8), _size(0) {}
|
constexpr dynarray()
|
||||||
|
: _alloc(8)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
||||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some data.
|
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||||
constexpr dynarray(const alloc_t& alloc)
|
/// data.
|
||||||
|
explicit constexpr dynarray(const alloc_t& alloc)
|
||||||
: _alloc(8, alloc)
|
: _alloc(8, alloc)
|
||||||
, _size(0) {
|
, _size(0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Sized Allocation, create an allocation with a size of `n` elements, initialized with the default constructor.
|
/// \brief Alloc Move Constructor, initialize empty allocation with allocator instance.
|
||||||
constexpr dynarray(size_t n)
|
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||||
|
/// data.
|
||||||
|
explicit constexpr dynarray(alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(8, alloc)
|
||||||
|
, _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation, initializes a dynarray with `n` elements using the default constructor.
|
||||||
|
/// \param n The number of elements.
|
||||||
|
explicit constexpr dynarray(size_t n)
|
||||||
: _alloc(n)
|
: _alloc(n)
|
||||||
, _size(n)
|
, _size(n)
|
||||||
{
|
{
|
||||||
element_t* addr = _alloc.data();
|
value_t* addr = _alloc.data();
|
||||||
for(; n > 0; --n, ++addr) {
|
for(; n > 0; --n, ++addr) {
|
||||||
fennec::construct(addr);
|
fennec::construct(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief
|
/// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator `alloc` and `n` elements
|
||||||
/// \param n
|
/// using the default constructor.
|
||||||
/// \param alloc
|
/// \param n The number of elements
|
||||||
|
/// \param alloc The allocator object to copy
|
||||||
constexpr dynarray(size_t n, const alloc_t& alloc)
|
constexpr dynarray(size_t n, const alloc_t& alloc)
|
||||||
: _alloc(n, alloc)
|
: _alloc(n, alloc)
|
||||||
, _size(n) {
|
, _size(n) {
|
||||||
element_t* addr = _alloc.data();
|
value_t* addr = _alloc.data();
|
||||||
for(; n > 0; --n, ++addr) {
|
for(; n > 0; --n, ++addr) {
|
||||||
fennec::construct(addr);
|
fennec::construct(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Create an allocation of size `n`, with each element constructed using the copy constructor
|
/// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator `alloc` and `n` elements
|
||||||
/// \brief n the number of elements
|
/// using the default constructor.
|
||||||
|
/// \param n The number of elements
|
||||||
|
/// \param alloc The allocator object to copy
|
||||||
|
constexpr dynarray(size_t n, alloc_t&& alloc)
|
||||||
|
: _alloc(n, alloc)
|
||||||
|
, _size(n) {
|
||||||
|
value_t* addr = _alloc.data();
|
||||||
|
for(; n > 0; --n, ++addr) {
|
||||||
|
fennec::construct(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Sized Allocation Copy Constructor, Create an allocation of size `n` elements, with each element
|
||||||
|
/// constructed using the copy constructor
|
||||||
|
/// \param n the number of elements
|
||||||
|
/// \param val the value to copy
|
||||||
constexpr dynarray(size_t n, const TypeT& val)
|
constexpr dynarray(size_t n, const TypeT& val)
|
||||||
: _alloc(n)
|
: _alloc(n)
|
||||||
, _size(n) {
|
, _size(n) {
|
||||||
element_t* addr = _alloc.data();
|
value_t* addr = _alloc.data();
|
||||||
for(; n > 0; --n, ++addr) {
|
for(; n > 0; --n, ++addr) {
|
||||||
fennec::construct(addr, val);
|
fennec::construct(addr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This constructor should not be invokable since moving is a single object operation and will cause undefined
|
||||||
|
// behaviour when moving to multiple elements
|
||||||
constexpr dynarray(size_t n, TypeT&&) = delete;
|
constexpr dynarray(size_t n, TypeT&&) = delete;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Constructor
|
||||||
|
/// \tparam ArgsT A sequence of argument types
|
||||||
|
/// \param n The number of objects to create
|
||||||
|
/// \param args The arguments to create each object with
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr dynarray(size_t n, ArgsT&&...args) {
|
constexpr explicit dynarray(size_t n, ArgsT&&...args)
|
||||||
element_t* addr = _alloc.data();
|
: _alloc(n)
|
||||||
for(; n > 0; --n, ++addr) {
|
, _size(n) {
|
||||||
fennec::construct(addr, fennec::forward<ArgsT>(args)...);
|
for(; n > 0; --n) {
|
||||||
|
fennec::construct(&_alloc[n], fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, uses the copy constructor to copy each element
|
||||||
|
/// \param arr the dynarray to copy
|
||||||
|
constexpr dynarray(const dynarray& arr)
|
||||||
|
: _alloc(arr._size)
|
||||||
|
, _size(arr._size) {
|
||||||
|
for (size_t i = 0; i < _size; ++i) {
|
||||||
|
fennec::construct(&_alloc[i], arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership of the allocation
|
||||||
|
/// \param arr the dynarray to move
|
||||||
|
constexpr dynarray(dynarray&& arr) noexcept
|
||||||
|
: _alloc(fennec::move(arr._alloc))
|
||||||
|
, _size(arr._size) {
|
||||||
|
arr._size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Destructor, destructs all elements and frees the underlying allocation
|
||||||
constexpr ~dynarray() {
|
constexpr ~dynarray() {
|
||||||
element_t* addr = _alloc.data();
|
value_t* addr = _alloc.data();
|
||||||
|
if (addr == nullptr) return;
|
||||||
for(int n = _size; n > 0; --n, ++addr) {
|
for(int n = _size; n > 0; --n, ++addr) {
|
||||||
fennec::destruct(addr);
|
fennec::destruct(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param arr the array to copy
|
||||||
|
/// \returns A dynarray after having copied each element of `arr`
|
||||||
|
constexpr dynarray& operator=(const dynarray& arr) {
|
||||||
|
this->clear();
|
||||||
|
_alloc.creallocate(_size = arr._size);
|
||||||
|
for (size_t i = 0; i < _size; ++i) {
|
||||||
|
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param arr the array to move
|
||||||
|
/// \returns A dynarray after having taken ownership of the contents of `arr`
|
||||||
|
constexpr dynarray& operator=(dynarray&& arr) noexcept {
|
||||||
|
this->clear();
|
||||||
|
_alloc = fennec::move(arr._alloc);
|
||||||
|
_size = arr._size;
|
||||||
|
arr._size = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the dynarray in elements
|
||||||
constexpr size_t size() const {
|
constexpr size_t size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The current capacity, in elements, of the underlying allocation
|
||||||
constexpr size_t capacity() const {
|
constexpr size_t capacity() const {
|
||||||
return _alloc.capacity();
|
return _alloc.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns True when there are no elements active, otherwise false
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return _size == 0;
|
return _size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr TypeT& operator[](int i) {
|
/// @}
|
||||||
assertd(i >= 0 and size_t(i) < _size, "Array Out of Bounds");
|
|
||||||
|
|
||||||
|
// Element Access ======================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i The index to access
|
||||||
|
/// \returns A reference to the element at index `i`
|
||||||
|
constexpr TypeT& operator[](size_t i) {
|
||||||
|
assertd(i < _size, "Array Out of Bounds");
|
||||||
return _alloc.data()[i];
|
return _alloc.data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const TypeT& operator[](int i) const {
|
///
|
||||||
assertd(i >= 0 and size_t(i) < _size, "Array Out of Bounds");
|
/// \brief Array Access Operator (const)
|
||||||
|
/// \param i The index to access
|
||||||
|
/// \returns A const qualified reference to the element at index `i`
|
||||||
|
constexpr const TypeT& operator[](size_t i) const {
|
||||||
|
assertd(i < _size, "Array Out of Bounds");
|
||||||
return _alloc.data()[i];
|
return _alloc.data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr TypeT* begin() { return _alloc.data(); }
|
///
|
||||||
constexpr TypeT* end() { return begin() + _size; }
|
/// \returns Reference to the first element in the dynarray
|
||||||
|
constexpr TypeT& front() {
|
||||||
|
return this->operator[](0);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr const TypeT* begin() const { return _alloc; }
|
///
|
||||||
constexpr const TypeT* end() const { return begin() + _size; }
|
/// \returns A const-qualified reference to the first element in the dynarray
|
||||||
|
constexpr const TypeT& front() const {
|
||||||
|
return this->operator[](0);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A reference to the last element in the dynarray
|
||||||
constexpr TypeT& back() {
|
constexpr TypeT& back() {
|
||||||
return this->operator[](size() - 1);
|
return this->operator[](size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A const-qualified reference to the last element in the dynarray
|
||||||
constexpr const TypeT& back() const {
|
constexpr const TypeT& back() const {
|
||||||
return this->operator[](size() - 1);
|
return this->operator[](size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param i index to insert at
|
||||||
|
/// \param val the value to initialize with
|
||||||
constexpr void insert(size_t i, TypeT&& val) {
|
constexpr void insert(size_t i, TypeT&& val) {
|
||||||
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
@@ -180,6 +341,10 @@ public:
|
|||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param i index to insert at
|
||||||
|
/// \param val the value to initialize with
|
||||||
constexpr void insert(size_t i, const TypeT& val) {
|
constexpr void insert(size_t i, const TypeT& val) {
|
||||||
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
@@ -190,9 +355,10 @@ public:
|
|||||||
// Move the data if we are not inserting at the end of the array
|
// Move the data if we are not inserting at the end of the array
|
||||||
if((i = min(i, _size)) < _size) {
|
if((i = min(i, _size)) < _size) {
|
||||||
fennec::memmove(
|
fennec::memmove(
|
||||||
(void*)(_alloc.data() + i)
|
(void*)(_alloc.data() + i),
|
||||||
, (void*)(_alloc.data() + i + 1)
|
(void*)(_alloc.data() + i + 1),
|
||||||
, (_size - i) * sizeof(TypeT));
|
(_size - i) * sizeof(TypeT)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the element
|
// Insert the element
|
||||||
@@ -200,6 +366,11 @@ public:
|
|||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \param i index to insert at
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void emplace(size_t i, ArgsT&&...args) {
|
constexpr void emplace(size_t i, ArgsT&&...args) {
|
||||||
|
|
||||||
@@ -221,42 +392,91 @@ public:
|
|||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Copy
|
||||||
|
/// \param val Value to initialize with
|
||||||
constexpr void push_back(const TypeT& val) {
|
constexpr void push_back(const TypeT& val) {
|
||||||
dynarray::insert(_size, val);
|
dynarray::insert(_size, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Move
|
||||||
|
/// \param val Value to initialize with
|
||||||
constexpr void push_back(TypeT&& val) {
|
constexpr void push_back(TypeT&& val) {
|
||||||
dynarray::insert(_size, fennec::forward<TypeT>(val));
|
dynarray::insert(_size, fennec::forward<TypeT>(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void pop_back() {
|
///
|
||||||
fennec::destruct(&_alloc[_size--]);
|
/// \brief Emplace Back
|
||||||
}
|
/// \tparam ArgsT Argument Types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void emplace_back(ArgsT...args) {
|
constexpr void emplace_back(ArgsT...args) {
|
||||||
dynarray::emplace(_size, fennec::forward<ArgsT>(args)...);
|
dynarray::emplace(_size, fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void resize(size_t n) {
|
///
|
||||||
_alloc.reallocate(n);
|
/// \brief Erase last element
|
||||||
|
constexpr void pop_back() {
|
||||||
if (_size < n) {
|
fennec::destruct(&_alloc[--_size]);
|
||||||
_size = n;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Resize the dynarray, invoking the default constructor for all new elements
|
||||||
|
/// \param n The new size in elements
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_alloc.creallocate(n);
|
||||||
|
|
||||||
while (_size < n) {
|
while (_size < n) {
|
||||||
emplace_back();
|
emplace_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
///
|
||||||
constexpr void _grow() {
|
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
|
||||||
_alloc.reallocate(_alloc.capacity() * 2);
|
constexpr void clear() {
|
||||||
|
while (_size > 0) {
|
||||||
|
fennec::destruct(&_alloc[--_size]);
|
||||||
|
}
|
||||||
|
_alloc.deallocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
allocation<element_t, alloc_t> _alloc;
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief "Iterator" Begin Function
|
||||||
|
/// \returns A pointer to the first element in the dynarray
|
||||||
|
constexpr TypeT* begin() { return _alloc.data(); }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief "Iterator" End Function
|
||||||
|
/// \return A pointer to the address after the last element in the dynarray
|
||||||
|
constexpr TypeT* end() { return begin() + _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const "Iterator" Begin Function
|
||||||
|
/// \returns A const qualified pointer to the first element in the dynarray
|
||||||
|
constexpr const TypeT* begin() const { return _alloc; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const "Iterator" End Function
|
||||||
|
/// \return A const qualified pointer to the address after the last element in the dynarray
|
||||||
|
constexpr const TypeT* end() const { return begin() + _size; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr void _grow() {
|
||||||
|
_alloc.creallocate(_alloc.capacity() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
allocation<value_t, alloc_t> _alloc;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
518
include/fennec/containers/graph.h
Normal file
518
include/fennec/containers/graph.h
Normal file
@@ -0,0 +1,518 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file graph.h
|
||||||
|
/// \brief A header containing the definition for a graph of vertices connected by edges
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_GRAPH_H
|
||||||
|
#define FENNEC_CONTAINERS_GRAPH_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/map.h>
|
||||||
|
#include <fennec/containers/object_pool.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With the directed tree we were able to cheat a little, the structure has more rules to it which allows
|
||||||
|
* tighter constraints. A graph is basically no rules whatsoever. Some variants, such as weighted graphs, assign
|
||||||
|
* properties or rules to edges which can simply be an extension to this graph.
|
||||||
|
*
|
||||||
|
* The most effective way to do this is to have a dynarray of lists, however this results in double the
|
||||||
|
* memory being used. This can also result in two edge objects being created.
|
||||||
|
*
|
||||||
|
* There is no nice way to avoid the problem of mapping vertices to edges
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Graph Data Structure, describes sets of arbitrarily connected vertices
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(N)\f$ |
|
||||||
|
///
|
||||||
|
/// Graphs contain vertices and edges. Graphs are either directed
|
||||||
|
/// or undirected. This structure allows the creation of both directed and undirected edges. As
|
||||||
|
/// far as what that means; a directed graph means that edges have direction, where there are edges
|
||||||
|
/// that are "to" and "from," rather than "between" which is used in undirected graphs.
|
||||||
|
///
|
||||||
|
/// An undirected graph is connected if there is a path between every pair of vertices in the graph.
|
||||||
|
///
|
||||||
|
/// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would
|
||||||
|
/// produce a connected graph. We will call this "disjointed"
|
||||||
|
///
|
||||||
|
/// A directed graph is semi-connected if there is a directed path p for `u` → `v` *or* `v` → `u` for every
|
||||||
|
/// pair of vertices `u, v`. We will call this "unilateral"
|
||||||
|
///
|
||||||
|
/// A directed graph is strongly-connected if there is a directed path p for `u` → `v` *and* `v` → `u` for every pair
|
||||||
|
/// of vertices `u, v`. We will call this "connected"
|
||||||
|
///
|
||||||
|
/// \tparam VertexT The type associated with each vertex
|
||||||
|
/// \tparam EdgeT The type associated with each edge
|
||||||
|
template<typename VertexT, typename EdgeT = empty_t>
|
||||||
|
struct graph {
|
||||||
|
public:
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
using edge_t = EdgeT; ///< Alias for the edge type
|
||||||
|
using vertex_t = VertexT; ///< Alias for the vertex type
|
||||||
|
using vertex_pool_t = object_pool<vertex_t>; ///< Alias for a pool of vertices
|
||||||
|
using edge_map_t = dynarray<map<size_t, size_t>>; ///< Alias for edge mapping
|
||||||
|
using edge_pool_t = object_pool<edge_t>; ///< Alias for a pool of edges
|
||||||
|
|
||||||
|
static constexpr size_t npos = -1; ///< Constant for a non-existent vertex
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty graph
|
||||||
|
constexpr graph() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor
|
||||||
|
constexpr ~graph() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
/// \name Assignment Operators
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param g The graph to copy
|
||||||
|
/// \returns A reference to this after assigning g
|
||||||
|
constexpr graph& operator=(const graph& g) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param g The graph to copy
|
||||||
|
/// \returns A reference to this after assigning g
|
||||||
|
constexpr graph& operator=(graph&& g) = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of vertices in the graph
|
||||||
|
constexpr size_t num_vertices() const {
|
||||||
|
return _vertex_pool.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of edges in the graph
|
||||||
|
constexpr size_t num_edges() const {
|
||||||
|
return _edge_pool.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the vertex pool
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _vertex_pool.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no vertices in the graph, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return num_vertices() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e` that starts from `a` and ends at `b`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if the edge exists, `false` otherwise
|
||||||
|
constexpr bool exists(size_t a, size_t b) const {
|
||||||
|
return _edge_map[a][b] != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e0` that starts from `a` and ends at `b` and `e1` that starts from `b`
|
||||||
|
/// and ends at `a`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if both edges exist, `false` otherwise
|
||||||
|
constexpr bool is_symmetric(size_t a, size_t b) const {
|
||||||
|
return exists(a, b) and exists(b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Checks if there exists an edge `e` between `a` and `b`
|
||||||
|
/// \param a The first vertex
|
||||||
|
/// \param b The second vertex
|
||||||
|
/// \returns `true` if both edges exist, `false` otherwise
|
||||||
|
constexpr bool is_undirected(size_t a, size_t b) const {
|
||||||
|
const auto* e0 = _edge_map[a][b];
|
||||||
|
const auto* e1 = _edge_map[b][a];
|
||||||
|
if (not (e0 != nullptr && e1 != nullptr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return *e0 == *e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: connected, disjoint, unilateral, get_component
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief vertex Access Operator
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A reference to the value stored in the vertex
|
||||||
|
constexpr vertex_t& operator[](size_t vertex) {
|
||||||
|
return _vertex_pool[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief vertex Const Access Operator
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A reference to the value stored in the vertex
|
||||||
|
constexpr const vertex_t& operator[](size_t vertex) const {
|
||||||
|
return _vertex_pool[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief edge Access Operator
|
||||||
|
/// \param a The id of the first vertex
|
||||||
|
/// \param b The id of the second vertex
|
||||||
|
/// \returns A pointer to the value stored in the edge, `nullptr` if not found
|
||||||
|
constexpr edge_t* operator[](size_t a, size_t b) {
|
||||||
|
if (empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
edge_t* it = _edge_map[a][b];
|
||||||
|
if (it) {
|
||||||
|
return _edge_pool[*it];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief edge Const Access Operator
|
||||||
|
/// \param a The id of the first vertex
|
||||||
|
/// \param b The id of the second vertex
|
||||||
|
/// \returns A const-qualified pointer to the value stored in the edge, `nullptr` if not found
|
||||||
|
constexpr const edge_t* operator[](size_t a, size_t b) const {
|
||||||
|
if (empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const edge_t* it = _edge_map[a][b];
|
||||||
|
if (it) {
|
||||||
|
return _edge_pool[*it];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` with edges from `vertex` to `x...`
|
||||||
|
list<size_t> outgoing(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge from `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` with edges from `x...` to `vertex`
|
||||||
|
list<size_t> incoming(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (size_t n = 0; n < _edge_map.size(); ++n) {
|
||||||
|
if (_edge_map[n][vertex]) {
|
||||||
|
res.push_back(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...`
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||||
|
list<size_t> symmetric(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
if (_edge_map[it.first][vertex]) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...` and share the same value
|
||||||
|
/// \details
|
||||||
|
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
|
||||||
|
/// turned into a directed edge by changing the weight object associated with the edge, or by
|
||||||
|
/// removing one of the sub-edges.
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||||
|
list<size_t> undirected(size_t vertex) {
|
||||||
|
list<size_t> res;
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
for (const auto& it : _edge_map[vertex]) {
|
||||||
|
const auto* at = _edge_map[it.first][vertex];
|
||||||
|
if (at != nullptr && *at == it.second) {
|
||||||
|
res.push_back(it.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Getter for the internal storage of mapped edges from this vertex.
|
||||||
|
/// Use this when you want to iterate over edges that start from this vertex.
|
||||||
|
/// \param vertex The id of the vertex
|
||||||
|
/// \returns A pointer to a map containing edges mapped from this vertex
|
||||||
|
const auto* edges(size_t vertex) {
|
||||||
|
if (empty() || vertex >= _edge_map.size()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &_edge_map[vertex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move a new vertex into the graph
|
||||||
|
/// \param vertex The vertex to move into the graph
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
constexpr size_t insert(vertex_t&& vertex) {
|
||||||
|
return this->_insert(fennec::forward<vertex_t>(vertex));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy a new vertex into the graph
|
||||||
|
/// \param vertex The vertex to copy into the graph
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
constexpr size_t insert(const vertex_t& vertex) {
|
||||||
|
return this->_insert(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Construct a new vertex in the graph
|
||||||
|
/// \tparam ArgsT The types of the arguments
|
||||||
|
/// \param args The arguments to construct the vertex with
|
||||||
|
/// \returns The id of the new vertex
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a vertex from the graph
|
||||||
|
/// \param vertex The id of the vertex to erase
|
||||||
|
constexpr void erase(size_t vertex) {
|
||||||
|
cut(vertex);
|
||||||
|
_vertex_pool.erase(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Form an edge from vertex `a` to vertex `b`
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
/// \param args The arguments to construct the edge with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) {
|
||||||
|
if (a == b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_edge_map.size() < _vertex_pool.capacity()) {
|
||||||
|
_edge_map.resize(_vertex_pool.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _edge_map[a][b];
|
||||||
|
size_t conn;
|
||||||
|
if (it != nullptr) {
|
||||||
|
conn = *it;
|
||||||
|
_edge_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
conn = _edge_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
_edge_map[a].emplace(b, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Form an undirected edge between vertex `a` and vertex `b`
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
/// \param args The arguments to construct the edge with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) {
|
||||||
|
if (a == b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_edge_map.size() < _vertex_pool.capacity()) {
|
||||||
|
_edge_map.resize(_vertex_pool.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _edge_map[a][b];
|
||||||
|
size_t conn;
|
||||||
|
if (it != nullptr) {
|
||||||
|
conn = *it;
|
||||||
|
_edge_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
conn = _edge_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
_edge_map[a].emplace(b, conn);
|
||||||
|
_edge_map[b].emplace(a, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Disconnect an edge from vertex `a` to vertex `b`
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
constexpr void cut_edge(size_t a, size_t b) {
|
||||||
|
|
||||||
|
// Find the edge object
|
||||||
|
const auto* it = _edge_map[a][b];
|
||||||
|
if (not it) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t c = *it;
|
||||||
|
|
||||||
|
// Check if undirected
|
||||||
|
const auto* at = _edge_map[b][a];
|
||||||
|
if (not at || *at != c) {
|
||||||
|
_edge_pool.erase(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the edge mapping
|
||||||
|
_edge_map[a].erase(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Disconnect both directed edges between vertices `a` and `b`
|
||||||
|
/// \param a The first vertex id
|
||||||
|
/// \param b The second vertex id
|
||||||
|
constexpr void cut_edge2(size_t a, size_t b) {
|
||||||
|
const auto* ita = _edge_map[a][b];
|
||||||
|
const auto* itb = _edge_map[a][b];
|
||||||
|
if (not (ita || itb)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ita) _edge_pool.erase(*ita);
|
||||||
|
if (itb) _edge_pool.erase(*itb);
|
||||||
|
_edge_map[a].erase(b);
|
||||||
|
_edge_map[b].erase(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Break *all* edges to and from `n`
|
||||||
|
/// \param n The vertex id
|
||||||
|
void cut(size_t n) {
|
||||||
|
for (const auto it : outgoing(n)) {
|
||||||
|
cut_edge(n, it);
|
||||||
|
}
|
||||||
|
for (const auto it : incoming(n)) {
|
||||||
|
cut_edge(it, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clear the graph, destructing all vertices and edges.
|
||||||
|
void clear() {
|
||||||
|
_vertex_pool.clear();
|
||||||
|
_edge_pool.clear();
|
||||||
|
_edge_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// edges =========================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
vertex_pool_t _vertex_pool;
|
||||||
|
edge_pool_t _edge_pool;
|
||||||
|
edge_map_t _edge_map;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
size_t _insert(ArgsT&&...args) {
|
||||||
|
return _vertex_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_GRAPH_H
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \file list.h
|
/// \file list.h
|
||||||
/// \brief List of elements
|
/// \brief A header containing the definition for a linked list of values
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \details
|
/// \details
|
||||||
@@ -43,172 +43,392 @@ namespace fennec
|
|||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// \brief wrapper for lists of elements
|
/// \brief Data Structure defining lists of elements
|
||||||
/// \details
|
/// \details
|
||||||
|
/// This data-structure behaves like a linked list, but does not use pointers. Instead, it is in-array. This creates the
|
||||||
|
/// following properties:
|
||||||
|
///
|
||||||
/// | Property | Value |
|
/// | Property | Value |
|
||||||
/// |-----------|--------------|
|
/// |:----------:|:----------:|
|
||||||
/// | stable | \emoji anger |
|
/// | stable | ⛔ |
|
||||||
/// | access | \f$O(1)\f$ |
|
/// | dynamic | ✅ |
|
||||||
/// | insertion | \f$O(1)\f$ |
|
/// | homogenous | ✅ |
|
||||||
/// | deletion | \f$O(1)\f$ |
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
/// | space | \f$O(N)\f$ |
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(N)\f$ |
|
||||||
|
/// | insertion | \f$O(N)\f$ |
|
||||||
|
/// | deletion | \f$O(N)\f$ |
|
||||||
///
|
///
|
||||||
/// \tparam TypeT value type
|
/// \tparam TypeT value type
|
||||||
template<class TypeT, class Alloc = allocator<TypeT>>
|
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||||
struct list {
|
struct list {
|
||||||
public:
|
|
||||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
|
||||||
using value_t = TypeT;
|
|
||||||
static constexpr size_t npos = -1;
|
|
||||||
|
|
||||||
class iterator;
|
// Definitions =========================================================================================================
|
||||||
class const_iterator;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct node;
|
struct node;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using elem_t = node;
|
/// \brief Alias for the allocator type, rebound to list nodes
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<node>;
|
||||||
|
|
||||||
|
using value_t = TypeT; ///< Alias for the value type
|
||||||
|
|
||||||
|
static constexpr size_t npos = -1; ///< Constant representing a non-existant position
|
||||||
|
|
||||||
|
class iterator; ///< Iterator type for forward iteration over the list
|
||||||
|
class const_iterator; ///< Iterator type for forward iteration over a constant list
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty list.
|
||||||
constexpr list()
|
constexpr list()
|
||||||
: _table(), _freed(), _root(npos), _last(npos), _size(0) {
|
: _table(), _freed(), _root(npos), _last(npos), _size(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ~list() = default;
|
///
|
||||||
|
/// \brief Copy Constructor, copies all elements in `l` with optimized layout
|
||||||
|
/// \param l The list to copy
|
||||||
|
constexpr list(const list& l)
|
||||||
|
: list() {
|
||||||
|
for (const value_t& it : l) {
|
||||||
|
this->push_back(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr bool size() const { return _size; }
|
|
||||||
constexpr bool capacity() const { return _table.capacity(); }
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership of the list
|
||||||
|
/// \param l The list to move
|
||||||
|
constexpr list(list&& l) noexcept
|
||||||
|
: _table(fennec::move(l._table))
|
||||||
|
, _freed(fennec::move(l._freed))
|
||||||
|
, _root(l._root)
|
||||||
|
, _last(l._last)
|
||||||
|
, _size(l._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, destructs all elements then releases the allocation.
|
||||||
|
constexpr ~list() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_table[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param l the list to copy
|
||||||
|
/// \returns `this` after having copied all elements of `l`
|
||||||
|
constexpr list& operator=(const list& l) {
|
||||||
|
this->clear();
|
||||||
|
for (const value_t& it : l) {
|
||||||
|
this->push_back(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param l the list to copy
|
||||||
|
/// \returns `this` after having taken ownership over the contents of `l`
|
||||||
|
constexpr list& operator=(list&& l) noexcept {
|
||||||
|
this->clear();
|
||||||
|
_table = fennec::move(l._table);
|
||||||
|
_freed = fennec::move(l._freed);
|
||||||
|
_root = l._root; _last = l._last;
|
||||||
|
_size = l._size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the list in elements.
|
||||||
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the list in elements.
|
||||||
|
constexpr size_t capacity() const { return _table.capacity(); }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the list is empty, `false` otherwise.
|
||||||
constexpr bool empty() const { return _root == npos; }
|
constexpr bool empty() const { return _root == npos; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i Index to access
|
||||||
|
/// \returns A reference to the element at `i`
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
constexpr value_t& operator[](int i) {
|
constexpr value_t& operator[](int i) {
|
||||||
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||||
size_t n = _walk(i);
|
size_t n = _walk(i);
|
||||||
assertd(n != npos, "Index out of Bounds");
|
assertd(n != npos, "Index out of Bounds");
|
||||||
return *_table[n].data;
|
return *_table[n].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Array Access Operator
|
||||||
|
/// \param i Index to access
|
||||||
|
/// \returns A const-qualified reference to the element at `i`
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
constexpr const value_t& operator[](int i) const {
|
constexpr const value_t& operator[](int i) const {
|
||||||
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||||
size_t n = _walk(i);
|
size_t n = _walk(i);
|
||||||
assertd(n != npos, "Index out of Bounds");
|
assertd(n != npos, "Index out of Bounds");
|
||||||
return *_table[n].data;
|
return *_table[n].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(const iterator& it, value_t&& x) {
|
///
|
||||||
if (size() == capacity()) {
|
/// \brief Access Front Element
|
||||||
_expand();
|
/// \returns A reference to the first element in the list
|
||||||
|
constexpr value_t& front() {
|
||||||
|
return *_table[_root].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t n = it._n;
|
///
|
||||||
size_t p = _next_free();
|
/// \brief Const Access Front Element
|
||||||
fennec::construct(&_table[p].data, fennec::forward<value_t>(x));
|
/// \returns A const-qualified reference to the first element in the list
|
||||||
if (n == npos) {
|
constexpr const value_t& front() const {
|
||||||
if (empty()) {
|
return *_table[_root].value;
|
||||||
_root = p;
|
|
||||||
_table[p].next = npos;
|
|
||||||
_table[p].prev = npos;
|
|
||||||
} else {
|
|
||||||
_table[p].prev = n;
|
|
||||||
_table[p].next = npos;
|
|
||||||
_last = n;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_table[p].next = n;
|
|
||||||
_table[p].prev = _prev(n);
|
|
||||||
_table[n].prev = p;
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(size_t i, value_t&& x) {
|
|
||||||
assert(i <= size(), "Index out of Bounds");
|
|
||||||
if (size() == capacity()) {
|
|
||||||
_expand();
|
|
||||||
}
|
|
||||||
size_t n = _walk(min(i, size_t(size() - 1)));
|
|
||||||
size_t p = _next_free();
|
|
||||||
if (n == npos) {
|
|
||||||
_root = p;
|
|
||||||
_table[p].data = fennec::forward<value_t>(x);
|
|
||||||
_table[p].next = npos;
|
|
||||||
_table[p].prev = npos;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_table[p].data = fennec::forward<value_t>(x);
|
|
||||||
if (i == size()) {
|
|
||||||
_table[p].prev = n;
|
|
||||||
_last = n;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_table[p].next = n;
|
|
||||||
_table[p].prev = _prev(n);
|
|
||||||
_table[n].prev = p;
|
|
||||||
}
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(size_t i, const value_t& x) {
|
|
||||||
this->insert(i, elem_t(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_front(const value_t& x) {
|
|
||||||
this->insert(0, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_front(value_t&& x) {
|
|
||||||
this->insert(0, fennec::forward<value_t>(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back(const value_t& x) {
|
|
||||||
this->insert(_size, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back(value_t&& x) {
|
|
||||||
this->insert(_size, fennec::forward<value_t>(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
void erase(size_t i) {
|
|
||||||
size_t j = _walk(i);
|
|
||||||
if (j == npos) return;
|
|
||||||
if (not _table[j].data) return;
|
|
||||||
|
|
||||||
// Get the prev and next indices
|
|
||||||
size_t p = _prev(j);
|
|
||||||
size_t n = _next(j);
|
|
||||||
|
|
||||||
// clear the node
|
|
||||||
_table[j].data = nullopt;
|
|
||||||
_table[j].prev = npos;
|
|
||||||
_table[j].next = npos;
|
|
||||||
|
|
||||||
// Fix prev and next nodes
|
|
||||||
if (p != npos) _table[p].next = n;
|
|
||||||
else _root = n;
|
|
||||||
if (n != npos) _table[n].prev = p;
|
|
||||||
else _last = p;
|
|
||||||
|
|
||||||
// Mark node as freed
|
|
||||||
_freed.push_back(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_front() {
|
|
||||||
erase(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_back() {
|
|
||||||
erase(_size - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Access Back Element
|
||||||
|
/// \returns A reference to the last element in the list
|
||||||
constexpr value_t& back() {
|
constexpr value_t& back() {
|
||||||
return this->operator[](size() - 1);
|
return *_table[_last].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Access Back Element
|
||||||
|
/// \returns A const-qualified reference to the last element in the list
|
||||||
constexpr const value_t& back() const {
|
constexpr const value_t& back() const {
|
||||||
return this->operator[](size() - 1);
|
return *_table[_last].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param it Location to insert at
|
||||||
|
/// \param x value to copy
|
||||||
|
///
|
||||||
|
/// \details \f$O(1)\f$
|
||||||
|
constexpr size_t insert(const iterator& it, const value_t& x) {
|
||||||
|
return this->_insert(it._n, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param it Location to insert at
|
||||||
|
/// \param x value to move
|
||||||
|
///
|
||||||
|
/// \details \f$O(1)\f$
|
||||||
|
constexpr size_t insert(const iterator& it, value_t&& x) {
|
||||||
|
return this->_insert(it._n, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param x value to copy
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr size_t insert(size_t i, const value_t& x) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param x value to move
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
constexpr size_t insert(size_t i, value_t&& x) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param i Index to insert at
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
///
|
||||||
|
/// \details \f$O(N)\f$
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(size_t i, ArgsT&&...args) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
|
||||||
|
size_t n = _walk(min(i, size_t(size() - 1)));
|
||||||
|
return this->_insert(n, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Copy
|
||||||
|
/// \param x Value to copy
|
||||||
|
constexpr size_t push_front(const value_t& x) {
|
||||||
|
return this->_insert(_root, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Front Move
|
||||||
|
/// \param x Value to move
|
||||||
|
constexpr size_t push_front(value_t&& x) {
|
||||||
|
return this->_insert(_root, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Front
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace_front(ArgsT&&...args) {
|
||||||
|
return this->_insert(_root, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Copy
|
||||||
|
/// \param x Value to copy
|
||||||
|
constexpr size_t push_back(const value_t& x) {
|
||||||
|
return this->_insert(npos, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Push Back Move
|
||||||
|
/// \param x Value to move
|
||||||
|
constexpr size_t push_back(value_t&& x) {
|
||||||
|
return this->_insert(npos, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Back
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace_back(ArgsT&&...args) {
|
||||||
|
return this->_insert(npos, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase Element
|
||||||
|
/// \param i Index to erase
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
assert(i < size(), "Index out of Bounds!");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
_erase(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase Element
|
||||||
|
/// \param it Location to Erase
|
||||||
|
constexpr void erase(const iterator& it) {
|
||||||
|
_erase(it._n);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pop Front, erases first element
|
||||||
|
constexpr void pop_front() {
|
||||||
|
_erase(_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pop Back, erases first element
|
||||||
|
constexpr void pop_back() {
|
||||||
|
_erase(_last);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the list, destructing all elements in order
|
||||||
|
constexpr void clear() {
|
||||||
|
size_t i = _root;
|
||||||
|
while (i != npos) {
|
||||||
|
fennec::destruct(_table[i]);
|
||||||
|
i = this->_next(i);
|
||||||
|
}
|
||||||
|
_table.deallocate(_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
// ITERATOR ============================================================================================================
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns An iterator for the first element in the list
|
||||||
|
constexpr iterator begin() {
|
||||||
|
return iterator(this, _root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns An iterator for the end of the list
|
||||||
|
constexpr iterator end() {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `begin()`
|
||||||
|
/// \returns A const iterator for the first element in the list
|
||||||
|
constexpr const_iterator begin() const {
|
||||||
|
return const_iterator(this, _root);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const C++ Iterator Specification `end()`
|
||||||
|
/// \returns A const iterator for the end of the list
|
||||||
|
constexpr const_iterator end() const {
|
||||||
|
return const_iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Class
|
||||||
class iterator {
|
class iterator {
|
||||||
public:
|
public:
|
||||||
~iterator() {
|
~iterator() {
|
||||||
@@ -231,11 +451,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr value_t& operator*() {
|
constexpr value_t& operator*() {
|
||||||
return *(_list->_table[_n].data);
|
return *(_list->_table[_n].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr value_t* operator->() {
|
constexpr value_t* operator->() {
|
||||||
return &*(_list->_table[_n].data);
|
return &*(_list->_table[_n].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const iterator& it) {
|
constexpr bool operator==(const iterator& it) {
|
||||||
@@ -257,6 +477,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Class for Const Access
|
||||||
class const_iterator {
|
class const_iterator {
|
||||||
public:
|
public:
|
||||||
~const_iterator() {
|
~const_iterator() {
|
||||||
@@ -279,11 +501,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const value_t& operator*() {
|
constexpr const value_t& operator*() {
|
||||||
return *(_list->_table[_n].data);
|
return *(_list->_table[_n].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const value_t* operator->() {
|
constexpr const value_t* operator->() {
|
||||||
return &*(_list->_table[_n].data);
|
return &*(_list->_table[_n].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const const_iterator& it) {
|
constexpr bool operator==(const const_iterator& it) {
|
||||||
@@ -305,51 +527,35 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr iterator begin() {
|
|
||||||
return iterator(this, _root);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr iterator end() {
|
|
||||||
return iterator(this, npos);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const_iterator begin() const {
|
|
||||||
return const_iterator(this, _root);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const_iterator end() const {
|
|
||||||
return const_iterator(this, npos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
allocation<elem_t, alloc_t> _table;
|
allocation<node, alloc_t> _table;
|
||||||
dynarray<size_t> _freed;
|
dynarray<size_t> _freed;
|
||||||
size_t _root, _last, _size;
|
size_t _root, _last, _size;
|
||||||
|
|
||||||
friend class iterator;
|
friend class iterator;
|
||||||
|
|
||||||
constexpr void _expand() {
|
constexpr void _expand() {
|
||||||
_table.reallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
|
_table.creallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node {
|
struct node {
|
||||||
optional<value_t> data;
|
optional<value_t> value;
|
||||||
size_t prev, next;
|
size_t prev, next;
|
||||||
|
|
||||||
constexpr node()
|
constexpr node()
|
||||||
: data()
|
: value()
|
||||||
, prev(npos)
|
, prev(npos)
|
||||||
, next(npos) {
|
, next(npos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr node(size_t p, size_t n)
|
constexpr node(size_t p, size_t n)
|
||||||
: data()
|
: value()
|
||||||
, prev(p)
|
, prev(p)
|
||||||
, next(n) {
|
, next(n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr node(size_t p, size_t n, value_t&& val)
|
constexpr node(size_t p, size_t n, value_t&& val)
|
||||||
: data(fennec::forward<value_t>(val))
|
: value(fennec::forward<value_t>(val))
|
||||||
, prev(p)
|
, prev(p)
|
||||||
, next(n) {
|
, next(n) {
|
||||||
}
|
}
|
||||||
@@ -357,21 +563,21 @@ private:
|
|||||||
constexpr ~node() = default;
|
constexpr ~node() = default;
|
||||||
|
|
||||||
constexpr void clear() {
|
constexpr void clear() {
|
||||||
data = nullopt;
|
value = nullopt;
|
||||||
prev = npos;
|
prev = npos;
|
||||||
next = npos;
|
next = npos;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t _next(size_t n) const {
|
constexpr size_t _next(size_t n) const {
|
||||||
return _table[n].next;
|
return _table[n].next;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _prev(size_t n) const {
|
constexpr size_t _prev(size_t n) const {
|
||||||
return _table[n].prev;
|
return _table[n].prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _walk(size_t i) const {
|
constexpr size_t _walk(size_t i) const {
|
||||||
size_t n = _root;
|
size_t n = _root;
|
||||||
if (n == npos) return n;
|
if (n == npos) return n;
|
||||||
while (i > 0 && n != npos) {
|
while (i > 0 && n != npos) {
|
||||||
@@ -380,15 +586,68 @@ private:
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _next_free() {
|
constexpr size_t _next_free() {
|
||||||
if (not _freed.empty()) {
|
if (not _freed.empty()) {
|
||||||
size_t n = _freed.back();
|
size_t n = _freed.back();
|
||||||
_freed.pop_back();
|
_freed.pop_back();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
_table[_size];
|
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t _insert(size_t n, ArgsT&&...args) {
|
||||||
|
if (size() == capacity()) {
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = _next_free();
|
||||||
|
++_size;
|
||||||
|
fennec::construct(&_table[i].value, fennec::forward<ArgsT>(args)...);
|
||||||
|
|
||||||
|
if (_root == npos) {
|
||||||
|
_table[i].prev = npos;
|
||||||
|
_table[i].next = npos;
|
||||||
|
_root = _last = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == npos) {
|
||||||
|
_table[_last].next = i;
|
||||||
|
_table[i].prev = _last;
|
||||||
|
_table[i].next = npos;
|
||||||
|
_last = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
_table[i].prev = _prev(n);
|
||||||
|
_table[i].next = n;
|
||||||
|
_table[n].prev = i;
|
||||||
|
_root = n == _root ? i : _root;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void _erase(size_t n) {
|
||||||
|
if (n == npos) return;
|
||||||
|
|
||||||
|
fennec::destruct(&_table[n].value);
|
||||||
|
_freed.push_back(n);
|
||||||
|
--_size;
|
||||||
|
|
||||||
|
size_t prev = _prev(n);
|
||||||
|
size_t next = _next(n);
|
||||||
|
|
||||||
|
if (prev != npos) {
|
||||||
|
_table[prev].next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next != npos) {
|
||||||
|
_table[next].prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
_root = (n == _root) ? next : _root;
|
||||||
|
_last = (n == _last) ? prev : _last;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,18 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file map.h
|
||||||
|
/// \brief A header containing the definition for a mapping of keys to values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_MAP_H
|
#ifndef FENNEC_CONTAINERS_MAP_H
|
||||||
#define FENNEC_CONTAINERS_MAP_H
|
#define FENNEC_CONTAINERS_MAP_H
|
||||||
|
|
||||||
@@ -25,14 +37,12 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO: Document
|
|
||||||
|
|
||||||
/* Ramblings
|
/* Ramblings
|
||||||
*
|
*
|
||||||
* Definitions:
|
* Definitions:
|
||||||
* user = Programmer using this data structure
|
* user = Programmer using this data structure
|
||||||
*
|
*
|
||||||
* The STL unordered-map is very contrived. Some of its functionality encourages younger programmers to use
|
* The STL maps are very contrived. Some of its functionality encourages younger programmers to use
|
||||||
* the exception model. Ideally, I would like this structure to never throw an error with typical use.
|
* the exception model. Ideally, I would like this structure to never throw an error with typical use.
|
||||||
*
|
*
|
||||||
* The array access operator is, in my opinion, poorly implemented. I do not think that this operator should handle
|
* The array access operator is, in my opinion, poorly implemented. I do not think that this operator should handle
|
||||||
@@ -40,19 +50,46 @@ namespace fennec
|
|||||||
* data structure modifies contents by inherently calling operator[].
|
* data structure modifies contents by inherently calling operator[].
|
||||||
*
|
*
|
||||||
* Currently, I am considering implementing this as the following:
|
* Currently, I am considering implementing this as the following:
|
||||||
* Access will be handled only via operator[]. Return value will be an optional which forces user validation.
|
* Access will be handled only via operator[]. Return value will be a pointer which forces user validation.
|
||||||
* Insertions will be handled only via an insert/emplace function.
|
* Insertions will be handled only via an insert/emplace function.
|
||||||
* Deletions will be handled only via an erase function.
|
* Deletions will be handled only via an erase function.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Structure defining a mapping of `key` \f$KeyT\f$ to `value` \f$ValueT\f$
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ✅ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam KeyT The Key Type
|
||||||
|
/// \tparam ValueT The Value Type
|
||||||
|
/// \tparam Hash The Hash to Use
|
||||||
|
/// \tparam Alloc The Allocator to Use
|
||||||
template<typename KeyT, typename ValueT, typename Hash = hash<KeyT>, typename Alloc = allocator<pair<KeyT, ValueT>>>
|
template<typename KeyT, typename ValueT, typename Hash = hash<KeyT>, typename Alloc = allocator<pair<KeyT, ValueT>>>
|
||||||
struct map {
|
struct map {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
public:
|
public:
|
||||||
using key_t = KeyT;
|
struct key_hash; ///< Hash for node keys
|
||||||
using value_t = ValueT;
|
struct key_equals; ///< Comparison for node keys
|
||||||
using elem_t = pair<KeyT, ValueT>;
|
using key_t = KeyT; ///< The key type
|
||||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>;
|
using value_t = ValueT; ///< The value type
|
||||||
using hash_t = Hash;
|
using elem_t = pair<KeyT, ValueT>; ///< then node type
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>; ///< Rebinds the allocator type to nodes
|
||||||
|
using hash_t = Hash; ///< The hash type
|
||||||
|
using set_t = set<elem_t, key_hash, key_equals, alloc_t>; ///< The underlying set
|
||||||
|
using iterator = set_t::iterator; ///< Iterator type
|
||||||
|
|
||||||
// We only want to hash the key
|
// We only want to hash the key
|
||||||
struct key_hash : hash_t {
|
struct key_hash : hash_t {
|
||||||
@@ -62,114 +99,191 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We only want to compare the keys
|
// We only want to compare the keys
|
||||||
struct node_equals : equality<KeyT> {
|
struct key_equals : equality<KeyT> {
|
||||||
constexpr bool operator()(const elem_t& a, const elem_t& b) const {
|
constexpr bool operator()(const elem_t& a, const elem_t& b) const {
|
||||||
return equality<KeyT>::operator()(a.first, b.first);
|
return equality<KeyT>::operator()(a.first, b.first);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty map
|
||||||
constexpr map() = default;
|
constexpr map() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, Destructs all elements and releases the allocation
|
||||||
constexpr ~map() = default;
|
constexpr ~map() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the set
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no elements in the set, `false` otherwise
|
||||||
|
constexpr size_t empty() const {
|
||||||
|
return _set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _set.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key Access Operator
|
||||||
|
/// \param key Key value to access
|
||||||
|
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
constexpr value_t* operator[](const KeyT& key) {
|
constexpr value_t* operator[](const KeyT& key) {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
auto it = _set.at(this->_find(key));
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
return it ? &it->second : nullptr;
|
||||||
pair<KeyT, ValueT> val;
|
|
||||||
|
|
||||||
~U() {
|
|
||||||
fennec::destruct(&root);
|
|
||||||
}
|
|
||||||
} trick = { .root = { key, 0 } };
|
|
||||||
auto it = _set.find(trick.val);
|
|
||||||
if (it == _set.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &_set.at(it)->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key Const Access Operator
|
||||||
|
/// \param key Key value to access
|
||||||
|
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
constexpr const value_t* operator[](const KeyT& key) const {
|
constexpr const value_t* operator[](const KeyT& key) const {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
auto it = _set.at(this->_find(key));
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
return it ? &it->second : nullptr;
|
||||||
pair<KeyT, ValueT> val;
|
|
||||||
|
|
||||||
~U() {
|
|
||||||
fennec::destruct(&root);
|
|
||||||
}
|
|
||||||
} trick = { .root = { key, 0 } }; // Only initialize root
|
|
||||||
auto it = _set.find(trick.val);
|
|
||||||
if (it == _set.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &_set.at(it)->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Key Access Operator
|
||||||
|
/// \tparam ArgT Argument Type
|
||||||
|
/// \param arg Argument to construct the key with
|
||||||
|
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr value_t* operator[](ArgsT&&...args) {
|
constexpr value_t* operator[](ArgsT&&...args) {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
return it ? &it->second : nullptr;
|
||||||
pair<KeyT, ValueT> val;
|
|
||||||
|
|
||||||
~U() {
|
|
||||||
fennec::destruct(&root);
|
|
||||||
}
|
|
||||||
} trick = { .root = { key_t(fennec::forward<ArgsT>(args)...), 0 } }; // Only initialize root
|
|
||||||
auto it = _set.find(trick.val);
|
|
||||||
if (it == _set.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &_set.at(it)->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Key Const Access Operator
|
||||||
|
/// \tparam ArgsT Argument Type
|
||||||
|
/// \param args Argument to construct the key with
|
||||||
|
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present.
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr const value_t* operator[](ArgsT&&...args) const {
|
constexpr const value_t* operator[](ArgsT&&...args) const {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
return it ? &it->second : nullptr;
|
||||||
pair<KeyT, ValueT> val;
|
|
||||||
|
|
||||||
~U() {
|
|
||||||
fennec::destruct(&root);
|
|
||||||
}
|
|
||||||
} trick = { .root = { key_t(fennec::forward<ArgsT>(args)...), 0 } }; // Only initialize root
|
|
||||||
auto it = _set.find(trick.val);
|
|
||||||
if (it == _set.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &_set.at(it)->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param pair a pair containing the key and its value
|
||||||
constexpr void insert(elem_t&& pair) {
|
constexpr void insert(elem_t&& pair) {
|
||||||
auto it = _set.find(pair);
|
this->_insert(fennec::forward<elem_t>(pair));
|
||||||
if (it == _set.end()) {
|
|
||||||
_set.at(it)->second = fennec::move(pair.second);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_set.insert(fennec::forward<elem_t>(pair));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param args Arguments for constructing the key-value pair
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace(const KeyT& key, ArgsT&&...args) {
|
||||||
|
this->_insert(key, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Key-Value Insertion
|
||||||
|
/// \param args Arguments for constructing the key-value pair
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void emplace(ArgsT&&...args) {
|
constexpr void emplace(ArgsT&&...args) {
|
||||||
_set.insert(elem_t(args...));
|
this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a key
|
||||||
|
/// \param key key to erase
|
||||||
constexpr void erase(KeyT&& key) {
|
constexpr void erase(KeyT&& key) {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
_set.erase(this->_find(fennec::forward<KeyT>(key)));
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
|
||||||
pair<KeyT, ValueT> val;
|
|
||||||
|
|
||||||
~U() {
|
|
||||||
fennec::destruct(&root);
|
|
||||||
}
|
|
||||||
} trick = { .root = { fennec::forward<KeyT>(key), 0 } };
|
|
||||||
_set.erase(trick.val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a key
|
||||||
|
/// \param key key to erase
|
||||||
constexpr void erase(const KeyT& key) {
|
constexpr void erase(const KeyT& key) {
|
||||||
KeyT val = key;
|
_set.erase(this->_find(key));
|
||||||
erase(fennec::move(val));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Argument Erase
|
||||||
|
/// \tparam ArgsT Argument Types
|
||||||
|
/// \param args Arguments to construct a key to erase
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void erase(ArgsT&&...args) {
|
constexpr void erase(ArgsT&&...args) {
|
||||||
|
_set.erase(this->_find(fennec::forward<ArgsT>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Clears the map destructing all elements
|
||||||
|
void clear() {
|
||||||
|
_set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns an iterator at the start of the map
|
||||||
|
constexpr iterator begin() {
|
||||||
|
return _set.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns an iterator at the end of the map
|
||||||
|
constexpr iterator end() {
|
||||||
|
return _set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
set_t _set;
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
set_t::iterator _find(ArgsT&&...args) const {
|
||||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||||
pair<KeyT, ValueT> val;
|
pair<KeyT, ValueT> val;
|
||||||
@@ -178,12 +292,19 @@ public:
|
|||||||
fennec::destruct(&root);
|
fennec::destruct(&root);
|
||||||
}
|
}
|
||||||
} trick = { .root = { KeyT(fennec::forward<ArgsT>(args)...), 0 } };
|
} trick = { .root = { KeyT(fennec::forward<ArgsT>(args)...), 0 } };
|
||||||
_set.erase(trick.val);
|
return _set.find(trick.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
private:
|
constexpr void _insert(ArgsT&&...args) {
|
||||||
set<elem_t, key_hash, node_equals, alloc_t> _set;
|
elem_t elem(fennec::forward<ArgsT>(args)...);
|
||||||
|
auto it = this->_find(elem.first);
|
||||||
|
if (it != _set.end()) {
|
||||||
|
_set.at(it)->second = fennec::move(elem.second);
|
||||||
|
} else {
|
||||||
|
_set.insert(fennec::move(elem));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
586
include/fennec/containers/multiset.h
Normal file
586
include/fennec/containers/multiset.h
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file multiset.h
|
||||||
|
/// \brief A header containing the definition for a set of repeating values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_MULTISET_H
|
||||||
|
#define FENNEC_CONTAINERS_MULTISET_H
|
||||||
|
|
||||||
|
// https://programming.guide/robin-hood-hashing.html
|
||||||
|
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/multiset.h>
|
||||||
|
#include <fennec/lang/compare.h>
|
||||||
|
#include <fennec/math/ext/primes.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
#include <fennec/lang/hashing.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \brief A Data Structure that defines a set of elements that may repeat
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT The type to contain
|
||||||
|
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
|
||||||
|
struct multiset {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||||
|
using hash_t = Hash;
|
||||||
|
using equal_t = Equals;
|
||||||
|
using elem_t = TypeT;
|
||||||
|
|
||||||
|
class iterator;
|
||||||
|
class value_iterator;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
static constexpr double default_load = 0.8;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
optional<elem_t> value;
|
||||||
|
int psl;
|
||||||
|
|
||||||
|
constexpr node() = default;
|
||||||
|
constexpr ~node() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty multiset
|
||||||
|
constexpr multiset()
|
||||||
|
: _alloc()
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Constructor, initializes empty multiset with a hash
|
||||||
|
constexpr multiset(const hash_t& hash)
|
||||||
|
: _alloc()
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Constructor, initializes empty multiset with a hash
|
||||||
|
constexpr multiset(hash_t&& hash) noexcept
|
||||||
|
: _alloc()
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Copy Constructor, initializes empty multiset with an allocator
|
||||||
|
constexpr multiset(const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Alloc Move Constructor, initializes empty multiset with an allocator
|
||||||
|
constexpr multiset(alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash()
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Alloc Copy Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(const hash_t& hash, const alloc_t& alloc)
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Alloc Move Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(const hash_t& hash, alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Alloc Move Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(hash_t&& hash, alloc_t&& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Move Alloc Copy Constructor, initializes empty multiset with a hash and allocator
|
||||||
|
constexpr multiset(hash_t&& hash, const alloc_t& alloc) noexcept
|
||||||
|
: _alloc(alloc)
|
||||||
|
, _hash(hash)
|
||||||
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
|
, _load(default_load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Copy Constructor
|
||||||
|
/// \param multiset Set to copy
|
||||||
|
constexpr multiset(const multiset& multiset)
|
||||||
|
: _alloc( multiset._alloc)
|
||||||
|
, _hash( multiset._hash)
|
||||||
|
, _size( multiset._size)
|
||||||
|
, _sumpsl( multiset._sumpsl)
|
||||||
|
, _load( multiset._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Move Constructor
|
||||||
|
/// \param multiset Set to move
|
||||||
|
constexpr multiset(multiset&& multiset) noexcept
|
||||||
|
: _alloc(fennec::move( multiset._alloc))
|
||||||
|
, _hash(fennec::move( multiset._hash))
|
||||||
|
, _size(fennec::move( multiset._size))
|
||||||
|
, _sumpsl( multiset._sumpsl)
|
||||||
|
, _load( multiset._load) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, destructs all elements and releases the allocation
|
||||||
|
constexpr ~multiset() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Size of the multiset in elements
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the set is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Capacity of the multiset in elements
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _alloc.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find an Element
|
||||||
|
/// \param val Value to find
|
||||||
|
/// \returns An iterator at the location of the first instance of `value`
|
||||||
|
constexpr iterator find(const elem_t& val, size_t c = 0) const {
|
||||||
|
if (capacity() == 0) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
size_t s = _hash(val) % capacity(); // Initial search index
|
||||||
|
int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl
|
||||||
|
size_t i = (s + psl) % capacity(); // Median search
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
// Check the first element;
|
||||||
|
if (_alloc[i].psl >= psl && _alloc[i].value) {
|
||||||
|
if (*_alloc[i].value == val) {
|
||||||
|
return iterator(this, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop while there is a value and its psl is greater than our probe
|
||||||
|
while (c > 0) {
|
||||||
|
++n;
|
||||||
|
size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow
|
||||||
|
size_t i1 = (i + n) % capacity();
|
||||||
|
int p0 = psl - n, p1 = psl + n;
|
||||||
|
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
|
||||||
|
|
||||||
|
if (c0 && _alloc[i0].value) {
|
||||||
|
if (*_alloc[i0].value == val) {
|
||||||
|
if (c-- == 0) {
|
||||||
|
return iterator(this, i0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 && _alloc[i1].value) {
|
||||||
|
if (*_alloc[i1].value == val) {
|
||||||
|
if (c-- == 0) {
|
||||||
|
return iterator(this, i1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not(c0 or c1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Check if a multiset contains a value
|
||||||
|
/// \param val Value to check
|
||||||
|
/// \returns `true` if `val` can be found, `false` otherwise
|
||||||
|
constexpr bool contains(const elem_t& val) const {
|
||||||
|
return this->find(val) != end();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A pointer to the element, `nullptr` if not found.
|
||||||
|
/// The value should not be changed in a manner that will change the hash of the element.
|
||||||
|
constexpr elem_t* at(const iterator& it) {
|
||||||
|
if (it == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Const Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A const-qualified pointer to the element, `nullptr` if not found.
|
||||||
|
constexpr const elem_t* at(const iterator& it) const {
|
||||||
|
if (not _alloc[it._i].value) return nullptr;
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr void insert(elem_t&& val) {
|
||||||
|
this->_insert(fennec::forward<elem_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr void insert(const elem_t& val) {
|
||||||
|
this->_insert(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace(ArgsT&&...args) {
|
||||||
|
this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param it Location to erase
|
||||||
|
constexpr void erase(iterator it) {
|
||||||
|
size_t i = it._i;
|
||||||
|
if (i >= capacity()) {
|
||||||
|
return;
|
||||||
|
} // These are separated due to compilers being inconsistent
|
||||||
|
if (not _alloc[i].value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
_sumpsl -= _alloc[i].psl;
|
||||||
|
--_size;
|
||||||
|
size_t p = i;
|
||||||
|
while (_alloc[i = (i + 1) % capacity()].value) {
|
||||||
|
if (_alloc[i].psl == 0) break;
|
||||||
|
|
||||||
|
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
|
||||||
|
--_alloc[p].psl, --_sumpsl;
|
||||||
|
p = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param val Value to erase
|
||||||
|
constexpr void erase(const elem_t& val) {
|
||||||
|
this->erase(this->find(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `begin()`
|
||||||
|
/// \returns An iterator for all elements of the set in no particular order
|
||||||
|
constexpr iterator begin() const {
|
||||||
|
iterator it(this, 0);
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C++ Iterator Specification `end()`
|
||||||
|
/// \returns An iterator representing the end of the set
|
||||||
|
constexpr iterator end() const {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Class for Iterating the Set
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
constexpr ~iterator() {
|
||||||
|
_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr iterator& operator++() {
|
||||||
|
while (++_i < _set->capacity()) {
|
||||||
|
if (_set->_alloc[_i].value) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_i = npos;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator operator++(int) {
|
||||||
|
iterator prev = *this;
|
||||||
|
this->operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t& operator*() const {
|
||||||
|
return *_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
|
return _set == it._set and _i == it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
|
return _set != it._set or _i != it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const multiset* _set;
|
||||||
|
size_t _i;
|
||||||
|
friend multiset;
|
||||||
|
|
||||||
|
constexpr iterator(const multiset* multiset, size_t i)
|
||||||
|
: _set(multiset)
|
||||||
|
, _i(i) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class value_iterator {
|
||||||
|
public:
|
||||||
|
constexpr ~value_iterator() {
|
||||||
|
_set = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix operator
|
||||||
|
constexpr value_iterator& operator++() {
|
||||||
|
while (_psl <= _set->_alloc[_i].psl) {
|
||||||
|
if (not _set->_alloc[_i].value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_i = npos;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr value_iterator operator++(int) {
|
||||||
|
value_iterator prev = *this;
|
||||||
|
this->operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t& operator*() const {
|
||||||
|
return *_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
|
return _set == it._set and _i == it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
|
return _set != it._set or _i != it._i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const multiset* _set;
|
||||||
|
size_t _i;
|
||||||
|
int _psl;
|
||||||
|
elem_t _value;
|
||||||
|
friend multiset;
|
||||||
|
|
||||||
|
constexpr value_iterator(const multiset* multiset, size_t i, int psl, const elem_t& value)
|
||||||
|
: _set(multiset)
|
||||||
|
, _i(i)
|
||||||
|
, _value(value) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// PRIVATE =============================================================================================================
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr void _expand() {
|
||||||
|
multiset cpy; // Create a new multiset
|
||||||
|
cpy._alloc.callocate(
|
||||||
|
fennec::next_prime2(_alloc.capacity())
|
||||||
|
);
|
||||||
|
|
||||||
|
// rehash
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
if (_alloc[i].value) {
|
||||||
|
cpy.insert(fennec::move(*_alloc[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
fennec::swap(_alloc, cpy._alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void _insert(ArgsT&&...args) {
|
||||||
|
if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
elem_t value(fennec::forward<ArgsT>(args)...);
|
||||||
|
size_t i = _hash(value) % capacity(); // Initial search index
|
||||||
|
int psl = 0;
|
||||||
|
while (_alloc[i].value) { // Search for empty cell
|
||||||
|
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
|
_sumpsl += psl - _alloc[i].psl;
|
||||||
|
fennec::swap(_alloc[i].psl, psl);
|
||||||
|
fennec::swap(*_alloc[i].value, value);
|
||||||
|
}
|
||||||
|
i = (i + 1) % capacity(); ++psl;
|
||||||
|
}
|
||||||
|
_alloc[i].value = fennec::move(value);
|
||||||
|
_sumpsl += (_alloc[i].psl = psl);
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocation<node, alloc_t> _alloc;
|
||||||
|
hash_t _hash;
|
||||||
|
equal_t _equal;
|
||||||
|
size_t _size;
|
||||||
|
size_t _sumpsl;
|
||||||
|
float _load;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_SET_H
|
||||||
209
include/fennec/containers/object_pool.h
Normal file
209
include/fennec/containers/object_pool.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file object_pool.h
|
||||||
|
/// \brief A header containing the definition for a pool of objects associated by ids
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
|
#define FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Struct which holds a pool of objects associated with ids
|
||||||
|
/// \tparam TypeT The value type
|
||||||
|
/// \tparam AllocT The allocator type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct object_pool {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
public:
|
||||||
|
using value_t = TypeT;
|
||||||
|
using elem_t = optional<TypeT>;
|
||||||
|
using table_t = dynarray<elem_t, AllocT>;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an empty object pool
|
||||||
|
constexpr object_pool()
|
||||||
|
: _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Destructor, destructs objects then releases the allocation.
|
||||||
|
constexpr ~object_pool() = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of active objects in the pool
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _table.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no objects in the pool, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Retrieve the next id `i` that would be assigned to an object `o` were it added to the object pool
|
||||||
|
///
|
||||||
|
/// \details This can be useful if there are constant members that need to be assigned at construction.
|
||||||
|
/// \returns The id of the next inserted node
|
||||||
|
constexpr size_t next_id() const {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Access Operator
|
||||||
|
/// \param i id of the object
|
||||||
|
/// \returns a reference to the object with id `i`
|
||||||
|
constexpr value_t& operator[](size_t i) {
|
||||||
|
assert(i < capacity(), "Index out of Bounds!");
|
||||||
|
assert(_table[i], "Attempted to access Null Object.");
|
||||||
|
return *_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Array Const Access Operator
|
||||||
|
/// \param i id of the object
|
||||||
|
/// \returns a const-qualified reference to the object with id `i`
|
||||||
|
constexpr const value_t& operator[](size_t i) const {
|
||||||
|
assert(i < capacity(), "Index out of Bounds!");
|
||||||
|
assert(_table[i], "Attempted to access Null Object.");
|
||||||
|
return *_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion, inserts `x` into the pool
|
||||||
|
/// \param x the object to move
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
constexpr size_t insert(value_t&& x) {
|
||||||
|
return this->_insert(fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion, inserts a copy of `x` into the pool
|
||||||
|
/// \param x the object to copy
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
constexpr size_t insert(const value_t& x) {
|
||||||
|
return this->_insert(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplacement, constructs a new object using `args...`
|
||||||
|
/// \param args The arguments to construct the new object with
|
||||||
|
/// \returns An integer corresponding to the id of the node
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase an object from the pool
|
||||||
|
/// \param i The id of the object
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
_table[i] = nullopt;
|
||||||
|
_freed.push_back(i);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
dynarray<elem_t, AllocT> _table;
|
||||||
|
list<size_t> _freed;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
size_t _next_free() {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
_freed.pop_front();
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
size_t _insert(ArgsT&&...args) {
|
||||||
|
size_t i = _next_free();
|
||||||
|
if (i >= _table.size()) {
|
||||||
|
_table.emplace_back();
|
||||||
|
}
|
||||||
|
_table[i].emplace(fennec::forward<ArgsT>(args)...);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||||
@@ -16,6 +16,18 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file optional.h
|
||||||
|
/// \brief A header containing the definition for a container with an optionally present variable
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_OPTIONAL_H
|
#ifndef FENNEC_CONTAINERS_OPTIONAL_H
|
||||||
#define FENNEC_CONTAINERS_OPTIONAL_H
|
#define FENNEC_CONTAINERS_OPTIONAL_H
|
||||||
|
|
||||||
@@ -37,13 +49,20 @@ constexpr nullopt_t nullopt_v = {};
|
|||||||
/// \tparam T
|
/// \tparam T
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct optional {
|
struct optional {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
public:
|
public:
|
||||||
// Constructors ========================================================================================================
|
|
||||||
using reference_t = T&;
|
using reference_t = T&;
|
||||||
using pointer_t = T*;
|
using pointer_t = T*;
|
||||||
using const_reference_t = T&;
|
using const_reference_t = T&;
|
||||||
using const_pointer_t = const T*;
|
using const_pointer_t = const T*;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Default Constructor
|
/// \brief Default Constructor
|
||||||
constexpr optional()
|
constexpr optional()
|
||||||
@@ -59,18 +78,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Fundamental Type Constructor
|
/// \brief Type Copy Constructor
|
||||||
/// \param val the value to initialize the underlying object with
|
/// \param val the value to initialize the underlying object with
|
||||||
constexpr optional(T val) requires(is_fundamental_v<T> or is_pointer_v<T>)
|
constexpr optional(const T& val)
|
||||||
: _val(val)
|
: _val(val)
|
||||||
, _set(true) {
|
, _set(true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Type Copy Constructor
|
/// \brief Type Move Constructor
|
||||||
/// \param val the value to initialize the underlying object with
|
/// \param val the value to initialize the underlying object with
|
||||||
constexpr optional(const T& val)
|
constexpr optional(T&& val)
|
||||||
: _val(val)
|
: _val(fennec::forward<T>(val))
|
||||||
, _set(true) {
|
, _set(true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +116,12 @@ public:
|
|||||||
opt = nullopt;
|
opt = nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr optional(ArgsT&&...args)
|
||||||
|
: _val(fennec::forward<ArgsT>(args)...)
|
||||||
|
, _set(true) {
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ~optional() {
|
constexpr ~optional() {
|
||||||
if constexpr(is_fundamental_v<T>) {
|
if constexpr(is_fundamental_v<T>) {
|
||||||
return;
|
return;
|
||||||
@@ -106,12 +131,37 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Implicit Boolean Check, returns `true` when there is a value contained
|
||||||
|
constexpr operator bool() const {
|
||||||
|
return _set;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there is no held value, `false` otherwise.
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return not _set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
// Assignment Operators ================================================================================================
|
// Assignment Operators ================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Fundamental Type Assignment
|
/// \brief Fundamental Type Assignment
|
||||||
/// \val The value to set with
|
/// \param val The value to set with
|
||||||
constexpr optional& operator=(nullopt_t) {
|
constexpr optional& operator=(nullopt_t) {
|
||||||
if constexpr(not is_fundamental_v<T>) {
|
if constexpr(not is_fundamental_v<T>) {
|
||||||
if (_set) {
|
if (_set) {
|
||||||
@@ -125,7 +175,7 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Type Copy Assignment
|
/// \brief Type Copy Assignment
|
||||||
/// \val The value to set with
|
/// \param val The value to set with
|
||||||
constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
||||||
if (_set) {
|
if (_set) {
|
||||||
_val = val;
|
_val = val;
|
||||||
@@ -138,12 +188,12 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Type Move Assignment
|
/// \brief Type Move Assignment
|
||||||
/// \val The value to set with
|
/// \param val The value to set with
|
||||||
constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
||||||
if (_set) {
|
if (_set) {
|
||||||
_val = fennec::move(val);
|
_val = fennec::forward<T>(val);
|
||||||
} else {
|
} else {
|
||||||
fennec::construct(&_val, fennec::move(val));
|
fennec::construct(&_val, fennec::forward<T>(val));
|
||||||
_set = true;
|
_set = true;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@@ -151,7 +201,7 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Copy Assignment
|
/// \brief Copy Assignment
|
||||||
/// \val The optional to copy
|
/// \param opt The optional to copy
|
||||||
constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
|
||||||
if (_set != opt._set) {
|
if (_set != opt._set) {
|
||||||
_set = opt._set;
|
_set = opt._set;
|
||||||
@@ -169,7 +219,7 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Move Assignment
|
/// \brief Move Assignment
|
||||||
/// \val The optional to move
|
/// \param opt The optional to move
|
||||||
constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> {
|
||||||
if (_set != opt._set) {
|
if (_set != opt._set) {
|
||||||
_set = opt._set;
|
_set = opt._set;
|
||||||
@@ -185,6 +235,68 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
/// \name Access
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A pointer to the value, `nullptr` if there is no value
|
||||||
|
constexpr pointer_t operator->() noexcept {
|
||||||
|
return _set ? &_val : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns A const-qualified pointer to the value, `nullptr` if there is no value
|
||||||
|
constexpr const_pointer_t operator->() const noexcept {
|
||||||
|
return _set ? &_val : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Dereference Operator
|
||||||
|
/// \returns A reference to the value
|
||||||
|
constexpr T& operator*() & noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Dereference Operator
|
||||||
|
/// \returns A const-qualified reference to the value
|
||||||
|
constexpr const T& operator*() const& noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Dereference Operator
|
||||||
|
/// \returns A reference to the value
|
||||||
|
constexpr T&& operator*() && noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Const Dereference Operator
|
||||||
|
/// \returns A const-qualified reference to the value
|
||||||
|
constexpr const T&& operator*() const&& noexcept {
|
||||||
|
assertd(_set, "Attempted to reference the value of an unset optional");
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Assignment
|
||||||
|
/// \val The optional to move
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr T& emplace(ArgsT&&...args) {
|
constexpr T& emplace(ArgsT&&...args) {
|
||||||
if (_set) {
|
if (_set) {
|
||||||
@@ -196,44 +308,13 @@ public:
|
|||||||
return _val;
|
return _val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Reset the Optional
|
||||||
void reset() {
|
void reset() {
|
||||||
this->operator=(nullopt);
|
this->operator=(nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
// Operators ===========================================================================================================
|
|
||||||
|
|
||||||
constexpr operator bool() const {
|
|
||||||
return _set;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr pointer_t operator->() noexcept {
|
|
||||||
return _set ? &_val : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const_pointer_t operator->() const noexcept {
|
|
||||||
return _set ? &_val : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr T& operator*() & noexcept {
|
|
||||||
assertd(_set, "Attempted to reference the value of an unset optional");
|
|
||||||
return _val;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const T& operator*() const& noexcept {
|
|
||||||
assertd(_set, "Attempted to reference the value of an unset optional");
|
|
||||||
return _val;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr T&& operator*() && noexcept {
|
|
||||||
assertd(_set, "Attempted to reference the value of an unset optional");
|
|
||||||
return _val;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const T&& operator*() const&& noexcept {
|
|
||||||
assertd(_set, "Attempted to reference the value of an unset optional");
|
|
||||||
return _val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,18 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file pair.h
|
||||||
|
/// \brief A header containing the definition for a container holding a pair of values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_PAIR_H
|
#ifndef FENNEC_CONTAINERS_PAIR_H
|
||||||
#define FENNEC_CONTAINERS_PAIR_H
|
#define FENNEC_CONTAINERS_PAIR_H
|
||||||
|
|
||||||
@@ -28,67 +40,144 @@ namespace fennec
|
|||||||
|
|
||||||
// TODO: Document
|
// TODO: Document
|
||||||
|
|
||||||
template<typename T0, typename T1>
|
///
|
||||||
|
/// \brief Struct for holding a pair of values
|
||||||
|
/// \tparam TypeT0 The type of the first value
|
||||||
|
/// \tparam TypeT1 The type of the second value
|
||||||
|
template<typename TypeT0, typename TypeT1>
|
||||||
struct pair {
|
struct pair {
|
||||||
|
|
||||||
|
// Members =============================================================================================================
|
||||||
|
|
||||||
|
TypeT0 first; ///< The first value in the pair
|
||||||
|
TypeT1 second; ///< The second value in the pair
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, invokes default constructor for both elements
|
||||||
constexpr pair() = default;
|
constexpr pair() = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, invokes destructor for both elements
|
||||||
constexpr ~pair() = default;
|
constexpr ~pair() = default;
|
||||||
|
|
||||||
constexpr pair(const T0& x, const T1& y)
|
///
|
||||||
|
/// \brief Pair Copy Constructor
|
||||||
|
/// \param x Value to copy for the first element
|
||||||
|
/// \param y Value to copy for the first element
|
||||||
|
constexpr pair(const TypeT0& x, const TypeT1& y)
|
||||||
: first(x)
|
: first(x)
|
||||||
, second(y) {
|
, second(y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr pair(T0&& x, T1&& y) noexcept
|
///
|
||||||
: first(fennec::forward<T0>(x))
|
/// \brief Pair Move Constructor
|
||||||
, second(fennec::forward<T1>(y)) {
|
/// \param x Value to move for the first element
|
||||||
|
/// \param y Value to move for the first element
|
||||||
|
constexpr pair(TypeT0&& x, TypeT1&& y) noexcept
|
||||||
|
: first(fennec::forward<TypeT0>(x))
|
||||||
|
, second(fennec::forward<TypeT1>(y)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Pair Implicit Constructor
|
||||||
|
/// \param arg1 Value to initialize the first element
|
||||||
|
/// \param arg2 Value to initialize the first element
|
||||||
template<typename Arg1T, typename Arg2T>
|
template<typename Arg1T, typename Arg2T>
|
||||||
constexpr pair(Arg1T&& arg1, Arg2T&& arg2)
|
constexpr pair(Arg1T&& arg1, Arg2T&& arg2)
|
||||||
: first(fennec::forward<Arg1T>(arg1))
|
: first(fennec::forward<Arg1T>(arg1))
|
||||||
, second(fennec::forward<Arg2T>(arg2)) {
|
, second(fennec::forward<Arg2T>(arg2)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, copies both elements
|
||||||
constexpr pair(const pair&) = default;
|
constexpr pair(const pair&) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, moves both elements
|
||||||
constexpr pair(pair&&) noexcept = default;
|
constexpr pair(pair&&) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment, copies both elements
|
||||||
constexpr pair& operator=(const pair&) = default;
|
constexpr pair& operator=(const pair&) = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment, moves both elements
|
||||||
constexpr pair& operator=(pair&&) noexcept = default;
|
constexpr pair& operator=(pair&&) noexcept = default;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Comparison ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Comparison
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Equality Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns `true` when both elements of each pair are equal
|
||||||
constexpr bool operator==(const pair& p) const {
|
constexpr bool operator==(const pair& p) const {
|
||||||
return first == p.first and second == p.second;
|
return first == p.first and second == p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Inequality Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns `true` when either element of each pair are equal
|
||||||
constexpr bool operator!=(const pair& p) const {
|
constexpr bool operator!=(const pair& p) const {
|
||||||
return first != p.first or second != p.second;
|
return first != p.first or second != p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Less Than Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are
|
||||||
|
/// equal and the second element is less
|
||||||
constexpr bool operator<(const pair& p) const {
|
constexpr bool operator<(const pair& p) const {
|
||||||
return first < p.first or (first == p.first and second < p.second);
|
return first < p.first or (first == p.first and second < p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Less Equal Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are
|
||||||
|
/// equal and the second element is less or equal
|
||||||
constexpr bool operator<=(const pair& p) const {
|
constexpr bool operator<=(const pair& p) const {
|
||||||
return first < p.first or (first == p.first and second <= p.second);
|
return first < p.first or (first == p.first and second <= p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Greater Than Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are
|
||||||
|
/// equal and the second element is greater
|
||||||
constexpr bool operator>(const pair& p) const {
|
constexpr bool operator>(const pair& p) const {
|
||||||
return first > p.first or (first == p.first and second > p.second);
|
return first > p.first or (first == p.first and second > p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Greater Equal Operator
|
||||||
|
/// \param p Pair to compare with
|
||||||
|
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are
|
||||||
|
/// equal and the second element is greater or equal
|
||||||
constexpr bool operator>=(const pair& p) const {
|
constexpr bool operator>=(const pair& p) const {
|
||||||
return first > p.first or (first == p.first and second >= p.second);
|
return first > p.first or (first == p.first and second >= p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
T0 first;
|
/// @}
|
||||||
T1 second;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T0, typename T1>
|
template<typename TypeT0, typename TypeT1>
|
||||||
struct hash<pair<T0, T1>> : hash<T0>, hash<T1> {
|
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
|
||||||
constexpr size_t operator()(const pair<T0, T1>& p) const {
|
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
|
||||||
return fennec::pair_hash( // pair the hashes of both elements
|
return fennec::pair_hash( // pair the hashes of both elements
|
||||||
hash<T0>::operator()(p.first),
|
hash<TypeT0>::operator()(p.first),
|
||||||
hash<T1>::operator()(p.second)
|
hash<TypeT1>::operator()(p.second)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
626
include/fennec/containers/rdtree.h
Normal file
626
include/fennec/containers/rdtree.h
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file rdtree.h
|
||||||
|
/// \brief A header containing the definition for a tree with a root and directed edges
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_RDTREE_H
|
||||||
|
#define FENNEC_CONTAINERS_RDTREE_H
|
||||||
|
|
||||||
|
#include <fennec/containers/list.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/traversal.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Rooted-Directed Tree
|
||||||
|
/// \tparam TypeT Data type
|
||||||
|
/// \tparam AllocT Allocator Type
|
||||||
|
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||||
|
struct rdtree {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
protected:
|
||||||
|
struct node;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_t = TypeT;
|
||||||
|
using alloc_t = typename allocator_traits<AllocT>::template rebind<node>;
|
||||||
|
static constexpr size_t root = 0;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct node {
|
||||||
|
optional<TypeT> value;
|
||||||
|
size_t parent, child, prev, next;
|
||||||
|
size_t depth, num_children;
|
||||||
|
|
||||||
|
constexpr node()
|
||||||
|
: value(nullopt)
|
||||||
|
, parent(npos), child(npos)
|
||||||
|
, prev(npos), next(npos)
|
||||||
|
, depth(0), num_children(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr node(size_t p, size_t c, size_t v, size_t n, size_t d, ArgsT&&...args)
|
||||||
|
: value(fennec::forward<ArgsT>(args)...)
|
||||||
|
, parent(p), child(c), prev(v), next(n)
|
||||||
|
, depth(d), num_children(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~node() {
|
||||||
|
parent = npos;
|
||||||
|
child = npos;
|
||||||
|
prev = npos;
|
||||||
|
next = npos;
|
||||||
|
depth = 0;
|
||||||
|
num_children = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Root Constructor, constructs the root node of the tree
|
||||||
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param args The arguments to construct the root with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
explicit constexpr rdtree(ArgsT&&...args)
|
||||||
|
: _table(), _freed(), _size(1) {
|
||||||
|
_table.creallocate(8);
|
||||||
|
fennec::construct(&_table[0], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Constructor, copies the contents of `tree`
|
||||||
|
/// \param tree the rdtree to copy
|
||||||
|
constexpr rdtree(const rdtree& tree)
|
||||||
|
: _table(tree._table), _freed(tree._freed), _size(tree._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Constructor, takes ownership over the contents of `tree`
|
||||||
|
/// \param tree the rdtree to move
|
||||||
|
constexpr rdtree(rdtree&& tree) noexcept
|
||||||
|
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Assignment
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Assignment Operator
|
||||||
|
/// \param rhs the rdtree to copy
|
||||||
|
/// \returns `this` after copying the contents of `rhs`
|
||||||
|
constexpr rdtree& operator=(const rdtree& rhs) {
|
||||||
|
for (value_t* it : this->_table) {
|
||||||
|
fennec::destruct(it);
|
||||||
|
}
|
||||||
|
_table = rhs._table;
|
||||||
|
_freed = rhs._freed;
|
||||||
|
_size = rhs._size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Assignment Operator
|
||||||
|
/// \param rhs the rdtree to move
|
||||||
|
/// \returns `this` after taking ownership over the contents of `rhs`
|
||||||
|
constexpr rdtree& operator=(rdtree&& rhs) noexcept {
|
||||||
|
for (value_t* it : _table) {
|
||||||
|
fennec::destruct(it);
|
||||||
|
}
|
||||||
|
_table = fennec::move(rhs._table);
|
||||||
|
_freed = fennec::move(rhs._freed);
|
||||||
|
_size = rhs._size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of nodes in the tree
|
||||||
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the underlying allocation
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _table.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no nodes in the tree, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the parent node
|
||||||
|
constexpr size_t parent(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
return i == npos ? npos : _table[i].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the child node
|
||||||
|
constexpr size_t child(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
size_t c = i == npos ? npos : _table[i].child;
|
||||||
|
if (n != 0)
|
||||||
|
return next(c, n == npos ? npos : n - 1);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the next node
|
||||||
|
constexpr size_t next(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if (i == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t org = i;
|
||||||
|
size_t nxt = _table[i].next;
|
||||||
|
while (nxt != npos) {
|
||||||
|
i = nxt;
|
||||||
|
nxt = _table[i].next;
|
||||||
|
if (n != npos) {
|
||||||
|
if (n-- == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == org && n != npos ? npos : i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The id of the previous node
|
||||||
|
constexpr size_t prev(size_t i, size_t n = 0) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if (i == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t org = i;
|
||||||
|
size_t prv = _table[i].prev;
|
||||||
|
while (prv != npos) {
|
||||||
|
i = prv;
|
||||||
|
prv = _table[i].prev;
|
||||||
|
if (n != npos) {
|
||||||
|
if (n-- == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i == org && n != npos ? npos : i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i the node to start at
|
||||||
|
/// \returns the left-most child of node `i`
|
||||||
|
constexpr size_t left_most(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
size_t n = i;
|
||||||
|
if ((n = child(n)) == npos) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
size_t p = n;
|
||||||
|
if ((n = child(n)) == npos) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i the node to start at
|
||||||
|
/// \returns the right-most child of node `i`
|
||||||
|
constexpr size_t right_most(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
if ((i = child(i)) == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
size_t n;
|
||||||
|
while ((n = next(i)) != npos) {
|
||||||
|
i = n;
|
||||||
|
}
|
||||||
|
n = i;
|
||||||
|
if ((i = child(i)) == npos) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The depth of the node
|
||||||
|
constexpr size_t depth(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return npos;
|
||||||
|
return i == npos ? npos : _table[i].depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to check
|
||||||
|
/// \returns The number of children the node has
|
||||||
|
constexpr size_t num_children(size_t i) const {
|
||||||
|
if (i >= _table.capacity()) return 0;
|
||||||
|
return i == npos ? 0 : _table[i].num_children;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The next node id were `insert` or `emplace` to be called
|
||||||
|
constexpr size_t next_id() const {
|
||||||
|
size_t i = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
i = _freed.front();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to access
|
||||||
|
/// \returns A reference to the value of the node wrapped in an optional
|
||||||
|
constexpr value_t* operator[](size_t i) {
|
||||||
|
auto& it = _table[i].value;
|
||||||
|
if (it) {
|
||||||
|
return &*_table[i].value;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \param i The id of the node to access
|
||||||
|
/// \returns A const-qualified reference to the value of the node wrapped in an optional
|
||||||
|
constexpr const value_t* operator[](size_t i) const {
|
||||||
|
const auto& it = _table[i].value;
|
||||||
|
if (it) {
|
||||||
|
return &*_table[i].value;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Insertion & Deletion ================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param val the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
constexpr size_t insert(size_t parent, size_t next, const value_t& val) {
|
||||||
|
return this->_insert(parent, next, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param val the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
constexpr size_t insert(size_t parent, size_t next, value_t&& val) {
|
||||||
|
return this->_insert(parent, next, fennec::forward<value_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Insertion, creates a node in the tree with parent `parent`
|
||||||
|
/// \param parent the parent node, if `npos` sets the value of the root node
|
||||||
|
/// \param next the next node, as an index relative to the parent
|
||||||
|
/// \param args the args to construct the value to insert
|
||||||
|
/// \returns the index of the created node
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t emplace(size_t parent, size_t next, ArgsT&&...args) {
|
||||||
|
return this->_insert(parent, next, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Swap two nodes
|
||||||
|
/// \param i0 The id of the first node
|
||||||
|
/// \param i1 The id of the second node
|
||||||
|
constexpr void swap(size_t i0, size_t i1) {
|
||||||
|
assertf(i0 != root and i1 != root, "Cannot Swap With Root");
|
||||||
|
|
||||||
|
size_t p0 = parent(i0);
|
||||||
|
size_t p1 = parent(i1);
|
||||||
|
|
||||||
|
fennec::swap(_table[i0].parent, _table[i1].parent);
|
||||||
|
fennec::swap(_table[i0].child, _table[i1].child);
|
||||||
|
fennec::swap(_table[i0].next, _table[i1].next);
|
||||||
|
fennec::swap(_table[i0].prev, _table[i1].prev);
|
||||||
|
fennec::swap(_table[i0].depth, _table[i1].depth);
|
||||||
|
fennec::swap(_table[i0].num_children, _table[i1].num_children);
|
||||||
|
|
||||||
|
if (child(p0) == i0) _table[p0].child = i1;
|
||||||
|
if (child(p1) == i1) _table[p1].child = i0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Erase a node in the tree and all of it's children
|
||||||
|
/// \param i the index of the node
|
||||||
|
constexpr void erase(size_t i) {
|
||||||
|
_erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Traversal ===========================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Traverse the tree using a specified order and visiting functor
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id.
|
||||||
|
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum
|
||||||
|
///
|
||||||
|
/// \tparam OrderT The order with which to traverse the tree.
|
||||||
|
/// \tparam VisitorT The visitor, should fulfill the signature `uint8_t visit(TypeT&, size_t)`
|
||||||
|
/// \param visit The visiting object
|
||||||
|
/// \param i The node to start at
|
||||||
|
template<typename OrderT, typename VisitorT>
|
||||||
|
void traverse(VisitorT&& visit, size_t i = root) {
|
||||||
|
OrderT order;
|
||||||
|
i = order(*this, i);
|
||||||
|
while (i != npos) {
|
||||||
|
uint8_t mode = traversal_control_continue;
|
||||||
|
if (_table[i].value) {
|
||||||
|
mode = visit(*_table[i].value, i);
|
||||||
|
}
|
||||||
|
if (mode == traversal_control_break) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = order[*this, i, mode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pre_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree&, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nxt = tree.next(node);
|
||||||
|
size_t chd = tree.child(node);
|
||||||
|
|
||||||
|
if (nxt != npos && node != head) {
|
||||||
|
visit.push_front(nxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chd != npos && mode != traversal_control_jump_over) {
|
||||||
|
visit.push_front(chd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct in_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree& tree, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return tree.left_most(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t prnt = tree.parent(node);
|
||||||
|
size_t next = tree.next(node);
|
||||||
|
if (node != head) {
|
||||||
|
if (tree.child(prnt) == node) {
|
||||||
|
visit.push_back(prnt);
|
||||||
|
if (next != npos) {
|
||||||
|
visit.push_back(tree.left_most(next));
|
||||||
|
}
|
||||||
|
} else if (next != npos) {
|
||||||
|
visit.push_front(tree.left_most(next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct post_order {
|
||||||
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
|
size_t operator()(const rdtree& tree, size_t start) {
|
||||||
|
head = start;
|
||||||
|
return tree.left_most(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t operator[](const rdtree& tree, size_t node, uint8_t) {
|
||||||
|
if (node == npos) {
|
||||||
|
return npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t prnt = tree.parent(node);
|
||||||
|
size_t next = tree.next(node);
|
||||||
|
|
||||||
|
if (node != head) {
|
||||||
|
if (next != npos) {
|
||||||
|
visit.push_front(tree.left_most(next));
|
||||||
|
} else {
|
||||||
|
visit.push_front(prnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not visit.empty()) {
|
||||||
|
node = visit.front();
|
||||||
|
visit.pop_front();
|
||||||
|
} else {
|
||||||
|
node = npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
allocation<node, alloc_t> _table;
|
||||||
|
list<size_t> _freed;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
void _expand() {
|
||||||
|
_table.creallocate(_table.capacity() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _next_free() {
|
||||||
|
size_t next = _size;
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
next = _freed.front();
|
||||||
|
_freed.pop_front();
|
||||||
|
}
|
||||||
|
if (_size >= capacity()) {
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr size_t _insert(size_t p, size_t n, ArgsT&&...args) {
|
||||||
|
if (_size == 0) {
|
||||||
|
fennec::construct(&_table[root], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||||
|
_size = 1;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == npos) {
|
||||||
|
_table[root].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
_size = _size == 0 ? 1 : _size;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = _next_free();
|
||||||
|
size_t nxt = child(p, n);
|
||||||
|
size_t prv = n == npos ? npos : prev(n);
|
||||||
|
|
||||||
|
++_table[p].num_children;
|
||||||
|
if ((nxt == child(p) && n != npos) || nxt == npos) {
|
||||||
|
_table[p].child = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == npos) {
|
||||||
|
if (nxt != npos) {
|
||||||
|
_table[nxt].next = idx;
|
||||||
|
}
|
||||||
|
fennec::construct(&_table[idx], p, npos, nxt, npos, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||||
|
} else {
|
||||||
|
if (nxt != npos) {
|
||||||
|
_table[nxt].prev = idx;
|
||||||
|
}
|
||||||
|
if (prv != npos) {
|
||||||
|
_table[prv].next = idx;
|
||||||
|
}
|
||||||
|
fennec::construct(&_table[idx], p, npos, prv, nxt, depth(p) + 1, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void _erase(size_t i) {
|
||||||
|
list<size_t> queue;
|
||||||
|
queue.push_back(child(i));
|
||||||
|
while (not queue.empty()) {
|
||||||
|
size_t n = queue.front(); queue.pop_front();
|
||||||
|
if (n == npos) continue;
|
||||||
|
queue.push_back(next(n));
|
||||||
|
queue.push_back(child(n));
|
||||||
|
fennec::destruct(&_table[n]);
|
||||||
|
_freed.push_back(n);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fennec::destruct(&_table[i]);
|
||||||
|
if (i != root) _freed.push_back(i);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_RDTREE_H
|
||||||
@@ -16,12 +16,25 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file set.h
|
||||||
|
/// \brief A header containing the definition for a set of unique values
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_SET_H
|
#ifndef FENNEC_CONTAINERS_SET_H
|
||||||
#define FENNEC_CONTAINERS_SET_H
|
#define FENNEC_CONTAINERS_SET_H
|
||||||
|
|
||||||
// https://programming.guide/robin-hood-hashing.html
|
// https://programming.guide/robin-hood-hashing.html
|
||||||
|
|
||||||
#include <fennec/containers/optional.h>
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/set.h>
|
||||||
#include <fennec/lang/compare.h>
|
#include <fennec/lang/compare.h>
|
||||||
#include <fennec/math/ext/primes.h>
|
#include <fennec/math/ext/primes.h>
|
||||||
#include <fennec/memory/allocator.h>
|
#include <fennec/memory/allocator.h>
|
||||||
@@ -30,15 +43,36 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO: Document
|
///
|
||||||
|
///
|
||||||
template<typename T, class Hash = hash<T>, class Equals = equality<T>, class Alloc = allocator<T>>
|
/// \brief wrapper for sets of elements
|
||||||
|
/// \details
|
||||||
|
/// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array
|
||||||
|
///
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ✅ |
|
||||||
|
/// | distinct | ✅ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | \f$O(1)\f$ |
|
||||||
|
/// | deletion | \f$O(1)\f$ |
|
||||||
|
///
|
||||||
|
/// \tparam TypeT The type to contain
|
||||||
|
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
|
||||||
struct set {
|
struct set {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
public:
|
public:
|
||||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<T>;
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||||
using hash_t = Hash;
|
using hash_t = Hash;
|
||||||
using equal_t = Equals;
|
using equal_t = Equals;
|
||||||
using elem_t = T;
|
using elem_t = TypeT;
|
||||||
|
|
||||||
class iterator;
|
class iterator;
|
||||||
static constexpr size_t npos = -1;
|
static constexpr size_t npos = -1;
|
||||||
@@ -53,160 +87,233 @@ private:
|
|||||||
constexpr ~node() = default;
|
constexpr ~node() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Constructors ========================================================================================================
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// \name Constructors & Destructor
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes empty set
|
||||||
constexpr set()
|
constexpr set()
|
||||||
: _alloc()
|
: _alloc()
|
||||||
, _hash()
|
, _hash()
|
||||||
, _size(0)
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
, _load(default_load) {
|
, _load(default_load) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Hash Copy Constructor, initializes empty set with a hash
|
||||||
|
/// \param hash the hash object
|
||||||
constexpr set(const hash_t& hash)
|
constexpr set(const hash_t& hash)
|
||||||
: _alloc()
|
: _alloc()
|
||||||
, _hash(hash)
|
, _hash(hash)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
, _load(default_load) {
|
, _load(default_load) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr set(hash_t&& hash) noexcept
|
///
|
||||||
: _alloc()
|
/// \brief Alloc Copy Constructor, initializes empty set with an allocator
|
||||||
, _hash(hash)
|
/// \param alloc the allocator object
|
||||||
, _size(0)
|
|
||||||
, _load(default_load) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr set(const alloc_t& alloc)
|
constexpr set(const alloc_t& alloc)
|
||||||
: _alloc(alloc)
|
: _alloc(alloc)
|
||||||
, _hash()
|
, _hash()
|
||||||
, _size(0)
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
, _load(default_load) {
|
, _load(default_load) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr set(alloc_t&& alloc) noexcept
|
///
|
||||||
: _alloc(alloc)
|
/// \brief Hash Alloc Copy Constructor, initializes empty set with a hash and allocator
|
||||||
, _hash()
|
/// \param hash the hash object
|
||||||
, _size(0)
|
/// \param alloc the allocator object
|
||||||
, _load(default_load) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr set(const hash_t& hash, const alloc_t& alloc)
|
constexpr set(const hash_t& hash, const alloc_t& alloc)
|
||||||
: _alloc(alloc)
|
: _alloc(alloc)
|
||||||
, _hash(hash)
|
, _hash(hash)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
|
, _sumpsl(0)
|
||||||
, _load(default_load) {
|
, _load(default_load) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr set(const hash_t& hash, alloc_t&& alloc) noexcept
|
///
|
||||||
: _alloc(alloc)
|
/// \brief Set Copy Constructor
|
||||||
, _hash(hash)
|
/// \param set Set to copy
|
||||||
, _size(0)
|
|
||||||
, _load(default_load) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr set(hash_t&& hash, alloc_t&& alloc) noexcept
|
|
||||||
: _alloc(alloc)
|
|
||||||
, _hash(hash)
|
|
||||||
, _size(0)
|
|
||||||
, _load(default_load) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr set(hash_t&& hash, const alloc_t& alloc) noexcept
|
|
||||||
: _alloc(alloc)
|
|
||||||
, _hash(hash)
|
|
||||||
, _size(0)
|
|
||||||
, _load(default_load) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr set(const set& set)
|
constexpr set(const set& set)
|
||||||
: _alloc(set._alloc)
|
: _alloc(set._alloc)
|
||||||
, _hash(set._hash)
|
, _hash(set._hash)
|
||||||
, _size(set._size)
|
, _size(set._size)
|
||||||
, _load(default_load) {
|
, _sumpsl(set._sumpsl)
|
||||||
|
, _load(set._load) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Set Move Constructor
|
||||||
|
/// \param set Set to move
|
||||||
constexpr set(set&& set) noexcept
|
constexpr set(set&& set) noexcept
|
||||||
: _alloc(fennec::move(set._alloc))
|
: _alloc(fennec::move(set._alloc))
|
||||||
, _hash(fennec::move(set._hash))
|
, _hash(fennec::move(set._hash))
|
||||||
, _size(fennec::move(set._size)) {
|
, _size(fennec::move(set._size))
|
||||||
|
, _sumpsl(set._sumpsl)
|
||||||
|
, _load(set._load) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ~set() = default;
|
///
|
||||||
|
/// \brief Destructor, destructs all elements and releases the allocation
|
||||||
|
constexpr ~set() {
|
||||||
|
for (size_t i = 0; i < capacity(); ++i) {
|
||||||
|
_alloc[i].value = nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
|
/// \name Properties
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Size of the set in elements
|
||||||
constexpr size_t size() const {
|
constexpr size_t size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when the set is empty, `false` otherwise
|
||||||
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns Capacity of the set in elements
|
||||||
constexpr size_t capacity() const {
|
constexpr size_t capacity() const {
|
||||||
return _alloc.capacity();
|
return _alloc.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void insert(elem_t&& val) {
|
/// @}
|
||||||
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
|
|
||||||
_expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
elem_t value = fennec::forward<elem_t>(val);
|
|
||||||
size_t i = _hash(value) % capacity(); // Initial search index
|
|
||||||
int psl = 0;
|
|
||||||
while (_alloc[i].value) { // Search for empty cell
|
|
||||||
if (_equal(*_alloc[i].value, val)) { // Check to see if this element is already inserted
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
|
||||||
fennec::swap(*_alloc[i].value, value);
|
|
||||||
fennec::swap(_alloc[i].psl, psl);
|
|
||||||
}
|
|
||||||
i = (i + 1) % capacity(); ++psl;
|
|
||||||
}
|
|
||||||
_alloc[i].value = fennec::move(value);
|
|
||||||
_alloc[i].psl = psl;
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void insert(const elem_t& val) {
|
// Access ==============================================================================================================
|
||||||
elem_t value = val; // Copy Constructor invoked here
|
|
||||||
this->insert(fennec::move(value)); // Only invokes moves
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...ArgsT>
|
/// \name Access
|
||||||
constexpr void emplace(ArgsT&&...args) {
|
/// @{
|
||||||
elem_t value = elem_t(fennec::forward<ArgsT>(args)...); // Constructor invoked here
|
|
||||||
this->insert(fennec::move(value)); // Only invokes moves
|
|
||||||
}
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find an Element
|
||||||
|
/// \param val Value to find
|
||||||
|
/// \returns An iterator at the location of the value
|
||||||
constexpr iterator find(const elem_t& val) const {
|
constexpr iterator find(const elem_t& val) const {
|
||||||
size_t i = _hash(val) % capacity(); // Initial search index
|
if (capacity() == 0) {
|
||||||
int psl = 0;
|
return end();
|
||||||
|
}
|
||||||
|
size_t s = _hash(val) % capacity(); // Initial search index
|
||||||
|
int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl
|
||||||
|
size_t i = (s + psl) % capacity(); // Median search
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
// Loop while there is a value and its psl is greater than our probe
|
// Check the first element;
|
||||||
while (_alloc[i].value && _alloc[i].psl <= psl) {
|
if (_alloc[i].psl >= psl && _alloc[i].value) {
|
||||||
if (_equal(*_alloc[i].value, val)) {
|
if (_equal(*_alloc[i].value, val)) {
|
||||||
return iterator(this, i);
|
return iterator(this, i);
|
||||||
}
|
}
|
||||||
i = (i + 1) % capacity(); ++psl;
|
}
|
||||||
|
|
||||||
|
// Loop while there is a value and its psl is greater than our probe
|
||||||
|
while (true) {
|
||||||
|
++n;
|
||||||
|
size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow
|
||||||
|
size_t i1 = (i + n) % capacity();
|
||||||
|
int p0 = psl - n, p1 = psl + n;
|
||||||
|
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
|
||||||
|
|
||||||
|
if (c0 && _alloc[i0].value) {
|
||||||
|
if (_equal(*_alloc[i0].value, val)) {
|
||||||
|
return iterator(this, i0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c1 && _alloc[i1].value) {
|
||||||
|
if (_equal(*_alloc[i1].value, val)) {
|
||||||
|
return iterator(this, i1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not(c0 or c1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iterator(this, npos);
|
return iterator(this, npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr elem_t* at(const iterator& it) {
|
///
|
||||||
size_t i = it._i;
|
/// \brief Check if a set contains a value
|
||||||
if (i >= capacity()) return nullptr;
|
/// \param val Value to check
|
||||||
if (not _alloc[i].value) return nullptr;
|
/// \returns `true` if `val` can be found, `false` otherwise
|
||||||
return &*_alloc[i].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const elem_t* at(const iterator& it) const {
|
|
||||||
size_t i = it._i;
|
|
||||||
if (i >= capacity()) return nullopt;
|
|
||||||
if (not _alloc[i].value) return nullopt;
|
|
||||||
return &*_alloc[i].value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool contains(const elem_t& val) const {
|
constexpr bool contains(const elem_t& val) const {
|
||||||
return this->find(val) != end();
|
return this->find(val) != end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A pointer to the element, `nullptr` if not found.
|
||||||
|
/// The value should not be changed in a manner that will change the hash of the element.
|
||||||
|
constexpr elem_t* at(const iterator& it) {
|
||||||
|
if (it == end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Iterator Const Access
|
||||||
|
/// \param it Location to access
|
||||||
|
/// \returns A const-qualified pointer to the element, `nullptr` if not found.
|
||||||
|
constexpr const elem_t* at(const iterator& it) const {
|
||||||
|
if (not _alloc[it._i].value) return nullptr;
|
||||||
|
return &*_alloc[it._i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
/// \name Modifiers
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Move Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr iterator insert(elem_t&& val) {
|
||||||
|
return this->_insert(fennec::forward<elem_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Copy Insertion
|
||||||
|
/// \param val Value to insert
|
||||||
|
constexpr iterator insert(const elem_t& val) {
|
||||||
|
return this->_insert(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Emplace Insertion
|
||||||
|
/// \tparam ArgsT Argument types
|
||||||
|
/// \param args Arguments to construct with
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr iterator emplace(ArgsT&&...args) {
|
||||||
|
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param it Location to erase
|
||||||
constexpr void erase(iterator it) {
|
constexpr void erase(iterator it) {
|
||||||
size_t i = it._i;
|
size_t i = it._i;
|
||||||
if (i >= capacity()) {
|
if (i >= capacity()) {
|
||||||
@@ -217,27 +324,68 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
_alloc[i].value = nullopt;
|
_alloc[i].value = nullopt;
|
||||||
|
_sumpsl -= _alloc[i].psl;
|
||||||
--_size;
|
--_size;
|
||||||
size_t p = i;
|
size_t p = i;
|
||||||
while (_alloc[i = (i + 1) % capacity()].value) {
|
while (_alloc[i = (i + 1) % capacity()].value) {
|
||||||
size_t psl = _alloc[i].psl;
|
if (_alloc[i].psl == 0) break;
|
||||||
if (psl == 0) break;
|
|
||||||
|
|
||||||
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
|
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
|
||||||
_alloc[p].psl = psl - 1;
|
--_alloc[p].psl, --_sumpsl;
|
||||||
p = i;
|
p = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Element Erase
|
||||||
|
/// \param val Value to erase
|
||||||
constexpr void erase(const elem_t& val) {
|
constexpr void erase(const elem_t& val) {
|
||||||
this->erase(this->find(val));
|
this->erase(this->find(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief
|
||||||
|
constexpr void clear() {
|
||||||
|
for (size_t i = 0; i < _alloc.capacity(); ++i) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
// ITERATOR ============================================================================================================
|
// ITERATOR ============================================================================================================
|
||||||
|
|
||||||
|
/// \name Iteration
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns An iterator for all elements of the set in no particular order
|
||||||
|
constexpr iterator begin() const {
|
||||||
|
iterator it(this, 0);
|
||||||
|
if (not _alloc[it._i].value) {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns An iterator representing the end of the set
|
||||||
|
constexpr iterator end() const {
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Class for Iterating the Set
|
||||||
class iterator {
|
class iterator {
|
||||||
public:
|
public:
|
||||||
|
constexpr iterator(const set* set, size_t i)
|
||||||
|
: _set(set)
|
||||||
|
, _i(i) {
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ~iterator() {
|
constexpr ~iterator() {
|
||||||
_set = nullptr;
|
_set = nullptr;
|
||||||
}
|
}
|
||||||
@@ -263,44 +411,34 @@ public:
|
|||||||
return *_set->_alloc[_i].value;
|
return *_set->_alloc[_i].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const iterator& it) {
|
constexpr const elem_t* operator->() const {
|
||||||
|
if (not _set->_alloc[_i].value) return nullptr;
|
||||||
|
return &*_set->_alloc[_i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const iterator& it) const {
|
||||||
return _set == it._set and _i == it._i;
|
return _set == it._set and _i == it._i;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator!=(const iterator& it) {
|
constexpr bool operator!=(const iterator& it) const {
|
||||||
return _set != it._set or _i != it._i;
|
return _set != it._set or _i != it._i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr size_t index() const { return _i; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const set* _set;
|
const set* _set;
|
||||||
size_t _i;
|
size_t _i;
|
||||||
friend set;
|
friend set;
|
||||||
|
|
||||||
constexpr iterator(const set* set, size_t i)
|
|
||||||
: _set(set)
|
|
||||||
, _i(i) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr iterator begin() const {
|
|
||||||
iterator it(this, 0);
|
|
||||||
if (not _alloc[it._i].value) {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr iterator end() const {
|
|
||||||
return iterator(this, npos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE =============================================================================================================
|
// PRIVATE =============================================================================================================
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr void _expand() {
|
constexpr void _expand() {
|
||||||
set cpy; // Create a new set
|
set cpy; // Create a new set
|
||||||
cpy._alloc.callocate(
|
cpy._alloc.resize(
|
||||||
fennec::next_prime2(_alloc.capacity())
|
fennec::next_prime2(_alloc.capacity())
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -315,11 +453,38 @@ private:
|
|||||||
fennec::swap(_alloc, cpy._alloc);
|
fennec::swap(_alloc, cpy._alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
allocation<node, alloc_t> _alloc;
|
template<typename...ArgsT>
|
||||||
|
constexpr iterator _insert(ArgsT&&...args) {
|
||||||
|
if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
elem_t value(fennec::forward<ArgsT>(args)...);
|
||||||
|
size_t i = _hash(value) % capacity(); // Initial search index
|
||||||
|
int psl = 0;
|
||||||
|
while (_alloc[i].value) { // Search for empty cell
|
||||||
|
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
||||||
|
return iterator(this, i);
|
||||||
|
}
|
||||||
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
|
_sumpsl += psl - _alloc[i].psl;
|
||||||
|
fennec::swap(_alloc[i].psl, psl);
|
||||||
|
fennec::swap(*_alloc[i].value, value);
|
||||||
|
}
|
||||||
|
i = (i + 1) % capacity(); ++psl;
|
||||||
|
}
|
||||||
|
_alloc[i].value = fennec::move(value);
|
||||||
|
_sumpsl += (_alloc[i].psl = psl);
|
||||||
|
++_size;
|
||||||
|
return iterator(this, npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynarray<node, alloc_t> _alloc;
|
||||||
hash_t _hash;
|
hash_t _hash;
|
||||||
equal_t _equal;
|
equal_t _equal;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
double _load;
|
size_t _sumpsl;
|
||||||
|
float _load;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
47
include/fennec/containers/traversal.h
Normal file
47
include/fennec/containers/traversal.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file traversal.h
|
||||||
|
/// \brief a header containing constants and utilities related to traversal
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
|
#define FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief A set of constants used in the traverser-visitor pattern
|
||||||
|
enum traversal_control_ {
|
||||||
|
traversal_control_continue = 0,
|
||||||
|
traversal_control_break = 1,
|
||||||
|
traversal_control_jump_over = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_TRAVERSAL_H
|
||||||
@@ -16,6 +16,18 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file tuple.h
|
||||||
|
/// \brief A header containing the definition for a container with multiple values of differing types
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_TUPLE_H
|
#ifndef FENNEC_CONTAINERS_TUPLE_H
|
||||||
#define FENNEC_CONTAINERS_TUPLE_H
|
#define FENNEC_CONTAINERS_TUPLE_H
|
||||||
|
|
||||||
@@ -27,38 +39,68 @@ namespace fennec
|
|||||||
|
|
||||||
// TODO: Document
|
// TODO: Document
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Tuple, holds a collection of values of different types
|
||||||
|
/// \details
|
||||||
|
/// | Property | Value |
|
||||||
|
/// |:----------:|:----------:|
|
||||||
|
/// | stable | ⛔ |
|
||||||
|
/// | dynamic | ✅ |
|
||||||
|
/// | homogenous | ⛔ |
|
||||||
|
/// | distinct | ⛔ |
|
||||||
|
/// | ordered | ⛔ |
|
||||||
|
/// | space | \f$O(N)\f$ |
|
||||||
|
/// | linear | ✅ |
|
||||||
|
/// | access | \f$O(1)\f$ |
|
||||||
|
/// | find | \f$O(1)\f$ |
|
||||||
|
/// | insertion | ⛔ |
|
||||||
|
/// | deletion | ⛔ |
|
||||||
|
///
|
||||||
|
/// \tparam TypesT The types to store
|
||||||
template<typename...TypesT> struct tuple;
|
template<typename...TypesT> struct tuple;
|
||||||
|
|
||||||
|
|
||||||
template<size_t i, typename...TypesT>
|
template<size_t i, typename...TypesT>
|
||||||
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
||||||
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
auto& it = static_cast<detail::_tuple_leaf<i, elem_t>>(x);
|
auto& it = *static_cast<detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||||
return it;
|
return it.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t i, typename...TypesT>
|
template<size_t i, typename...TypesT>
|
||||||
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
|
||||||
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
auto& it = static_cast<detail::_tuple_leaf<i, elem_t>>(x);
|
const auto& it = *static_cast<const detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||||
return it;
|
return it.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename ...TypesT>
|
template<typename ...TypesT>
|
||||||
struct tuple : detail::_tuple<make_index_sequence<sizeof...(TypesT)>, TypesT...> {
|
struct tuple : public detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>
|
||||||
|
{
|
||||||
public:
|
using base_t = detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>;
|
||||||
using base_t = detail::_tuple<make_index_sequence<sizeof...(TypesT)>, TypesT...>;
|
|
||||||
|
|
||||||
template<size_t i>
|
template<size_t i>
|
||||||
using elem_t = nth_element<i, TypesT...>;
|
using elem_t = typename nth_element<i, TypesT...>::type;
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr tuple(ArgsT&&...args) : base_t(args...) {
|
tuple(ArgsT&&...args)
|
||||||
|
: base_t(fennec::forward<ArgsT>(args)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple(const tuple& cpy)
|
||||||
|
: base_t(cpy) {
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple(tuple&& cpy)
|
||||||
|
: base_t(cpy) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is needed for
|
||||||
|
template<typename...TypesT>
|
||||||
|
tuple(TypesT...) -> tuple<TypesT...>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_CONTAINERS_TUPLE_H
|
#endif // FENNEC_CONTAINERS_TUPLE_H
|
||||||
|
|||||||
34
include/fennec/containers/variant.h
Normal file
34
include/fennec/containers/variant.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file variant.h
|
||||||
|
/// \brief Contains the definition for a structure that holds a single value from multiple types
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_CONTAINERS_VARIANT_H
|
||||||
|
#define FENNEC_CONTAINERS_VARIANT_H
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_VARIANT_H
|
||||||
@@ -29,19 +29,25 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \page documentation Documentation
|
/// \page contents Contents
|
||||||
///
|
///
|
||||||
/// 1. \ref introduction "Introduction"
|
/// 1. \ref introduction "Introduction"
|
||||||
/// 1. \ref coding-standards "Coding Standards"
|
/// 1. \ref coding-standards "Coding Standards"
|
||||||
/// 2. \ref building-from-source "Building from Source"
|
/// 2. \ref building-from-source "Building from Source"
|
||||||
/// 1. \ref building-from-terminal "Building from Terminal"
|
/// 1. \ref building-from-terminal "Building from Terminal"
|
||||||
|
/// 1. \ref debian "Debian"
|
||||||
|
/// 2. \ref arch "Arch"
|
||||||
|
/// 3. \ref fedora "Fedora"
|
||||||
/// 2. \ref building-on-windows "Building on Windows"
|
/// 2. \ref building-on-windows "Building on Windows"
|
||||||
/// 3. \ref running-the-test-suite "Running the Test Suite"
|
/// 3. \ref running-the-test-suite "Running the Test Suite"
|
||||||
/// 4. \ref usage "Usage"
|
/// 4. \ref usage "Usage"
|
||||||
|
/// 1. \ref licensing "Licensing"
|
||||||
/// 5. \ref contribution "Contribution"
|
/// 5. \ref contribution "Contribution"
|
||||||
/// 6. \subpage libraries
|
/// 6. \subpage libraries
|
||||||
/// 1. \ref fennec_lang "C++ Language Library"
|
/// 1. \ref fennec_lang "C++ Language Library"
|
||||||
/// 2. \ref fennec_math "Math Library"
|
/// 2. \ref fennec_math "Math Library"
|
||||||
|
/// 2. \ref fennec_memory "Memory Management Library"
|
||||||
|
/// 2. \ref fennec_containers "Containers Library"
|
||||||
///
|
///
|
||||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
///
|
///
|
||||||
@@ -50,10 +56,15 @@
|
|||||||
/// \page libraries Libraries
|
/// \page libraries Libraries
|
||||||
///
|
///
|
||||||
/// | Library | Brief |
|
/// | Library | Brief |
|
||||||
/// | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
/// |:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
/// | \subpage fennec_lang | Implementation for functions and classes related to the C++ Language, including base types, common utility functions, and metaprogramming templates |
|
/// | \subpage fennec_lang | Implementation for functions and classes related to the C++ Language, including base types, common utility functions, and metaprogramming templates |
|
||||||
/// | \subpage fennec_math | Implementation of math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf). Additional extensions are provided for other common math functions. |
|
/// | \subpage fennec_math | Implementation of math functions according to the [OpenGL 4.6 Shading Language Specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf). Additional extensions are provided for other common math functions. |
|
||||||
/// | \subpage fennec_memory | Implementation of functions related to memory management. |
|
/// | \subpage fennec_memory | Implementation of functions related to memory management. |
|
||||||
|
/// | \subpage fennec_containers | Implementation of common data structures, those that are specified in the C++ STD Library, and custom data structures that fennec uses. |
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
|
||||||
#ifndef FENNEC_CORE_ENGINE_H
|
#ifndef FENNEC_CORE_ENGINE_H
|
||||||
#define FENNEC_CORE_ENGINE_H
|
#define FENNEC_CORE_ENGINE_H
|
||||||
|
|||||||
47
include/fennec/core/system.h
Normal file
47
include/fennec/core/system.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_CORE_SYSTEM_H
|
||||||
|
#define FENNEC_CORE_SYSTEM_H
|
||||||
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class system {
|
||||||
|
public:
|
||||||
|
using tick_f = void (*)(system*, double);
|
||||||
|
using frame_f = void (*)(system*, size_t);
|
||||||
|
|
||||||
|
const string name;
|
||||||
|
const tick_f tick;
|
||||||
|
const frame_f frame;
|
||||||
|
|
||||||
|
system(const cstring& name, tick_f tick, frame_f frame)
|
||||||
|
: name(name), tick(tick), frame(frame) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~system() = default;
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void shutdown() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CORE_SYSTEM_H
|
||||||
@@ -84,7 +84,7 @@ void _assert_impl(const char* expression, const char* file, int line, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FENNEC_RELEASE
|
#if FENNEC_RELEASE
|
||||||
#define assertd(expression, description) (0)
|
#define assertd(expression, description)
|
||||||
#else
|
#else
|
||||||
#define assertd(expression, description) assert(expression, description)
|
#define assertd(expression, description) assert(expression, description)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ namespace fennec
|
|||||||
/// \endcode
|
/// \endcode
|
||||||
/// \tparam ValueT type of the values
|
/// \tparam ValueT type of the values
|
||||||
/// \tparam Values sequence values
|
/// \tparam Values sequence values
|
||||||
template<typename ValueT, ValueT...Values> struct sequence
|
template<typename ValueT, ValueT...Values> struct const_sequence
|
||||||
{
|
{
|
||||||
/// \brief type of the sequence
|
/// \brief type of the sequence
|
||||||
using value_type = ValueT;
|
using value_type = ValueT;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = sequence;
|
using type = const_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \brief returns the number of elements
|
||||||
@@ -119,13 +119,13 @@ template<typename ValueT, ValueT...Values> struct sequence
|
|||||||
/// \tparam IntT type of the values, must satisfy ```fennec::is_integral<T>```
|
/// \tparam IntT type of the values, must satisfy ```fennec::is_integral<T>```
|
||||||
/// \tparam Values sequence values
|
/// \tparam Values sequence values
|
||||||
template<typename IntT, IntT...Values> requires(is_integral_v<IntT>)
|
template<typename IntT, IntT...Values> requires(is_integral_v<IntT>)
|
||||||
struct integer_sequence : sequence<IntT, Values...>
|
struct const_integer_sequence : const_sequence<IntT, Values...>
|
||||||
{
|
{
|
||||||
/// \brief type of the sequence
|
/// \brief type of the sequence
|
||||||
using value_type = IntT;
|
using value_type = IntT;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = integer_sequence;
|
using type = const_integer_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \brief returns the number of elements
|
||||||
@@ -158,13 +158,13 @@ template<typename IntT, size_t N> using make_integer_sequence_t = typename make
|
|||||||
///
|
///
|
||||||
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
|
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
|
||||||
/// \tparam Indices sequence values
|
/// \tparam Indices sequence values
|
||||||
template<size_t...Indices> struct index_sequence : integer_sequence<size_t, Indices...>
|
template<size_t...Indices> struct const_index_sequence : const_integer_sequence<size_t, Indices...>
|
||||||
{
|
{
|
||||||
/// \brief type of the sequence
|
/// \brief type of the sequence
|
||||||
using value_type = size_t;
|
using value_type = size_t;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = index_sequence;
|
using type = const_index_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \brief returns the number of elements
|
||||||
@@ -213,31 +213,31 @@ template<typename SequenceT0, typename SequenceT1> using concat_sequence_t
|
|||||||
template<typename T, size_t N> struct make_integer_sequence : concat_sequence_t<make_integer_sequence_t<T, N / 2>, make_integer_sequence_t<T, N - N / 2>>{};
|
template<typename T, size_t N> struct make_integer_sequence : concat_sequence_t<make_integer_sequence_t<T, N / 2>, make_integer_sequence_t<T, N - N / 2>>{};
|
||||||
|
|
||||||
// Base Case of N=0
|
// Base Case of N=0
|
||||||
template<typename T> struct make_integer_sequence<T, 0> : integer_sequence<T> {};
|
template<typename T> struct make_integer_sequence<T, 0> : const_integer_sequence<T> {};
|
||||||
|
|
||||||
// Base Case of N=1
|
// Base Case of N=1
|
||||||
template<typename T> struct make_integer_sequence<T, 1> : integer_sequence<T, 0>{};
|
template<typename T> struct make_integer_sequence<T, 1> : const_integer_sequence<T, 0>{};
|
||||||
|
|
||||||
|
|
||||||
// Implementation for Generating an index_sequence
|
// Implementation for Generating an index_sequence
|
||||||
template<size_t N> struct make_index_sequence : concat_sequence_t<make_index_sequence_t<N / 2>, make_index_sequence_t<N - N / 2>>{};
|
template<size_t N> struct make_index_sequence : concat_sequence_t<make_index_sequence_t<N / 2>, make_index_sequence_t<N - N / 2>>{};
|
||||||
|
|
||||||
// Base Case of N=0
|
// Base Case of N=0
|
||||||
template<> struct make_index_sequence<0> : index_sequence<> {};
|
template<> struct make_index_sequence<0> : const_index_sequence<> {};
|
||||||
|
|
||||||
// Base Case of N=1
|
// Base Case of N=1
|
||||||
template<> struct make_index_sequence<1> : index_sequence<0>{};
|
template<> struct make_index_sequence<1> : const_index_sequence<0>{};
|
||||||
|
|
||||||
|
|
||||||
// Specialization for integer sequences
|
// Specialization for integer sequences
|
||||||
template<typename T, T...SequenceV0, T...SequenceV1>
|
template<typename T, T...SequenceV0, T...SequenceV1>
|
||||||
struct concat_sequence<integer_sequence<T, SequenceV0...>, integer_sequence<T, SequenceV1...>>
|
struct concat_sequence<const_integer_sequence<T, SequenceV0...>, const_integer_sequence<T, SequenceV1...>>
|
||||||
: integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
: const_integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
// Specialization for index sequences
|
// Specialization for index sequences
|
||||||
template<size_t...SequenceV0, size_t...SequenceV1>
|
template<size_t...SequenceV0, size_t...SequenceV1>
|
||||||
struct concat_sequence<index_sequence<SequenceV0...>, index_sequence<SequenceV1...>>
|
struct concat_sequence<const_index_sequence<SequenceV0...>, const_index_sequence<SequenceV1...>>
|
||||||
: index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
: const_index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -26,6 +26,8 @@
|
|||||||
#define __PTRDIFF_TYPE__ ptrdiff_t
|
#define __PTRDIFF_TYPE__ ptrdiff_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Include math since stdint will define its own versions of isinf and isnan
|
||||||
|
#include <math.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ namespace fennec::detail
|
|||||||
|
|
||||||
template<size_t n, size_t i, typename HeadT, typename...RestT>
|
template<size_t n, size_t i, typename HeadT, typename...RestT>
|
||||||
struct _nth_element<n, i, HeadT, RestT...> : conditional<
|
struct _nth_element<n, i, HeadT, RestT...> : conditional<
|
||||||
n == i, type_identity<HeadT>,
|
n == i, HeadT,
|
||||||
_nth_element<n, i + 1, RestT...>
|
typename _nth_element<n, i + 1, RestT...>::type
|
||||||
> {};
|
> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ namespace fennec
|
|||||||
using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type
|
using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type
|
||||||
using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof`
|
using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof`
|
||||||
using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers
|
using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers
|
||||||
|
struct empty_t {};
|
||||||
|
|
||||||
|
|
||||||
class undefined_t; ///< \brief undefined class for SFINAE
|
class undefined_t; ///< \brief undefined class for SFINAE
|
||||||
|
|||||||
@@ -42,6 +42,22 @@ FENNEC_NO_INLINE uint64_t typeuuid() {
|
|||||||
return id = detail::_typeuuid<RootT>();
|
return id = detail::_typeuuid<RootT>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename RootT = void>
|
||||||
|
struct typed {
|
||||||
|
public:
|
||||||
|
const uint64_t type;
|
||||||
|
|
||||||
|
template<typename TypeT>
|
||||||
|
bool is_type() const {
|
||||||
|
return type == typeuuid<TypeT, RootT>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeT>
|
||||||
|
typed(TypeT*)
|
||||||
|
: type(typeuuid<TypeT, RootT>()) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_LANG_TYPEUUID_H
|
#endif // FENNEC_LANG_TYPEUUID_H
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_IO_FILE_H
|
#ifndef FENNEC_LANGPROC_IO_FILE_H
|
||||||
#define FENNEC_FPROC_IO_FILE_H
|
#define FENNEC_LANGPROC_IO_FILE_H
|
||||||
|
|
||||||
#include <fennec/fproc/filesystem/path.h>
|
#include <fennec/langproc/filesystem/path.h>
|
||||||
|
|
||||||
#include <fennec/fproc/strings/cstring.h>
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
#include <fennec/fproc/strings/wstring.h>
|
#include <fennec/langproc/strings/wstring.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -34,7 +34,7 @@ namespace fennec
|
|||||||
/// fmode_binary and fmode_wide are independent of the other modes
|
/// fmode_binary and fmode_wide are independent of the other modes
|
||||||
///
|
///
|
||||||
/// \details Valid Flag Combinations
|
/// \details Valid Flag Combinations
|
||||||
/// <table width="100%" class="fieldtable" id="table_fennec_fproc_io_fmode">
|
/// <table width="100%" class="fieldtable" id="table_fennec_LANGPROC_io_fmode">
|
||||||
/// <tr><th style="vertical-align: top">Flags
|
/// <tr><th style="vertical-align: top">Flags
|
||||||
/// <th style="vertical-align: top">Description
|
/// <th style="vertical-align: top">Description
|
||||||
///
|
///
|
||||||
@@ -248,7 +248,7 @@ public:
|
|||||||
bool eof() const;
|
bool eof() const;
|
||||||
|
|
||||||
|
|
||||||
// Read Operations =====================================================================================================
|
// Binary Read Operations ==============================================================================================
|
||||||
|
|
||||||
char getc();
|
char getc();
|
||||||
wchar_t getwc();
|
wchar_t getwc();
|
||||||
@@ -269,13 +269,23 @@ public:
|
|||||||
wstring getwline();
|
wstring getwline();
|
||||||
|
|
||||||
|
|
||||||
// Write Operations ====================================================================================================
|
// Binary Write Operations =============================================================================================
|
||||||
|
|
||||||
bool putc(char c);
|
bool putc(char c);
|
||||||
bool putwc(wchar_t c);
|
bool putwc(wchar_t c);
|
||||||
|
|
||||||
size_t write(const void* data, size_t size, size_t n);
|
size_t write(const void* data, size_t size, size_t n);
|
||||||
|
|
||||||
|
template<size_t n>
|
||||||
|
size_t write(const char (&data)[n]) {
|
||||||
|
return write(data, sizeof(char), n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t n>
|
||||||
|
size_t write(const wchar_t (&data)[n]) {
|
||||||
|
return write(data, sizeof(wchar_t), n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_t write(const T* data, size_t n) {
|
size_t write(const T* data, size_t n) {
|
||||||
return write(static_cast<const void*>(data), sizeof(T), n);
|
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||||
@@ -287,6 +297,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Printing Operations =================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Error Handling ======================================================================================================
|
// Error Handling ======================================================================================================
|
||||||
|
|
||||||
const char* get_error() const { return _error; }
|
const char* get_error() const { return _error; }
|
||||||
@@ -301,4 +316,4 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_IO_FILE_H
|
#endif // FENNEC_LANGPROC_IO_FILE_H
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_IO_PATH_H
|
#ifndef FENNEC_LANGPROC_IO_PATH_H
|
||||||
#define FENNEC_FPROC_IO_PATH_H
|
#define FENNEC_LANGPROC_IO_PATH_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
/// \param str the cstring to convert
|
/// \param str the cstring to convert
|
||||||
path(const cstring& str)
|
path(const cstring& str)
|
||||||
: _str(str) {
|
: _str(str) {
|
||||||
while (not _str.empty() && _str[_str.size() - 1] == '/') {
|
if (str.size() > 2 && str[str.size() - 1] == '/') {
|
||||||
_str = _str.substring(0, str.size() - 1);
|
_str = _str.substring(0, str.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
/// \param str the string to convert
|
/// \param str the string to convert
|
||||||
path(const string& str)
|
path(const string& str)
|
||||||
: _str(str) {
|
: _str(str) {
|
||||||
while (_str[_str.size() - 1] == '/') {
|
if (str.size() > 2 && str[str.size() - 1] == '/') {
|
||||||
_str = _str.substring(0, str.size() - 1);
|
_str = _str.substring(0, str.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +85,16 @@ public:
|
|||||||
|
|
||||||
// Assignment Operators ================================================================================================
|
// Assignment Operators ================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief C-String Assignment Operator
|
||||||
|
/// \param str the cstring to assign
|
||||||
|
/// \returns a reference to `this` after assigning `p`
|
||||||
|
template<size_t n>
|
||||||
|
path& operator=(const char (&str)[n]) {
|
||||||
|
_str = str;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief C-String Assignment Operator
|
/// \brief C-String Assignment Operator
|
||||||
/// \param p the cstring to assign
|
/// \param p the cstring to assign
|
||||||
@@ -145,6 +155,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const string& str() const { return _str; }
|
const string& str() const { return _str; }
|
||||||
|
const char* cstr() const { return _str.cstr(); }
|
||||||
|
|
||||||
bool empty() {
|
bool empty() {
|
||||||
size_t size = _str.size();
|
size_t size = _str.size();
|
||||||
@@ -176,7 +187,7 @@ public:
|
|||||||
#else
|
#else
|
||||||
size_t start = _str.size() - 1;
|
size_t start = _str.size() - 1;
|
||||||
start = _str[start] == '/' ? start - 1 : start;
|
start = _str[start] == '/' ? start - 1 : start;
|
||||||
return _str.substring(0, _str.rfind('/', start));
|
return path(_str.substring(0, _str.rfind('/', start)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +206,7 @@ public:
|
|||||||
|
|
||||||
while (not parse.empty()) {
|
while (not parse.empty()) {
|
||||||
// Handle dots
|
// Handle dots
|
||||||
while (parse._str[0] == '.') {
|
while (not parse.empty() && parse._str[0] == '.') {
|
||||||
// Check for ".."
|
// Check for ".."
|
||||||
if (parse._str[1] == '.') {
|
if (parse._str[1] == '.') {
|
||||||
// ".."
|
// ".."
|
||||||
@@ -233,4 +244,4 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_IO_PATH_H
|
#endif // FENNEC_LANGPROC_IO_PATH_H
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_CSTRING_H
|
#ifndef FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
#define FENNEC_FPROC_STRINGS_CSTRING_H
|
#define FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/detail/_ctype.h>
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
#include <fennec/memory/detail/_string.h>
|
#include <fennec/memory/detail/_string.h>
|
||||||
|
|
||||||
#include <fennec/lang/assert.h>
|
#include <fennec/lang/assert.h>
|
||||||
@@ -171,6 +171,10 @@ public:
|
|||||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||||
constexpr size_t size() const { return _size; }
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
||||||
|
constexpr size_t capacity() const { return _size + 1; }
|
||||||
|
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return _cstr == nullptr || _size == 0;
|
return _cstr == nullptr || _size == 0;
|
||||||
}
|
}
|
||||||
@@ -198,9 +202,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Dereference Operator
|
/// \brief Data Access
|
||||||
/// \returns A const qualified pointer to the underlying allocation
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
constexpr const char* operator*() const {
|
constexpr char* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr const char* data() const {
|
||||||
return _cstr;
|
return _cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,11 +341,11 @@ private:
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct hash<cstring> : hash<byte_array> {
|
struct hash<cstring> : hash<byte_array> {
|
||||||
constexpr size_t operator()(const cstring& str) {
|
constexpr size_t operator()(const cstring& str) const {
|
||||||
return hash<byte_array>::operator()(byte_array(*str, str.size()));
|
return hash<byte_array>::operator()(byte_array(str, str.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_CSTRING_H
|
#endif // FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
|
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_LOCALE_H
|
#ifndef FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
#define FENNEC_FPROC_STRINGS_LOCALE_H
|
#define FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/detail/_locale.h>
|
#include <fennec/langproc/strings/detail/_locale.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -41,4 +41,4 @@ using ::localeconv;
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_LOCALE_H
|
#endif // FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_STRING_H
|
#ifndef FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
#define FENNEC_FPROC_STRINGS_STRING_H
|
#define FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/detail/_ctype.h>
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
#include <fennec/fproc/strings/cstring.h>
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
|
|
||||||
#include <fennec/lang/assert.h>
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
@@ -59,81 +59,104 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
|
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
||||||
/// \param n the number of characters
|
/// \param n the number of characters
|
||||||
///
|
|
||||||
/// \details adds additional character for null termination.
|
|
||||||
constexpr _string(size_t n)
|
|
||||||
: _string('\0', n) {
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` filled with the character `c`
|
|
||||||
/// \param c the character to fill with
|
/// \param c the character to fill with
|
||||||
/// \param n the number of characters
|
|
||||||
///
|
///
|
||||||
/// \details adds additional character for null termination.
|
/// \details adds additional character for null termination.
|
||||||
constexpr _string(char c, size_t n)
|
constexpr _string(size_t n, char c = '\0')
|
||||||
: _str(n + 1) {
|
: _str(n + 1) {
|
||||||
fennec::memset(_str.data(), c, n);
|
fennec::memset(_str, c, n);
|
||||||
_str[n] = '\0';
|
}
|
||||||
|
|
||||||
|
constexpr _string(const alloc_t& alloc)
|
||||||
|
: _str(alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string(size_t n, char c, const alloc_t& alloc)
|
||||||
|
: _str(n + 1, alloc) {
|
||||||
|
fennec::memset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string(const cstring& cstr)
|
||||||
|
: _str(cstr, cstr.size() + 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Buffer Copy Constructor
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
/// \param str the buffer to copy
|
/// \param str the buffer to wrap
|
||||||
/// \param n number of characters in the buffer
|
/// \tparam n the number of characters in the buffer including the null-terminator, if present
|
||||||
///
|
template<size_t n>
|
||||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
explicit constexpr _string(const char (&str)[n])
|
||||||
/// This constructor makes the assumption that `n` is the intended number of characters.
|
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||||
constexpr _string(const char* str, size_t n)
|
fennec::memcpy(_str, str, n);
|
||||||
: _str(n + 1) {
|
if (str[n - 1] != '\0') {
|
||||||
fennec::memcpy(_str.data(), str, n);
|
|
||||||
_str[n] = '\0';
|
_str[n] = '\0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Buffer Copy Constructor
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
/// \param str the buffer to copy
|
/// \param str the buffer to wrap
|
||||||
constexpr _string(const cstring& str)
|
/// \param n the number of characters in the buffer including the null-terminator, if present
|
||||||
: _str(str, str.size() + 1) {
|
constexpr _string(const char* buf, size_t n)
|
||||||
|
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
||||||
|
fennec::memcpy(_str, buf, n);
|
||||||
|
if (buf[n - 1] != '\0') {
|
||||||
|
_str[n] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Copy Constructor
|
/// \brief String Copy Constructor
|
||||||
/// \param str the string to copy
|
/// \param str the string to copy
|
||||||
constexpr _string(const _string& str)
|
constexpr _string(const _string& str) = default;
|
||||||
: _str(str._str) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr _string(_string&& str) noexcept
|
|
||||||
: _str(fennec::move(str._str)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Destructor, cleans up the underlying allocation
|
/// \brief String Move Constructor
|
||||||
constexpr ~_string() = default; // allocation cleans up itself
|
/// \param str the string to take ownership of
|
||||||
|
constexpr _string(_string&& str) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, cleans up underlying allocation
|
||||||
|
constexpr ~_string() = default;
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
constexpr _string& operator=(const cstring& cstr) {
|
||||||
|
_str.callocate(cstr.capacity());
|
||||||
|
fennec::memcpy(_str, cstr, cstr.capacity());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string& operator=(const _string& str) = default;
|
||||||
|
constexpr _string& operator=(_string&& str) noexcept = default;
|
||||||
|
|
||||||
// Properties ==========================================================================================================
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \returns The size of the string excluding null terminator
|
/// \returns The size of the string excluding null terminator
|
||||||
constexpr size_t size() const {
|
constexpr size_t size() const {
|
||||||
return _str.capacity() - 1;
|
return _str.capacity() > 0 ? _str.capacity() - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string including null terminator
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _str.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return size() == 0;
|
return size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Access ==============================================================================================================
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Array Access Operator
|
/// \brief Array Access Operator
|
||||||
/// \param i the index to access
|
/// \param i the index to access
|
||||||
/// \returns a reference to the character
|
/// \returns a reference to the character
|
||||||
constexpr char& operator[](int i) {
|
constexpr char& operator[](size_t i) {
|
||||||
return _str[i];
|
return _str[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,24 +164,21 @@ public:
|
|||||||
/// \brief Const-Array Access Operator
|
/// \brief Const-Array Access Operator
|
||||||
/// \param i the index to access
|
/// \param i the index to access
|
||||||
/// \returns a copy of the character
|
/// \returns a copy of the character
|
||||||
constexpr char operator[](int i) const {
|
constexpr const char& operator[](size_t i) const {
|
||||||
assertd(i >= 0 && (size_t)i < size(), "Array Out of Bounds");
|
|
||||||
return _str[i];
|
return _str[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
constexpr char* data() {
|
||||||
/// \brief Dereference Operator
|
return _str;
|
||||||
/// \returns A const qualified pointer to the underlying allocation
|
|
||||||
constexpr const char* operator*() const {
|
|
||||||
return _str.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
constexpr const char* data() const {
|
||||||
/// \brief Implicit Dereference Cast
|
return _str;
|
||||||
constexpr operator const char*() const {
|
|
||||||
return _str.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr const char* cstr() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
// Examination =========================================================================================================
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
@@ -179,7 +199,7 @@ public:
|
|||||||
}
|
}
|
||||||
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||||
|
|
||||||
return ::strncmp(_str.data() + i, str, n);
|
return ::strncmp(_str + i, str, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -193,7 +213,7 @@ public:
|
|||||||
}
|
}
|
||||||
n = min(n, max(size(), str.size()) + 1);
|
n = min(n, max(size(), str.size()) + 1);
|
||||||
|
|
||||||
return ::strncmp(_str.data() + i, str, n);
|
return ::strncmp(_str + i, str.data(), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const _string& str) const {
|
constexpr bool operator==(const _string& str) const {
|
||||||
@@ -209,8 +229,8 @@ public:
|
|||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* loc = ::strchr(_str.data() + i, c); // get location using strchr
|
const char* loc = ::strchr(_str + i, c); // get location using strchr
|
||||||
return loc ? loc - _str.data() : size(); // return size if not found
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -299,63 +319,6 @@ public:
|
|||||||
return size(); // base case
|
return size(); // base case
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manipulation ========================================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Resize the string, filling additional bytes with `'\0'`
|
|
||||||
/// \param n the new size of the string
|
|
||||||
constexpr void resize(size_t n) {
|
|
||||||
size_t i = size();
|
|
||||||
_str.reallocate(n + 1);
|
|
||||||
if (n > i) fennec::memset(_str.data() + i, '\0', n + 1 - i);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Copy Assignment Operator
|
|
||||||
/// \param str the string to copy
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr _string& operator=(const cstring& str) {
|
|
||||||
if (str.empty()) {
|
|
||||||
_str.deallocate();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
resize(str.size());
|
|
||||||
fennec::memcpy(_str.data(), str, str.size());
|
|
||||||
_str[str.size()] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Copy Assignment Operator
|
|
||||||
/// \param str the string to copy
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr _string& operator=(const string& str) {
|
|
||||||
resize(str.size());
|
|
||||||
fennec::memcpy(_str.data(), str, str.size());
|
|
||||||
_str[str.size()] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Move Assignment Operator
|
|
||||||
/// \param str the string to move
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr _string& operator=(string&& str) noexcept {
|
|
||||||
_str = move(str._str);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Replace all instances of `x` with `y`
|
|
||||||
/// \param x the character to search for
|
|
||||||
/// \param y the character to replace with
|
|
||||||
void replace(char x, char y) {
|
|
||||||
size_t i = 0;
|
|
||||||
while ((i = find(x, 0)) != size()) {
|
|
||||||
_str[i] = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Retrieve a substring of a string
|
/// \brief Retrieve a substring of a string
|
||||||
/// \param i the start index
|
/// \param i the start index
|
||||||
@@ -365,59 +328,97 @@ public:
|
|||||||
if (i >= size()) {
|
if (i >= size()) {
|
||||||
return _string("");
|
return _string("");
|
||||||
}
|
}
|
||||||
n = min(n, size() - i);
|
n = fennec::min(n, size() - i);
|
||||||
return _string(_str.data() + i, n);
|
_string res;
|
||||||
}
|
res._str.callocate(n + 1);
|
||||||
|
fennec::memcpy(res.data(), _str + i, n);
|
||||||
///
|
|
||||||
/// \brief Returns a string with `c` appended to it
|
|
||||||
/// \param c
|
|
||||||
/// \returns
|
|
||||||
constexpr _string operator+(char c) const {
|
|
||||||
// Copy contents with one additional byte.
|
|
||||||
_string res(_str.data(), _str.size());
|
|
||||||
res[size()] = c; // Set the last character to c
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend constexpr _string operator+(char c, _string& str) {
|
|
||||||
return _string(c, 1) + str;
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_str.creallocate(n + 1);
|
||||||
|
_str[size()] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr _string operator+(const cstring& str) const {
|
constexpr _string operator+(char c) const {
|
||||||
_string res(size() + str.size()); // Make a new string with the size of this + str
|
if (_str == nullptr) {
|
||||||
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
return _string(1, c);
|
||||||
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(capacity() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
res[size()] = c;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr _string operator+(char c, const _string& str) {
|
||||||
|
_string res(1, c);
|
||||||
|
return res += str;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _string operator+(const cstring& cstr) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _string(cstr);
|
||||||
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(size() + cstr.size() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
fennec::memcpy(res.data() + size(), cstr, cstr.size());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr _string operator+(const _string& str) const {
|
constexpr _string operator+(const _string& str) const {
|
||||||
_string res(size() + str.size()); // Make a new string with the size of this + str
|
if (_str == nullptr) {
|
||||||
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
return _string(str);
|
||||||
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return _string(*this);
|
||||||
|
}
|
||||||
|
_string res;
|
||||||
|
res._str.callocate(size() + str.size() + 1);
|
||||||
|
fennec::memcpy(res.data(), _str, size());
|
||||||
|
fennec::memcpy(res.data() + size(), str.data(), str.size());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr _string& operator+=(char c) {
|
constexpr _string& operator+=(char c) {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + 1);
|
_str.callocate(2);
|
||||||
_str[x] = c;
|
_str[0] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
_str.creallocate(capacity() + 1);
|
||||||
|
_str[size() - 1] = c;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr _string& operator+=(const cstring& str) {
|
constexpr _string& operator+=(const cstring& cstr) {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + str.size());
|
return *this = cstr;
|
||||||
fennec::memcpy(&_str[x], str, str.size());
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + cstr.size() + 1);
|
||||||
|
fennec::memcpy(_str + middle, cstr, cstr.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr _string& operator+=(const _string& str) {
|
constexpr _string& operator+=(const _string& str) {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + str.size());
|
return *this = str;
|
||||||
fennec::memcpy(&_str[x], str, str.size());
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + str.size() + 1);
|
||||||
|
fennec::memcpy(_str + middle, str.data(), str.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alloc_t _str;
|
alloc_t _str;
|
||||||
@@ -426,11 +427,11 @@ private:
|
|||||||
template<>
|
template<>
|
||||||
struct hash<string> : hash<byte_array> {
|
struct hash<string> : hash<byte_array> {
|
||||||
constexpr size_t operator()(const string& str) const {
|
constexpr size_t operator()(const string& str) const {
|
||||||
return hash<byte_array>::operator()(byte_array(*str, str.size()));
|
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_STRING_H
|
#endif // FENNEC_LANGPROC_STRINGS_STRING_H
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_STRINGS_wcstring_H
|
#ifndef FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
#define FENNEC_FPROC_STRINGS_wcstring_H
|
#define FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/detail/_ctype.h>
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
#include <fennec/memory/detail/_string.h>
|
#include <fennec/memory/detail/_string.h>
|
||||||
|
|
||||||
#include <fennec/lang/assert.h>
|
#include <fennec/lang/assert.h>
|
||||||
@@ -66,9 +66,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// \brief Default Constructor, initializes with nullptr
|
/// \brief Default Constructor, initializes with nullptr
|
||||||
constexpr wcstring()
|
constexpr wcstring()
|
||||||
: _str(nullptr)
|
: _str(nullptr), _size(0), _const(true) {
|
||||||
, _size(0)
|
|
||||||
, _const(true) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -148,7 +146,7 @@ public:
|
|||||||
template<size_t n>
|
template<size_t n>
|
||||||
constexpr wcstring& operator=(wchar_t(&str)[n]) {
|
constexpr wcstring& operator=(wchar_t(&str)[n]) {
|
||||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
_str = str; _size = n - 1; _const = false;
|
_str = str, _size = n - 1, _const = false;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +173,10 @@ public:
|
|||||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||||
constexpr size_t size() const { return _size; }
|
constexpr size_t size() const { return _size; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
||||||
|
constexpr size_t capacity() const { return _size + 1; }
|
||||||
|
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return _cstr == nullptr || _size == 0;
|
return _cstr == nullptr || _size == 0;
|
||||||
}
|
}
|
||||||
@@ -196,15 +198,22 @@ public:
|
|||||||
/// \brief Const-Array Access Operator
|
/// \brief Const-Array Access Operator
|
||||||
/// \param i the index to access
|
/// \param i the index to access
|
||||||
/// \returns a copy of the character
|
/// \returns a copy of the character
|
||||||
constexpr wchar_t operator[](size_t i) const {
|
constexpr const wchar_t& operator[](size_t i) const {
|
||||||
assertd(i < size(), "Array Out of Bounds");
|
assertd(i < size(), "Array Out of Bounds");
|
||||||
return _cstr[i];
|
return _cstr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Dereference Operator
|
/// \brief Data Access
|
||||||
/// \returns A const qualified pointer to the underlying allocation
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
constexpr const wchar_t* operator*() const {
|
constexpr wchar_t* data() {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Data Access
|
||||||
|
/// \returns A const qualified pointer to the underlying allocation
|
||||||
|
constexpr const wchar_t* data() const {
|
||||||
return _cstr;
|
return _cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,12 +229,14 @@ public:
|
|||||||
///
|
///
|
||||||
/// \returns The length of the string to the first null-terminator
|
/// \returns The length of the string to the first null-terminator
|
||||||
constexpr size_t length() const {
|
constexpr size_t length() const {
|
||||||
return find(L'\0');
|
return find('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Comparison
|
/// \brief String Comparison
|
||||||
/// \param str the string to compare against
|
/// \param str the string to compare against
|
||||||
|
/// \param i the index to start at
|
||||||
|
/// \param n the number of characters to compare
|
||||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
/// current locale, otherwise a positive value.
|
/// current locale, otherwise a positive value.
|
||||||
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
@@ -237,6 +248,15 @@ public:
|
|||||||
return ::wcsncmp(_cstr + i, str, n);
|
return ::wcsncmp(_cstr + i, str, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief String Equality
|
||||||
|
/// \param str the string to compare against
|
||||||
|
/// \returns True if all characters are equal, false otherwise
|
||||||
|
template<size_t n>
|
||||||
|
constexpr bool operator==(const wchar_t (&str)[n]) const {
|
||||||
|
return compare(wcstring(str)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Equality
|
/// \brief String Equality
|
||||||
/// \param str the string to compare against
|
/// \param str the string to compare against
|
||||||
@@ -278,7 +298,7 @@ public:
|
|||||||
/// \param c the string to find
|
/// \param c the string to find
|
||||||
/// \param i the index to start at
|
/// \param i the index to start at
|
||||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
constexpr size_t rfind(wchar_t c, size_t i = npos) const {
|
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||||
if (_size == 0) {
|
if (_size == 0) {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
@@ -300,7 +320,7 @@ public:
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t first = str[0];
|
const char first = str[0];
|
||||||
i = min(i, _size - str._size);
|
i = min(i, _size - str._size);
|
||||||
do {
|
do {
|
||||||
if(_cstr[i] == first) {
|
if(_cstr[i] == first) {
|
||||||
@@ -321,6 +341,13 @@ private:
|
|||||||
bool _const;
|
bool _const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<wcstring> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const wcstring& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str, str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_STRINGS_wcstring_H
|
#endif // FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef FENNEC_FPROC_wstringS_wstring_H
|
#ifndef FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
#define FENNEC_FPROC_wstringS_wstring_H
|
#define FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/detail/_ctype.h>
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||||
#include <fennec/fproc/strings/wcstring.h>
|
#include <fennec/langproc/strings/wcstring.h>
|
||||||
|
|
||||||
#include <fennec/lang/assert.h>
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
@@ -59,110 +59,126 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
|
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
||||||
/// \param n the number of characters
|
/// \param n the number of wchar_tacters
|
||||||
|
/// \param c the wchar_tacter to fill with
|
||||||
///
|
///
|
||||||
/// \details adds additional character for null termination.
|
/// \details adds additional wchar_tacter for null termination.
|
||||||
constexpr _wstring(size_t n)
|
constexpr _wstring(size_t n, wchar_t c = '\0')
|
||||||
: _wstring('\0', n) {
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` filled with the character `c`
|
|
||||||
/// \param c the characters to fill with
|
|
||||||
/// \param n the number of characters
|
|
||||||
///
|
|
||||||
/// \details adds additional character for null termination.
|
|
||||||
constexpr _wstring(wchar_t c, size_t n)
|
|
||||||
: _str(n + 1) {
|
: _str(n + 1) {
|
||||||
fennec::wmemset(_str.data(), c, n); _str[n] = '\0';
|
fennec::wmemset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(const alloc_t& alloc)
|
||||||
|
: _str(alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(size_t n, wchar_t c, const alloc_t& alloc)
|
||||||
|
: _str(n + 1, alloc) {
|
||||||
|
fennec::wmemset(_str, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring(const wcstring& cstr)
|
||||||
|
: _str(cstr, cstr.size() + 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Buffer Copy Constructor
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
/// \param str the buffer to copy
|
/// \param str the buffer to wrap
|
||||||
/// \param len number of characters in the buffer
|
/// \tparam n the number of wchar_tacters in the buffer including the null-terminator, if present
|
||||||
///
|
template<size_t n>
|
||||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
explicit constexpr _wstring(const wchar_t (&str)[n])
|
||||||
/// This constructor makes the assumption that `len` is the intended number of characters.
|
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||||
constexpr _wstring(const wchar_t* str, size_t n)
|
fennec::wmemcpy(_str, str, n);
|
||||||
: _str(str, n + 1) {
|
if (str[n - 1] != '\0') {
|
||||||
::wcsncpy(_str.data(), str, n);
|
|
||||||
_str[n] = '\0';
|
_str[n] = '\0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Buffer Copy Constructor
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||||
/// \param str the buffer to copy
|
/// \param str the buffer to wrap
|
||||||
/// \param len number of characters in the buffer
|
/// \param n the number of wchar_tacters in the buffer including the null-terminator, if present
|
||||||
///
|
constexpr _wstring(const wchar_t* buf, size_t n)
|
||||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
||||||
/// This constructor makes the assumption that `len` is the intended number of characters.
|
fennec::wmemcpy(_str, buf, n);
|
||||||
constexpr _wstring(const wcstring& str)
|
if (buf[n - 1] != '\0') {
|
||||||
: _str(str, str.size() + 1) {
|
_str[n] = '\0';
|
||||||
_str[str.size()] = '\0';
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Copy Constructor
|
/// \brief String Copy Constructor
|
||||||
/// \param str the string to copy
|
/// \param str the string to copy
|
||||||
constexpr _wstring(const wstring& str)
|
constexpr _wstring(const _wstring& str) = default;
|
||||||
: _wstring(str, str.size() - 1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr _wstring(_wstring&& str) noexcept
|
|
||||||
: _str(fennec::move(str._str)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Destructor, cleans up the underlying allocation
|
/// \brief String Move Constructor
|
||||||
constexpr ~_wstring() = default; // allocation cleans up itself
|
/// \param str the string to take ownership of
|
||||||
|
constexpr _wstring(_wstring&& str) noexcept = default;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Destructor, cleans up underlying allocation
|
||||||
|
constexpr ~_wstring() = default;
|
||||||
|
|
||||||
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
|
constexpr _wstring& operator=(const wcstring& cstr) {
|
||||||
|
_str.callocate(cstr.capacity());
|
||||||
|
fennec::wmemcpy(_str, cstr, cstr.capacity());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator=(const _wstring& str) = default;
|
||||||
|
constexpr _wstring& operator=(_wstring&& str) noexcept = default;
|
||||||
|
|
||||||
// Properties ==========================================================================================================
|
// Properties ==========================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \returns The size of the string excluding null terminator
|
/// \returns The size of the string excluding null terminator
|
||||||
constexpr size_t size() const {
|
constexpr size_t size() const {
|
||||||
return _str.capacity() - 1;
|
return _str.capacity() > 0 ? _str.capacity() - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The size of the string including null terminator
|
||||||
|
constexpr size_t capacity() const {
|
||||||
|
return _str.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return size() == 0;
|
return size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Access ==============================================================================================================
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Array Access Operator
|
/// \brief Array Access Operator
|
||||||
/// \param i the index to access
|
/// \param i the index to access
|
||||||
/// \returns a reference to the character
|
/// \returns a reference to the wchar_tacter
|
||||||
constexpr wchar_t& operator[](int i) {
|
constexpr wchar_t& operator[](size_t i) {
|
||||||
return _str[i];
|
return _str[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Const-Array Access Operator
|
/// \brief Const-Array Access Operator
|
||||||
/// \param i the index to access
|
/// \param i the index to access
|
||||||
/// \returns a copy of the character
|
/// \returns a copy of the wchar_tacter
|
||||||
constexpr wchar_t operator[](int i) const {
|
constexpr const wchar_t& operator[](size_t i) const {
|
||||||
assertd(i >= 0 && i < size(), "Array Out of Bounds");
|
|
||||||
return _str[i];
|
return _str[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
constexpr wchar_t* data() {
|
||||||
/// \brief Dereference Operator
|
return _str;
|
||||||
/// \returns A const qualified pointer to the underlying allocation
|
|
||||||
constexpr const wchar_t* operator*() const {
|
|
||||||
return _str.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
constexpr const wchar_t* data() const {
|
||||||
/// \brief Implicit Dereference Cast
|
return _str;
|
||||||
constexpr operator const wchar_t*() const {
|
|
||||||
return _str.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr const wchar_t* cstr() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
// Examination =========================================================================================================
|
// Examination =========================================================================================================
|
||||||
|
|
||||||
@@ -183,7 +199,7 @@ public:
|
|||||||
}
|
}
|
||||||
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||||
|
|
||||||
return ::wcsncmp(_str.data() + i, str, n);
|
return ::wcsncmp(_str + i, str, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -191,13 +207,13 @@ public:
|
|||||||
/// \param ostr the string to compare against
|
/// \param ostr the string to compare against
|
||||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||||
/// current locale, otherwise a positive value.
|
/// current locale, otherwise a positive value.
|
||||||
constexpr int compare(const wstring& str, size_t i = 0, size_t n = npos) const {
|
constexpr int compare(const _wstring& str, size_t i = 0, size_t n = npos) const {
|
||||||
if (i >= size()) { // bounds check
|
if (i >= size()) { // bounds check
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = min(n, max(size(), str.size()) + 1);
|
n = min(n, max(size(), str.size()) + 1);
|
||||||
|
|
||||||
return ::wcsncmp(_str.data() + i, str, n);
|
return ::wcsncmp(_str + i, str.data(), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const _wstring& str) const {
|
constexpr bool operator==(const _wstring& str) const {
|
||||||
@@ -206,22 +222,22 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Finds the index of the first occurrence of `c` in the string
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||||
/// \param c the character to find
|
/// \param c the wchar_tacter to find
|
||||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||||
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
||||||
if (i >= size()) { // bounds check
|
if (i >= size()) { // bounds check
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t* loc = ::wcschr(_str.data() + i, c); // get location using strchr
|
const wchar_t* loc = ::wcschr(_str + i, c); // get location using strchr
|
||||||
return loc ? loc - _str.data() : size(); // return size if not found
|
return loc ? loc - _str : size(); // return size if not found
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Finds the index of the first occurrence of `str` in the string.
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||||
/// \param str the string to find
|
/// \param str the string to find
|
||||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
constexpr size_t find(const wstring& str, size_t i = 0) const { // bounds check
|
constexpr size_t find(const _wstring& str, size_t i = 0) const { // bounds check
|
||||||
if (i >= size()) { // bounds check
|
if (i >= size()) { // bounds check
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
@@ -287,7 +303,7 @@ public:
|
|||||||
/// \param str the string to find
|
/// \param str the string to find
|
||||||
/// \param i the index to start at
|
/// \param i the index to start at
|
||||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||||
constexpr size_t rfind(const wstring& str, size_t i = npos) const {
|
constexpr size_t rfind(const string& str, size_t i = npos) const {
|
||||||
if (size() == 0) {
|
if (size() == 0) {
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
@@ -303,116 +319,119 @@ public:
|
|||||||
return size(); // base case
|
return size(); // base case
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manipulation ========================================================================================================
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Resize the string, filling additional bytes with `'\0'`
|
|
||||||
/// \param n the new size of the string
|
|
||||||
constexpr void resize(size_t n) {
|
|
||||||
size_t i = size();
|
|
||||||
_str.reallocate(n + 1);
|
|
||||||
if (n > i) fennec::wmemset(_str.data() + i, L'\0', n - i);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Copy Assignment Operator
|
|
||||||
/// \param str the string to copy
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr wstring& operator=(const wcstring& str) {
|
|
||||||
if (str.empty()) {
|
|
||||||
_str.deallocate();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
if (str.size() > size()) resize(str.size());
|
|
||||||
fennec::wmemcpy(_str.data(), str, str.size());
|
|
||||||
_str[str.size()] = L'\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Copy Assignment Operator
|
|
||||||
/// \param str the string to copy
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr wstring& operator=(const wstring& str) {
|
|
||||||
if (str.size() > size()) resize(str.size());
|
|
||||||
fennec::wmemcpy(_str.data(), str, str.size());
|
|
||||||
_str[str.size()] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// \brief Move Assignment Operator
|
|
||||||
/// \param str the string to move
|
|
||||||
/// \returns a reference to `this`
|
|
||||||
constexpr wstring& operator=(wstring&& str) noexcept {
|
|
||||||
_str = fennec::move(str._str);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Retrieve a substring of a string
|
/// \brief Retrieve a substring of a string
|
||||||
/// \param i the start index
|
/// \param i the start index
|
||||||
/// \param n the number of characters
|
/// \param n the number of wchar_tacters
|
||||||
/// \return
|
/// \return
|
||||||
constexpr wstring substring(size_t i, size_t n = npos) const {
|
constexpr _wstring substring(size_t i, size_t n = npos) const {
|
||||||
if (i >= size()) {
|
if (i >= size()) {
|
||||||
return wstring("");
|
return _wstring("");
|
||||||
}
|
}
|
||||||
n = min(n, size() - i);
|
n = fennec::min(n, size() - i);
|
||||||
return wstring(_str.data() + i, n);
|
_wstring res;
|
||||||
}
|
res._str.callocate(n + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str + i, n);
|
||||||
///
|
|
||||||
/// \brief Returns a string with `c` appended to it
|
|
||||||
/// \param c
|
|
||||||
/// \returns
|
|
||||||
constexpr wstring operator+(wchar_t c) const {
|
|
||||||
// Copy contents with one additional byte.
|
|
||||||
wstring res(_str, _str.size());
|
|
||||||
res[size()] = c; // Set the last character to c
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wstring operator+(const wcstring& str) const {
|
|
||||||
wstring res(size() + str.size()); // Make a new string with the size of this + str
|
|
||||||
fennec::wmemcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
// Modifiers ===========================================================================================================
|
||||||
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
|
|
||||||
|
constexpr void resize(size_t n) {
|
||||||
|
_str.creallocate(n + 1);
|
||||||
|
_str[size()] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring operator+(wchar_t c) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _wstring(1, c);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(capacity() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
res[size()] = c;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wstring operator+(const wstring& str) const {
|
friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
|
||||||
wstring res(size() + str.size()); // Make a new string with the size of this + str
|
_wstring res(1, c);
|
||||||
fennec::wmemcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
return res += str;
|
||||||
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
|
}
|
||||||
|
|
||||||
|
constexpr _wstring operator+(const wcstring& cstr) const {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
return _wstring(cstr);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(size() + cstr.size() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
fennec::wmemcpy(res.data() + size(), cstr, cstr.size());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wstring& operator+=(wchar_t c) {
|
constexpr _wstring operator+(const _wstring& str) const {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + 1);
|
return _wstring(str);
|
||||||
_str[x] = c;
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
|
return _wstring(*this);
|
||||||
|
}
|
||||||
|
_wstring res;
|
||||||
|
res._str.callocate(size() + str.size() + 1);
|
||||||
|
fennec::wmemcpy(res.data(), _str, size());
|
||||||
|
fennec::wmemcpy(res.data() + size(), str.data(), str.size());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr _wstring& operator+=(wchar_t c) {
|
||||||
|
if (_str == nullptr) {
|
||||||
|
_str.callocate(2);
|
||||||
|
_str[0] = c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
_str.creallocate(capacity() + 1);
|
||||||
|
_str[size() - 1] = c;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wstring& operator+=(const wcstring& str) {
|
constexpr _wstring& operator+=(const wcstring& cstr) {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + str.size());
|
return *this = cstr;
|
||||||
fennec::wmemcpy(&_str[x], str, str.size());
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + cstr.size() + 1);
|
||||||
|
fennec::wmemcpy(_str + middle, cstr, cstr.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wstring& operator+=(const wstring& str) {
|
constexpr _wstring& operator+=(const _wstring& str) {
|
||||||
size_t x = size();
|
if (_str == nullptr) {
|
||||||
resize(x + str.size());
|
return *this = str;
|
||||||
fennec::wmemcpy(&_str[x], str, str.size());
|
}
|
||||||
|
if (str.data() == nullptr) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
size_t middle = size();
|
||||||
|
_str.creallocate(middle + str.size() + 1);
|
||||||
|
fennec::wmemcpy(_str + middle, str.data(), str.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alloc_t _str;
|
alloc_t _str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<wstring> : hash<byte_array> {
|
||||||
|
constexpr size_t operator()(const string& str) const {
|
||||||
|
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // FENNEC_FPROC_wstringS_wstring_H
|
#endif // FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#ifndef FENNEC_MATH_DETAIL_TYPES_H
|
#ifndef FENNEC_MATH_DETAIL_TYPES_H
|
||||||
#define FENNEC_MATH_DETAIL_TYPES_H
|
#define FENNEC_MATH_DETAIL_TYPES_H
|
||||||
|
|
||||||
#include <fennec/lang/sequences.h>
|
#include <fennec/lang/const_sequences.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -28,11 +28,11 @@ namespace detail
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<template<typename, size_t...> typename VectorT, typename ScalarT, size_t...IndicesV>
|
template<template<typename, size_t...> typename VectorT, typename ScalarT, size_t...IndicesV>
|
||||||
VectorT<ScalarT, IndicesV...> _gen_vector(index_sequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
|
VectorT<ScalarT, IndicesV...> _gen_vector(const_index_sequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
|
||||||
|
|
||||||
|
|
||||||
template<template<typename, size_t...> typename MatrixT, typename ScalarT, size_t RowsV, size_t...IndicesV>
|
template<template<typename, size_t...> typename MatrixT, typename ScalarT, size_t RowsV, size_t...IndicesV>
|
||||||
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(index_sequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
|
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(const_index_sequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,46 +33,46 @@ namespace detail
|
|||||||
// Helpers for vector traits
|
// Helpers for vector traits
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __is_vector_helper
|
struct _is_vector_helper
|
||||||
: false_type {}; // Default false case
|
: false_type {}; // Default false case
|
||||||
|
|
||||||
|
|
||||||
template<typename ScalarT, size_t...IndicesV>
|
template<typename ScalarT, size_t...IndicesV>
|
||||||
struct __is_vector_helper<vector<ScalarT, IndicesV...>>
|
struct _is_vector_helper<vector<ScalarT, IndicesV...>>
|
||||||
: true_type {}; // True for vectors
|
: true_type {}; // True for vectors
|
||||||
|
|
||||||
|
|
||||||
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
||||||
struct __is_vector_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
|
struct _is_vector_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
|
||||||
: true_type {}; // True for swizzles
|
: true_type {}; // True for swizzles
|
||||||
|
|
||||||
// get number of components of a type
|
// get number of components of a type
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __component_count_helper;
|
struct _component_count_helper;
|
||||||
|
|
||||||
// numeric types reduce to 1
|
// numeric types reduce to 1
|
||||||
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
|
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
|
||||||
struct __component_count_helper<TypeT>
|
struct _component_count_helper<TypeT>
|
||||||
: integral_constant<size_t, 1> {};
|
: integral_constant<size_t, 1> {};
|
||||||
|
|
||||||
// Vectors reduce to the number of elements
|
// Vectors reduce to the number of elements
|
||||||
template<typename ScalarT, size_t...IndicesV>
|
template<typename ScalarT, size_t...IndicesV>
|
||||||
struct __component_count_helper<vector<ScalarT, IndicesV...>>
|
struct _component_count_helper<vector<ScalarT, IndicesV...>>
|
||||||
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
||||||
|
|
||||||
// Swizzles reduce to number of elements
|
// Swizzles reduce to number of elements
|
||||||
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
||||||
struct __component_count_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
|
struct _component_count_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
|
||||||
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
||||||
|
|
||||||
// Matrices reduce to the number of cells
|
// Matrices reduce to the number of cells
|
||||||
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
|
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
|
||||||
struct __component_count_helper<matrix<ScalarT, RowsV, ColIndicesV...>>
|
struct _component_count_helper<matrix<ScalarT, RowsV, ColIndicesV...>>
|
||||||
: integral_constant<size_t, RowsV * sizeof...(ColIndicesV)> {};
|
: integral_constant<size_t, RowsV * sizeof...(ColIndicesV)> {};
|
||||||
|
|
||||||
// default case reduces to 0
|
// default case reduces to 0
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __component_count_helper
|
struct _component_count_helper
|
||||||
: integral_constant<size_t, 0> {};
|
: integral_constant<size_t, 0> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -292,7 +292,7 @@ struct matrix
|
|||||||
/// \param args
|
/// \param args
|
||||||
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
||||||
constexpr matrix(ArgsT&&...args) {
|
constexpr matrix(ArgsT&&...args) {
|
||||||
matrix::__construct(fennec::forward<ArgsT>(args)...);
|
matrix::_construct(fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@@ -579,7 +579,7 @@ struct matrix
|
|||||||
/// \param rhs the vector
|
/// \param rhs the vector
|
||||||
/// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$
|
/// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$
|
||||||
constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) {
|
constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) {
|
||||||
return __mul(lhs, rhs);
|
return _mul(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -625,7 +625,7 @@ struct matrix
|
|||||||
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
|
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
|
||||||
constexpr friend matrix<scalar_t, RowsV, OColIndicesV...> operator*(const matrix_t& lhs, const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
|
constexpr friend matrix<scalar_t, RowsV, OColIndicesV...> operator*(const matrix_t& lhs, const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
|
||||||
return matrix<scalar_t, RowsV, OColIndicesV...>(
|
return matrix<scalar_t, RowsV, OColIndicesV...>(
|
||||||
matrix::__mul(lhs, rhs[OColIndicesV])...
|
matrix::_mul(lhs, rhs[OColIndicesV])...
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,43 +645,43 @@ private:
|
|||||||
|
|
||||||
// ReSharper disable once CppMemberFunctionMayBeStatic
|
// ReSharper disable once CppMemberFunctionMayBeStatic
|
||||||
template<size_t i0 = 0>
|
template<size_t i0 = 0>
|
||||||
constexpr void __construct() {
|
constexpr void _construct() {
|
||||||
// base case, does nothing, this will get optimized away
|
// base case, does nothing, this will get optimized away
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for parsing parameter packs
|
// helper for parsing parameter packs
|
||||||
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
||||||
constexpr void __construct(HeadT&& head, RestT&&...rest) {
|
constexpr void _construct(HeadT&& head, RestT&&...rest) {
|
||||||
matrix::__insert<i0>(head); // insert the head element
|
matrix::_insert<i0>(head); // insert the head element
|
||||||
matrix::__construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
|
matrix::_construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a scalar value
|
// helper for inserting a scalar value
|
||||||
template<size_t i0 = 0>
|
template<size_t i0 = 0>
|
||||||
constexpr void __insert(scalar_t s) {
|
constexpr void _insert(scalar_t s) {
|
||||||
data[i0 / rows][i0 % rows] = s;
|
data[i0 / rows][i0 % rows] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a scalar value of differing type
|
// helper for inserting a scalar value of differing type
|
||||||
template<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
|
template<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
|
||||||
constexpr void __insert(OScalarT s) {
|
constexpr void _insert(OScalarT s) {
|
||||||
data[i0 / rows][i0 % rows] = scalar_t(s);
|
data[i0 / rows][i0 % rows] = scalar_t(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a vector
|
// helper for inserting a vector
|
||||||
template<size_t i0 = 0, size_t...i>
|
template<size_t i0 = 0, size_t...i>
|
||||||
constexpr void __insert(const vector<scalar_t, i...>& v) {
|
constexpr void _insert(const vector<scalar_t, i...>& v) {
|
||||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a vector of differing type
|
// helper for inserting a vector of differing type
|
||||||
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
||||||
constexpr void __insert(const vector<OScalarT, i...>& v) {
|
constexpr void _insert(const vector<OScalarT, i...>& v) {
|
||||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for a linear algebraic multiply
|
// helper for a linear algebraic multiply
|
||||||
static constexpr column_t __mul(const matrix_t& lhs, const row_t& rhs) {
|
static constexpr column_t _mul(const matrix_t& lhs, const row_t& rhs) {
|
||||||
// the compiler will optimize this better than writing out a specific definition
|
// the compiler will optimize this better than writing out a specific definition
|
||||||
// when compared to glm or CxxSwizzle, this is faster by a significant margin
|
// when compared to glm or CxxSwizzle, this is faster by a significant margin
|
||||||
// all implementations provide 7 decimal places of precision
|
// all implementations provide 7 decimal places of precision
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -65,9 +65,10 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
///
|
using byte = uint8_t;
|
||||||
/// \brief an unsigned integer
|
using ubyte = uint8_t;
|
||||||
using uint = unsigned int;
|
using ushort = uint16_t;
|
||||||
|
using uint = uint32_t;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
|
||||||
#include <fennec/lang/sequences.h>
|
#include <fennec/lang/const_sequences.h>
|
||||||
|
|
||||||
#include <fennec/math/swizzle_storage.h>
|
#include <fennec/math/swizzle_storage.h>
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<size_t...VecIndicesV>
|
template<size_t...VecIndicesV>
|
||||||
constexpr VectorT& decay_impl(VectorT& vec, index_sequence<VecIndicesV...>) {
|
constexpr VectorT& decay_impl(VectorT& vec, const_index_sequence<VecIndicesV...>) {
|
||||||
return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec);
|
return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
|||||||
/// \param args arguments
|
/// \param args arguments
|
||||||
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
|
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
|
||||||
explicit constexpr vector(ArgsT&&... args) {
|
explicit constexpr vector(ArgsT&&... args) {
|
||||||
vector::__construct<0>(args...);
|
vector::_construct<0>(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@@ -1078,30 +1078,30 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<size_t IndexV = 0, typename HeadT, typename... TailT>
|
template<size_t IndexV = 0, typename HeadT, typename... TailT>
|
||||||
constexpr void __construct(HeadT&& head, TailT&&... rest) {
|
constexpr void _construct(HeadT&& head, TailT&&... rest) {
|
||||||
vector::__insert<IndexV>(fennec::forward<HeadT>(head));
|
vector::_insert<IndexV>(fennec::forward<HeadT>(head));
|
||||||
|
|
||||||
if constexpr (sizeof...(TailT) > 0)
|
if constexpr (sizeof...(TailT) > 0)
|
||||||
vector::__construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
|
vector::_construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV>
|
template<size_t OffsetV>
|
||||||
constexpr void __insert(ScalarT& x) {
|
constexpr void _insert(ScalarT& x) {
|
||||||
data[OffsetV] = x;
|
data[OffsetV] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV, typename OScalarT>
|
template<size_t OffsetV, typename OScalarT>
|
||||||
constexpr void __insert(OScalarT& x) {
|
constexpr void _insert(OScalarT& x) {
|
||||||
data[OffsetV] = ScalarT(x);
|
data[OffsetV] = ScalarT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
|
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
|
||||||
constexpr void __insert(vector<OScalarT, OIndicesV...>& vec) {
|
constexpr void _insert(vector<OScalarT, OIndicesV...>& vec) {
|
||||||
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
|
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
|
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
|
||||||
constexpr void __insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
|
constexpr void _insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace fennec
|
|||||||
///
|
///
|
||||||
/// \brief check if \p T is a fennec::vector type
|
/// \brief check if \p T is a fennec::vector type
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct is_vector : detail::__is_vector_helper<remove_cvr_t<T>>{};
|
template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```is_vector<T>::value```
|
/// \brief shorthand for ```is_vector<T>::value```
|
||||||
@@ -81,7 +81,7 @@ template<typename T> constexpr bool is_vector_v = is_vector<T>::value;
|
|||||||
///
|
///
|
||||||
/// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic<T>```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases
|
/// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic<T>```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases
|
||||||
/// \tparam T type to check
|
/// \tparam T type to check
|
||||||
template<typename T> struct component_count : detail::__component_count_helper<remove_cvr_t<T>>{};
|
template<typename T> struct component_count : detail::_component_count_helper<remove_cvr_t<T>>{};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief shorthand for ```component_count<T>::value```
|
/// \brief shorthand for ```component_count<T>::value```
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
#ifndef FENNEC_MEMORY_ALLOCATOR_H
|
#ifndef FENNEC_MEMORY_ALLOCATOR_H
|
||||||
#define FENNEC_MEMORY_ALLOCATOR_H
|
#define FENNEC_MEMORY_ALLOCATOR_H
|
||||||
|
|
||||||
#include <fennec/memory/ptr_traits.h>
|
#include <fennec/memory/pointer_traits.h>
|
||||||
#include <fennec/memory/new.h>
|
#include <fennec/memory/new.h>
|
||||||
|
|
||||||
#include <fennec/lang/conditional_types.h>
|
#include <fennec/lang/conditional_types.h>
|
||||||
@@ -61,40 +61,40 @@ struct allocator_traits
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// These help with using concepts in `detect_t`
|
// These help with using concepts in `detect_t`
|
||||||
template<typename ClassT> using __pointer = typename ClassT::pointer_t;
|
template<typename ClassT> using _pointer = typename ClassT::pointer_t;
|
||||||
template<typename ClassT> using __const_pointer = typename ClassT::const_pointer_t;
|
template<typename ClassT> using _const_pointer = typename ClassT::const_pointer_t;
|
||||||
template<typename ClassT> using __void_pointer = typename ClassT::void_pointer_t;
|
template<typename ClassT> using _void_pointer = typename ClassT::void_pointer_t;
|
||||||
template<typename ClassT> using __void_const_pointer = typename ClassT::void_const_pointer_t;
|
template<typename ClassT> using _void_const_pointer = typename ClassT::void_const_pointer_t;
|
||||||
|
|
||||||
// Propagation Patterns
|
// Propagation Patterns
|
||||||
template<typename ClassT> using __propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment;
|
template<typename ClassT> using _propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment;
|
||||||
template<typename ClassT> using __propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment;
|
template<typename ClassT> using _propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment;
|
||||||
template<typename ClassT> using __propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap;
|
template<typename ClassT> using _propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap;
|
||||||
|
|
||||||
template<typename ClassT> using __is_always_equal = typename ClassT::is_always_equal;
|
template<typename ClassT> using _is_always_equal = typename ClassT::is_always_equal;
|
||||||
|
|
||||||
template<typename AllocT, typename TypeT>
|
template<typename AllocT, typename TypeT>
|
||||||
struct __rebind : replace_first_element<AllocT, TypeT> {};
|
struct _rebind : replace_first_element<AllocT, TypeT> {};
|
||||||
|
|
||||||
template<typename AllocT, typename TypeT>
|
template<typename AllocT, typename TypeT>
|
||||||
requires requires { typename AllocT::template rebind<TypeT>::other; }
|
requires requires { typename AllocT::template rebind<TypeT>::other; }
|
||||||
struct __rebind<AllocT, TypeT> { using type = typename AllocT::template rebind<TypeT>::other; };
|
struct _rebind<AllocT, TypeT> { using type = typename AllocT::template rebind<TypeT>::other; };
|
||||||
|
|
||||||
// This detects AllocT::diff_t if present, otherwise uses the diff_t associated with PtrT
|
// This detects AllocT::diff_t if present, otherwise uses the diff_t associated with PtrT
|
||||||
// It works using SFINAE, 'typename = void' forces the second __diff to be evaluated first when
|
// It works using SFINAE, 'typename = void' forces the second _diff to be evaluated first when
|
||||||
// __diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t'
|
// _diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t'
|
||||||
// however, if it fails, the compiler moves on to the original definition. __size works in the same manner.
|
// however, if it fails, the compiler moves on to the original definition. _size works in the same manner.
|
||||||
template<typename AllocT, typename PtrT, typename = void>
|
template<typename AllocT, typename PtrT, typename = void>
|
||||||
struct __diff { using type = typename ptr_traits<PtrT>::diff_t; };
|
struct _diff { using type = typename pointer_traits<PtrT>::diff_t; };
|
||||||
|
|
||||||
template<typename AllocT, typename PtrT>
|
template<typename AllocT, typename PtrT>
|
||||||
struct __diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
|
struct _diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
|
||||||
|
|
||||||
template<typename AllocT, typename DiffT, typename = void>
|
template<typename AllocT, typename DiffT, typename = void>
|
||||||
struct __size : make_unsigned<DiffT> {};
|
struct _size : make_unsigned<DiffT> {};
|
||||||
|
|
||||||
template<typename AllocT, typename DiffT>
|
template<typename AllocT, typename DiffT>
|
||||||
struct __size<AllocT, DiffT, void_t<typename AllocT::size_t>> { using type = typename AllocT::size_t; };
|
struct _size<AllocT, DiffT, void_t<typename AllocT::size_t>> { using type = typename AllocT::size_t; };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -105,33 +105,33 @@ public:
|
|||||||
using value_t = typename Alloc::value_t;
|
using value_t = typename Alloc::value_t;
|
||||||
|
|
||||||
/// \brief Alias for a pointer to the value type. Will use `Alloc::pointer_t` if present
|
/// \brief Alias for a pointer to the value type. Will use `Alloc::pointer_t` if present
|
||||||
using pointer_t = detect_t<value_t*, __pointer, Alloc>;
|
using pointer_t = detect_t<value_t*, _pointer, Alloc>;
|
||||||
|
|
||||||
/// \brief Alias for a const pointer to the value type. Will use `Alloc::const_pointer_t` if present
|
/// \brief Alias for a const pointer to the value type. Will use `Alloc::const_pointer_t` if present
|
||||||
using const_pointer_t = detect_t<const value_t*, __const_pointer, Alloc>;
|
using const_pointer_t = detect_t<const value_t*, _const_pointer, Alloc>;
|
||||||
|
|
||||||
/// \brief Alias for a pointer to void. Will use `Alloc::void_pointer_t` if present
|
/// \brief Alias for a pointer to void. Will use `Alloc::void_pointer_t` if present
|
||||||
using void_pointer_t = detect_t<void*, __void_pointer, Alloc>;
|
using void_pointer_t = detect_t<void*, _void_pointer, Alloc>;
|
||||||
|
|
||||||
/// \brief Alias for a const pointer to void. Will use `Alloc::const_void_pointer_t` if present
|
/// \brief Alias for a const pointer to void. Will use `Alloc::const_void_pointer_t` if present
|
||||||
using const_void_pointer_t = detect_t<const void*, __void_const_pointer, Alloc>;
|
using const_void_pointer_t = detect_t<const void*, _void_const_pointer, Alloc>;
|
||||||
|
|
||||||
/// \brief Alias for differences between pointers. Will use `Alloc::diff_t` if present
|
/// \brief Alias for differences between pointers. Will use `Alloc::diff_t` if present
|
||||||
using diff_t = typename __diff<Alloc, pointer_t>::type;
|
using diff_t = typename _diff<Alloc, pointer_t>::type;
|
||||||
|
|
||||||
/// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present
|
/// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present
|
||||||
using size_t = typename __size<Alloc, pointer_t>::type;
|
using size_t = typename _size<Alloc, pointer_t>::type;
|
||||||
|
|
||||||
// TODO: Document propagation
|
// TODO: Document propagation
|
||||||
using propagate_on_container_copy_assignment = detect_t<false_type, __propagate_on_containter_copy_assignment, Alloc>;
|
using propagate_on_container_copy_assignment = detect_t<false_type, _propagate_on_containter_copy_assignment, Alloc>;
|
||||||
using propagate_on_container_move_assignment = detect_t<false_type, __propagate_on_containter_move_assignment, Alloc>;
|
using propagate_on_container_move_assignment = detect_t<false_type, _propagate_on_containter_move_assignment, Alloc>;
|
||||||
using propagate_on_container_swap = detect_t<false_type, __propagate_on_containter_swap, Alloc>;
|
using propagate_on_container_swap = detect_t<false_type, _propagate_on_containter_swap, Alloc>;
|
||||||
|
|
||||||
/// \brief Checks if this allocator type is always equal to another allocator of similar type
|
/// \brief Checks if this allocator type is always equal to another allocator of similar type
|
||||||
using is_always_equal = detect_t<false_type, __is_always_equal, Alloc>;
|
using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>;
|
||||||
|
|
||||||
/// \brief Rebinds the allocator type to produce an element type of type `TypeT`
|
/// \brief Rebinds the allocator type to produce an element type of type `TypeT`
|
||||||
template<typename TypeT> using rebind = typename __rebind<Alloc, TypeT>::type;
|
template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type;
|
||||||
|
|
||||||
// TODO: allocator_traits static functions
|
// TODO: allocator_traits static functions
|
||||||
};
|
};
|
||||||
@@ -310,7 +310,7 @@ public:
|
|||||||
/// \param n The number of elements of type `T` to allocate for
|
/// \param n The number of elements of type `T` to allocate for
|
||||||
explicit constexpr allocation(size_t n) noexcept
|
explicit constexpr allocation(size_t n) noexcept
|
||||||
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||||
allocate(n);
|
callocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -320,7 +320,7 @@ public:
|
|||||||
/// \param n the number of elements
|
/// \param n the number of elements
|
||||||
constexpr allocation(const T* data, size_t n)
|
constexpr allocation(const T* data, size_t n)
|
||||||
: allocation(n) {
|
: allocation(n) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(_data, data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -331,7 +331,7 @@ public:
|
|||||||
: _data(nullptr)
|
: _data(nullptr)
|
||||||
, _capacity(0)
|
, _capacity(0)
|
||||||
, _alignment(align) {
|
, _alignment(align) {
|
||||||
allocate(n, align);
|
callocate(n, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -342,7 +342,7 @@ public:
|
|||||||
/// \param align The alignment of the allocation
|
/// \param align The alignment of the allocation
|
||||||
constexpr allocation(const T* data, size_t n, align_t align)
|
constexpr allocation(const T* data, size_t n, align_t align)
|
||||||
: allocation(n, align) {
|
: allocation(n, align) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -367,7 +367,7 @@ public:
|
|||||||
: _alloc(alloc)
|
: _alloc(alloc)
|
||||||
, _data(nullptr)
|
, _data(nullptr)
|
||||||
, _capacity(0) {
|
, _capacity(0) {
|
||||||
allocate(n);
|
callocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -380,7 +380,7 @@ public:
|
|||||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||||
constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
|
constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
|
||||||
: allocation(n, alloc) {
|
: allocation(n, alloc) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -395,7 +395,7 @@ public:
|
|||||||
, _data(nullptr)
|
, _data(nullptr)
|
||||||
, _capacity(0)
|
, _capacity(0)
|
||||||
, _alignment(zero<align_t>()) {
|
, _alignment(zero<align_t>()) {
|
||||||
allocate(n, align);
|
callocate(n, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -409,7 +409,7 @@ public:
|
|||||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||||
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
|
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
|
||||||
: allocation(n, align, alloc) {
|
: allocation(n, align, alloc) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(_data, data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -420,7 +420,7 @@ public:
|
|||||||
, _data(_alloc.allocate(alloc._capacity))
|
, _data(_alloc.allocate(alloc._capacity))
|
||||||
, _capacity(alloc._capacity)
|
, _capacity(alloc._capacity)
|
||||||
, _alignment(alloc._alignment) {
|
, _alignment(alloc._alignment) {
|
||||||
fennec::memcpy(_data, alloc._data, alloc._capacity * sizeof(T));
|
fennec::memmove(static_cast<void*>(_data), alloc._data, alloc._capacity * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -451,7 +451,7 @@ public:
|
|||||||
/// \returns a reference to `this`
|
/// \returns a reference to `this`
|
||||||
constexpr allocation& operator=(const allocation& alloc) {
|
constexpr allocation& operator=(const allocation& alloc) {
|
||||||
allocation::allocate(alloc.capacity());
|
allocation::allocate(alloc.capacity());
|
||||||
fennec::memcpy(_data, alloc, size());
|
fennec::memmove(_data, alloc, size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,13 +491,7 @@ public:
|
|||||||
/// If there is already an allocated block of memory, the previous allocation is released.
|
/// If there is already an allocated block of memory, the previous allocation is released.
|
||||||
/// \param n The number of elements of type `T` to allocate for
|
/// \param n The number of elements of type `T` to allocate for
|
||||||
constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||||
deallocate();
|
allocate(n, align);
|
||||||
|
|
||||||
if (align != zero<align_t>()) {
|
|
||||||
_data = _alloc.allocate(_capacity = n, _alignment = align);
|
|
||||||
} else {
|
|
||||||
_data = _alloc.allocate(_capacity = n);
|
|
||||||
}
|
|
||||||
fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T));
|
fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,11 +517,38 @@ public:
|
|||||||
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||||
if (_data == nullptr) {
|
if (_data == nullptr) {
|
||||||
allocate(n, align);
|
allocate(n, align);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* old = _data; size_t old_cap = _capacity;
|
||||||
|
_data = nullptr;
|
||||||
|
allocate(n, align);
|
||||||
|
|
||||||
|
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
|
||||||
|
|
||||||
|
_alloc.deallocate(old);
|
||||||
|
_capacity = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Reallocate the block with a new size.
|
||||||
|
/// Contents are copied to the new allocation.
|
||||||
|
constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||||
|
if (_data == nullptr) {
|
||||||
|
callocate(n, align);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* old = _data; size_t old_cap = _capacity;
|
||||||
|
_data = nullptr;
|
||||||
|
allocate(n, align);
|
||||||
|
|
||||||
|
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
|
||||||
|
|
||||||
|
if (_capacity > old_cap) {
|
||||||
|
fennec::memset(static_cast<void*>(_data + old_cap), 0, _capacity - old_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t* old = _data;
|
|
||||||
_data = _alloc.allocate(n);
|
|
||||||
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
|
||||||
_alloc.deallocate(old);
|
_alloc.deallocate(old);
|
||||||
_capacity = n;
|
_capacity = n;
|
||||||
}
|
}
|
||||||
@@ -536,20 +557,39 @@ public:
|
|||||||
// Access ==============================================================================================================
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
constexpr value_t& operator[](size_t i) {
|
constexpr value_t& operator[](size_t i) {
|
||||||
assertd(i < size(), "Array Out of Bounds");
|
assertd(i < capacity(), "Array Out of Bounds");
|
||||||
return _data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr value_t operator[](size_t i) const requires is_fundamental_v<value_t> {
|
|
||||||
assertd(i < size(), "Array Out of Bounds");
|
|
||||||
return _data[i];
|
return _data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const value_t& operator[](size_t i) const {
|
constexpr const value_t& operator[](size_t i) const {
|
||||||
assertd(i < size(), "Array Out of Bounds");
|
assertd(i < capacity(), "Array Out of Bounds");
|
||||||
return _data[i];
|
return _data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr operator value_t*() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr operator const value_t*() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* begin() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t* end() {
|
||||||
|
return _data + capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_t* begin() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_t* end() const {
|
||||||
|
return _data + capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Modification ========================================================================================================
|
// Modification ========================================================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -24,14 +24,20 @@
|
|||||||
// implementation
|
// implementation
|
||||||
|
|
||||||
#if FENNEC_COMPILER_GCC
|
#if FENNEC_COMPILER_GCC
|
||||||
|
#ifndef __OPTIMIZE__
|
||||||
# define __OPTIMIZE__
|
# define __OPTIMIZE__
|
||||||
|
#else
|
||||||
|
# define FENNEC_OPTIMIZE_FOUND
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#if FENNEC_COMPILER_GCC
|
#if FENNEC_COMPILER_GCC
|
||||||
|
#ifndef FENNEC_OPTIMIZE_FOUND
|
||||||
#undef __OPTIMIZE__
|
#undef __OPTIMIZE__
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // FENNEC_MEMORY_DETAIL_MEMORY_H
|
#endif // FENNEC_MEMORY_DETAIL_MEMORY_H
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,12 +29,12 @@ namespace fennec
|
|||||||
/// \brief Class for retrieving the traits of Pointer-like types
|
/// \brief Class for retrieving the traits of Pointer-like types
|
||||||
/// \tparam ClassT The Pointer class type
|
/// \tparam ClassT The Pointer class type
|
||||||
template<typename ClassT>
|
template<typename ClassT>
|
||||||
struct ptr_traits
|
struct pointer_traits
|
||||||
: detail::_ptr_traits_impl<ClassT, detail::_ptr_get_element<ClassT>> {};
|
: detail::_ptr_traits_impl<ClassT, detail::_ptr_get_element<ClassT>> {};
|
||||||
|
|
||||||
// overload for C-Style Pointers
|
// overload for C-Style Pointers
|
||||||
template<typename ElemT>
|
template<typename ElemT>
|
||||||
struct ptr_traits<ElemT*> : detail::_ptr_traits_ptr_to<ElemT*, ElemT>
|
struct pointer_traits<ElemT*> : detail::_ptr_traits_ptr_to<ElemT*, ElemT>
|
||||||
{
|
{
|
||||||
using pointer_t = ElemT*;
|
using pointer_t = ElemT*;
|
||||||
using element_t = ElemT;
|
using element_t = ElemT;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// fennec, a free and open source game engine
|
||||||
// Copyright (C) 2025 Medusa Slockbower
|
// Copyright © 2025 Medusa Slockbower
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_H
|
#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_H
|
||||||
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H
|
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
#include <fennec/lang/types.h>
|
#include <fennec/lang/types.h>
|
||||||
#include <fennec/lang/typeuuid.h>
|
#include <fennec/lang/typeuuid.h>
|
||||||
#include <fennec/platform/interface/fwd.h>
|
#include <fennec/platform/interface/fwd.h>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
class display
|
class display : public typed<display>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct pixel_format {
|
struct pixel_format {
|
||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
virtual bool connected() const = 0;
|
virtual bool connected() const = 0;
|
||||||
virtual ~display();
|
virtual ~display();
|
||||||
|
|
||||||
virtual window* create_window() = 0;
|
virtual window* create_window(window* parent) = 0;
|
||||||
|
|
||||||
const pixel_format& get_color_format() const {
|
const pixel_format& get_color_format() const {
|
||||||
return _config.format;
|
return _config.format;
|
||||||
@@ -55,7 +55,6 @@ public:
|
|||||||
gfxcontext* get_context() { return _context; }
|
gfxcontext* get_context() { return _context; }
|
||||||
|
|
||||||
const string name;
|
const string name;
|
||||||
const uint64_t uuid;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
platform* _platform;
|
platform* _platform;
|
||||||
@@ -63,9 +62,9 @@ protected:
|
|||||||
config _config;
|
config _config;
|
||||||
|
|
||||||
template<typename DisplayT>
|
template<typename DisplayT>
|
||||||
explicit display(platform* platform, const cstring& name, DisplayT*)
|
explicit display(platform* platform, const cstring& name, DisplayT* type)
|
||||||
: name(name)
|
: typed(type)
|
||||||
, uuid(typeuuid<DisplayT>())
|
, name(name)
|
||||||
, _platform(platform)
|
, _platform(platform)
|
||||||
, _context(nullptr)
|
, _context(nullptr)
|
||||||
, _config {
|
, _config {
|
||||||
|
|||||||
@@ -19,30 +19,42 @@
|
|||||||
#ifndef FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
|
#ifndef FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
|
||||||
#define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
|
#define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
|
||||||
|
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
#include <fennec/lang/typeuuid.h>
|
#include <fennec/lang/typeuuid.h>
|
||||||
#include <fennec/platform/interface/fwd.h>
|
#include <fennec/platform/interface/fwd.h>
|
||||||
|
#include <fennec/platform/interface/window.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
class gfxcontext {
|
class gfxcontext : public typed<gfxcontext> {
|
||||||
public:
|
public:
|
||||||
const string name;
|
const string name;
|
||||||
const uint64_t uuid;
|
|
||||||
|
|
||||||
virtual bool connected() = 0;
|
virtual bool connected() = 0;
|
||||||
|
virtual const cstring& get_name() = 0;
|
||||||
|
virtual int32_t get_version_major() = 0;
|
||||||
|
virtual int32_t get_version_minor() = 0;
|
||||||
|
virtual int32_t get_version() = 0;
|
||||||
|
|
||||||
|
virtual bool check_extension(const cstring& ext) = 0;
|
||||||
virtual void make_current(gfxsurface* surface) = 0;
|
virtual void make_current(gfxsurface* surface) = 0;
|
||||||
|
|
||||||
|
virtual gfxsurface* create_surface(window* window) = 0;
|
||||||
|
|
||||||
virtual ~gfxcontext() = default;
|
virtual ~gfxcontext() = default;
|
||||||
|
|
||||||
|
display* get_display() {
|
||||||
|
return _display;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
display* _display;
|
display* _display;
|
||||||
|
|
||||||
template<typename ContextT>
|
template<typename ContextT>
|
||||||
gfxcontext(display* display, const cstring& name, ContextT*)
|
gfxcontext(display* display, const cstring& name, ContextT* type)
|
||||||
: name(name)
|
: typed(type)
|
||||||
, uuid(typeuuid<ContextT>())
|
, name(name)
|
||||||
, _display(display) {
|
, _display(display) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
76
include/fennec/platform/interface/gfxsurface.h
Normal file
76
include/fennec/platform/interface/gfxsurface.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file gfxsurface.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H
|
||||||
|
#define FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H
|
||||||
|
|
||||||
|
#include <fennec/lang/types.h>
|
||||||
|
#include <fennec/lang/typeuuid.h>
|
||||||
|
#include <fennec/platform/interface/fwd.h>
|
||||||
|
#include <fennec/platform/interface/window.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class gfxsurface : public typed<gfxsurface> {
|
||||||
|
public:
|
||||||
|
virtual ~gfxsurface() = default;
|
||||||
|
|
||||||
|
virtual void resize(size_t width, size_t height) {
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxcontext* get_context() {
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
|
||||||
|
window* get_window() {
|
||||||
|
return _window;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
gfxcontext* _context;
|
||||||
|
window* _window;
|
||||||
|
size_t _width, _height;
|
||||||
|
|
||||||
|
template<typename SurfaceT>
|
||||||
|
gfxsurface(gfxcontext* ctx, window* window, SurfaceT* type)
|
||||||
|
: typed(type)
|
||||||
|
, _context(ctx)
|
||||||
|
, _window(window)
|
||||||
|
, _width(window->get_width()), _height(window->get_height()) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
|
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
|
||||||
|
|
||||||
#include <fennec/containers/list.h>
|
#include <fennec/containers/list.h>
|
||||||
#include <fennec/fproc/strings/cstring.h>
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
#include <fennec/lang/typeuuid.h>
|
#include <fennec/lang/typeuuid.h>
|
||||||
#include <fennec/platform/interface/fwd.h>
|
#include <fennec/platform/interface/fwd.h>
|
||||||
|
|
||||||
@@ -59,13 +59,12 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
class platform {
|
class platform : public typed<platform> {
|
||||||
public:
|
public:
|
||||||
using shared_object = struct shared_object;
|
using shared_object = struct shared_object;
|
||||||
using symbol = void*;
|
using symbol = void*;
|
||||||
|
|
||||||
const string name;
|
const string name;
|
||||||
const uint64_t uuid;
|
|
||||||
|
|
||||||
virtual ~platform() = default;
|
virtual ~platform() = default;
|
||||||
|
|
||||||
@@ -81,9 +80,9 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
template<typename PlatformT>
|
template<typename PlatformT>
|
||||||
explicit platform(const cstring& name, PlatformT*)
|
explicit platform(const cstring& name, PlatformT* type)
|
||||||
: name(name)
|
: typed(type)
|
||||||
, uuid(typeuuid<PlatformT>()) {
|
, name(name) {
|
||||||
auto& globals = _get_globals();
|
auto& globals = _get_globals();
|
||||||
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
|
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
|
||||||
globals.singleton = this;
|
globals.singleton = this;
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H
|
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H
|
||||||
|
|
||||||
#include <fennec/containers/optional.h>
|
#include <fennec/containers/optional.h>
|
||||||
#include <fennec/fproc/strings/string.h>
|
#include <fennec/langproc/strings/string.h>
|
||||||
#include <fennec/platform/interface/fwd.h>
|
#include <fennec/platform/interface/fwd.h>
|
||||||
|
#include <fennec/platform/linux/wayland/display.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -29,7 +30,7 @@ namespace fennec
|
|||||||
///
|
///
|
||||||
/// \brief interface for handling windows
|
/// \brief interface for handling windows
|
||||||
/// \details the interface makes no guarantees about the bit-depth and is completely dependent on the implementation.
|
/// \details the interface makes no guarantees about the bit-depth and is completely dependent on the implementation.
|
||||||
class window {
|
class window : public typed<window> {
|
||||||
public:
|
public:
|
||||||
enum class fullscreen_mode {
|
enum class fullscreen_mode {
|
||||||
windowed = 0,
|
windowed = 0,
|
||||||
@@ -53,6 +54,8 @@ public:
|
|||||||
fullscreen_mode fullscreen;
|
fullscreen_mode fullscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual ~window() = default;
|
||||||
|
|
||||||
virtual bool running() = 0;
|
virtual bool running() = 0;
|
||||||
virtual void configure(const config& config) = 0;
|
virtual void configure(const config& config) = 0;
|
||||||
virtual bool initialize(bool modal) = 0;
|
virtual bool initialize(bool modal) = 0;
|
||||||
@@ -63,7 +66,7 @@ public:
|
|||||||
|
|
||||||
virtual bool set_width(size_t w) = 0;
|
virtual bool set_width(size_t w) = 0;
|
||||||
virtual bool set_height(size_t h) = 0;
|
virtual bool set_height(size_t h) = 0;
|
||||||
virtual bool set_size(size_t w, size_t h) = 0;
|
virtual bool resize(size_t w, size_t h) = 0;
|
||||||
|
|
||||||
virtual bool set_fullscreen_mode(fullscreen_mode mode) = 0;
|
virtual bool set_fullscreen_mode(fullscreen_mode mode) = 0;
|
||||||
|
|
||||||
@@ -73,6 +76,8 @@ public:
|
|||||||
virtual bool grab_mouse(bool e) = 0;
|
virtual bool grab_mouse(bool e) = 0;
|
||||||
virtual bool block_screensaver(bool e) = 0;
|
virtual bool block_screensaver(bool e) = 0;
|
||||||
|
|
||||||
|
virtual struct wl_surface* get_native_handle() = 0;
|
||||||
|
|
||||||
bool is_child() const {
|
bool is_child() const {
|
||||||
if (not _config) return false;
|
if (not _config) return false;
|
||||||
return _config->flags & flags_child;
|
return _config->flags & flags_child;
|
||||||
@@ -91,9 +96,13 @@ public:
|
|||||||
return _display;
|
return _display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const config& get_config() const {
|
||||||
|
return *_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const string& get_title() const {
|
const string& get_title() const {
|
||||||
static const string _null = { "null" };
|
static const string _null{"null"};
|
||||||
if (not _config) return _null;
|
if (not _config) return _null;
|
||||||
return _config->title;
|
return _config->title;
|
||||||
}
|
}
|
||||||
@@ -137,13 +146,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~window() = default;
|
template<typename TypeT>
|
||||||
window(display* display, window* parent);
|
window(display* display, window* parent, TypeT* type)
|
||||||
|
: typed(type)
|
||||||
|
, _display(display)
|
||||||
|
, _parent(parent)
|
||||||
|
, _surface(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
display* _display;
|
display* _display;
|
||||||
window* _parent;
|
window* _parent;
|
||||||
optional<config> _config;
|
optional<config> _config;
|
||||||
gfxsurface* _context;
|
gfxsurface* _surface;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#define FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H
|
#define FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H
|
||||||
|
|
||||||
#include <fennec/platform/interface/display.h>
|
#include <fennec/platform/interface/display.h>
|
||||||
#include <fennec/platform/linux/wayland/lib/fwd.h>
|
#include <fennec/platform/linux/wayland/lib/wayland.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -33,13 +33,28 @@ public:
|
|||||||
bool connected() const override;
|
bool connected() const override;
|
||||||
void* get_native_handle() override { return _handle; }
|
void* get_native_handle() override { return _handle; }
|
||||||
|
|
||||||
window* create_window() override;
|
window* create_window(window* parent) override;
|
||||||
|
|
||||||
|
wl_registry* get_registry() { return _registry; }
|
||||||
|
const wl_registry* get_registry() const { return _registry; }
|
||||||
|
|
||||||
|
wl_compositor* get_compositor() { return _compositor; }
|
||||||
|
const wl_compositor* get_compositor() const { return _compositor; }
|
||||||
|
|
||||||
|
// xdg_wm_base* get_shell() { return _shell; }
|
||||||
|
//const xdg_wm_base* get_shell() const { return _shell; }
|
||||||
|
|
||||||
|
wl_seat* get_seat() { return _seat; }
|
||||||
|
const wl_seat* get_seat() const { return _seat; }
|
||||||
|
|
||||||
|
wl_shm* get_shm() { return _shm; }
|
||||||
|
const wl_shm* get_shm() const { return _shm; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_display* _handle;
|
wl_display* _handle;
|
||||||
wl_registry* _registry;
|
wl_registry* _registry;
|
||||||
wl_compositor* _compositor;
|
wl_compositor* _compositor;
|
||||||
wl_shell* _shell;
|
//xdg_wm_base* _shell;
|
||||||
wl_seat* _seat;
|
wl_seat* _seat;
|
||||||
wl_shm* _shm;
|
wl_shm* _shm;
|
||||||
bool _fifo;
|
bool _fifo;
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
// =====================================================================================================================
|
|
||||||
// fennec, a free and open source game engine
|
|
||||||
// Copyright © 2025 Medusa Slockbower
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// =====================================================================================================================
|
|
||||||
|
|
||||||
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIB_FWD_H
|
|
||||||
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIB_FWD_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright © 2008 Kristian Høgsberg
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the
|
|
||||||
* next paragraph) shall be included in all copies or substantial
|
|
||||||
* portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fennec/lang/types.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
struct wl_object;
|
|
||||||
struct wl_proxy;
|
|
||||||
struct wl_display;
|
|
||||||
struct wl_event_queue;
|
|
||||||
struct wl_buffer;
|
|
||||||
struct wl_callback;
|
|
||||||
struct wl_compositor;
|
|
||||||
struct wl_data_device;
|
|
||||||
struct wl_data_device_manager;
|
|
||||||
struct wl_data_offer;
|
|
||||||
struct wl_data_source;
|
|
||||||
struct wl_keyboard;
|
|
||||||
struct wl_output;
|
|
||||||
struct wl_pointer;
|
|
||||||
struct wl_region;
|
|
||||||
struct wl_registry;
|
|
||||||
struct wl_seat;
|
|
||||||
struct wl_shell;
|
|
||||||
struct wl_shell_surface;
|
|
||||||
struct wl_shm;
|
|
||||||
struct wl_shm_pool;
|
|
||||||
struct wl_subcompositor;
|
|
||||||
struct wl_subsurface;
|
|
||||||
struct wl_surface;
|
|
||||||
struct wl_touch;
|
|
||||||
|
|
||||||
struct wl_egl_window;
|
|
||||||
struct wl_surface;
|
|
||||||
|
|
||||||
typedef int32_t wl_fixed_t;
|
|
||||||
|
|
||||||
#define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y)))
|
|
||||||
typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0);
|
|
||||||
|
|
||||||
#define WL_MARSHAL_FLAG_DESTROY (1 << 0)
|
|
||||||
|
|
||||||
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIB_FWD_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3248
include/fennec/platform/linux/wayland/lib/protocols/wayland.xml
Normal file
3248
include/fennec/platform/linux/wayland/lib/protocols/wayland.xml
Normal file
File diff suppressed because it is too large
Load Diff
1383
include/fennec/platform/linux/wayland/lib/protocols/xdg-shell.xml
Normal file
1383
include/fennec/platform/linux/wayland/lib/protocols/xdg-shell.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,526 @@
|
|||||||
|
/* Generated by wayland-scanner 1.23.1 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright © 2008-2011 Kristian Høgsberg
|
||||||
|
* Copyright © 2010-2011 Intel Corporation
|
||||||
|
* Copyright © 2012-2013 Collabora, Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial
|
||||||
|
* portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "wayland-util.h"
|
||||||
|
|
||||||
|
#ifndef __has_attribute
|
||||||
|
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||||
|
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define WL_PRIVATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct wl_interface wl_buffer_interface;
|
||||||
|
extern const struct wl_interface wl_callback_interface;
|
||||||
|
extern const struct wl_interface wl_data_device_interface;
|
||||||
|
extern const struct wl_interface wl_data_offer_interface;
|
||||||
|
extern const struct wl_interface wl_data_source_interface;
|
||||||
|
extern const struct wl_interface wl_keyboard_interface;
|
||||||
|
extern const struct wl_interface wl_output_interface;
|
||||||
|
extern const struct wl_interface wl_pointer_interface;
|
||||||
|
extern const struct wl_interface wl_region_interface;
|
||||||
|
extern const struct wl_interface wl_registry_interface;
|
||||||
|
extern const struct wl_interface wl_seat_interface;
|
||||||
|
extern const struct wl_interface wl_shell_surface_interface;
|
||||||
|
extern const struct wl_interface wl_shm_pool_interface;
|
||||||
|
extern const struct wl_interface wl_subsurface_interface;
|
||||||
|
extern const struct wl_interface wl_surface_interface;
|
||||||
|
extern const struct wl_interface wl_touch_interface;
|
||||||
|
|
||||||
|
static const struct wl_interface *wayland_types[] = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_callback_interface,
|
||||||
|
&wl_registry_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_region_interface,
|
||||||
|
&wl_buffer_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_shm_pool_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_data_source_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_data_source_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_data_offer_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_data_offer_interface,
|
||||||
|
&wl_data_offer_interface,
|
||||||
|
&wl_data_source_interface,
|
||||||
|
&wl_data_device_interface,
|
||||||
|
&wl_seat_interface,
|
||||||
|
&wl_shell_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_output_interface,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_output_interface,
|
||||||
|
&wl_buffer_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_callback_interface,
|
||||||
|
&wl_region_interface,
|
||||||
|
&wl_region_interface,
|
||||||
|
&wl_output_interface,
|
||||||
|
&wl_output_interface,
|
||||||
|
&wl_pointer_interface,
|
||||||
|
&wl_keyboard_interface,
|
||||||
|
&wl_touch_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_surface_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_subsurface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_display_requests[] = {
|
||||||
|
{ "sync", "n", wayland_types + 8 },
|
||||||
|
{ "get_registry", "n", wayland_types + 9 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_display_events[] = {
|
||||||
|
{ "error", "ous", wayland_types + 0 },
|
||||||
|
{ "delete_id", "u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_display_interface = {
|
||||||
|
"wl_display", 1,
|
||||||
|
2, wl_display_requests,
|
||||||
|
2, wl_display_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_registry_requests[] = {
|
||||||
|
{ "bind", "usun", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_registry_events[] = {
|
||||||
|
{ "global", "usu", wayland_types + 0 },
|
||||||
|
{ "global_remove", "u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_registry_interface = {
|
||||||
|
"wl_registry", 1,
|
||||||
|
1, wl_registry_requests,
|
||||||
|
2, wl_registry_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_callback_events[] = {
|
||||||
|
{ "done", "u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_callback_interface = {
|
||||||
|
"wl_callback", 1,
|
||||||
|
0, NULL,
|
||||||
|
1, wl_callback_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_compositor_requests[] = {
|
||||||
|
{ "create_surface", "n", wayland_types + 10 },
|
||||||
|
{ "create_region", "n", wayland_types + 11 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_compositor_interface = {
|
||||||
|
"wl_compositor", 6,
|
||||||
|
2, wl_compositor_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shm_pool_requests[] = {
|
||||||
|
{ "create_buffer", "niiiiu", wayland_types + 12 },
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "resize", "i", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_shm_pool_interface = {
|
||||||
|
"wl_shm_pool", 2,
|
||||||
|
3, wl_shm_pool_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shm_requests[] = {
|
||||||
|
{ "create_pool", "nhi", wayland_types + 18 },
|
||||||
|
{ "release", "2", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shm_events[] = {
|
||||||
|
{ "format", "u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_shm_interface = {
|
||||||
|
"wl_shm", 2,
|
||||||
|
2, wl_shm_requests,
|
||||||
|
1, wl_shm_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_buffer_requests[] = {
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_buffer_events[] = {
|
||||||
|
{ "release", "", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_buffer_interface = {
|
||||||
|
"wl_buffer", 1,
|
||||||
|
1, wl_buffer_requests,
|
||||||
|
1, wl_buffer_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_offer_requests[] = {
|
||||||
|
{ "accept", "u?s", wayland_types + 0 },
|
||||||
|
{ "receive", "sh", wayland_types + 0 },
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "finish", "3", wayland_types + 0 },
|
||||||
|
{ "set_actions", "3uu", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_offer_events[] = {
|
||||||
|
{ "offer", "s", wayland_types + 0 },
|
||||||
|
{ "source_actions", "3u", wayland_types + 0 },
|
||||||
|
{ "action", "3u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_data_offer_interface = {
|
||||||
|
"wl_data_offer", 3,
|
||||||
|
5, wl_data_offer_requests,
|
||||||
|
3, wl_data_offer_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_source_requests[] = {
|
||||||
|
{ "offer", "s", wayland_types + 0 },
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "set_actions", "3u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_source_events[] = {
|
||||||
|
{ "target", "?s", wayland_types + 0 },
|
||||||
|
{ "send", "sh", wayland_types + 0 },
|
||||||
|
{ "cancelled", "", wayland_types + 0 },
|
||||||
|
{ "dnd_drop_performed", "3", wayland_types + 0 },
|
||||||
|
{ "dnd_finished", "3", wayland_types + 0 },
|
||||||
|
{ "action", "3u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_data_source_interface = {
|
||||||
|
"wl_data_source", 3,
|
||||||
|
3, wl_data_source_requests,
|
||||||
|
6, wl_data_source_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_device_requests[] = {
|
||||||
|
{ "start_drag", "?oo?ou", wayland_types + 21 },
|
||||||
|
{ "set_selection", "?ou", wayland_types + 25 },
|
||||||
|
{ "release", "2", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_device_events[] = {
|
||||||
|
{ "data_offer", "n", wayland_types + 27 },
|
||||||
|
{ "enter", "uoff?o", wayland_types + 28 },
|
||||||
|
{ "leave", "", wayland_types + 0 },
|
||||||
|
{ "motion", "uff", wayland_types + 0 },
|
||||||
|
{ "drop", "", wayland_types + 0 },
|
||||||
|
{ "selection", "?o", wayland_types + 33 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_data_device_interface = {
|
||||||
|
"wl_data_device", 3,
|
||||||
|
3, wl_data_device_requests,
|
||||||
|
6, wl_data_device_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_data_device_manager_requests[] = {
|
||||||
|
{ "create_data_source", "n", wayland_types + 34 },
|
||||||
|
{ "get_data_device", "no", wayland_types + 35 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = {
|
||||||
|
"wl_data_device_manager", 3,
|
||||||
|
2, wl_data_device_manager_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shell_requests[] = {
|
||||||
|
{ "get_shell_surface", "no", wayland_types + 37 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_shell_interface = {
|
||||||
|
"wl_shell", 1,
|
||||||
|
1, wl_shell_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shell_surface_requests[] = {
|
||||||
|
{ "pong", "u", wayland_types + 0 },
|
||||||
|
{ "move", "ou", wayland_types + 39 },
|
||||||
|
{ "resize", "ouu", wayland_types + 41 },
|
||||||
|
{ "set_toplevel", "", wayland_types + 0 },
|
||||||
|
{ "set_transient", "oiiu", wayland_types + 44 },
|
||||||
|
{ "set_fullscreen", "uu?o", wayland_types + 48 },
|
||||||
|
{ "set_popup", "ouoiiu", wayland_types + 51 },
|
||||||
|
{ "set_maximized", "?o", wayland_types + 57 },
|
||||||
|
{ "set_title", "s", wayland_types + 0 },
|
||||||
|
{ "set_class", "s", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_shell_surface_events[] = {
|
||||||
|
{ "ping", "u", wayland_types + 0 },
|
||||||
|
{ "configure", "uii", wayland_types + 0 },
|
||||||
|
{ "popup_done", "", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_shell_surface_interface = {
|
||||||
|
"wl_shell_surface", 1,
|
||||||
|
10, wl_shell_surface_requests,
|
||||||
|
3, wl_shell_surface_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_surface_requests[] = {
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "attach", "?oii", wayland_types + 58 },
|
||||||
|
{ "damage", "iiii", wayland_types + 0 },
|
||||||
|
{ "frame", "n", wayland_types + 61 },
|
||||||
|
{ "set_opaque_region", "?o", wayland_types + 62 },
|
||||||
|
{ "set_input_region", "?o", wayland_types + 63 },
|
||||||
|
{ "commit", "", wayland_types + 0 },
|
||||||
|
{ "set_buffer_transform", "2i", wayland_types + 0 },
|
||||||
|
{ "set_buffer_scale", "3i", wayland_types + 0 },
|
||||||
|
{ "damage_buffer", "4iiii", wayland_types + 0 },
|
||||||
|
{ "offset", "5ii", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_surface_events[] = {
|
||||||
|
{ "enter", "o", wayland_types + 64 },
|
||||||
|
{ "leave", "o", wayland_types + 65 },
|
||||||
|
{ "preferred_buffer_scale", "6i", wayland_types + 0 },
|
||||||
|
{ "preferred_buffer_transform", "6u", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_surface_interface = {
|
||||||
|
"wl_surface", 6,
|
||||||
|
11, wl_surface_requests,
|
||||||
|
4, wl_surface_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_seat_requests[] = {
|
||||||
|
{ "get_pointer", "n", wayland_types + 66 },
|
||||||
|
{ "get_keyboard", "n", wayland_types + 67 },
|
||||||
|
{ "get_touch", "n", wayland_types + 68 },
|
||||||
|
{ "release", "5", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_seat_events[] = {
|
||||||
|
{ "capabilities", "u", wayland_types + 0 },
|
||||||
|
{ "name", "2s", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_seat_interface = {
|
||||||
|
"wl_seat", 9,
|
||||||
|
4, wl_seat_requests,
|
||||||
|
2, wl_seat_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_pointer_requests[] = {
|
||||||
|
{ "set_cursor", "u?oii", wayland_types + 69 },
|
||||||
|
{ "release", "3", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_pointer_events[] = {
|
||||||
|
{ "enter", "uoff", wayland_types + 73 },
|
||||||
|
{ "leave", "uo", wayland_types + 77 },
|
||||||
|
{ "motion", "uff", wayland_types + 0 },
|
||||||
|
{ "button", "uuuu", wayland_types + 0 },
|
||||||
|
{ "axis", "uuf", wayland_types + 0 },
|
||||||
|
{ "frame", "5", wayland_types + 0 },
|
||||||
|
{ "axis_source", "5u", wayland_types + 0 },
|
||||||
|
{ "axis_stop", "5uu", wayland_types + 0 },
|
||||||
|
{ "axis_discrete", "5ui", wayland_types + 0 },
|
||||||
|
{ "axis_value120", "8ui", wayland_types + 0 },
|
||||||
|
{ "axis_relative_direction", "9uu", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_pointer_interface = {
|
||||||
|
"wl_pointer", 9,
|
||||||
|
2, wl_pointer_requests,
|
||||||
|
11, wl_pointer_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_keyboard_requests[] = {
|
||||||
|
{ "release", "3", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_keyboard_events[] = {
|
||||||
|
{ "keymap", "uhu", wayland_types + 0 },
|
||||||
|
{ "enter", "uoa", wayland_types + 79 },
|
||||||
|
{ "leave", "uo", wayland_types + 82 },
|
||||||
|
{ "key", "uuuu", wayland_types + 0 },
|
||||||
|
{ "modifiers", "uuuuu", wayland_types + 0 },
|
||||||
|
{ "repeat_info", "4ii", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_keyboard_interface = {
|
||||||
|
"wl_keyboard", 9,
|
||||||
|
1, wl_keyboard_requests,
|
||||||
|
6, wl_keyboard_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_touch_requests[] = {
|
||||||
|
{ "release", "3", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_touch_events[] = {
|
||||||
|
{ "down", "uuoiff", wayland_types + 84 },
|
||||||
|
{ "up", "uui", wayland_types + 0 },
|
||||||
|
{ "motion", "uiff", wayland_types + 0 },
|
||||||
|
{ "frame", "", wayland_types + 0 },
|
||||||
|
{ "cancel", "", wayland_types + 0 },
|
||||||
|
{ "shape", "6iff", wayland_types + 0 },
|
||||||
|
{ "orientation", "6if", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_touch_interface = {
|
||||||
|
"wl_touch", 9,
|
||||||
|
1, wl_touch_requests,
|
||||||
|
7, wl_touch_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_output_requests[] = {
|
||||||
|
{ "release", "3", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_output_events[] = {
|
||||||
|
{ "geometry", "iiiiissi", wayland_types + 0 },
|
||||||
|
{ "mode", "uiii", wayland_types + 0 },
|
||||||
|
{ "done", "2", wayland_types + 0 },
|
||||||
|
{ "scale", "2i", wayland_types + 0 },
|
||||||
|
{ "name", "4s", wayland_types + 0 },
|
||||||
|
{ "description", "4s", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_output_interface = {
|
||||||
|
"wl_output", 4,
|
||||||
|
1, wl_output_requests,
|
||||||
|
6, wl_output_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_region_requests[] = {
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "add", "iiii", wayland_types + 0 },
|
||||||
|
{ "subtract", "iiii", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_region_interface = {
|
||||||
|
"wl_region", 1,
|
||||||
|
3, wl_region_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_subcompositor_requests[] = {
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "get_subsurface", "noo", wayland_types + 90 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_subcompositor_interface = {
|
||||||
|
"wl_subcompositor", 1,
|
||||||
|
2, wl_subcompositor_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message wl_subsurface_requests[] = {
|
||||||
|
{ "destroy", "", wayland_types + 0 },
|
||||||
|
{ "set_position", "ii", wayland_types + 0 },
|
||||||
|
{ "place_above", "o", wayland_types + 93 },
|
||||||
|
{ "place_below", "o", wayland_types + 94 },
|
||||||
|
{ "set_sync", "", wayland_types + 0 },
|
||||||
|
{ "set_desync", "", wayland_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface wl_subsurface_interface = {
|
||||||
|
"wl_subsurface", 1,
|
||||||
|
6, wl_subsurface_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
/* Generated by wayland-scanner 1.23.1 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright © 2008-2013 Kristian Høgsberg
|
||||||
|
* Copyright © 2013 Rafael Antognolli
|
||||||
|
* Copyright © 2013 Jasper St. Pierre
|
||||||
|
* Copyright © 2010-2013 Intel Corporation
|
||||||
|
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
|
||||||
|
* Copyright © 2015-2017 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "wayland-util.h"
|
||||||
|
|
||||||
|
#ifndef __has_attribute
|
||||||
|
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
|
||||||
|
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define WL_PRIVATE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct wl_interface wl_output_interface;
|
||||||
|
extern const struct wl_interface wl_seat_interface;
|
||||||
|
extern const struct wl_interface wl_surface_interface;
|
||||||
|
extern const struct wl_interface xdg_popup_interface;
|
||||||
|
extern const struct wl_interface xdg_positioner_interface;
|
||||||
|
extern const struct wl_interface xdg_surface_interface;
|
||||||
|
extern const struct wl_interface xdg_toplevel_interface;
|
||||||
|
|
||||||
|
static const struct wl_interface *xdg_shell_types[] = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&xdg_positioner_interface,
|
||||||
|
&xdg_surface_interface,
|
||||||
|
&wl_surface_interface,
|
||||||
|
&xdg_toplevel_interface,
|
||||||
|
&xdg_popup_interface,
|
||||||
|
&xdg_surface_interface,
|
||||||
|
&xdg_positioner_interface,
|
||||||
|
&xdg_toplevel_interface,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&wl_output_interface,
|
||||||
|
&wl_seat_interface,
|
||||||
|
NULL,
|
||||||
|
&xdg_positioner_interface,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_wm_base_requests[] = {
|
||||||
|
{ "destroy", "", xdg_shell_types + 0 },
|
||||||
|
{ "create_positioner", "n", xdg_shell_types + 4 },
|
||||||
|
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
|
||||||
|
{ "pong", "u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_wm_base_events[] = {
|
||||||
|
{ "ping", "u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
|
||||||
|
"xdg_wm_base", 6,
|
||||||
|
4, xdg_wm_base_requests,
|
||||||
|
1, xdg_wm_base_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_positioner_requests[] = {
|
||||||
|
{ "destroy", "", xdg_shell_types + 0 },
|
||||||
|
{ "set_size", "ii", xdg_shell_types + 0 },
|
||||||
|
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
|
||||||
|
{ "set_anchor", "u", xdg_shell_types + 0 },
|
||||||
|
{ "set_gravity", "u", xdg_shell_types + 0 },
|
||||||
|
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
|
||||||
|
{ "set_offset", "ii", xdg_shell_types + 0 },
|
||||||
|
{ "set_reactive", "3", xdg_shell_types + 0 },
|
||||||
|
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
|
||||||
|
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
|
||||||
|
"xdg_positioner", 6,
|
||||||
|
10, xdg_positioner_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_surface_requests[] = {
|
||||||
|
{ "destroy", "", xdg_shell_types + 0 },
|
||||||
|
{ "get_toplevel", "n", xdg_shell_types + 7 },
|
||||||
|
{ "get_popup", "n?oo", xdg_shell_types + 8 },
|
||||||
|
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
|
||||||
|
{ "ack_configure", "u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_surface_events[] = {
|
||||||
|
{ "configure", "u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
|
||||||
|
"xdg_surface", 6,
|
||||||
|
5, xdg_surface_requests,
|
||||||
|
1, xdg_surface_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_toplevel_requests[] = {
|
||||||
|
{ "destroy", "", xdg_shell_types + 0 },
|
||||||
|
{ "set_parent", "?o", xdg_shell_types + 11 },
|
||||||
|
{ "set_title", "s", xdg_shell_types + 0 },
|
||||||
|
{ "set_app_id", "s", xdg_shell_types + 0 },
|
||||||
|
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
|
||||||
|
{ "move", "ou", xdg_shell_types + 16 },
|
||||||
|
{ "resize", "ouu", xdg_shell_types + 18 },
|
||||||
|
{ "set_max_size", "ii", xdg_shell_types + 0 },
|
||||||
|
{ "set_min_size", "ii", xdg_shell_types + 0 },
|
||||||
|
{ "set_maximized", "", xdg_shell_types + 0 },
|
||||||
|
{ "unset_maximized", "", xdg_shell_types + 0 },
|
||||||
|
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
|
||||||
|
{ "unset_fullscreen", "", xdg_shell_types + 0 },
|
||||||
|
{ "set_minimized", "", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_toplevel_events[] = {
|
||||||
|
{ "configure", "iia", xdg_shell_types + 0 },
|
||||||
|
{ "close", "", xdg_shell_types + 0 },
|
||||||
|
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
|
||||||
|
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
|
||||||
|
"xdg_toplevel", 6,
|
||||||
|
14, xdg_toplevel_requests,
|
||||||
|
4, xdg_toplevel_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_popup_requests[] = {
|
||||||
|
{ "destroy", "", xdg_shell_types + 0 },
|
||||||
|
{ "grab", "ou", xdg_shell_types + 22 },
|
||||||
|
{ "reposition", "3ou", xdg_shell_types + 24 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_popup_events[] = {
|
||||||
|
{ "configure", "iiii", xdg_shell_types + 0 },
|
||||||
|
{ "popup_done", "", xdg_shell_types + 0 },
|
||||||
|
{ "repositioned", "3u", xdg_shell_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
|
||||||
|
"xdg_popup", 6,
|
||||||
|
3, xdg_popup_requests,
|
||||||
|
3, xdg_popup_events,
|
||||||
|
};
|
||||||
|
|
||||||
@@ -17,32 +17,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#include <fennec/lang/types.h>
|
#include <fennec/lang/types.h>
|
||||||
#include <fennec/platform/linux/wayland/lib/fwd.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright © 2008 Kristian Høgsberg
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the
|
|
||||||
* next paragraph) shall be included in all copies or substantial
|
|
||||||
* portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FENNEC_LIB
|
#ifndef FENNEC_LIB
|
||||||
#define FENNEC_LIB(...)
|
#define FENNEC_LIB(...)
|
||||||
@@ -60,7 +34,7 @@
|
|||||||
FENNEC_LIB(WAYLAND);
|
FENNEC_LIB(WAYLAND);
|
||||||
|
|
||||||
FENNEC_SYMBOL(void, wl_proxy_marshal, struct wl_proxy*, uint32_t, ...);
|
FENNEC_SYMBOL(void, wl_proxy_marshal, struct wl_proxy*, uint32_t, ...);
|
||||||
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_flags, struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, ...);
|
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_flags, struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, uint32_t, ...);
|
||||||
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_create, struct wl_proxy*, const struct wl_interface*);
|
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_create, struct wl_proxy*, const struct wl_interface*);
|
||||||
FENNEC_SYMBOL(void, wl_proxy_destroy, struct wl_proxy*);
|
FENNEC_SYMBOL(void, wl_proxy_destroy, struct wl_proxy*);
|
||||||
FENNEC_SYMBOL(int, wl_proxy_add_listener, struct wl_proxy*, void (**)(void), void*);
|
FENNEC_SYMBOL(int, wl_proxy_add_listener, struct wl_proxy*, void (**)(void), void*);
|
||||||
@@ -72,6 +46,11 @@ FENNEC_SYMBOL(const char*, wl_proxy_get_class, st
|
|||||||
FENNEC_SYMBOL(void, wl_proxy_set_queue, struct wl_proxy*, struct wl_event_queue*);
|
FENNEC_SYMBOL(void, wl_proxy_set_queue, struct wl_proxy*, struct wl_event_queue*);
|
||||||
FENNEC_SYMBOL(void*, wl_proxy_create_wrapper, void*);
|
FENNEC_SYMBOL(void*, wl_proxy_create_wrapper, void*);
|
||||||
FENNEC_SYMBOL(void, wl_proxy_wrapper_destroy, void*);
|
FENNEC_SYMBOL(void, wl_proxy_wrapper_destroy, void*);
|
||||||
|
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor, struct wl_proxy*, uint32_t, const struct wl_interface*, ...);
|
||||||
|
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor_versioned, struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, ...);
|
||||||
|
FENNEC_SYMBOL(void, wl_proxy_set_tag, struct wl_proxy*, const char* const*);
|
||||||
|
FENNEC_SYMBOL(const char* const*, wl_proxy_get_tag, struct wl_proxy*);
|
||||||
|
|
||||||
FENNEC_SYMBOL(struct wl_display*, wl_display_connect, const char*);
|
FENNEC_SYMBOL(struct wl_display*, wl_display_connect, const char*);
|
||||||
FENNEC_SYMBOL(struct wl_display*, wl_display_connect_to_fd, int);
|
FENNEC_SYMBOL(struct wl_display*, wl_display_connect_to_fd, int);
|
||||||
FENNEC_SYMBOL(void, wl_display_disconnect, struct wl_display*);
|
FENNEC_SYMBOL(void, wl_display_disconnect, struct wl_display*);
|
||||||
@@ -88,6 +67,7 @@ FENNEC_SYMBOL(int, wl_display_get_error, st
|
|||||||
FENNEC_SYMBOL(int, wl_display_flush, struct wl_display*);
|
FENNEC_SYMBOL(int, wl_display_flush, struct wl_display*);
|
||||||
FENNEC_SYMBOL(int, wl_display_roundtrip, struct wl_display*);
|
FENNEC_SYMBOL(int, wl_display_roundtrip, struct wl_display*);
|
||||||
FENNEC_SYMBOL(struct wl_event_queue*, wl_display_create_queue, struct wl_display*);
|
FENNEC_SYMBOL(struct wl_event_queue*, wl_display_create_queue, struct wl_display*);
|
||||||
|
|
||||||
FENNEC_SYMBOL(void, wl_event_queue_destroy, struct wl_event_queue*);
|
FENNEC_SYMBOL(void, wl_event_queue_destroy, struct wl_event_queue*);
|
||||||
FENNEC_SYMBOL(void, wl_log_set_handler_client, wl_log_func_t);
|
FENNEC_SYMBOL(void, wl_log_set_handler_client, wl_log_func_t);
|
||||||
FENNEC_SYMBOL(void, wl_list_init, struct wl_list*);
|
FENNEC_SYMBOL(void, wl_list_init, struct wl_list*);
|
||||||
@@ -96,10 +76,6 @@ FENNEC_SYMBOL(void, wl_list_remove, st
|
|||||||
FENNEC_SYMBOL(int, wl_list_length, const struct wl_list*);
|
FENNEC_SYMBOL(int, wl_list_length, const struct wl_list*);
|
||||||
FENNEC_SYMBOL(int, wl_list_empty, const struct wl_list*);
|
FENNEC_SYMBOL(int, wl_list_empty, const struct wl_list*);
|
||||||
FENNEC_SYMBOL(void, wl_list_insert_list, struct wl_list*, struct wl_list*);
|
FENNEC_SYMBOL(void, wl_list_insert_list, struct wl_list*, struct wl_list*);
|
||||||
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor, struct wl_proxy*, uint32_t opcode, const struct wl_interface*interface, ...);
|
|
||||||
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor_versioned, struct wl_proxy*proxy, uint32_t opcode, const struct wl_interface*interface, uint32_t version, ...);
|
|
||||||
FENNEC_SYMBOL(void, wl_proxy_set_tag, struct wl_proxy*, const char* const*);
|
|
||||||
FENNEC_SYMBOL(const char* const*, wl_proxy_get_tag, struct wl_proxy*);
|
|
||||||
|
|
||||||
FENNEC_GLOBAL(const struct wl_interface, wl_display_interface);
|
FENNEC_GLOBAL(const struct wl_interface, wl_display_interface);
|
||||||
FENNEC_GLOBAL(const struct wl_interface, wl_registry_interface);
|
FENNEC_GLOBAL(const struct wl_interface, wl_registry_interface);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,198 +0,0 @@
|
|||||||
// =====================================================================================================================
|
|
||||||
// fennec, a free and open source game engine
|
|
||||||
// Copyright © 2025 Medusa Slockbower
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
// =====================================================================================================================
|
|
||||||
|
|
||||||
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_UTIL_H
|
|
||||||
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_UTIL_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright © 2008 Kristian Høgsberg
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
* the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice (including the
|
|
||||||
* next paragraph) shall be included in all copies or substantial
|
|
||||||
* portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
|
||||||
#define WL_EXPORT __attribute__ ((visibility("default")))
|
|
||||||
#else
|
|
||||||
#define WL_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ >= 202311L
|
|
||||||
#define WL_DEPRECATED [[deprecated]]
|
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
|
||||||
#define WL_DEPRECATED __attribute__ ((deprecated))
|
|
||||||
#else
|
|
||||||
#define WL_DEPRECATED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
|
||||||
#define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y)))
|
|
||||||
#else
|
|
||||||
#define WL_PRINTF(x, y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ >= 202311L
|
|
||||||
#define WL_TYPEOF(expr) typeof(expr)
|
|
||||||
#else
|
|
||||||
#define WL_TYPEOF(expr) __typeof__(expr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct wl_message {
|
|
||||||
const char *name;
|
|
||||||
const char *signature;
|
|
||||||
const struct wl_interface **types;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl_interface {
|
|
||||||
const char *name;
|
|
||||||
int version;
|
|
||||||
int method_count;
|
|
||||||
const struct wl_message *methods;
|
|
||||||
int event_count;
|
|
||||||
const struct wl_message *events;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wl_list {
|
|
||||||
struct wl_list *prev;
|
|
||||||
struct wl_list *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define wl_container_of(ptr, sample, member) \
|
|
||||||
(WL_TYPEOF(sample))((char *)(ptr) - \
|
|
||||||
offsetof(WL_TYPEOF(*sample), member))
|
|
||||||
|
|
||||||
#define wl_list_for_each(pos, head, member) \
|
|
||||||
for (pos = wl_container_of((head)->next, pos, member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = wl_container_of(pos->member.next, pos, member))
|
|
||||||
|
|
||||||
#define wl_list_for_each_safe(pos, tmp, head, member) \
|
|
||||||
for (pos = wl_container_of((head)->next, pos, member), \
|
|
||||||
tmp = wl_container_of((pos)->member.next, tmp, member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = tmp, \
|
|
||||||
tmp = wl_container_of(pos->member.next, tmp, member))
|
|
||||||
|
|
||||||
#define wl_list_for_each_reverse(pos, head, member) \
|
|
||||||
for (pos = wl_container_of((head)->prev, pos, member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = wl_container_of(pos->member.prev, pos, member))
|
|
||||||
|
|
||||||
#define wl_list_for_each_reverse_safe(pos, tmp, head, member) \
|
|
||||||
for (pos = wl_container_of((head)->prev, pos, member), \
|
|
||||||
tmp = wl_container_of((pos)->member.prev, tmp, member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = tmp, \
|
|
||||||
tmp = wl_container_of(pos->member.prev, tmp, member))
|
|
||||||
|
|
||||||
struct wl_array {
|
|
||||||
size_t size;
|
|
||||||
size_t alloc;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
wl_array_init(struct wl_array *array);
|
|
||||||
|
|
||||||
void
|
|
||||||
wl_array_release(struct wl_array *array);
|
|
||||||
|
|
||||||
void *
|
|
||||||
wl_array_add(struct wl_array *array, size_t size);
|
|
||||||
|
|
||||||
int
|
|
||||||
wl_array_copy(struct wl_array *array, struct wl_array *source);
|
|
||||||
|
|
||||||
#define wl_array_for_each(pos, array) \
|
|
||||||
for (pos = (array)->data; \
|
|
||||||
(array)->size != 0 && \
|
|
||||||
(const char *) pos < ((const char *) (array)->data + (array)->size); \
|
|
||||||
(pos)++)
|
|
||||||
|
|
||||||
typedef int32_t wl_fixed_t;
|
|
||||||
|
|
||||||
static inline double
|
|
||||||
wl_fixed_to_double(wl_fixed_t f)
|
|
||||||
{
|
|
||||||
return f / 256.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline wl_fixed_t
|
|
||||||
wl_fixed_from_double(double d)
|
|
||||||
{
|
|
||||||
return (wl_fixed_t) (d * 256.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
wl_fixed_to_int(wl_fixed_t f)
|
|
||||||
{
|
|
||||||
return f / 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline wl_fixed_t
|
|
||||||
wl_fixed_from_int(int i)
|
|
||||||
{
|
|
||||||
return i * 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
union wl_argument {
|
|
||||||
int32_t i;
|
|
||||||
uint32_t u;
|
|
||||||
wl_fixed_t f;
|
|
||||||
const char *s;
|
|
||||||
struct wl_object *o;
|
|
||||||
uint32_t n;
|
|
||||||
struct wl_array *a;
|
|
||||||
int32_t h;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int (*wl_dispatcher_func_t)(const void *user_data, void *target,
|
|
||||||
uint32_t opcode, const struct wl_message *msg,
|
|
||||||
union wl_argument *args);
|
|
||||||
|
|
||||||
typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0);
|
|
||||||
|
|
||||||
enum wl_iterator_result {
|
|
||||||
WL_ITERATOR_STOP,
|
|
||||||
WL_ITERATOR_CONTINUE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_UTIL_H
|
|
||||||
98
include/fennec/platform/linux/wayland/lib/wayland.h
Normal file
98
include/fennec/platform/linux/wayland/lib/wayland.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H
|
||||||
|
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H
|
||||||
|
|
||||||
|
#include <wayland-client-core.h>
|
||||||
|
|
||||||
|
#define FENNEC_LIB(name) extern "C" bool FENNEC_HAS_LIB_##name;
|
||||||
|
#define FENNEC_SYMBOL(ret, fn, ...) using WAYLAND_sym_##fn = ret(*)(__VA_ARGS__); \
|
||||||
|
extern "C" WAYLAND_sym_##fn WAYLAND_##fn;
|
||||||
|
#define FENNEC_GLOBAL(type, name) extern "C" type* WAYLAND_##name;
|
||||||
|
#include <fennec/platform/linux/wayland/lib/sym.h>
|
||||||
|
|
||||||
|
#define wl_proxy_marshal WAYLAND_wl_proxy_marshal
|
||||||
|
#define wl_proxy_marshal_flags WAYLAND_wl_proxy_marshal_flags
|
||||||
|
#define wl_proxy_create WAYLAND_wl_proxy_create
|
||||||
|
#define wl_proxy_destroy WAYLAND_wl_proxy_destroy
|
||||||
|
#define wl_proxy_add_listener WAYLAND_wl_proxy_add_listener
|
||||||
|
#define wl_proxy_set_user_data WAYLAND_wl_proxy_set_user_data
|
||||||
|
#define wl_proxy_get_user_data WAYLAND_wl_proxy_get_user_data
|
||||||
|
#define wl_proxy_get_version WAYLAND_wl_proxy_get_version
|
||||||
|
#define wl_proxy_get_id WAYLAND_wl_proxy_get_id
|
||||||
|
#define wl_proxy_get_class WAYLAND_wl_proxy_get_class
|
||||||
|
#define wl_proxy_set_queue WAYLAND_wl_proxy_set_queue
|
||||||
|
#define wl_proxy_create_wrapper WAYLAND_wl_proxy_create_wrapper
|
||||||
|
#define wl_proxy_wrapper_destroy WAYLAND_wl_proxy_wrapper_destroy
|
||||||
|
#define wl_proxy_marshal_constructor WAYLAND_wl_proxy_marshal_constructor
|
||||||
|
#define wl_proxy_marshal_constructor_versioned WAYLAND_wl_proxy_marshal_constructor_versioned
|
||||||
|
#define wl_proxy_set_tag WAYLAND_wl_proxy_set_tag
|
||||||
|
#define wl_proxy_get_tag WAYLAND_wl_proxy_get_tag
|
||||||
|
|
||||||
|
#define wl_event_queue_destroy WAYLAND_wl_event_queue_destroy
|
||||||
|
#define wl_log_set_handler_client WAYLAND_wl_log_set_handler_client
|
||||||
|
#define wl_list_init WAYLAND_wl_list_init
|
||||||
|
#define wl_list_insert WAYLAND_wl_list_insert
|
||||||
|
#define wl_list_remove WAYLAND_wl_list_remove
|
||||||
|
#define wl_list_length WAYLAND_wl_list_length
|
||||||
|
#define wl_list_empty WAYLAND_wl_list_empty
|
||||||
|
#define wl_list_insert_list WAYLAND_wl_list_insert_list
|
||||||
|
|
||||||
|
#define wl_display_connect WAYLAND_wl_display_connect
|
||||||
|
#define wl_display_connect_to_fd WAYLAND_wl_display_connect_to_fd
|
||||||
|
#define wl_display_reconnect WAYLAND_wl_display_reconnect
|
||||||
|
#define wl_display_disconnect WAYLAND_wl_display_disconnect
|
||||||
|
#define wl_display_get_fd WAYLAND_wl_display_get_fd
|
||||||
|
#define wl_display_dispatch WAYLAND_wl_display_dispatch
|
||||||
|
#define wl_display_dispatch_queue WAYLAND_wl_display_dispatch_queue
|
||||||
|
#define wl_display_dispatch_queue_pending WAYLAND_wl_display_dispatch_queue_pending
|
||||||
|
#define wl_display_dispatch_pending WAYLAND_wl_display_dispatch_pending
|
||||||
|
#define wl_display_prepare_read WAYLAND_wl_display_prepare_read
|
||||||
|
#define wl_display_prepare_read_queue WAYLAND_wl_display_prepare_read_queue
|
||||||
|
#define wl_display_read_events WAYLAND_wl_display_read_events
|
||||||
|
#define wl_display_cancel_read WAYLAND_wl_display_cancel_read
|
||||||
|
#define wl_display_get_error WAYLAND_wl_display_get_error
|
||||||
|
#define wl_display_flush WAYLAND_wl_display_flush
|
||||||
|
#define wl_display_roundtrip WAYLAND_wl_display_roundtrip
|
||||||
|
#define wl_display_create_queue WAYLAND_wl_display_create_queue
|
||||||
|
|
||||||
|
#define wl_seat_interface *WAYLAND_wl_seat_interface
|
||||||
|
#define wl_surface_interface *WAYLAND_wl_surface_interface
|
||||||
|
#define wl_shm_pool_interface *WAYLAND_wl_shm_pool_interface
|
||||||
|
#define wl_buffer_interface *WAYLAND_wl_buffer_interface
|
||||||
|
#define wl_registry_interface *WAYLAND_wl_registry_interface
|
||||||
|
#define wl_region_interface *WAYLAND_wl_region_interface
|
||||||
|
#define wl_pointer_interface *WAYLAND_wl_pointer_interface
|
||||||
|
#define wl_keyboard_interface *WAYLAND_wl_keyboard_interface
|
||||||
|
#define wl_compositor_interface *WAYLAND_wl_compositor_interface
|
||||||
|
#define wl_output_interface *WAYLAND_wl_output_interface
|
||||||
|
#define wl_shm_interface *WAYLAND_wl_shm_interface
|
||||||
|
#define wl_data_device_interface *WAYLAND_wl_data_device_interface
|
||||||
|
#define wl_data_offer_interface *WAYLAND_wl_data_offer_interface
|
||||||
|
#define wl_data_source_interface *WAYLAND_wl_data_source_interface
|
||||||
|
#define wl_data_device_manager_interface *WAYLAND_wl_data_device_manager_interface
|
||||||
|
|
||||||
|
#define wl_egl_window_create WAYLAND_wl_egl_window_create
|
||||||
|
#define wl_egl_window_destroy WAYLAND_wl_egl_window_destroy
|
||||||
|
#define wl_egl_window_resize WAYLAND_wl_egl_window_resize
|
||||||
|
#define wl_egl_window_get_attached_size WAYLAND_wl_egl_window_get_attached_size
|
||||||
|
|
||||||
|
#include <fennec/platform/linux/wayland/lib/headers/wayland-client-protocols.h>
|
||||||
|
|
||||||
|
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H
|
||||||
83
include/fennec/platform/linux/wayland/window.h
Normal file
83
include/fennec/platform/linux/wayland/window.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file window.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
|
#define FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
|
|
||||||
|
#include <fennec/platform/interface/window.h>
|
||||||
|
#include <fennec/platform/linux/wayland/display.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class wayland_window : public window {
|
||||||
|
public:
|
||||||
|
bool running() override;
|
||||||
|
|
||||||
|
void configure(const config& config) override;
|
||||||
|
|
||||||
|
bool initialize(bool modal) override;
|
||||||
|
|
||||||
|
bool shutdown() override;
|
||||||
|
|
||||||
|
bool set_title(const cstring& title) override;
|
||||||
|
bool set_title(const string& title) override;
|
||||||
|
|
||||||
|
bool set_width(size_t w) override;
|
||||||
|
bool set_height(size_t h) override;
|
||||||
|
bool resize(size_t w, size_t h) override;
|
||||||
|
bool set_resizable(bool e) override;
|
||||||
|
bool set_fullscreen_mode(fullscreen_mode mode) override;
|
||||||
|
|
||||||
|
bool grab_keyboard(bool e) override;
|
||||||
|
bool grab_mouse(bool e) override;
|
||||||
|
|
||||||
|
bool block_screensaver(bool e) override;
|
||||||
|
|
||||||
|
wayland_window(wayland_display* display, wayland_window* parent);
|
||||||
|
~wayland_window() override;
|
||||||
|
|
||||||
|
struct wl_surface* get_native_handle() override {
|
||||||
|
return _handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wl_surface* _handle;
|
||||||
|
wl_shell_surface* _shell;
|
||||||
|
size_t _nfs_width, _nfs_height;
|
||||||
|
|
||||||
|
static void listen_ping(void*, wl_shell_surface*, uint32_t);
|
||||||
|
static void listen_configure(void*, wl_shell_surface*, uint32_t, int32_t, int32_t);
|
||||||
|
static void listen_popup_done(void*, wl_shell_surface*);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user