Compare commits
39 Commits
3d42dea9eb
...
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 |
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/
|
||||
/bin/
|
||||
/lib/
|
||||
/doxy/README.md
|
||||
|
||||
@@ -20,20 +20,38 @@ cmake_minimum_required(VERSION 3.30)
|
||||
project(fennec)
|
||||
|
||||
# External dependencies should be loaded here
|
||||
|
||||
# CppTrace is a dependency of the project, added as a git submodule
|
||||
add_subdirectory(external/cpptrace)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
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("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
|
||||
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
|
||||
include("${FENNEC_SOURCE_DIR}/cmake/build.cmake")
|
||||
include("${FENNEC_SOURCE_DIR}/cmake/compiler.cmake")
|
||||
|
||||
# common defines
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS "NULL=0")
|
||||
|
||||
# find dependencies
|
||||
find_package(Doxygen)
|
||||
fennec_check_platform()
|
||||
@@ -58,16 +76,32 @@ add_library(fennec STATIC
|
||||
include/fennec/core/engine.h source/core/engine.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 ===========================================================================================================
|
||||
include/fennec/containers/containers.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/traversal.h
|
||||
include/fennec/containers/tuple.h
|
||||
include/fennec/containers/variant.h
|
||||
|
||||
|
||||
include/fennec/containers/detail/_tuple.h
|
||||
|
||||
@@ -83,7 +117,7 @@ add_library(fennec STATIC
|
||||
include/fennec/lang/intrinsics.h
|
||||
include/fennec/lang/limits.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/type_identity.h
|
||||
include/fennec/lang/type_operators.h
|
||||
@@ -95,6 +129,9 @@ add_library(fennec STATIC
|
||||
include/fennec/lang/utility.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/_int.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/_typeuuid.h
|
||||
|
||||
include/fennec/lang/assert.h source/lang/assert.cpp
|
||||
|
||||
|
||||
# MEMORY ===============================================================================================================
|
||||
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/memory.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
|
||||
|
||||
# CONCURRENCY ==========================================================================================================
|
||||
include/fennec/concurrency/thread.h
|
||||
include/fennec/concurrency/mutex.h
|
||||
include/fennec/concurrency/atomic.h
|
||||
|
||||
# DEBUG ================================================================================================================
|
||||
source/debug/assert_impl.cpp
|
||||
|
||||
@@ -184,19 +214,15 @@ add_library(fennec STATIC
|
||||
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/gfxcontext.h
|
||||
include/fennec/platform/interface/gfxsurface.h
|
||||
|
||||
|
||||
# EXTRA SOURCES ========================================================================================================
|
||||
|
||||
${FENNEC_EXTRA_SOURCES}
|
||||
include/fennec/renderers/interface/renderer.h
|
||||
include/fennec/containers/rdtree.h
|
||||
include/fennec/scene/scene.h
|
||||
include/fennec/scene/component.h
|
||||
include/fennec/core/system.h
|
||||
)
|
||||
|
||||
add_dependencies(fennec metaprogramming)
|
||||
add_dependencies(fennec metaprogramming fennec-dependencies)
|
||||
|
||||
target_compile_definitions(fennec PUBLIC
|
||||
${FENNEC_COMPILE_DEFINITIONS}
|
||||
@@ -208,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
|
||||
|
||||
target_link_libraries(fennec PRIVATE
|
||||
cpptrace::cpptrace
|
||||
${FENNEC_LINK_LIBRARIES}
|
||||
|
||||
cpptrace::cpptrace
|
||||
)
|
||||
|
||||
|
||||
@@ -222,6 +249,7 @@ file(COPY logo DESTINATION docs/logo)
|
||||
if(DOXYGEN_FOUND)
|
||||
add_dependencies(fennec fennecdocs)
|
||||
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
|
||||
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
|
||||
|
||||
761
PLANNING.md
761
PLANNING.md
@@ -1,761 +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-langproc)
|
||||
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/langproc/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) ✔
|
||||
- XKB
|
||||
- PulseAudio
|
||||
- Vulkan
|
||||
- X11
|
||||
- ALSA
|
||||
- Vulkan
|
||||
- Microsoft Windows
|
||||
- XInput
|
||||
- OpenGL (WGL)
|
||||
- WASAPI
|
||||
- Vulkan
|
||||
- Android
|
||||
- OpenGL ES
|
||||
- AAudio
|
||||
- openslES
|
||||
- macOS/iOS
|
||||
- cocoa
|
||||
- OpenGL
|
||||
- Core Audio
|
||||
- Vulkan
|
||||
- Metal
|
||||
|
||||
Linux Wayland will be implemented first. Once setup, the core engine will be implemented and tested on top of Wayland.
|
||||
Once the engine is in a stable state, then support for other platforms will be resumed.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Language Processing (`langproc`)
|
||||
|
||||
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 (`langproc/strings`)
|
||||
* Search
|
||||
* Manipulation
|
||||
* Delimiting
|
||||
* Regex
|
||||
|
||||
- File Formats (`langproc/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
|
||||
unfortunately, most formats are esoteric due to copyright/trademark/etc. I will be using assimp for the
|
||||
time being, below is a list of formats supported by assimp.
|
||||
- 3D
|
||||
- 3DS
|
||||
- 3MF
|
||||
- AC
|
||||
- AC3D
|
||||
- ACC
|
||||
- AMJ
|
||||
- ASE
|
||||
- ASK
|
||||
- B3D
|
||||
- BVH
|
||||
- CSM
|
||||
- COB
|
||||
- DAE/Collada
|
||||
- DXF
|
||||
- ENFF
|
||||
- FBX
|
||||
- glTF 1.0 + GLB
|
||||
- glTF 2.0
|
||||
- HMB
|
||||
- IFC-STEP
|
||||
- IQM
|
||||
- IRR / IRRMESH
|
||||
- LWO
|
||||
- LWS
|
||||
- LXO
|
||||
- M3D
|
||||
- MD2
|
||||
- MD3
|
||||
- MD5
|
||||
- MDC
|
||||
- MDL
|
||||
- MESH / MESH.XML
|
||||
- MOT
|
||||
- MS3D
|
||||
- NDO
|
||||
- NFF
|
||||
- OBJ
|
||||
- OFF
|
||||
- OGEX
|
||||
- PLY
|
||||
- PMX
|
||||
- PRJ
|
||||
- Q3O
|
||||
- Q3S
|
||||
- RAW
|
||||
- SCN
|
||||
- SIB
|
||||
- SMD
|
||||
- STP
|
||||
- STL
|
||||
- TER
|
||||
- UC
|
||||
- USD
|
||||
- VTA
|
||||
- X
|
||||
- X3D
|
||||
- XGL
|
||||
- ZGL
|
||||
- Video Formats
|
||||
- MP4
|
||||
- AVI
|
||||
- MPG
|
||||
- MOV
|
||||
|
||||
**TODO LATER**
|
||||
* Compilation (`langproc/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 Accelerations)
|
||||
- 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.
|
||||
|
||||
There will be three profiles for OpenGL implementation:
|
||||
- modern
|
||||
- fallback
|
||||
- legacy
|
||||
|
||||
All profiles will have the same feature set, however their implementations will differ.
|
||||
The modern context will use up-to-date features to get as much performance out of the pipeline as
|
||||
possible.
|
||||
|
||||
|
||||
|
||||
### 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;
|
||||
uint32 material, lighting;
|
||||
}
|
||||
```
|
||||
|
||||
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 and 3D textures 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 R Cubemap `1024, 512, 256, 128` (4)
|
||||
- 8-Bit RGB Cubemap `1024, 512, 256, 128` (4)
|
||||
|
||||
* 16-Bit HDR R Texture `4096, 2048, 1024, 512` (8)
|
||||
* 16-Bit HDR RGB Texture `4096, 2048, 1024, 512` (8)
|
||||
* 16-Bit HDR RGBA Texture `4096, 2048, 1024, 512` (8)
|
||||
* 16-Bit HDR R Cubemap `1024, 512, 256, 128` (4)
|
||||
* 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)
|
||||
|
||||
* 8-Bit 3D R Texture `256, 128, 64, 32` (4)
|
||||
* 8-Bit 3D RGB Texture `256, 128, 64, 32` (4)
|
||||
* 16-Bit 3D HDR R Texture `256, 128, 64, 32` (4)
|
||||
* 16-Bit 3D HDR RGB Texture `256, 128, 64, 32` (4)
|
||||
|
||||
Documentation should provide guidelines on categories of Art Assets and the resolution of textures to use.
|
||||
|
||||
Textures are identified by a 32-bit integer.
|
||||
- `8 bits` → the texture buffer
|
||||
- `24 bits` → 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.
|
||||
|
||||
Types of materials:
|
||||
- Surface (Vertex & Fragment)
|
||||
- Opaque / Masked
|
||||
- Translucent (Forward)
|
||||
- Volume (Path Traced Volumetrics / Forward)
|
||||
- Light (Lighting Model)
|
||||
- Post-Process
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 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
|
||||
|
||||
- Generate Dynamic Shadows
|
||||
- Generate Dynamic Reflections (Optional)
|
||||
- SSAO (Optional)
|
||||
- Deferred Lighting Pass `(10 Bpp, 80 bpp) [1920x1080] ≈ 2 x 16.3MB + 8.3MB ≈ 24.6MB`
|
||||
- Depth Buffer → `D24`
|
||||
- Lighting Buffer → `RGB16` w/ Mipmapping
|
||||
- Stencil Buffer $rarr; `S8`
|
||||
- Apply Lighting Model
|
||||
|
||||
Debug View: Shadows, Reflections, SSAO, Deferred Lighting
|
||||
|
||||
We can combine all of these into one framebuffer:
|
||||
|
||||
- Depth - Stencil → `D24_S8`
|
||||
- Visibility Info → `RGB32I`
|
||||
- Diffuse → `RGBA8`
|
||||
- Emission → `RGB8`
|
||||
- Normal → `RGB8`
|
||||
- Specular → `RGB8`
|
||||
- Lighting Buffer → `RGB16` w/ Mipmapping
|
||||
- One more slot left open for another
|
||||
|
||||
* 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>
|
||||
|
||||
## 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>
|
||||
@@ -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 |
|
||||
| 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 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 |
|
||||
@@ -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
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
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.
|
||||
|
||||
@@ -206,23 +255,26 @@ information displayed is correct.
|
||||
## Usage
|
||||
|
||||
|
||||
<a id="licensing"></a>
|
||||
### Licensing
|
||||
|
||||
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.
|
||||
|
||||
  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.
|
||||
TLDR; You may license your game under whichever license you please. Any C++ code that is by definition a derivative work
|
||||
must be licensed under GPLv3 and freely available, everything else; assets, scripts, design documents, etc. may be under
|
||||
the license of your choosing and remain proprietary.
|
||||
|
||||
  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
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
8
build.sh
8
build.sh
@@ -38,7 +38,7 @@ Help()
|
||||
Debug()
|
||||
{
|
||||
mkdir -p build/debug
|
||||
cd ./build/debug
|
||||
cd ./build/debug || exit
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../.. -B .
|
||||
cmake --build . --target fennec
|
||||
cd ../..
|
||||
@@ -47,7 +47,7 @@ Debug()
|
||||
Release()
|
||||
{
|
||||
mkdir -p build/release
|
||||
cd ./build/release
|
||||
cd ./build/release || exit
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S ../.. -B .
|
||||
cmake --build . --target fennec
|
||||
cd ../..
|
||||
@@ -56,7 +56,7 @@ Release()
|
||||
RelWithDebInfo()
|
||||
{
|
||||
mkdir -p build/relwithdebinfo
|
||||
cd ./build/relwithdebinfo
|
||||
cd ./build/relwithdebinfo || exit
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -S ../.. -B .
|
||||
cmake --build . --target fennec
|
||||
cd ../..
|
||||
@@ -65,7 +65,7 @@ RelWithDebInfo()
|
||||
MinSizeRel()
|
||||
{
|
||||
mkdir -p build/minsizerel
|
||||
cd ./build/minsizerel
|
||||
cd ./build/minsizerel || exit
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel -S ../.. -B .
|
||||
cmake --build . --target fennec
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
# compile definitions
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
||||
fennec_add_definitions(
|
||||
FENNEC_PLATFORM_NAME="Linux"
|
||||
FENNEC_PLATFORM_LINUX=1
|
||||
)
|
||||
|
||||
# extra source files
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
fennec_add_sources(
|
||||
include/fennec/platform/linux/platform.h source/platform/linux/platform.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -18,14 +18,17 @@
|
||||
|
||||
if(FENNEC_GRAPHICS_WANT_EGL)
|
||||
find_package(OpenGL REQUIRED COMPONENTS EGL)
|
||||
find_package(GLEW REQUIRED)
|
||||
message(STATUS "EGL Requested")
|
||||
else()
|
||||
find_package(OpenGL)
|
||||
find_package(GLEW REQUIRED)
|
||||
endif()
|
||||
|
||||
if(TARGET OpenGL::GL)
|
||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::GL)
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_OPENGL=1)
|
||||
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
|
||||
message(STATUS "Found OpenGL: ${OPENGL_gl_LIBRARY}")
|
||||
fennec_add_link_libraries(OpenGL::GL GLEW::GLEW)
|
||||
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
|
||||
else()
|
||||
message(FATAL_ERROR "No Suitable OpenGL implementation found.")
|
||||
endif()
|
||||
@@ -35,12 +38,20 @@ if(FENNEC_GRAPHICS_WANT_EGL)
|
||||
message(FATAL_ERROR "EGL Library not found.")
|
||||
endif()
|
||||
|
||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::EGL)
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_EGL=1)
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
|
||||
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
|
||||
|
||||
include/fennec/renderers/opengl/modern.h
|
||||
include/fennec/renderers/opengl/fallback.h
|
||||
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/surface.h source/platform/opengl/egl/surface.cpp
|
||||
)
|
||||
endif()
|
||||
@@ -19,11 +19,11 @@
|
||||
# generic unix functionality
|
||||
|
||||
# compile definitions
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
||||
fennec_add_definitions(
|
||||
FENNEC_PLATFORM_UNIX=1
|
||||
)
|
||||
|
||||
# extra source files
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
fennec_add_sources(
|
||||
include/fennec/platform/unix/platform.h source/platform/unix/platform.cpp
|
||||
)
|
||||
@@ -19,6 +19,23 @@
|
||||
# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a
|
||||
# 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)
|
||||
set(WAYLAND_CLIENT_FOUND 0)
|
||||
|
||||
@@ -30,6 +47,7 @@ macro(fennec_check_wayland)
|
||||
WAYLAND_CLIENT_LIBRARY
|
||||
NAMES wayland-client libwayland-client
|
||||
)
|
||||
find_program(WAYLAND_SCANNER NAMES wayland-scanner)
|
||||
|
||||
# EGL is required
|
||||
find_path(
|
||||
@@ -41,13 +59,34 @@ macro(fennec_check_wayland)
|
||||
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))
|
||||
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")
|
||||
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(
|
||||
WAYLAND_CLIENT_LIBRARY
|
||||
${WAYLAND_CLIENT_LIBRARY}
|
||||
@@ -63,19 +102,18 @@ macro(fennec_check_wayland)
|
||||
set(WAYLAND_EGL_FOUND 1)
|
||||
set(FENNEC_GRAPHICS_WANT_EGL 1)
|
||||
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
fennec_add_sources(
|
||||
# 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/wayland-client.h
|
||||
include/fennec/platform/linux/wayland/lib/wayland-util.h
|
||||
include/fennec/platform/linux/wayland/lib/wayland.h
|
||||
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
|
||||
|
||||
# Fennec Files
|
||||
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_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
|
||||
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
|
||||
|
||||
@@ -41,17 +41,16 @@ macro(fennec_check_xkb)
|
||||
|
||||
set(XKB_FOUND 1)
|
||||
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
fennec_add_sources(
|
||||
# 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/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
|
||||
|
||||
# Fennec files
|
||||
)
|
||||
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS
|
||||
fennec_add_definitions(
|
||||
FENNEC_HAS_XKB=1
|
||||
FENNEC_LIB_XKB="${XKB_LIBRARY}"
|
||||
)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
<includes visible="$SHOW_HEADERFILE"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
@@ -83,7 +84,6 @@
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
@@ -105,6 +105,7 @@
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
@@ -121,7 +122,6 @@
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
@@ -150,6 +150,7 @@
|
||||
<includegraph visible="yes"/>
|
||||
<includedbygraph visible="yes"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
@@ -167,7 +168,6 @@
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
@@ -185,6 +185,7 @@
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<modules visible="yes" title=""/>
|
||||
@@ -210,7 +211,6 @@
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
@@ -237,6 +237,7 @@
|
||||
<module>
|
||||
<briefdescription visible="yes"/>
|
||||
<exportedmodules visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<concepts visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
@@ -246,7 +247,6 @@
|
||||
<variables title=""/>
|
||||
<membergroups title=""/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
@@ -256,10 +256,10 @@
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
|
||||
@@ -944,7 +944,7 @@ WARN_LOGFILE =
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = "/home/medusa/Documents/Work/Personal/fennec/include" \
|
||||
"/home/medusa/Documents/Work/Personal/fennec/source" \
|
||||
"/home/medusa/Documents/Work/Personal/fennec/source" \
|
||||
"/home/medusa/Documents/Work/Personal/fennec/README.md"
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
||||
# that contain images that are to be included in the documentation (see the
|
||||
# \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
|
||||
# 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.
|
||||
# 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
|
||||
# invoked.
|
||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
||||
# The default value is: 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
|
||||
# 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.
|
||||
# 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
|
||||
# dependency graph for every global function or class method.
|
||||
|
||||
@@ -944,7 +944,7 @@ WARN_LOGFILE =
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = "@PROJECT_SOURCE_DIR@/include" \
|
||||
"@PROJECT_SOURCE_DIR@/source" \
|
||||
"@PROJECT_SOURCE_DIR@/source" \
|
||||
"@PROJECT_SOURCE_DIR@/README.md"
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
@@ -1099,7 +1099,7 @@ EXAMPLE_RECURSIVE = NO
|
||||
# that contain images that are to be included in the documentation (see the
|
||||
# \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
|
||||
# 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.
|
||||
# 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
|
||||
# invoked.
|
||||
@@ -2664,7 +2664,7 @@ TEMPLATE_RELATIONS = NO
|
||||
# The default value is: 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
|
||||
# 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.
|
||||
# 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
|
||||
# dependency graph for every global function or class method.
|
||||
|
||||
@@ -287,3 +287,8 @@ html.dark-mode {
|
||||
td.odd_c {
|
||||
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
|
||||
/// \brief statically allocated array wrapper
|
||||
/// \brief A header containing the definition for a static/stack allocated array
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -40,61 +40,48 @@ namespace fennec
|
||||
|
||||
///
|
||||
///
|
||||
/// \brief wrapper for fixed size arrays
|
||||
/// \brief Data Structure that defines a compile-time allocated array
|
||||
///
|
||||
/// \details
|
||||
/// | Property | Value |
|
||||
/// |----------|-------------------------|
|
||||
/// | stable | \emoji heavy_check_mark |
|
||||
/// | access | \f$O(1)\f$ |
|
||||
/// | space | \f$O(N)\f$ |
|
||||
/// | Property | Value |
|
||||
/// |:----------:|:----------:|
|
||||
/// | stable | ✅ |
|
||||
/// | dynamic | ⛔ |
|
||||
/// | homogenous | ✅ |
|
||||
/// | distinct | ⛔ |
|
||||
/// | ordered | ⛔ |
|
||||
/// | space | \f$O(N)\f$ |
|
||||
/// | linear | ✅ |
|
||||
/// | access | \f$O(1)\f$ |
|
||||
/// | find | \f$O(N)\f$ |
|
||||
/// | insertion | ⛔ |
|
||||
/// | deletion | ⛔ |
|
||||
///
|
||||
/// \tparam ValueT value type
|
||||
/// \tparam ElemV number of elements
|
||||
template<typename ValueT, size_t ElemV>
|
||||
struct array
|
||||
{
|
||||
///
|
||||
/// \brief backing c-style array handle
|
||||
ValueT elements[ElemV];
|
||||
struct array {
|
||||
|
||||
/// \name Element Access
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
using value_t = ValueT; ///< Alias for `ValueT`
|
||||
|
||||
// Public Members ======================================================================================================
|
||||
|
||||
/// \name Public Members
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \copydetails array::operator[](size_t) const
|
||||
constexpr ValueT& operator[](size_t i) {
|
||||
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; }
|
||||
/// \brief backing c-style array handle
|
||||
value_t data[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
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief
|
||||
/// \brief Checks if all elements in the arrays are equal
|
||||
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
|
||||
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) {
|
||||
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:
|
||||
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]) && ...);
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||
#include <fennec/lang/sequences.h>
|
||||
#include <fennec/lang/const_sequences.h>
|
||||
#include <fennec/lang/utility.h>
|
||||
|
||||
namespace fennec::detail
|
||||
{
|
||||
|
||||
// leaves
|
||||
template<size_t i, typename T>
|
||||
struct _tuple_leaf {
|
||||
T value;
|
||||
|
||||
template<typename...ArgsT>
|
||||
_tuple_leaf(ArgsT&&...args) : value(args...) {
|
||||
}
|
||||
template <std::size_t I, typename T>
|
||||
struct _tuple_leaf
|
||||
{
|
||||
template <typename ArgT>
|
||||
constexpr _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {}
|
||||
|
||||
constexpr operator T&() {
|
||||
return value;
|
||||
}
|
||||
constexpr ~_tuple_leaf() = default;
|
||||
|
||||
constexpr operator const T&() const {
|
||||
return value;
|
||||
}
|
||||
constexpr _tuple_leaf& operator=(const _tuple_leaf&) = default;
|
||||
constexpr _tuple_leaf& operator=(_tuple_leaf&&) noexcept = default;
|
||||
|
||||
T value;
|
||||
};
|
||||
|
||||
// proxy
|
||||
template<typename, typename...TypesT>
|
||||
template <typename, typename...>
|
||||
struct _tuple;
|
||||
|
||||
template<size_t...i, typename...TypesT>
|
||||
struct _tuple<index_sequence<i...>, TypesT...> : _tuple_leaf<i, TypesT>... {
|
||||
template <size_t...IndicesV, typename...TypesT>
|
||||
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
|
||||
{
|
||||
template <typename...ArgsT>
|
||||
constexpr _tuple(ArgsT&&... args)
|
||||
: _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
_tuple(ArgsT&&...args) : _tuple_leaf<i, TypesT>(args)... {
|
||||
}
|
||||
constexpr _tuple& operator=(const _tuple&) = default;
|
||||
constexpr _tuple& operator=(_tuple&&) noexcept = default;
|
||||
|
||||
constexpr ~_tuple() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
///
|
||||
/// \file dynarray.h
|
||||
/// \brief dynamically allocated array wrapper
|
||||
/// \brief A header containing the definition for a dynamically allocated array
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -40,126 +40,287 @@ namespace fennec
|
||||
|
||||
///
|
||||
///
|
||||
/// \brief wrapper for dynamically sized arrays
|
||||
/// \brief Wrapper for dynamically sized and allocated arrays
|
||||
/// \details
|
||||
/// | Property | Value |
|
||||
/// |-----------|--------------|
|
||||
/// | stable | \emoji anger |
|
||||
/// | access | \f$O(1)\f$ |
|
||||
/// | insertion | \f$O(N)\f$ |
|
||||
/// | deletion | \f$O(N)\f$ |
|
||||
/// | space | \f$O(N)\f$ |
|
||||
/// | 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(N)\f$ |
|
||||
/// | deletion | \f$O(N)\f$ |
|
||||
///
|
||||
/// This structure prefers shallow moves and deep copies.
|
||||
///
|
||||
/// \tparam TypeT value type
|
||||
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||
class dynarray {
|
||||
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.
|
||||
constexpr dynarray() : _alloc(8), _size(0) {}
|
||||
constexpr dynarray()
|
||||
: _alloc(8)
|
||||
, _size(0) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \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.
|
||||
constexpr dynarray(const alloc_t& alloc)
|
||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||
/// data.
|
||||
explicit constexpr dynarray(const alloc_t& alloc)
|
||||
: _alloc(8, alloc)
|
||||
, _size(0) {
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Sized Allocation, create an allocation with a size of `n` elements, initialized with the default constructor.
|
||||
constexpr dynarray(size_t n)
|
||||
/// \brief Alloc Move 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.
|
||||
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)
|
||||
, _size(n)
|
||||
{
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief
|
||||
/// \param n
|
||||
/// \param alloc
|
||||
/// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator `alloc` and `n` elements
|
||||
/// using the default constructor.
|
||||
/// \param n The number of elements
|
||||
/// \param alloc The allocator object to copy
|
||||
constexpr dynarray(size_t n, const alloc_t& alloc)
|
||||
: _alloc(n, alloc)
|
||||
, _size(n) {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Create an allocation of size `n`, with each element constructed using the copy constructor
|
||||
/// \brief n the number of elements
|
||||
/// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator `alloc` and `n` 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)
|
||||
: _alloc(n)
|
||||
, _size(n) {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
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;
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr dynarray(size_t n, ArgsT&&...args) {
|
||||
element_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr, fennec::forward<ArgsT>(args)...);
|
||||
constexpr explicit dynarray(size_t n, ArgsT&&...args)
|
||||
: _alloc(n)
|
||||
, _size(n) {
|
||||
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() {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
if (addr == nullptr) return;
|
||||
for(int n = _size; n > 0; --n, ++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 {
|
||||
return _size;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The current capacity, in elements, of the underlying allocation
|
||||
constexpr size_t capacity() const {
|
||||
return _alloc.capacity();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns True when there are no elements active, otherwise false
|
||||
constexpr bool empty() const {
|
||||
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];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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() {
|
||||
return this->operator[](size() - 1);
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns A const-qualified reference to the last element in the dynarray
|
||||
constexpr const TypeT& back() const {
|
||||
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) {
|
||||
|
||||
// Grow if the size has reached the capacity of the allocation
|
||||
@@ -180,6 +341,10 @@ public:
|
||||
++_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) {
|
||||
|
||||
// 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
|
||||
if((i = min(i, _size)) < _size) {
|
||||
fennec::memmove(
|
||||
(void*)(_alloc.data() + i)
|
||||
, (void*)(_alloc.data() + i + 1)
|
||||
, (_size - i) * sizeof(TypeT));
|
||||
(void*)(_alloc.data() + i),
|
||||
(void*)(_alloc.data() + i + 1),
|
||||
(_size - i) * sizeof(TypeT)
|
||||
);
|
||||
}
|
||||
|
||||
// Insert the element
|
||||
@@ -200,6 +366,11 @@ public:
|
||||
++_size;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Emplace Insertion
|
||||
/// \param i index to insert at
|
||||
/// \param args Arguments to construct with
|
||||
/// \tparam ArgsT Argument types
|
||||
template<typename...ArgsT>
|
||||
constexpr void emplace(size_t i, ArgsT&&...args) {
|
||||
|
||||
@@ -221,42 +392,91 @@ public:
|
||||
++_size;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Push Back Copy
|
||||
/// \param val Value to initialize with
|
||||
constexpr void push_back(const TypeT& val) {
|
||||
dynarray::insert(_size, val);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Push Back Move
|
||||
/// \param val Value to initialize with
|
||||
constexpr void push_back(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>
|
||||
constexpr void emplace_back(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() {
|
||||
fennec::destruct(&_alloc[--_size]);
|
||||
}
|
||||
|
||||
if (_size < n) {
|
||||
_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) {
|
||||
emplace_back();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void _grow() {
|
||||
_alloc.reallocate(_alloc.capacity() * 2);
|
||||
///
|
||||
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
/// \brief List of elements
|
||||
/// \brief A header containing the definition for a linked list of values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -43,267 +43,392 @@ namespace fennec
|
||||
|
||||
///
|
||||
///
|
||||
/// \brief wrapper for lists of elements
|
||||
/// \brief Data Structure defining lists of elements
|
||||
/// \details
|
||||
/// | Property | Value |
|
||||
/// |-----------|--------------|
|
||||
/// | stable | \emoji anger |
|
||||
/// | access | \f$O(1)\f$ |
|
||||
/// | insertion | \f$O(1)\f$ |
|
||||
/// | deletion | \f$O(1)\f$ |
|
||||
/// | space | \f$O(N)\f$ |
|
||||
/// 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 |
|
||||
/// |:----------:|:----------:|
|
||||
/// | stable | ⛔ |
|
||||
/// | dynamic | ✅ |
|
||||
/// | homogenous | ✅ |
|
||||
/// | distinct | ⛔ |
|
||||
/// | ordered | ⛔ |
|
||||
/// | 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
|
||||
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||
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;
|
||||
class const_iterator;
|
||||
// Definitions =========================================================================================================
|
||||
|
||||
private:
|
||||
struct node;
|
||||
|
||||
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()
|
||||
: _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(); }
|
||||
constexpr bool empty() const { return _root == npos; }
|
||||
|
||||
///
|
||||
/// \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; }
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// 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) {
|
||||
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||
size_t n = _walk(i);
|
||||
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 {
|
||||
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
|
||||
size_t n = _walk(i);
|
||||
assertd(n != npos, "Index out of Bounds");
|
||||
return *_table[n].data;
|
||||
}
|
||||
|
||||
void insert(const iterator& it, const value_t& x) {
|
||||
if (size() == capacity()) {
|
||||
_expand();
|
||||
}
|
||||
|
||||
size_t n = it._n;
|
||||
size_t p = _next_free();
|
||||
fennec::construct(&_table[p].data, x);
|
||||
if (n == npos) {
|
||||
if (empty()) {
|
||||
_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(const iterator& it, value_t&& x) {
|
||||
if (size() == capacity()) {
|
||||
_expand();
|
||||
}
|
||||
|
||||
size_t n = it._n;
|
||||
size_t p = _next_free();
|
||||
fennec::construct(&_table[p].data, fennec::forward<value_t>(x));
|
||||
if (n == npos) {
|
||||
if (empty()) {
|
||||
_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, const 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();
|
||||
fennec::construct(&_table[p].data, x);
|
||||
if (n == npos) {
|
||||
if (empty()) {
|
||||
_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();
|
||||
fennec::construct(&_table[p].data, fennec::forward<value_t>(x));
|
||||
if (n == npos) {
|
||||
if (empty()) {
|
||||
_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;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void emplace(size_t i, ArgsT&&...args) {
|
||||
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();
|
||||
fennec::construct(&_table[p].data, fennec::forward<ArgsT>(args)...);
|
||||
if (n == npos) {
|
||||
if (empty()) {
|
||||
_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 push_front(const value_t& x) {
|
||||
this->insert(0, x);
|
||||
}
|
||||
|
||||
void push_front(value_t&& x) {
|
||||
this->insert(0, fennec::forward<value_t>(x));
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void emplace_front(ArgsT...args) {
|
||||
this->emplace(0, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void emplace_back(ArgsT...args) {
|
||||
this->emplace(_size, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
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);
|
||||
return *_table[n].value;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Access Front Element
|
||||
/// \returns A reference to the first element in the list
|
||||
constexpr value_t& front() {
|
||||
return *_table[_root].data;
|
||||
return *_table[_root].value;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const Access Front Element
|
||||
/// \returns A const-qualified reference to the first element in the list
|
||||
constexpr const value_t& front() const {
|
||||
return *_table[_root].data;
|
||||
return *_table[_root].value;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Access Back Element
|
||||
/// \returns A reference to the last element in the list
|
||||
constexpr value_t& back() {
|
||||
return *_table[_last].data;
|
||||
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 {
|
||||
return *_table[_last].data;
|
||||
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 ============================================================================================================
|
||||
|
||||
/// \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 {
|
||||
public:
|
||||
~iterator() {
|
||||
@@ -326,11 +451,11 @@ public:
|
||||
}
|
||||
|
||||
constexpr value_t& operator*() {
|
||||
return *(_list->_table[_n].data);
|
||||
return *(_list->_table[_n].value);
|
||||
}
|
||||
|
||||
constexpr value_t* operator->() {
|
||||
return &*(_list->_table[_n].data);
|
||||
return &*(_list->_table[_n].value);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const iterator& it) {
|
||||
@@ -352,6 +477,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Iterator Class for Const Access
|
||||
class const_iterator {
|
||||
public:
|
||||
~const_iterator() {
|
||||
@@ -374,11 +501,11 @@ public:
|
||||
}
|
||||
|
||||
constexpr const value_t& operator*() {
|
||||
return *(_list->_table[_n].data);
|
||||
return *(_list->_table[_n].value);
|
||||
}
|
||||
|
||||
constexpr const value_t* operator->() {
|
||||
return &*(_list->_table[_n].data);
|
||||
return &*(_list->_table[_n].value);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const const_iterator& it) {
|
||||
@@ -400,24 +527,8 @@ 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:
|
||||
allocation<elem_t, alloc_t> _table;
|
||||
allocation<node, alloc_t> _table;
|
||||
dynarray<size_t> _freed;
|
||||
size_t _root, _last, _size;
|
||||
|
||||
@@ -428,23 +539,23 @@ private:
|
||||
}
|
||||
|
||||
struct node {
|
||||
optional<value_t> data;
|
||||
optional<value_t> value;
|
||||
size_t prev, next;
|
||||
|
||||
constexpr node()
|
||||
: data()
|
||||
: value()
|
||||
, prev(npos)
|
||||
, next(npos) {
|
||||
}
|
||||
|
||||
constexpr node(size_t p, size_t n)
|
||||
: data()
|
||||
: value()
|
||||
, prev(p)
|
||||
, next(n) {
|
||||
}
|
||||
|
||||
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)
|
||||
, next(n) {
|
||||
}
|
||||
@@ -452,21 +563,21 @@ private:
|
||||
constexpr ~node() = default;
|
||||
|
||||
constexpr void clear() {
|
||||
data = nullopt;
|
||||
value = nullopt;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
}
|
||||
};
|
||||
|
||||
size_t _next(size_t n) const {
|
||||
constexpr size_t _next(size_t n) const {
|
||||
return _table[n].next;
|
||||
}
|
||||
|
||||
size_t _prev(size_t n) const {
|
||||
constexpr size_t _prev(size_t n) const {
|
||||
return _table[n].prev;
|
||||
}
|
||||
|
||||
size_t _walk(size_t i) const {
|
||||
constexpr size_t _walk(size_t i) const {
|
||||
size_t n = _root;
|
||||
if (n == npos) return n;
|
||||
while (i > 0 && n != npos) {
|
||||
@@ -475,15 +586,68 @@ private:
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t _next_free() {
|
||||
constexpr size_t _next_free() {
|
||||
if (not _freed.empty()) {
|
||||
size_t n = _freed.back();
|
||||
_freed.pop_back();
|
||||
return n;
|
||||
}
|
||||
_table[_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/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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
|
||||
#define FENNEC_CONTAINERS_MAP_H
|
||||
|
||||
@@ -25,14 +37,12 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
// TODO: Document
|
||||
|
||||
/* Ramblings
|
||||
*
|
||||
* Definitions:
|
||||
* 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 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[].
|
||||
*
|
||||
* 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.
|
||||
* 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>>>
|
||||
struct map {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
using key_t = KeyT;
|
||||
using value_t = ValueT;
|
||||
using elem_t = pair<KeyT, ValueT>;
|
||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>;
|
||||
using hash_t = Hash;
|
||||
struct key_hash; ///< Hash for node keys
|
||||
struct key_equals; ///< Comparison for node keys
|
||||
using key_t = KeyT; ///< The key type
|
||||
using value_t = ValueT; ///< The value type
|
||||
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
|
||||
struct key_hash : hash_t {
|
||||
@@ -62,114 +99,191 @@ public:
|
||||
};
|
||||
|
||||
// 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 {
|
||||
return equality<KeyT>::operator()(a.first, b.first);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Constructors & Destructor ===========================================================================================
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes empty map
|
||||
constexpr map() = default;
|
||||
|
||||
///
|
||||
/// \brief Destructor, Destructs all elements and releases the allocation
|
||||
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) {
|
||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||
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;
|
||||
auto it = _set.at(this->_find(key));
|
||||
return it ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \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 {
|
||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||
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;
|
||||
auto it = _set.at(this->_find(key));
|
||||
return it ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr value_t* operator[](ArgsT&&...args) {
|
||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||
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;
|
||||
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||
return it ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr const value_t* operator[](ArgsT&&...args) const {
|
||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||
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;
|
||||
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
|
||||
return it ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Modifiers ===========================================================================================================
|
||||
|
||||
/// \name Modifiers
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Key-Value Insertion
|
||||
/// \param pair a pair containing the key and its value
|
||||
constexpr void insert(elem_t&& pair) {
|
||||
auto it = _set.find(pair);
|
||||
if (it == _set.end()) {
|
||||
_set.at(it)->second = fennec::move(pair.second);
|
||||
return;
|
||||
}
|
||||
_set.insert(fennec::forward<elem_t>(pair));
|
||||
this->_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>
|
||||
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) {
|
||||
union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers
|
||||
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);
|
||||
_set.erase(this->_find(fennec::forward<KeyT>(key)));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Erase a key
|
||||
/// \param key key to erase
|
||||
constexpr void erase(const KeyT& key) {
|
||||
KeyT val = key;
|
||||
erase(fennec::move(val));
|
||||
_set.erase(this->_find(key));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Argument Erase
|
||||
/// \tparam ArgsT Argument Types
|
||||
/// \param args Arguments to construct a key to erase
|
||||
template<typename...ArgsT>
|
||||
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
|
||||
pair<KeyT, char[sizeof(ValueT)]> root;
|
||||
pair<KeyT, ValueT> val;
|
||||
@@ -178,12 +292,19 @@ public:
|
||||
fennec::destruct(&root);
|
||||
}
|
||||
} trick = { .root = { KeyT(fennec::forward<ArgsT>(args)...), 0 } };
|
||||
_set.erase(trick.val);
|
||||
return _set.find(trick.val);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
set<elem_t, key_hash, node_equals, alloc_t> _set;
|
||||
template<typename...ArgsT>
|
||||
constexpr void _insert(ArgsT&&...args) {
|
||||
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/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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
|
||||
#define FENNEC_CONTAINERS_OPTIONAL_H
|
||||
|
||||
@@ -37,13 +49,20 @@ constexpr nullopt_t nullopt_v = {};
|
||||
/// \tparam T
|
||||
template<typename T>
|
||||
struct optional {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
// Constructors ========================================================================================================
|
||||
using reference_t = T&;
|
||||
using pointer_t = T*;
|
||||
using const_reference_t = T&;
|
||||
using const_pointer_t = const T*;
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Default Constructor
|
||||
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
|
||||
constexpr optional(T val) requires(is_fundamental_v<T> or is_pointer_v<T>)
|
||||
constexpr optional(const T& val)
|
||||
: _val(val)
|
||||
, _set(true) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Type Copy Constructor
|
||||
/// \brief Type Move Constructor
|
||||
/// \param val the value to initialize the underlying object with
|
||||
constexpr optional(const T& val)
|
||||
: _val(val)
|
||||
constexpr optional(T&& val)
|
||||
: _val(fennec::forward<T>(val))
|
||||
, _set(true) {
|
||||
}
|
||||
|
||||
@@ -97,6 +116,12 @@ public:
|
||||
opt = nullopt;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr optional(ArgsT&&...args)
|
||||
: _val(fennec::forward<ArgsT>(args)...)
|
||||
, _set(true) {
|
||||
}
|
||||
|
||||
constexpr ~optional() {
|
||||
if constexpr(is_fundamental_v<T>) {
|
||||
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 ================================================================================================
|
||||
|
||||
/// \name Assignment
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Fundamental Type Assignment
|
||||
/// \val The value to set with
|
||||
/// \param val The value to set with
|
||||
constexpr optional& operator=(nullopt_t) {
|
||||
if constexpr(not is_fundamental_v<T>) {
|
||||
if (_set) {
|
||||
@@ -125,7 +175,7 @@ public:
|
||||
|
||||
///
|
||||
/// \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> {
|
||||
if (_set) {
|
||||
_val = val;
|
||||
@@ -138,12 +188,12 @@ public:
|
||||
|
||||
///
|
||||
/// \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> {
|
||||
if (_set) {
|
||||
_val = fennec::move(val);
|
||||
_val = fennec::forward<T>(val);
|
||||
} else {
|
||||
fennec::construct(&_val, fennec::move(val));
|
||||
fennec::construct(&_val, fennec::forward<T>(val));
|
||||
_set = true;
|
||||
}
|
||||
return *this;
|
||||
@@ -151,7 +201,7 @@ public:
|
||||
|
||||
///
|
||||
/// \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> {
|
||||
if (_set != opt._set) {
|
||||
_set = opt._set;
|
||||
@@ -169,7 +219,7 @@ public:
|
||||
|
||||
///
|
||||
/// \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> {
|
||||
if (_set != opt._set) {
|
||||
_set = opt._set;
|
||||
@@ -185,6 +235,68 @@ public:
|
||||
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>
|
||||
constexpr T& emplace(ArgsT&&...args) {
|
||||
if (_set) {
|
||||
@@ -196,44 +308,13 @@ public:
|
||||
return _val;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Reset the Optional
|
||||
void reset() {
|
||||
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/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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
|
||||
#define FENNEC_CONTAINERS_PAIR_H
|
||||
|
||||
@@ -28,67 +40,144 @@ namespace fennec
|
||||
|
||||
// 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 {
|
||||
|
||||
// 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;
|
||||
|
||||
///
|
||||
/// \brief Destructor, invokes destructor for both elements
|
||||
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)
|
||||
, second(y) {
|
||||
}
|
||||
|
||||
constexpr pair(T0&& x, T1&& y) noexcept
|
||||
: first(fennec::forward<T0>(x))
|
||||
, second(fennec::forward<T1>(y)) {
|
||||
///
|
||||
/// \brief Pair Move Constructor
|
||||
/// \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>
|
||||
constexpr pair(Arg1T&& arg1, Arg2T&& arg2)
|
||||
: first(fennec::forward<Arg1T>(arg1))
|
||||
, second(fennec::forward<Arg2T>(arg2)) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Constructor, copies both elements
|
||||
constexpr pair(const pair&) = default;
|
||||
|
||||
///
|
||||
/// \brief Move Constructor, moves both elements
|
||||
constexpr pair(pair&&) noexcept = default;
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment, copies both elements
|
||||
constexpr pair& operator=(const pair&) = default;
|
||||
|
||||
///
|
||||
/// \brief Move Assignment, moves both elements
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return first > p.first or (first == p.first and second >= p.second);
|
||||
}
|
||||
|
||||
T0 first;
|
||||
T1 second;
|
||||
/// @}
|
||||
};
|
||||
|
||||
template<typename T0, typename T1>
|
||||
struct hash<pair<T0, T1>> : hash<T0>, hash<T1> {
|
||||
constexpr size_t operator()(const pair<T0, T1>& p) const {
|
||||
template<typename TypeT0, typename TypeT1>
|
||||
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
|
||||
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
|
||||
return fennec::pair_hash( // pair the hashes of both elements
|
||||
hash<T0>::operator()(p.first),
|
||||
hash<T1>::operator()(p.second)
|
||||
hash<TypeT0>::operator()(p.first),
|
||||
hash<TypeT1>::operator()(p.second)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,19 +16,38 @@
|
||||
// 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 {
|
||||
private:
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
protected:
|
||||
struct node;
|
||||
|
||||
public:
|
||||
@@ -41,18 +60,29 @@ 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, ArgsT&&...args)
|
||||
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) {
|
||||
, parent(p), child(c), prev(v), next(n)
|
||||
, depth(d), num_children(0) {
|
||||
}
|
||||
|
||||
constexpr ~node() {
|
||||
parent = npos;
|
||||
child = npos;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
parent = npos;
|
||||
child = npos;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
depth = 0;
|
||||
num_children = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,69 +90,250 @@ 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)
|
||||
: _data(), _freed(), _size(1) {
|
||||
_data.callocate(10);
|
||||
fennec::construct(&_data[0], npos, npos, npos, npos, fennec::forward<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)
|
||||
: _data(tree._data), _freed(tree._freed), _size(tree._size) {
|
||||
: _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
|
||||
: _data(fennec::move(tree._data)), _freed(fennec::move(tree._freed)), _size(tree._size) {
|
||||
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
friend constexpr rdtree& operator=(rdtree& lhs, const rdtree& rhs) {
|
||||
for (value_t* it : lhs._data) {
|
||||
/// \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);
|
||||
}
|
||||
lhs._data = rhs._data;
|
||||
lhs._freed = rhs._freed;
|
||||
lhs._size = rhs._size;
|
||||
return lhs;
|
||||
_table = rhs._table;
|
||||
_freed = rhs._freed;
|
||||
_size = rhs._size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend constexpr rdtree& operator=(rdtree& lhs, rdtree&& rhs) noexcept {
|
||||
for (value_t* it : lhs._data) {
|
||||
///
|
||||
/// \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);
|
||||
}
|
||||
lhs._data = fennec::move(rhs._data);
|
||||
lhs._freed = fennec::move(rhs._freed);
|
||||
lhs._size = rhs._size;
|
||||
return lhs;
|
||||
_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 {
|
||||
return _data[i].parent;
|
||||
if (i >= _table.capacity()) return npos;
|
||||
return i == npos ? npos : _table[i].parent;
|
||||
}
|
||||
|
||||
constexpr size_t child(size_t i) const {
|
||||
return _data[i].child;
|
||||
///
|
||||
/// \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;
|
||||
}
|
||||
|
||||
constexpr size_t next(size_t i) const {
|
||||
return _data[i].next;
|
||||
///
|
||||
/// \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;
|
||||
}
|
||||
|
||||
constexpr size_t prev(size_t i) const {
|
||||
return _data[i].prev;
|
||||
///
|
||||
/// \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;
|
||||
}
|
||||
|
||||
constexpr optional<value_t>& operator[](size_t i) {
|
||||
return *_data[i].value;
|
||||
///
|
||||
/// \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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const optional<value_t>& operator[](size_t i) const {
|
||||
return *_data[i].value;
|
||||
///
|
||||
/// \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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,88 +342,283 @@ public:
|
||||
///
|
||||
/// \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, const value_t& val) {
|
||||
if (parent == npos || _size == 0) {
|
||||
if (_size == 0) {
|
||||
fennec::construct(&_data[root], npos, npos, npos, npos, val);
|
||||
_size = 1;
|
||||
} else {
|
||||
_data[root].value = val;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
size_t i = _next_free();
|
||||
size_t n = child(parent);
|
||||
_data[parent].child = i;
|
||||
fennec::construct(&_data[i], parent, npos, n, npos);
|
||||
return i;
|
||||
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, value_t&& val) {
|
||||
if (parent == npos || _size == 0) {
|
||||
if (_size == 0) {
|
||||
fennec::construct(&_data[root], npos, npos, npos, npos, fennec::forward<value_t>(val));
|
||||
_size = 1;
|
||||
} else {
|
||||
_data[root].value = fennec::forward<value_t>(val);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
size_t i = _next_free();
|
||||
size_t n = child(parent);
|
||||
_data[parent].child = i;
|
||||
fennec::construct(&_data[i], parent, npos, n, npos);
|
||||
return i;
|
||||
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) {
|
||||
list<size_t> queue;
|
||||
if (child(i) != npos) {
|
||||
queue.push_back(i);
|
||||
}
|
||||
|
||||
while (not queue.empty()) {
|
||||
size_t n = queue.front(); queue.pop_front();
|
||||
if (next(n) != npos) queue.push_back(next(n));
|
||||
if (child(n) != npos) queue.push_back(child(n));
|
||||
fennec::destruct(&_data[n]);
|
||||
_freed.push_back(n);
|
||||
}
|
||||
|
||||
fennec::destruct(&_data[i]);
|
||||
_freed.push_back(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> _data;
|
||||
allocation<node, alloc_t> _table;
|
||||
list<size_t> _freed;
|
||||
size_t _size;
|
||||
|
||||
void _expand() {
|
||||
_data.creallocate(_data.capacity() * 2);
|
||||
_table.creallocate(_table.capacity() * 2);
|
||||
}
|
||||
|
||||
size_t _next_free() {
|
||||
size_t next = _size + 1;
|
||||
size_t next = _size;
|
||||
if (not _freed.empty()) {
|
||||
next = _freed.back();
|
||||
_freed.pop_back();
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// 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
|
||||
#define FENNEC_CONTAINERS_SET_H
|
||||
|
||||
@@ -31,15 +43,36 @@
|
||||
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 {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
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 equal_t = Equals;
|
||||
using elem_t = T;
|
||||
using elem_t = TypeT;
|
||||
|
||||
class iterator;
|
||||
static constexpr size_t npos = -1;
|
||||
@@ -54,7 +87,14 @@ private:
|
||||
constexpr ~node() = default;
|
||||
};
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
public:
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes empty set
|
||||
constexpr set()
|
||||
: _alloc()
|
||||
, _hash()
|
||||
@@ -63,6 +103,9 @@ public:
|
||||
, _load(default_load) {
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Hash Copy Constructor, initializes empty set with a hash
|
||||
/// \param hash the hash object
|
||||
constexpr set(const hash_t& hash)
|
||||
: _alloc()
|
||||
, _hash(hash)
|
||||
@@ -71,14 +114,9 @@ public:
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
constexpr set(hash_t&& hash) noexcept
|
||||
: _alloc()
|
||||
, _hash(hash)
|
||||
, _size(0)
|
||||
, _sumpsl(0)
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Alloc Copy Constructor, initializes empty set with an allocator
|
||||
/// \param alloc the allocator object
|
||||
constexpr set(const alloc_t& alloc)
|
||||
: _alloc(alloc)
|
||||
, _hash()
|
||||
@@ -87,14 +125,10 @@ public:
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
constexpr set(alloc_t&& alloc) noexcept
|
||||
: _alloc(alloc)
|
||||
, _hash()
|
||||
, _size(0)
|
||||
, _sumpsl(0)
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Hash Alloc Copy Constructor, initializes empty set with a hash and allocator
|
||||
/// \param hash the hash object
|
||||
/// \param alloc the allocator object
|
||||
constexpr set(const hash_t& hash, const alloc_t& alloc)
|
||||
: _alloc(alloc)
|
||||
, _hash(hash)
|
||||
@@ -103,30 +137,9 @@ public:
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
constexpr set(const hash_t& hash, alloc_t&& alloc) noexcept
|
||||
: _alloc(alloc)
|
||||
, _hash(hash)
|
||||
, _size(0)
|
||||
, _sumpsl(0)
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
constexpr set(hash_t&& hash, alloc_t&& alloc) noexcept
|
||||
: _alloc(alloc)
|
||||
, _hash(hash)
|
||||
, _size(0)
|
||||
, _sumpsl(0)
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
constexpr set(hash_t&& hash, const alloc_t& alloc) noexcept
|
||||
: _alloc(alloc)
|
||||
, _hash(hash)
|
||||
, _size(0)
|
||||
, _sumpsl(0)
|
||||
, _load(default_load) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Set Copy Constructor
|
||||
/// \param set Set to copy
|
||||
constexpr set(const set& set)
|
||||
: _alloc(set._alloc)
|
||||
, _hash(set._hash)
|
||||
@@ -135,6 +148,9 @@ public:
|
||||
, _load(set._load) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Set Move Constructor
|
||||
/// \param set Set to move
|
||||
constexpr set(set&& set) noexcept
|
||||
: _alloc(fennec::move(set._alloc))
|
||||
, _hash(fennec::move(set._hash))
|
||||
@@ -143,52 +159,56 @@ public:
|
||||
, _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 {
|
||||
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 {
|
||||
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
|
||||
_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;
|
||||
}
|
||||
|
||||
constexpr void insert(const elem_t& val) {
|
||||
elem_t value = val; // Copy Constructor invoked here
|
||||
this->insert(fennec::move(value)); // Only invokes moves
|
||||
}
|
||||
// Access ==============================================================================================================
|
||||
|
||||
template<typename...ArgsT>
|
||||
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
|
||||
}
|
||||
/// \name Access
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \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 {
|
||||
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
|
||||
@@ -196,7 +216,7 @@ public:
|
||||
|
||||
// Check the first element;
|
||||
if (_alloc[i].psl >= psl && _alloc[i].value) {
|
||||
if (*_alloc[i].value == val) {
|
||||
if (_equal(*_alloc[i].value, val)) {
|
||||
return iterator(this, i);
|
||||
}
|
||||
}
|
||||
@@ -207,17 +227,17 @@ public:
|
||||
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 = false, c1 = false;
|
||||
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
|
||||
|
||||
if ((c0 = (p0 > 0 && _alloc[i0].psl >= p0)) && _alloc[i0].value) {
|
||||
if (*_alloc[i0].value == val) {
|
||||
return iterator(this, i);
|
||||
if (c0 && _alloc[i0].value) {
|
||||
if (_equal(*_alloc[i0].value, val)) {
|
||||
return iterator(this, i0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((c1 = (_alloc[i1].psl >= p1)) && _alloc[i1].value) {
|
||||
if (*_alloc[i1].value == val) {
|
||||
return iterator(this, i);
|
||||
if (c1 && _alloc[i1].value) {
|
||||
if (_equal(*_alloc[i1].value, val)) {
|
||||
return iterator(this, i1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,24 +249,71 @@ public:
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
constexpr elem_t* at(const iterator& it) {
|
||||
size_t i = it._i;
|
||||
if (i >= capacity()) return nullptr;
|
||||
if (not _alloc[i].value) return nullptr;
|
||||
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;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Check if a set 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 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) {
|
||||
size_t i = it._i;
|
||||
if (i >= capacity()) {
|
||||
@@ -269,15 +336,56 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Element Erase
|
||||
/// \param val Value to erase
|
||||
constexpr void erase(const elem_t& val) {
|
||||
this->erase(this->find(val));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief
|
||||
constexpr void clear() {
|
||||
for (size_t i = 0; i < _alloc.capacity(); ++i) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
constexpr iterator(const set* set, size_t i)
|
||||
: _set(set)
|
||||
, _i(i) {
|
||||
}
|
||||
|
||||
constexpr ~iterator() {
|
||||
_set = nullptr;
|
||||
}
|
||||
@@ -303,44 +411,34 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const iterator& it) {
|
||||
constexpr bool operator!=(const iterator& it) const {
|
||||
return _set != it._set or _i != it._i;
|
||||
}
|
||||
|
||||
constexpr size_t index() const { return _i; }
|
||||
|
||||
private:
|
||||
const set* _set;
|
||||
size_t _i;
|
||||
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:
|
||||
constexpr void _expand() {
|
||||
set cpy; // Create a new set
|
||||
cpy._alloc.callocate(
|
||||
cpy._alloc.resize(
|
||||
fennec::next_prime2(_alloc.capacity())
|
||||
);
|
||||
|
||||
@@ -355,12 +453,38 @@ private:
|
||||
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;
|
||||
equal_t _equal;
|
||||
size_t _size;
|
||||
size_t _sumpsl;
|
||||
double _load;
|
||||
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/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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
|
||||
#define FENNEC_CONTAINERS_TUPLE_H
|
||||
|
||||
@@ -27,38 +39,68 @@ namespace fennec
|
||||
|
||||
// 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<size_t i, typename...TypesT>
|
||||
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
||||
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||
auto& it = static_cast<detail::_tuple_leaf<i, elem_t>>(x);
|
||||
return it;
|
||||
auto& it = *static_cast<detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||
return it.value;
|
||||
}
|
||||
|
||||
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>;
|
||||
auto& it = static_cast<detail::_tuple_leaf<i, elem_t>>(x);
|
||||
return it;
|
||||
const auto& it = *static_cast<const detail::_tuple_leaf<i, elem_t>*>(&x);
|
||||
return it.value;
|
||||
}
|
||||
|
||||
|
||||
template<typename...TypesT>
|
||||
struct tuple : detail::_tuple<make_index_sequence<sizeof...(TypesT)>, TypesT...> {
|
||||
|
||||
public:
|
||||
using base_t = detail::_tuple<make_index_sequence<sizeof...(TypesT)>, TypesT...>;
|
||||
template<typename ...TypesT>
|
||||
struct tuple : public detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>
|
||||
{
|
||||
using base_t = detail::_tuple<make_index_sequence_t<sizeof...(TypesT)>, TypesT...>;
|
||||
|
||||
template<size_t i>
|
||||
using elem_t = nth_element<i, TypesT...>;
|
||||
using elem_t = typename nth_element<i, TypesT...>::type;
|
||||
|
||||
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
|
||||
|
||||
@@ -16,21 +16,19 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_RENDERERS_OPENGL_MODERN_H
|
||||
#define FENNEC_RENDERERS_OPENGL_MODERN_H
|
||||
///
|
||||
/// \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))
|
||||
///
|
||||
///
|
||||
|
||||
/*
|
||||
*
|
||||
* Requires the following:
|
||||
* OpenGL 4.6 OR
|
||||
* - ARB_shader_draw_parameters
|
||||
* - ARB_multi_draw_indirect
|
||||
* - EXT_texture_array
|
||||
* - ARB_compute_shader
|
||||
* - ARB_shader_image_load_store
|
||||
* - ARB_texture_cube_map_array
|
||||
*
|
||||
* This will support >91.31% of devices on Steam, including all Desktop GPUs and iGPUs since 2012
|
||||
*/
|
||||
#ifndef FENNEC_CONTAINERS_VARIANT_H
|
||||
#define FENNEC_CONTAINERS_VARIANT_H
|
||||
|
||||
#endif // FENNEC_RENDERERS_OPENGL_MODERN_H
|
||||
#endif // FENNEC_CONTAINERS_VARIANT_H
|
||||
@@ -29,19 +29,25 @@
|
||||
///
|
||||
|
||||
///
|
||||
/// \page documentation Documentation
|
||||
/// \page contents Contents
|
||||
///
|
||||
/// 1. \ref introduction "Introduction"
|
||||
/// 1. \ref coding-standards "Coding Standards"
|
||||
/// 2. \ref building-from-source "Building from Source"
|
||||
/// 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"
|
||||
/// 3. \ref running-the-test-suite "Running the Test Suite"
|
||||
/// 4. \ref usage "Usage"
|
||||
/// 1. \ref licensing "Licensing"
|
||||
/// 5. \ref contribution "Contribution"
|
||||
/// 6. \subpage libraries
|
||||
/// 1. \ref fennec_lang "C++ Language 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))
|
||||
///
|
||||
@@ -49,11 +55,16 @@
|
||||
///
|
||||
/// \page libraries Libraries
|
||||
///
|
||||
/// | 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_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. |
|
||||
/// | 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_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_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
|
||||
#define FENNEC_CORE_ENGINE_H
|
||||
|
||||
@@ -84,7 +84,7 @@ void _assert_impl(const char* expression, const char* file, int line, const char
|
||||
}
|
||||
|
||||
#if FENNEC_RELEASE
|
||||
#define assertd(expression, description) (0)
|
||||
#define assertd(expression, description)
|
||||
#else
|
||||
#define assertd(expression, description) assert(expression, description)
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -91,13 +91,13 @@ namespace fennec
|
||||
/// \endcode
|
||||
/// \tparam ValueT type of the 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
|
||||
using value_type = ValueT;
|
||||
|
||||
/// \brief self-referential type
|
||||
using type = sequence;
|
||||
using type = const_sequence;
|
||||
|
||||
///
|
||||
/// \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 Values sequence values
|
||||
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
|
||||
using value_type = IntT;
|
||||
|
||||
/// \brief self-referential type
|
||||
using type = integer_sequence;
|
||||
using type = const_integer_sequence;
|
||||
|
||||
///
|
||||
/// \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.
|
||||
/// \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
|
||||
using value_type = size_t;
|
||||
|
||||
/// \brief self-referential type
|
||||
using type = index_sequence;
|
||||
using type = const_index_sequence;
|
||||
|
||||
///
|
||||
/// \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>>{};
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
template<> struct make_index_sequence<0> : index_sequence<> {};
|
||||
template<> struct make_index_sequence<0> : const_index_sequence<> {};
|
||||
|
||||
// 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
|
||||
template<typename T, T...SequenceV0, T...SequenceV1>
|
||||
struct concat_sequence<integer_sequence<T, SequenceV0...>, integer_sequence<T, SequenceV1...>>
|
||||
: integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||
struct concat_sequence<const_integer_sequence<T, SequenceV0...>, const_integer_sequence<T, SequenceV1...>>
|
||||
: const_integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||
|
||||
// Specialization for index sequences
|
||||
template<size_t...SequenceV0, size_t...SequenceV1>
|
||||
struct concat_sequence<index_sequence<SequenceV0...>, index_sequence<SequenceV1...>>
|
||||
: index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||
struct concat_sequence<const_index_sequence<SequenceV0...>, const_index_sequence<SequenceV1...>>
|
||||
: const_index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define __PTRDIFF_TYPE__ ptrdiff_t
|
||||
#endif
|
||||
|
||||
// Include math since stdint will define its own versions of isinf and isnan
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace fennec::detail
|
||||
|
||||
template<size_t n, size_t i, typename HeadT, typename...RestT>
|
||||
struct _nth_element<n, i, HeadT, RestT...> : conditional<
|
||||
n == i, type_identity<HeadT>,
|
||||
_nth_element<n, i + 1, RestT...>
|
||||
n == i, HeadT,
|
||||
typename _nth_element<n, i + 1, RestT...>::type
|
||||
> {};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// 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
|
||||
// Copyright (C) 2025 Medusa Slockbower
|
||||
// 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
|
||||
|
||||
@@ -249,6 +249,7 @@ namespace fennec
|
||||
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 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
|
||||
|
||||
@@ -42,6 +42,22 @@ FENNEC_NO_INLINE uint64_t typeuuid() {
|
||||
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
|
||||
|
||||
@@ -248,7 +248,7 @@ public:
|
||||
bool eof() const;
|
||||
|
||||
|
||||
// Read Operations =====================================================================================================
|
||||
// Binary Read Operations ==============================================================================================
|
||||
|
||||
char getc();
|
||||
wchar_t getwc();
|
||||
@@ -269,13 +269,23 @@ public:
|
||||
wstring getwline();
|
||||
|
||||
|
||||
// Write Operations ====================================================================================================
|
||||
// Binary Write Operations =============================================================================================
|
||||
|
||||
bool putc(char c);
|
||||
bool putwc(wchar_t c);
|
||||
|
||||
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>
|
||||
size_t write(const T* data, size_t n) {
|
||||
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||
@@ -287,6 +297,11 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Printing Operations =================================================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
// Error Handling ======================================================================================================
|
||||
|
||||
const char* get_error() const { return _error; }
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
/// \param str the cstring to convert
|
||||
path(const cstring& 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);
|
||||
}
|
||||
}
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
/// \brief String Conversion Constructor
|
||||
/// \param str the string to convert
|
||||
path(const string& str)
|
||||
: _str(str) {
|
||||
while (_str[_str.size() - 1] == '/') {
|
||||
: _str(str) {
|
||||
if (str.size() > 2 && str[str.size() - 1] == '/') {
|
||||
_str = _str.substring(0, str.size() - 1);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,16 @@ public:
|
||||
|
||||
// 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
|
||||
/// \param p the cstring to assign
|
||||
@@ -145,6 +155,7 @@ public:
|
||||
}
|
||||
|
||||
const string& str() const { return _str; }
|
||||
const char* cstr() const { return _str.cstr(); }
|
||||
|
||||
bool empty() {
|
||||
size_t size = _str.size();
|
||||
@@ -176,7 +187,7 @@ public:
|
||||
#else
|
||||
size_t start = _str.size() - 1;
|
||||
start = _str[start] == '/' ? start - 1 : start;
|
||||
return _str.substring(0, _str.rfind('/', start));
|
||||
return path(_str.substring(0, _str.rfind('/', start)));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -195,7 +206,7 @@ public:
|
||||
|
||||
while (not parse.empty()) {
|
||||
// Handle dots
|
||||
while (parse._str[0] == '.') {
|
||||
while (not parse.empty() && parse._str[0] == '.') {
|
||||
// Check for ".."
|
||||
if (parse._str[1] == '.') {
|
||||
// ".."
|
||||
|
||||
@@ -171,6 +171,10 @@ public:
|
||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||
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 {
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -330,8 +341,8 @@ private:
|
||||
|
||||
template<>
|
||||
struct hash<cstring> : hash<byte_array> {
|
||||
constexpr size_t operator()(const cstring& str) {
|
||||
return hash<byte_array>::operator()(byte_array(*str, str.size()));
|
||||
constexpr size_t operator()(const cstring& str) const {
|
||||
return hash<byte_array>::operator()(byte_array(str, str.size()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
///
|
||||
/// \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 n the number of characters
|
||||
///
|
||||
/// \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) {
|
||||
fennec::memset(_str.data(), c, n);
|
||||
_str[n] = '\0';
|
||||
fennec::memset(_str, c, n);
|
||||
}
|
||||
|
||||
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
|
||||
/// \param str the buffer to copy
|
||||
/// \param n number of characters in the buffer
|
||||
///
|
||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
||||
/// This constructor makes the assumption that `n` is the intended number of characters.
|
||||
constexpr _string(const char* str, size_t n)
|
||||
: _str(n + 1) {
|
||||
fennec::memcpy(_str.data(), str, n);
|
||||
_str[n] = '\0';
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||
/// \param str the buffer to wrap
|
||||
/// \tparam n the number of characters in the buffer including the null-terminator, if present
|
||||
template<size_t n>
|
||||
explicit constexpr _string(const char (&str)[n])
|
||||
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||
fennec::memcpy(_str, str, n);
|
||||
if (str[n - 1] != '\0') {
|
||||
_str[n] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Buffer Copy Constructor
|
||||
/// \param str the buffer to copy
|
||||
constexpr _string(const cstring& str)
|
||||
: _str(str, str.size() + 1) {
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||
/// \param str the buffer to wrap
|
||||
/// \param n the number of characters in the buffer including the null-terminator, if present
|
||||
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
|
||||
/// \param str the string to copy
|
||||
constexpr _string(const _string& str)
|
||||
: _str(str._str) {
|
||||
}
|
||||
|
||||
constexpr _string(_string&& str) noexcept
|
||||
: _str(fennec::move(str._str)) {
|
||||
}
|
||||
constexpr _string(const _string& str) = default;
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
constexpr ~_string() = default; // allocation cleans up itself
|
||||
/// \brief String Move Constructor
|
||||
/// \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 ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The size of the string excluding null terminator
|
||||
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 {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a reference to the character
|
||||
constexpr char& operator[](int i) {
|
||||
constexpr char& operator[](size_t i) {
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
@@ -141,24 +164,21 @@ public:
|
||||
/// \brief Const-Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a copy of the character
|
||||
constexpr char operator[](int i) const {
|
||||
assertd(i >= 0 && (size_t)i < size(), "Array Out of Bounds");
|
||||
constexpr const char& operator[](size_t i) const {
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const char* operator*() const {
|
||||
return _str.data();
|
||||
constexpr char* data() {
|
||||
return _str;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const char*() const {
|
||||
return _str.data();
|
||||
constexpr const char* data() const {
|
||||
return _str;
|
||||
}
|
||||
|
||||
constexpr const char* cstr() const {
|
||||
return _str;
|
||||
}
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
@@ -179,7 +199,7 @@ public:
|
||||
}
|
||||
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);
|
||||
|
||||
return ::strncmp(_str.data() + i, str, n);
|
||||
return ::strncmp(_str + i, str.data(), n);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const _string& str) const {
|
||||
@@ -209,8 +229,8 @@ public:
|
||||
return size();
|
||||
}
|
||||
|
||||
const char* loc = ::strchr(_str.data() + i, c); // get location using strchr
|
||||
return loc ? loc - _str.data() : size(); // return size if not found
|
||||
const char* loc = ::strchr(_str + i, c); // get location using strchr
|
||||
return loc ? loc - _str : size(); // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
@@ -299,63 +319,6 @@ public:
|
||||
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
|
||||
/// \param i the start index
|
||||
@@ -365,60 +328,98 @@ public:
|
||||
if (i >= size()) {
|
||||
return _string("");
|
||||
}
|
||||
n = min(n, size() - i);
|
||||
return _string(_str.data() + 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
|
||||
n = fennec::min(n, size() - i);
|
||||
_string res;
|
||||
res._str.callocate(n + 1);
|
||||
fennec::memcpy(res.data(), _str + i, n);
|
||||
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 {
|
||||
_string res(size() + str.size()); // Make a new string with the size of this + str
|
||||
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
||||
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
|
||||
constexpr _string operator+(char c) const {
|
||||
if (_str == nullptr) {
|
||||
return _string(1, c);
|
||||
}
|
||||
_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;
|
||||
}
|
||||
|
||||
constexpr _string operator+(const _string& str) const {
|
||||
_string res(size() + str.size()); // Make a new string with the size of this + str
|
||||
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
|
||||
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
|
||||
if (_str == nullptr) {
|
||||
return _string(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;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(char c) {
|
||||
size_t x = size();
|
||||
resize(x + 1);
|
||||
_str[x] = c;
|
||||
if (_str == nullptr) {
|
||||
_str.callocate(2);
|
||||
_str[0] = c;
|
||||
return *this;
|
||||
}
|
||||
_str.creallocate(capacity() + 1);
|
||||
_str[size() - 1] = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(const cstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::memcpy(&_str[x], str, str.size());
|
||||
constexpr _string& operator+=(const cstring& cstr) {
|
||||
if (_str == nullptr) {
|
||||
return *this = cstr;
|
||||
}
|
||||
size_t middle = size();
|
||||
_str.creallocate(middle + cstr.size() + 1);
|
||||
fennec::memcpy(_str + middle, cstr, cstr.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(const _string& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::memcpy(&_str[x], str, str.size());
|
||||
if (_str == nullptr) {
|
||||
return *this = str;
|
||||
}
|
||||
if (str.data() == nullptr) {
|
||||
return *this;
|
||||
}
|
||||
size_t middle = size();
|
||||
_str.creallocate(middle + str.size() + 1);
|
||||
fennec::memcpy(_str + middle, str.data(), str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
alloc_t _str;
|
||||
};
|
||||
@@ -426,7 +427,7 @@ private:
|
||||
template<>
|
||||
struct hash<string> : hash<byte_array> {
|
||||
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()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -66,9 +66,7 @@ public:
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr wcstring()
|
||||
: _str(nullptr)
|
||||
, _size(0)
|
||||
, _const(true) {
|
||||
: _str(nullptr), _size(0), _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
@@ -93,7 +91,7 @@ public:
|
||||
/// \param str the buffer to wrap
|
||||
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||
template<size_t n>
|
||||
constexpr wcstring(wchar_t(&str)[n])
|
||||
constexpr wcstring(wchar_t (&str)[n])
|
||||
: _str(str)
|
||||
, _size(n - 1)
|
||||
, _const(false) {
|
||||
@@ -116,7 +114,7 @@ public:
|
||||
/// \param str the buffer to wrap
|
||||
/// \tparam n the number of characters in the buffer plus the null terminator
|
||||
template<size_t n>
|
||||
constexpr wcstring(const wchar_t(&str)[n])
|
||||
constexpr wcstring(const wchar_t (&str)[n])
|
||||
: _cstr(str)
|
||||
, _size(n - 1)
|
||||
, _const(true) {
|
||||
@@ -148,7 +146,7 @@ public:
|
||||
template<size_t n>
|
||||
constexpr wcstring& operator=(wchar_t(&str)[n]) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
_str = str; _size = n - 1; _const = false;
|
||||
_str = str, _size = n - 1, _const = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -175,6 +173,10 @@ public:
|
||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||
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 {
|
||||
return _cstr == nullptr || _size == 0;
|
||||
}
|
||||
@@ -196,15 +198,22 @@ public:
|
||||
/// \brief Const-Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \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");
|
||||
return _cstr[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \brief Data Access
|
||||
/// \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;
|
||||
}
|
||||
|
||||
@@ -220,12 +229,14 @@ public:
|
||||
///
|
||||
/// \returns The length of the string to the first null-terminator
|
||||
constexpr size_t length() const {
|
||||
return find(L'\0');
|
||||
return find('\0');
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \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
|
||||
/// current locale, otherwise a positive value.
|
||||
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);
|
||||
}
|
||||
|
||||
///
|
||||
/// \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
|
||||
/// \param str the string to compare against
|
||||
@@ -278,7 +298,7 @@ public:
|
||||
/// \param c the string to find
|
||||
/// \param i the index to start at
|
||||
/// \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) {
|
||||
return _size;
|
||||
}
|
||||
@@ -300,7 +320,7 @@ public:
|
||||
return _size;
|
||||
}
|
||||
|
||||
const wchar_t first = str[0];
|
||||
const char first = str[0];
|
||||
i = min(i, _size - str._size);
|
||||
do {
|
||||
if(_cstr[i] == first) {
|
||||
@@ -321,6 +341,13 @@ private:
|
||||
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_LANGPROC_STRINGS_wcstring_H
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_wstringS_wstring_H
|
||||
#define FENNEC_LANGPROC_wstringS_wstring_H
|
||||
#ifndef FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||
#define FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||
#include <fennec/langproc/strings/wcstring.h>
|
||||
@@ -59,110 +59,126 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
|
||||
/// \param n the number of characters
|
||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
||||
/// \param n the number of wchar_tacters
|
||||
/// \param c the wchar_tacter to fill with
|
||||
///
|
||||
/// \details adds additional character for null termination.
|
||||
constexpr _wstring(size_t n)
|
||||
: _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)
|
||||
/// \details adds additional wchar_tacter for null termination.
|
||||
constexpr _wstring(size_t n, wchar_t c = '\0')
|
||||
: _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
|
||||
/// \param str the buffer to copy
|
||||
/// \param len number of characters in the buffer
|
||||
///
|
||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
||||
/// This constructor makes the assumption that `len` is the intended number of characters.
|
||||
constexpr _wstring(const wchar_t* str, size_t n)
|
||||
: _str(str, n + 1) {
|
||||
::wcsncpy(_str.data(), str, n);
|
||||
_str[n] = '\0';
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||
/// \param str the buffer to wrap
|
||||
/// \tparam n the number of wchar_tacters in the buffer including the null-terminator, if present
|
||||
template<size_t n>
|
||||
explicit constexpr _wstring(const wchar_t (&str)[n])
|
||||
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
||||
fennec::wmemcpy(_str, str, n);
|
||||
if (str[n - 1] != '\0') {
|
||||
_str[n] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Buffer Copy Constructor
|
||||
/// \param str the buffer to copy
|
||||
/// \param len number of characters in the buffer
|
||||
///
|
||||
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
|
||||
/// This constructor makes the assumption that `len` is the intended number of characters.
|
||||
constexpr _wstring(const wcstring& str)
|
||||
: _str(str, str.size() + 1) {
|
||||
_str[str.size()] = '\0';
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
||||
/// \param str the buffer to wrap
|
||||
/// \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)
|
||||
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
||||
fennec::wmemcpy(_str, buf, n);
|
||||
if (buf[n - 1] != '\0') {
|
||||
_str[n] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Copy Constructor
|
||||
/// \param str the string to copy
|
||||
constexpr _wstring(const wstring& str)
|
||||
: _wstring(str, str.size() - 1) {
|
||||
}
|
||||
|
||||
constexpr _wstring(_wstring&& str) noexcept
|
||||
: _str(fennec::move(str._str)) {
|
||||
}
|
||||
constexpr _wstring(const _wstring& str) = default;
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
constexpr ~_wstring() = default; // allocation cleans up itself
|
||||
/// \brief String Move Constructor
|
||||
/// \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 ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The size of the string excluding null terminator
|
||||
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 {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a reference to the character
|
||||
constexpr wchar_t& operator[](int i) {
|
||||
/// \returns a reference to the wchar_tacter
|
||||
constexpr wchar_t& operator[](size_t i) {
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const-Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a copy of the character
|
||||
constexpr wchar_t operator[](int i) const {
|
||||
assertd(i >= 0 && i < size(), "Array Out of Bounds");
|
||||
/// \returns a copy of the wchar_tacter
|
||||
constexpr const wchar_t& operator[](size_t i) const {
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const wchar_t* operator*() const {
|
||||
return _str.data();
|
||||
constexpr wchar_t* data() {
|
||||
return _str;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const wchar_t*() const {
|
||||
return _str.data();
|
||||
constexpr const wchar_t* data() const {
|
||||
return _str;
|
||||
}
|
||||
|
||||
constexpr const wchar_t* cstr() const {
|
||||
return _str;
|
||||
}
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
@@ -183,7 +199,7 @@ public:
|
||||
}
|
||||
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
|
||||
/// \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.
|
||||
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
|
||||
return -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 {
|
||||
@@ -206,22 +222,22 @@ public:
|
||||
|
||||
///
|
||||
/// \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()`
|
||||
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
||||
if (i >= size()) { // bounds check
|
||||
return size();
|
||||
}
|
||||
|
||||
const wchar_t* loc = ::wcschr(_str.data() + i, c); // get location using strchr
|
||||
return loc ? loc - _str.data() : size(); // return size if not found
|
||||
const wchar_t* loc = ::wcschr(_str + i, c); // get location using strchr
|
||||
return loc ? loc - _str : size(); // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \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
|
||||
return size();
|
||||
}
|
||||
@@ -287,7 +303,7 @@ public:
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \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) {
|
||||
return size();
|
||||
}
|
||||
@@ -303,116 +319,119 @@ public:
|
||||
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
|
||||
/// \param i the start index
|
||||
/// \param n the number of characters
|
||||
/// \param n the number of wchar_tacters
|
||||
/// \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()) {
|
||||
return wstring("");
|
||||
return _wstring("");
|
||||
}
|
||||
n = min(n, size() - i);
|
||||
return wstring(_str.data() + 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
|
||||
n = fennec::min(n, size() - i);
|
||||
_wstring res;
|
||||
res._str.callocate(n + 1);
|
||||
fennec::wmemcpy(res.data(), _str + i, n);
|
||||
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
|
||||
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
|
||||
|
||||
|
||||
// Modifiers ===========================================================================================================
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
constexpr wstring operator+(const wstring& 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
|
||||
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
|
||||
friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
|
||||
_wstring res(1, c);
|
||||
return res += 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;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(wchar_t c) {
|
||||
size_t x = size();
|
||||
resize(x + 1);
|
||||
_str[x] = c;
|
||||
constexpr _wstring operator+(const _wstring& str) const {
|
||||
if (_str == nullptr) {
|
||||
return _wstring(str);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(const wcstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::wmemcpy(&_str[x], str, str.size());
|
||||
constexpr _wstring& operator+=(const wcstring& cstr) {
|
||||
if (_str == nullptr) {
|
||||
return *this = cstr;
|
||||
}
|
||||
size_t middle = size();
|
||||
_str.creallocate(middle + cstr.size() + 1);
|
||||
fennec::wmemcpy(_str + middle, cstr, cstr.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(const wstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::wmemcpy(&_str[x], str, str.size());
|
||||
constexpr _wstring& operator+=(const _wstring& str) {
|
||||
if (_str == nullptr) {
|
||||
return *this = str;
|
||||
}
|
||||
if (str.data() == nullptr) {
|
||||
return *this;
|
||||
}
|
||||
size_t middle = size();
|
||||
_str.creallocate(middle + str.size() + 1);
|
||||
fennec::wmemcpy(_str + middle, str.data(), str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
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_LANGPROC_wstringS_wstring_H
|
||||
#endif // FENNEC_LANGPROC_wstringS_WSTRING_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef FENNEC_MATH_DETAIL_TYPES_H
|
||||
#define FENNEC_MATH_DETAIL_TYPES_H
|
||||
|
||||
#include <fennec/lang/sequences.h>
|
||||
#include <fennec/lang/const_sequences.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
@@ -28,11 +28,11 @@ namespace detail
|
||||
{
|
||||
|
||||
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>
|
||||
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
|
||||
|
||||
template<typename>
|
||||
struct __is_vector_helper
|
||||
struct _is_vector_helper
|
||||
: false_type {}; // Default false case
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
// get number of components of a type
|
||||
template<typename>
|
||||
struct __component_count_helper;
|
||||
struct _component_count_helper;
|
||||
|
||||
// numeric types reduce to 1
|
||||
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
|
||||
struct __component_count_helper<TypeT>
|
||||
struct _component_count_helper<TypeT>
|
||||
: integral_constant<size_t, 1> {};
|
||||
|
||||
// Vectors reduce to the number of elements
|
||||
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)> {};
|
||||
|
||||
// Swizzles reduce to number of elements
|
||||
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)> {};
|
||||
|
||||
// Matrices reduce to the number of cells
|
||||
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)> {};
|
||||
|
||||
// default case reduces to 0
|
||||
template<typename>
|
||||
struct __component_count_helper
|
||||
struct _component_count_helper
|
||||
: integral_constant<size_t, 0> {};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// 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
|
||||
// Copyright (C) 2025 Medusa Slockbower
|
||||
// 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -292,7 +292,7 @@ struct matrix
|
||||
/// \param args
|
||||
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
||||
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
|
||||
/// \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) {
|
||||
return __mul(lhs, rhs);
|
||||
return _mul(lhs, rhs);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -625,7 +625,7 @@ struct matrix
|
||||
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) {
|
||||
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
|
||||
template<size_t i0 = 0>
|
||||
constexpr void __construct() {
|
||||
constexpr void _construct() {
|
||||
// base case, does nothing, this will get optimized away
|
||||
}
|
||||
|
||||
// helper for parsing parameter packs
|
||||
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
||||
constexpr void __construct(HeadT&& head, RestT&&...rest) {
|
||||
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
|
||||
constexpr void _construct(HeadT&& head, RestT&&...rest) {
|
||||
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
|
||||
}
|
||||
|
||||
// helper for inserting a scalar value
|
||||
template<size_t i0 = 0>
|
||||
constexpr void __insert(scalar_t s) {
|
||||
constexpr void _insert(scalar_t s) {
|
||||
data[i0 / rows][i0 % rows] = s;
|
||||
}
|
||||
|
||||
// helper for inserting a scalar value of differing type
|
||||
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);
|
||||
}
|
||||
|
||||
// helper for inserting a vector
|
||||
template<size_t i0 = 0, size_t...i>
|
||||
constexpr void __insert(const vector<scalar_t, i...>& v) {
|
||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
||||
constexpr void _insert(const vector<scalar_t, i...>& v) {
|
||||
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||
}
|
||||
|
||||
// helper for inserting a vector of differing type
|
||||
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
||||
constexpr void __insert(const vector<OScalarT, i...>& v) {
|
||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
||||
constexpr void _insert(const vector<OScalarT, i...>& v) {
|
||||
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||
}
|
||||
|
||||
// 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
|
||||
// when compared to glm or CxxSwizzle, this is faster by a significant margin
|
||||
// all implementations provide 7 decimal places of precision
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -65,9 +65,10 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief an unsigned integer
|
||||
using uint = unsigned int;
|
||||
using byte = uint8_t;
|
||||
using ubyte = uint8_t;
|
||||
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>
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
|
||||
private:
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -334,7 +334,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
||||
/// \param args arguments
|
||||
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
|
||||
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:
|
||||
template<size_t IndexV = 0, typename HeadT, typename... TailT>
|
||||
constexpr void __construct(HeadT&& head, TailT&&... rest) {
|
||||
vector::__insert<IndexV>(fennec::forward<HeadT>(head));
|
||||
constexpr void _construct(HeadT&& head, TailT&&... rest) {
|
||||
vector::_insert<IndexV>(fennec::forward<HeadT>(head));
|
||||
|
||||
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>
|
||||
constexpr void __insert(ScalarT& x) {
|
||||
constexpr void _insert(ScalarT& x) {
|
||||
data[OffsetV] = x;
|
||||
}
|
||||
|
||||
template<size_t OffsetV, typename OScalarT>
|
||||
constexpr void __insert(OScalarT& x) {
|
||||
constexpr void _insert(OScalarT& x) {
|
||||
data[OffsetV] = ScalarT(x);
|
||||
}
|
||||
|
||||
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])), ...);
|
||||
}
|
||||
|
||||
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;
|
||||
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace fennec
|
||||
///
|
||||
/// \brief check if \p T is a fennec::vector type
|
||||
/// \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```
|
||||
@@ -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
|
||||
/// \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```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef 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/lang/conditional_types.h>
|
||||
@@ -61,40 +61,40 @@ struct allocator_traits
|
||||
{
|
||||
private:
|
||||
// These help with using concepts in `detect_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 __void_pointer = typename ClassT::void_pointer_t;
|
||||
template<typename ClassT> using __void_const_pointer = typename ClassT::void_const_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 _void_pointer = typename ClassT::void_pointer_t;
|
||||
template<typename ClassT> using _void_const_pointer = typename ClassT::void_const_pointer_t;
|
||||
|
||||
// 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_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_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_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>
|
||||
struct __rebind : replace_first_element<AllocT, TypeT> {};
|
||||
struct _rebind : replace_first_element<AllocT, TypeT> {};
|
||||
|
||||
template<typename AllocT, typename TypeT>
|
||||
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
|
||||
// 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'
|
||||
// however, if it fails, the compiler moves on to the original definition. __size works in the same manner.
|
||||
// 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'
|
||||
// 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>
|
||||
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>
|
||||
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>
|
||||
struct __size : make_unsigned<DiffT> {};
|
||||
struct _size : make_unsigned<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:
|
||||
|
||||
@@ -105,33 +105,33 @@ public:
|
||||
using value_t = typename Alloc::value_t;
|
||||
|
||||
/// \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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
using size_t = typename __size<Alloc, pointer_t>::type;
|
||||
using size_t = typename _size<Alloc, pointer_t>::type;
|
||||
|
||||
// TODO: Document propagation
|
||||
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_swap = detect_t<false_type, __propagate_on_containter_swap, 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_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
|
||||
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`
|
||||
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
|
||||
};
|
||||
@@ -310,7 +310,7 @@ public:
|
||||
/// \param n The number of elements of type `T` to allocate for
|
||||
explicit constexpr allocation(size_t n) noexcept
|
||||
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||
allocate(n);
|
||||
callocate(n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -320,7 +320,7 @@ public:
|
||||
/// \param n the number of elements
|
||||
constexpr allocation(const T* data, size_t n)
|
||||
: allocation(n) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(_data, data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
: _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _alignment(align) {
|
||||
allocate(n, align);
|
||||
callocate(n, align);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
/// \param align The alignment of the allocation
|
||||
constexpr allocation(const T* data, size_t n, align_t align)
|
||||
: allocation(n, align) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
: _alloc(alloc)
|
||||
, _data(nullptr)
|
||||
, _capacity(0) {
|
||||
allocate(n);
|
||||
callocate(n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -380,7 +380,7 @@ public:
|
||||
/// \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)
|
||||
: allocation(n, alloc) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -395,7 +395,7 @@ public:
|
||||
, _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _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.
|
||||
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& 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))
|
||||
, _capacity(alloc._capacity)
|
||||
, _alignment(alloc._alignment) {
|
||||
fennec::memcpy(_data, alloc._data, alloc._capacity * sizeof(T));
|
||||
fennec::memmove(static_cast<void*>(_data), alloc._data, alloc._capacity * sizeof(T));
|
||||
}
|
||||
|
||||
///
|
||||
@@ -443,7 +443,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
@@ -451,7 +451,7 @@ public:
|
||||
/// \returns a reference to `this`
|
||||
constexpr allocation& operator=(const allocation& alloc) {
|
||||
allocation::allocate(alloc.capacity());
|
||||
fennec::memcpy(_data, alloc, size());
|
||||
fennec::memmove(_data, alloc, size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -491,13 +491,7 @@ public:
|
||||
/// 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
|
||||
constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||
deallocate();
|
||||
|
||||
if (align != zero<align_t>()) {
|
||||
_data = _alloc.allocate(_capacity = n, _alignment = align);
|
||||
} else {
|
||||
_data = _alloc.allocate(_capacity = n);
|
||||
}
|
||||
allocate(n, align);
|
||||
fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T));
|
||||
}
|
||||
|
||||
@@ -523,11 +517,15 @@ public:
|
||||
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||
if (_data == nullptr) {
|
||||
allocate(n, align);
|
||||
return;
|
||||
}
|
||||
|
||||
value_t* old = _data;
|
||||
_data = _alloc.allocate(n);
|
||||
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
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;
|
||||
}
|
||||
@@ -538,14 +536,19 @@ public:
|
||||
constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
|
||||
if (_data == nullptr) {
|
||||
callocate(n, align);
|
||||
return;
|
||||
}
|
||||
|
||||
value_t* old = _data;
|
||||
_data = _alloc.allocate(n);
|
||||
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
if (n > _capacity) {
|
||||
fennec::memset(static_cast<void*>(_data + _capacity), 0, n - _capacity);
|
||||
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);
|
||||
}
|
||||
|
||||
_alloc.deallocate(old);
|
||||
_capacity = n;
|
||||
}
|
||||
@@ -558,14 +561,17 @@ public:
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
constexpr value_t operator[](size_t i) const requires is_fundamental_v<value_t> {
|
||||
constexpr const value_t& operator[](size_t i) const {
|
||||
assertd(i < capacity(), "Array Out of Bounds");
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
constexpr const value_t& operator[](size_t i) const {
|
||||
assertd(i < capacity(), "Array Out of Bounds");
|
||||
return _data[i];
|
||||
constexpr operator value_t*() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
constexpr operator const value_t*() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
value_t* begin() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// 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
|
||||
// Copyright (C) 2025 Medusa Slockbower
|
||||
// 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
|
||||
|
||||
@@ -24,14 +24,20 @@
|
||||
// implementation
|
||||
|
||||
#if FENNEC_COMPILER_GCC
|
||||
#define __OPTIMIZE__
|
||||
#ifndef __OPTIMIZE__
|
||||
# define __OPTIMIZE__
|
||||
#else
|
||||
# define FENNEC_OPTIMIZE_FOUND
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#if FENNEC_COMPILER_GCC
|
||||
#ifndef FENNEC_OPTIMIZE_FOUND
|
||||
#undef __OPTIMIZE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // FENNEC_MEMORY_DETAIL_MEMORY_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// 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
|
||||
// Copyright (C) 2025 Medusa Slockbower
|
||||
// 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
|
||||
@@ -29,12 +29,12 @@ namespace fennec
|
||||
/// \brief Class for retrieving the traits of Pointer-like types
|
||||
/// \tparam ClassT The Pointer class type
|
||||
template<typename ClassT>
|
||||
struct ptr_traits
|
||||
struct pointer_traits
|
||||
: detail::_ptr_traits_impl<ClassT, detail::_ptr_get_element<ClassT>> {};
|
||||
|
||||
// overload for C-Style Pointers
|
||||
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 element_t = ElemT;
|
||||
@@ -1,6 +1,6 @@
|
||||
// =====================================================================================================================
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class display
|
||||
class display : public typed<display>
|
||||
{
|
||||
public:
|
||||
struct pixel_format {
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
virtual bool connected() const = 0;
|
||||
virtual ~display();
|
||||
|
||||
virtual window* create_window() = 0;
|
||||
virtual window* create_window(window* parent) = 0;
|
||||
|
||||
const pixel_format& get_color_format() const {
|
||||
return _config.format;
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
gfxcontext* get_context() { return _context; }
|
||||
|
||||
const string name;
|
||||
const uint64_t uuid;
|
||||
|
||||
protected:
|
||||
platform* _platform;
|
||||
@@ -63,9 +62,9 @@ protected:
|
||||
config _config;
|
||||
|
||||
template<typename DisplayT>
|
||||
explicit display(platform* platform, const cstring& name, DisplayT*)
|
||||
: name(name)
|
||||
, uuid(typeuuid<DisplayT>())
|
||||
explicit display(platform* platform, const cstring& name, DisplayT* type)
|
||||
: typed(type)
|
||||
, name(name)
|
||||
, _platform(platform)
|
||||
, _context(nullptr)
|
||||
, _config {
|
||||
|
||||
@@ -22,33 +22,39 @@
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
#include <fennec/lang/typeuuid.h>
|
||||
#include <fennec/platform/interface/fwd.h>
|
||||
#include <fennec/platform/interface/window.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class gfxcontext {
|
||||
class gfxcontext : public typed<gfxcontext> {
|
||||
public:
|
||||
const string name;
|
||||
const uint64_t uuid;
|
||||
|
||||
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_context_version() = 0;
|
||||
virtual const cstring& get_context_name() = 0;
|
||||
virtual int32_t get_version() = 0;
|
||||
|
||||
virtual bool check_extension(const cstring& ext) = 0;
|
||||
virtual void make_current(gfxsurface* surface) = 0;
|
||||
|
||||
virtual gfxsurface* create_surface(window* window) = 0;
|
||||
|
||||
virtual ~gfxcontext() = default;
|
||||
|
||||
display* get_display() {
|
||||
return _display;
|
||||
}
|
||||
|
||||
protected:
|
||||
display* _display;
|
||||
|
||||
template<typename ContextT>
|
||||
gfxcontext(display* display, const cstring& name, ContextT*)
|
||||
: name(name)
|
||||
, uuid(typeuuid<ContextT>())
|
||||
gfxcontext(display* display, const cstring& name, ContextT* type)
|
||||
: typed(type)
|
||||
, name(name)
|
||||
, _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
|
||||
@@ -59,13 +59,12 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class platform {
|
||||
class platform : public typed<platform> {
|
||||
public:
|
||||
using shared_object = struct shared_object;
|
||||
using symbol = void*;
|
||||
|
||||
const string name;
|
||||
const uint64_t uuid;
|
||||
|
||||
virtual ~platform() = default;
|
||||
|
||||
@@ -81,9 +80,9 @@ public:
|
||||
|
||||
protected:
|
||||
template<typename PlatformT>
|
||||
explicit platform(const cstring& name, PlatformT*)
|
||||
: name(name)
|
||||
, uuid(typeuuid<PlatformT>()) {
|
||||
explicit platform(const cstring& name, PlatformT* type)
|
||||
: typed(type)
|
||||
, name(name) {
|
||||
auto& globals = _get_globals();
|
||||
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
|
||||
globals.singleton = this;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <fennec/containers/optional.h>
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
#include <fennec/platform/interface/fwd.h>
|
||||
#include <fennec/platform/linux/wayland/display.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
@@ -29,7 +30,7 @@ namespace fennec
|
||||
///
|
||||
/// \brief interface for handling windows
|
||||
/// \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:
|
||||
enum class fullscreen_mode {
|
||||
windowed = 0,
|
||||
@@ -53,6 +54,8 @@ public:
|
||||
fullscreen_mode fullscreen;
|
||||
};
|
||||
|
||||
virtual ~window() = default;
|
||||
|
||||
virtual bool running() = 0;
|
||||
virtual void configure(const config& config) = 0;
|
||||
virtual bool initialize(bool modal) = 0;
|
||||
@@ -63,7 +66,7 @@ public:
|
||||
|
||||
virtual bool set_width(size_t w) = 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;
|
||||
|
||||
@@ -73,6 +76,8 @@ public:
|
||||
virtual bool grab_mouse(bool e) = 0;
|
||||
virtual bool block_screensaver(bool e) = 0;
|
||||
|
||||
virtual struct wl_surface* get_native_handle() = 0;
|
||||
|
||||
bool is_child() const {
|
||||
if (not _config) return false;
|
||||
return _config->flags & flags_child;
|
||||
@@ -91,9 +96,13 @@ public:
|
||||
return _display;
|
||||
}
|
||||
|
||||
const config& get_config() const {
|
||||
return *_config;
|
||||
}
|
||||
|
||||
|
||||
const string& get_title() const {
|
||||
static const string _null = { "null" };
|
||||
static const string _null{"null"};
|
||||
if (not _config) return _null;
|
||||
return _config->title;
|
||||
}
|
||||
@@ -137,13 +146,20 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~window() = default;
|
||||
window(display* display, window* parent);
|
||||
template<typename TypeT>
|
||||
window(display* display, window* parent, TypeT* type)
|
||||
: typed(type)
|
||||
, _display(display)
|
||||
, _parent(parent)
|
||||
, _surface(nullptr) {
|
||||
}
|
||||
|
||||
display* _display;
|
||||
window* _parent;
|
||||
optional<config> _config;
|
||||
gfxsurface* _context;
|
||||
gfxsurface* _surface;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define FENNEC_PLATFORM_LINUX_WAYLAND_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
|
||||
{
|
||||
@@ -33,13 +33,28 @@ public:
|
||||
bool connected() const override;
|
||||
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:
|
||||
wl_display* _handle;
|
||||
wl_registry* _registry;
|
||||
wl_compositor* _compositor;
|
||||
wl_shell* _shell;
|
||||
//xdg_wm_base* _shell;
|
||||
wl_seat* _seat;
|
||||
wl_shm* _shm;
|
||||
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/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
|
||||
#define FENNEC_LIB(...)
|
||||
@@ -60,7 +34,7 @@
|
||||
FENNEC_LIB(WAYLAND);
|
||||
|
||||
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(void, wl_proxy_destroy, struct wl_proxy*);
|
||||
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_create_wrapper, 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_to_fd, int);
|
||||
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_roundtrip, 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_log_set_handler_client, wl_log_func_t);
|
||||
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_empty, const 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_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
|
||||
@@ -1,215 +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_XKB_LIB_FWD_H
|
||||
#define FENNEC_PLATFORM_LINUX_XKB_LIB_FWD_H
|
||||
|
||||
#include <fennec/lang/types.h>
|
||||
|
||||
/*
|
||||
* Copyright © 2009-2012 Daniel Stone
|
||||
* Copyright © 2012 Intel Corporation
|
||||
* Copyright © 2012 Ran Benita
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
struct xkb_context;
|
||||
struct xkb_keymap;
|
||||
struct xkb_state;
|
||||
struct xkb_rule_names;
|
||||
|
||||
typedef uint32_t xkb_keycode_t;
|
||||
typedef uint32_t xkb_keysym_t;
|
||||
typedef uint32_t xkb_layout_index_t;
|
||||
typedef uint32_t xkb_layout_mask_t;
|
||||
typedef uint32_t xkb_level_index_t;
|
||||
typedef uint32_t xkb_mod_index_t;
|
||||
typedef uint32_t xkb_mod_mask_t;
|
||||
typedef uint32_t xkb_led_index_t;
|
||||
typedef uint32_t xkb_led_mask_t;
|
||||
|
||||
/**
|
||||
* The iterator used by xkb_keymap_key_for_each().
|
||||
*
|
||||
* @sa xkb_keymap_key_for_each
|
||||
* @memberof xkb_keymap
|
||||
* @since 0.3.1
|
||||
*/
|
||||
typedef void
|
||||
(*xkb_keymap_key_iter_t)(struct xkb_keymap *keymap, xkb_keycode_t key,
|
||||
void *data);
|
||||
|
||||
/** Flags for xkb_keysym_from_name(). */
|
||||
enum xkb_keysym_flags {
|
||||
/** Do not apply any flags. */
|
||||
XKB_KEYSYM_NO_FLAGS = 0,
|
||||
/** Find keysym by case-insensitive search. */
|
||||
XKB_KEYSYM_CASE_INSENSITIVE = (1 << 0)
|
||||
};
|
||||
|
||||
/** Flags for context creation. */
|
||||
enum xkb_context_flags {
|
||||
/** Do not apply any context flags. */
|
||||
XKB_CONTEXT_NO_FLAGS = 0,
|
||||
/** Create this context with an empty include path. */
|
||||
XKB_CONTEXT_NO_DEFAULT_INCLUDES = (1 << 0),
|
||||
/**
|
||||
* Don't take RMLVO names from the environment.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
XKB_CONTEXT_NO_ENVIRONMENT_NAMES = (1 << 1),
|
||||
/**
|
||||
* Disable the use of secure_getenv for this context, so that privileged
|
||||
* processes can use environment variables. Client uses at their own risk.
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
XKB_CONTEXT_NO_SECURE_GETENV = (1 << 2)
|
||||
};
|
||||
|
||||
/** Specifies a logging level. */
|
||||
enum xkb_log_level {
|
||||
XKB_LOG_LEVEL_CRITICAL = 10, /**< Log critical internal errors only. */
|
||||
XKB_LOG_LEVEL_ERROR = 20, /**< Log all errors. */
|
||||
XKB_LOG_LEVEL_WARNING = 30, /**< Log warnings and errors. */
|
||||
XKB_LOG_LEVEL_INFO = 40, /**< Log information, warnings, and errors. */
|
||||
XKB_LOG_LEVEL_DEBUG = 50 /**< Log everything. */
|
||||
};
|
||||
|
||||
/** Flags for keymap compilation. */
|
||||
enum xkb_keymap_compile_flags {
|
||||
/** Do not apply any flags. */
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS = 0
|
||||
};
|
||||
|
||||
/** The possible keymap formats. */
|
||||
enum xkb_keymap_format {
|
||||
/** The current/classic XKB text format, as generated by xkbcomp -xkb. */
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1 = 1
|
||||
};
|
||||
|
||||
/** Specifies the direction of the key (press / release). */
|
||||
enum xkb_key_direction {
|
||||
XKB_KEY_UP, /**< The key was released. */
|
||||
XKB_KEY_DOWN /**< The key was pressed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Modifier and layout types for state objects. This enum is bitmaskable,
|
||||
* e.g. (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED) is valid to
|
||||
* exclude locked modifiers.
|
||||
*
|
||||
* In XKB, the DEPRESSED components are also known as 'base'.
|
||||
*/
|
||||
enum xkb_state_component {
|
||||
/** Depressed modifiers, i.e. a key is physically holding them. */
|
||||
XKB_STATE_MODS_DEPRESSED = (1 << 0),
|
||||
/** Latched modifiers, i.e. will be unset after the next non-modifier
|
||||
* key press. */
|
||||
XKB_STATE_MODS_LATCHED = (1 << 1),
|
||||
/** Locked modifiers, i.e. will be unset after the key provoking the
|
||||
* lock has been pressed again. */
|
||||
XKB_STATE_MODS_LOCKED = (1 << 2),
|
||||
/** Effective modifiers, i.e. currently active and affect key
|
||||
* processing (derived from the other state components).
|
||||
* Use this unless you explicitly care how the state came about. */
|
||||
XKB_STATE_MODS_EFFECTIVE = (1 << 3),
|
||||
/** Depressed layout, i.e. a key is physically holding it. */
|
||||
XKB_STATE_LAYOUT_DEPRESSED = (1 << 4),
|
||||
/** Latched layout, i.e. will be unset after the next non-modifier
|
||||
* key press. */
|
||||
XKB_STATE_LAYOUT_LATCHED = (1 << 5),
|
||||
/** Locked layout, i.e. will be unset after the key provoking the lock
|
||||
* has been pressed again. */
|
||||
XKB_STATE_LAYOUT_LOCKED = (1 << 6),
|
||||
/** Effective layout, i.e. currently active and affects key processing
|
||||
* (derived from the other state components).
|
||||
* Use this unless you explicitly care how the state came about. */
|
||||
XKB_STATE_LAYOUT_EFFECTIVE = (1 << 7),
|
||||
/** LEDs (derived from the other state components). */
|
||||
XKB_STATE_LEDS = (1 << 8)
|
||||
};
|
||||
|
||||
/**
|
||||
* Match flags for xkb_state_mod_indices_are_active() and
|
||||
* xkb_state_mod_names_are_active(), specifying the conditions for a
|
||||
* successful match. XKB_STATE_MATCH_NON_EXCLUSIVE is bitmaskable with
|
||||
* the other modes.
|
||||
*/
|
||||
enum xkb_state_match {
|
||||
/** Returns true if any of the modifiers are active. */
|
||||
XKB_STATE_MATCH_ANY = (1 << 0),
|
||||
/** Returns true if all of the modifiers are active. */
|
||||
XKB_STATE_MATCH_ALL = (1 << 1),
|
||||
/** Makes matching non-exclusive, i.e. will not return false if a
|
||||
* modifier not specified in the arguments is active. */
|
||||
XKB_STATE_MATCH_NON_EXCLUSIVE = (1 << 16)
|
||||
};
|
||||
|
||||
enum xkb_consumed_mode {
|
||||
/**
|
||||
* This is the mode defined in the XKB specification and used by libX11.
|
||||
*
|
||||
* A modifier is consumed if and only if it *may affect* key translation.
|
||||
*
|
||||
* For example, if `Control+Alt+<Backspace>` produces some assigned keysym,
|
||||
* then when pressing just `<Backspace>`, `Control` and `Alt` are consumed,
|
||||
* even though they are not active, since if they *were* active they would
|
||||
* have affected key translation.
|
||||
*/
|
||||
XKB_CONSUMED_MODE_XKB,
|
||||
/**
|
||||
* This is the mode used by the GTK+ toolkit.
|
||||
*
|
||||
* The mode consists of the following two independent heuristics:
|
||||
*
|
||||
* - The currently active set of modifiers, excluding modifiers which do
|
||||
* not affect the key (as described for @ref XKB_CONSUMED_MODE_XKB), are
|
||||
* considered consumed, if the keysyms produced when all of them are
|
||||
* active are different from the keysyms produced when no modifiers are
|
||||
* active.
|
||||
*
|
||||
* - A single modifier is considered consumed if the keysyms produced for
|
||||
* the key when it is the only active modifier are different from the
|
||||
* keysyms produced when no modifiers are active.
|
||||
*/
|
||||
XKB_CONSUMED_MODE_GTK
|
||||
};
|
||||
|
||||
#endif // FENNEC_PLATFORM_LINUX_XKB_LIB_FWD_H
|
||||
@@ -44,7 +44,6 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fennec/platform/linux/xkb/lib/fwd.h>
|
||||
|
||||
#ifndef FENNEC_LIB
|
||||
#define FENNEC_LIB(...)
|
||||
@@ -60,82 +59,85 @@
|
||||
|
||||
FENNEC_LIB(XKB);
|
||||
|
||||
FENNEC_SYMBOL(int, xkb_keysym_get_name, xkb_keysym_t keysym, char *buffer, size_t size);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_from_name, const char *name, enum xkb_keysym_flags flags);
|
||||
FENNEC_SYMBOL(int, xkb_keysym_to_utf8, xkb_keysym_t keysym, char *buffer, size_t size);
|
||||
FENNEC_SYMBOL(uint32_t, xkb_keysym_to_utf32, xkb_keysym_t keysym);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_utf32_to_keysym, uint32_t ucs);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_upper, xkb_keysym_t ks);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_lower, xkb_keysym_t ks);
|
||||
FENNEC_SYMBOL(struct xkb_context*, xkb_context_new, enum xkb_context_flags flags);
|
||||
FENNEC_SYMBOL(struct xkb_context*, xkb_context_ref, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(void, xkb_context_unref, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_user_data, struct xkb_context *context, void *user_data);
|
||||
FENNEC_SYMBOL(void*, xkb_context_get_user_data, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_append, struct xkb_context *context, const char *path);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_append_default, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_reset_defaults, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(void, xkb_context_include_path_clear, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(unsigned int, xkb_context_num_include_paths, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(const char*, xkb_context_include_path_get, struct xkb_context *context, unsigned int index);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_level, struct xkb_context *context, enum xkb_log_level level);
|
||||
FENNEC_SYMBOL(enum xkb_log_level, xkb_context_get_log_level, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_verbosity, struct xkb_context *context, int verbosity);
|
||||
FENNEC_SYMBOL(int, xkb_context_get_log_verbosity, struct xkb_context *context);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_fn, struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args));
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_names, struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_file, struct xkb_context *context, FILE *file, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_string, struct xkb_context *context, const char *string, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_buffer, struct xkb_context *context, const char *buffer, size_t length, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_ref, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(void, xkb_keymap_unref, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(char*, xkb_keymap_get_as_string, struct xkb_keymap *keymap, enum xkb_keymap_format format);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_min_keycode, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_max_keycode, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(void, xkb_keymap_key_for_each, struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter, void *data);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_key_get_name, struct xkb_keymap *keymap, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_key_by_name, struct xkb_keymap *keymap, const char *name);
|
||||
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_num_mods, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_mod_get_name, struct xkb_keymap *keymap, xkb_mod_index_t idx);
|
||||
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_mod_get_index, struct xkb_keymap *keymap, const char *name);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_layout_get_name, struct xkb_keymap *keymap, xkb_layout_index_t idx);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_layout_get_index, struct xkb_keymap *keymap, const char *name);
|
||||
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_num_leds, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_led_get_name, struct xkb_keymap *keymap, xkb_led_index_t idx);
|
||||
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_led_get_index, struct xkb_keymap *keymap, const char *name);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts_for_key, struct xkb_keymap *keymap, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(xkb_level_index_t, xkb_keymap_num_levels_for_key, struct xkb_keymap *keymap, xkb_keycode_t key, xkb_layout_index_t layout);
|
||||
FENNEC_SYMBOL(size_t, xkb_keymap_key_get_mods_for_level, struct xkb_keymap *keymap, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, xkb_mod_mask_t *masks_out, size_t masks_size);
|
||||
FENNEC_SYMBOL(int, xkb_keymap_key_get_syms_by_level, struct xkb_keymap *keymap, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, const xkb_keysym_t **syms_out);
|
||||
FENNEC_SYMBOL(int, xkb_keymap_key_repeats, struct xkb_keymap *keymap, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(struct xkb_state*, xkb_state_new, struct xkb_keymap *keymap);
|
||||
FENNEC_SYMBOL(struct xkb_state*, xkb_state_ref, struct xkb_state *state);
|
||||
FENNEC_SYMBOL(void, xkb_state_unref, struct xkb_state *state);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_state_get_keymap, struct xkb_state *state);
|
||||
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_key, struct xkb_state *state, xkb_keycode_t key, enum xkb_key_direction direction);
|
||||
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_mask, struct xkb_state *state, xkb_mod_mask_t depressed_mods, xkb_mod_mask_t latched_mods, xkb_mod_mask_t locked_mods, xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout, xkb_layout_index_t locked_layout);
|
||||
FENNEC_SYMBOL(int, xkb_state_key_get_syms, struct xkb_state *state, xkb_keycode_t key, const xkb_keysym_t **syms_out);
|
||||
FENNEC_SYMBOL(int, xkb_state_key_get_utf8, struct xkb_state *state, xkb_keycode_t key, char *buffer, size_t size);
|
||||
FENNEC_SYMBOL(uint32_t, xkb_state_key_get_utf32, struct xkb_state *state, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_state_key_get_one_sym, struct xkb_state *state, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_key_get_layout, struct xkb_state *state, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(xkb_level_index_t, xkb_state_key_get_level, struct xkb_state *state, xkb_keycode_t key, xkb_layout_index_t layout);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_serialize_mods, struct xkb_state *state, enum xkb_state_component components);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_serialize_layout, struct xkb_state *state, enum xkb_state_component components);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_name_is_active, struct xkb_state *state, const char *name, enum xkb_state_component type);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_names_are_active, struct xkb_state *state, enum xkb_state_component type, enum xkb_state_match match, ...);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_active, struct xkb_state *state, xkb_mod_index_t idx, enum xkb_state_component type);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_indices_are_active, struct xkb_state *state, enum xkb_state_component type, enum xkb_state_match match, ...);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods2, struct xkb_state *state, xkb_keycode_t key, enum xkb_consumed_mode mode);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods, struct xkb_state *state, xkb_keycode_t key);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed2, struct xkb_state *state, xkb_keycode_t key, xkb_mod_index_t idx, enum xkb_consumed_mode mode);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed, struct xkb_state *state, xkb_keycode_t key, xkb_mod_index_t idx);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_mod_mask_remove_consumed, struct xkb_state *state, xkb_keycode_t key, xkb_mod_mask_t mask);
|
||||
FENNEC_SYMBOL(int, xkb_state_layout_name_is_active, struct xkb_state *state, const char *name, enum xkb_state_component type);
|
||||
FENNEC_SYMBOL(int, xkb_state_layout_index_is_active, struct xkb_state *state, xkb_layout_index_t idx, enum xkb_state_component type);
|
||||
FENNEC_SYMBOL(int, xkb_state_led_name_is_active, struct xkb_state *state, const char *name);
|
||||
FENNEC_SYMBOL(int, xkb_state_led_index_is_active, struct xkb_state *state, xkb_led_index_t idx);
|
||||
FENNEC_SYMBOL(int, xkb_keysym_get_name, xkb_keysym_t, char*, size_t);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_from_name, const char*, enum xkb_keysym_flags);
|
||||
FENNEC_SYMBOL(int, xkb_keysym_to_utf8, xkb_keysym_t, char*, size_t);
|
||||
FENNEC_SYMBOL(uint32_t, xkb_keysym_to_utf32, xkb_keysym_t);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_utf32_to_keysym, uint32_t);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_upper, xkb_keysym_t);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_lower, xkb_keysym_t);
|
||||
|
||||
FENNEC_SYMBOL(struct xkb_context*, xkb_context_new, enum xkb_context_flags);
|
||||
FENNEC_SYMBOL(struct xkb_context*, xkb_context_ref, struct xkb_context*);
|
||||
FENNEC_SYMBOL(void, xkb_context_unref, struct xkb_context*);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_user_data, struct xkb_context*, void*);
|
||||
FENNEC_SYMBOL(void*, xkb_context_get_user_data, struct xkb_context*);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_append, struct xkb_context*, const char*);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_append_default, struct xkb_context*);
|
||||
FENNEC_SYMBOL(int, xkb_context_include_path_reset_defaults, struct xkb_context*);
|
||||
FENNEC_SYMBOL(void, xkb_context_include_path_clear, struct xkb_context*);
|
||||
FENNEC_SYMBOL(unsigned int, xkb_context_num_include_paths, struct xkb_context*);
|
||||
FENNEC_SYMBOL(const char*, xkb_context_include_path_get, struct xkb_context*, unsigned int);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_level, struct xkb_context*, enum xkb_log_level);
|
||||
FENNEC_SYMBOL(enum xkb_log_level, xkb_context_get_log_level, struct xkb_context*);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_verbosity, struct xkb_context*, int);
|
||||
FENNEC_SYMBOL(int, xkb_context_get_log_verbosity, struct xkb_context*);
|
||||
FENNEC_SYMBOL(void, xkb_context_set_log_fn, struct xkb_context*, void (*)(struct xkb_context*, enum xkb_log_level, const char*, va_list));
|
||||
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_names, struct xkb_context*, const struct xkb_rule_names*, enum xkb_keymap_compile_flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_file, struct xkb_context*, FILE*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_string, struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_buffer, struct xkb_context*, const char*, size_t, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_ref, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(void, xkb_keymap_unref, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(char*, xkb_keymap_get_as_string, struct xkb_keymap*, enum xkb_keymap_format);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_min_keycode, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_max_keycode, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(void, xkb_keymap_key_for_each, struct xkb_keymap*, xkb_keymap_key_iter_t, void*);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_key_get_name, struct xkb_keymap*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_key_by_name, struct xkb_keymap*, const char*);
|
||||
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_num_mods, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_mod_get_name, struct xkb_keymap*, xkb_mod_index_t);
|
||||
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_mod_get_index, struct xkb_keymap*, const char*);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_layout_get_name, struct xkb_keymap*, xkb_layout_index_t);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_layout_get_index, struct xkb_keymap*, const char*);
|
||||
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_num_leds, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(const char*, xkb_keymap_led_get_name, struct xkb_keymap*, xkb_led_index_t);
|
||||
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_led_get_index, struct xkb_keymap*, const char*);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts_for_key, struct xkb_keymap*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(xkb_level_index_t, xkb_keymap_num_levels_for_key, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t);
|
||||
FENNEC_SYMBOL(size_t, xkb_keymap_key_get_mods_for_level, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, xkb_mod_mask_t*, size_t);
|
||||
FENNEC_SYMBOL(int, xkb_keymap_key_get_syms_by_level, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, const xkb_keysym_t**);
|
||||
FENNEC_SYMBOL(int, xkb_keymap_key_repeats, struct xkb_keymap*, xkb_keycode_t);
|
||||
|
||||
FENNEC_SYMBOL(struct xkb_state*, xkb_state_new, struct xkb_keymap*);
|
||||
FENNEC_SYMBOL(struct xkb_state*, xkb_state_ref, struct xkb_state*);
|
||||
FENNEC_SYMBOL(void, xkb_state_unref, struct xkb_state*);
|
||||
FENNEC_SYMBOL(struct xkb_keymap*, xkb_state_get_keymap, struct xkb_state*);
|
||||
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_key, struct xkb_state*, xkb_keycode_t, enum xkb_key_direction);
|
||||
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_mask, struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
|
||||
FENNEC_SYMBOL(int, xkb_state_key_get_syms, struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
|
||||
FENNEC_SYMBOL(int, xkb_state_key_get_utf8, struct xkb_state*, xkb_keycode_t, char*, size_t);
|
||||
FENNEC_SYMBOL(uint32_t, xkb_state_key_get_utf32, struct xkb_state*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(xkb_keysym_t, xkb_state_key_get_one_sym, struct xkb_state*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_key_get_layout, struct xkb_state*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(xkb_level_index_t, xkb_state_key_get_level, struct xkb_state*, xkb_keycode_t, xkb_layout_index_t);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_serialize_mods, struct xkb_state*, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_serialize_layout, struct xkb_state*, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_name_is_active, struct xkb_state*, const char*, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_names_are_active, struct xkb_state*, enum xkb_state_component, enum xkb_state_match, ...);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_active, struct xkb_state*, xkb_mod_index_t, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_indices_are_active, struct xkb_state*, enum xkb_state_component, enum xkb_state_match, ...);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods2, struct xkb_state*, xkb_keycode_t, enum xkb_consumed_mode);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods, struct xkb_state*, xkb_keycode_t);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed2, struct xkb_state*, xkb_keycode_t, xkb_mod_index_t, enum xkb_consumed_mode);
|
||||
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed, struct xkb_state*, xkb_keycode_t, xkb_mod_index_t);
|
||||
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_mod_mask_remove_consumed, struct xkb_state*, xkb_keycode_t, xkb_mod_mask_t);
|
||||
FENNEC_SYMBOL(int, xkb_state_layout_name_is_active, struct xkb_state*, const char*, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(int, xkb_state_layout_index_is_active, struct xkb_state*, xkb_layout_index_t, enum xkb_state_component);
|
||||
FENNEC_SYMBOL(int, xkb_state_led_name_is_active, struct xkb_state*, const char*);
|
||||
FENNEC_SYMBOL(int, xkb_state_led_index_is_active, struct xkb_state*, xkb_led_index_t);
|
||||
|
||||
#undef FENNEC_LIB
|
||||
#undef FENNEC_SYMBOL
|
||||
|
||||
110
include/fennec/platform/linux/xkb/lib/xkb.h
Normal file
110
include/fennec/platform/linux/xkb/lib/xkb.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// =====================================================================================================================
|
||||
// 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_XKB_LIB_XKB_H
|
||||
#define FENNEC_PLATFORM_LINUX_XKB_LIB_XKB_H
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#define FENNEC_LIB(name) extern bool FENNEC_HAS_LIB_##name;
|
||||
#define FENNEC_SYMBOL(ret, fn, ...) using XKB_sym_##fn = ret(*)(__VA_ARGS__); \
|
||||
extern XKB_sym_##fn XKB_##fn;
|
||||
#define FENNEC_GLOBAL(type, name) extern type* XKB_##name;
|
||||
#include <fennec/platform/linux/xkb/lib/sym.h>
|
||||
|
||||
#define xkb_keysym_get_name XKB_xkb_keysym_get_name
|
||||
#define xkb_keysym_from_name XKB_xkb_keysym_from_name
|
||||
#define xkb_keysym_to_utf8 XKB_xkb_keysym_to_utf8
|
||||
#define xkb_keysym_to_utf32 XKB_xkb_keysym_to_utf32
|
||||
#define xkb_utf32_to_keysym XKB_xkb_utf32_to_keysym
|
||||
#define xkb_keysym_to_upper XKB_xkb_keysym_to_upper
|
||||
#define xkb_keysym_to_lower XKB_xkb_keysym_to_lower
|
||||
|
||||
#define xkb_context_new XKB_xkb_context_new
|
||||
#define xkb_context_ref XKB_xkb_context_ref
|
||||
#define xkb_context_unref XKB_xkb_context_unref
|
||||
#define xkb_context_set_user_data XKB_xkb_context_set_user_data
|
||||
#define xkb_context_get_user_data XKB_xkb_context_get_user_data
|
||||
#define xkb_context_include_path_append XKB_xkb_context_include_path_append
|
||||
#define xkb_context_include_path_append_default XKB_xkb_context_include_path_append_default
|
||||
#define xkb_context_include_path_reset_defaults XKB_xkb_context_include_path_reset_defaults
|
||||
#define xkb_context_include_path_clear XKB_xkb_context_include_path_clear
|
||||
#define xkb_context_num_include_paths XKB_xkb_context_num_include_paths
|
||||
#define xkb_context_include_path_get XKB_xkb_context_include_path_get
|
||||
#define xkb_context_set_log_level XKB_xkb_context_set_log_level
|
||||
#define xkb_context_get_log_level XKB_xkb_context_get_log_level
|
||||
#define xkb_context_set_log_verbosity XKB_xkb_context_set_log_verbosity
|
||||
#define xkb_context_get_log_verbosity XKB_xkb_context_get_log_verbosity
|
||||
#define xkb_context_set_log_fn XKB_xkb_context_set_log_fn
|
||||
|
||||
#define xkb_keymap_new_from_names XKB_xkb_keymap_new_from_names
|
||||
#define xkb_keymap_new_from_file XKB_xkb_keymap_new_from_file
|
||||
#define xkb_keymap_new_from_string XKB_xkb_keymap_new_from_string
|
||||
#define xkb_keymap_new_from_buffer XKB_xkb_keymap_new_from_buffer
|
||||
#define xkb_keymap_ref XKB_xkb_keymap_ref
|
||||
#define xkb_keymap_unref XKB_xkb_keymap_unref
|
||||
#define xkb_keymap_get_as_string XKB_xkb_keymap_get_as_string
|
||||
#define xkb_keymap_min_keycode XKB_xkb_keymap_min_keycode
|
||||
#define xkb_keymap_max_keycode XKB_xkb_keymap_max_keycode
|
||||
#define xkb_keymap_key_for_each XKB_xkb_keymap_key_for_each
|
||||
#define xkb_keymap_key_get_name XKB_xkb_keymap_key_get_name
|
||||
#define xkb_keymap_key_by_name XKB_xkb_keymap_key_by_name
|
||||
#define xkb_keymap_num_mods XKB_xkb_keymap_num_mods
|
||||
#define xkb_keymap_mod_get_name XKB_xkb_keymap_mod_get_name
|
||||
#define xkb_keymap_mod_get_index XKB_xkb_keymap_mod_get_index
|
||||
#define xkb_keymap_num_layouts XKB_xkb_keymap_num_layouts
|
||||
#define xkb_keymap_layout_get_name XKB_xkb_keymap_layout_get_name
|
||||
#define xkb_keymap_layout_get_index XKB_xkb_keymap_layout_get_index
|
||||
#define xkb_keymap_num_leds XKB_xkb_keymap_num_leds
|
||||
#define xkb_keymap_led_get_name XKB_xkb_keymap_led_get_name
|
||||
#define xkb_keymap_led_get_index XKB_xkb_keymap_led_get_index
|
||||
#define xkb_keymap_num_layouts_for_key XKB_xkb_keymap_num_layouts_for_key
|
||||
#define xkb_keymap_num_levels_for_key XKB_xkb_keymap_num_levels_for_key
|
||||
#define xkb_keymap_key_get_mods_for_level XKB_xkb_keymap_key_get_mods_for_level
|
||||
#define xkb_keymap_key_get_syms_by_level XKB_xkb_keymap_key_get_syms_by_level
|
||||
#define xkb_keymap_key_repeats XKB_xkb_keymap_key_repeats
|
||||
|
||||
#define xkb_state_new XKB_xkb_state_new
|
||||
#define xkb_state_ref XKB_xkb_state_ref
|
||||
#define xkb_state_unref XKB_xkb_state_unref
|
||||
#define xkb_state_get_keymap XKB_xkb_state_get_keymap
|
||||
#define xkb_state_update_key XKB_xkb_state_update_key
|
||||
#define xkb_state_update_mask XKB_xkb_state_update_mask
|
||||
#define xkb_state_key_get_syms XKB_xkb_state_key_get_syms
|
||||
#define xkb_state_key_get_utf8 XKB_xkb_state_key_get_utf8
|
||||
#define xkb_state_key_get_utf32 XKB_xkb_state_key_get_utf32
|
||||
#define xkb_state_key_get_one_sym XKB_xkb_state_key_get_one_sym
|
||||
#define xkb_state_key_get_layout XKB_xkb_state_key_get_layout
|
||||
#define xkb_state_key_get_level XKB_xkb_state_key_get_level
|
||||
#define xkb_state_serialize_mods XKB_xkb_state_serialize_mods
|
||||
#define xkb_state_serialize_layout XKB_xkb_state_serialize_layout
|
||||
#define xkb_state_mod_name_is_active XKB_xkb_state_mod_name_is_active
|
||||
#define xkb_state_mod_names_are_active XKB_xkb_state_mod_names_are_active
|
||||
#define xkb_state_mod_index_is_active XKB_xkb_state_mod_index_is_active
|
||||
#define xkb_state_mod_indices_are_active XKB_xkb_state_mod_indices_are_active
|
||||
#define xkb_state_key_get_consumed_mods2 XKB_xkb_state_key_get_consumed_mods2
|
||||
#define xkb_state_key_get_consumed_mods XKB_xkb_state_key_get_consumed_mods
|
||||
#define xkb_state_mod_index_is_consumed2 XKB_xkb_state_mod_index_is_consumed2
|
||||
#define xkb_state_mod_index_is_consumed XKB_xkb_state_mod_index_is_consumed
|
||||
#define xkb_state_mod_mask_remove_consumed XKB_xkb_state_mod_mask_remove_consumed
|
||||
#define xkb_state_layout_name_is_active XKB_xkb_state_layout_name_is_active
|
||||
#define xkb_state_layout_index_is_active XKB_xkb_state_layout_index_is_active
|
||||
#define xkb_state_led_name_is_active XKB_xkb_state_led_name_is_active
|
||||
#define xkb_state_led_index_is_active XKB_xkb_state_led_index_is_active
|
||||
|
||||
#endif // FENNEC_PLATFORM_LINUX_XKB_LIB_XKB_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifndef _XKBCOMMON_NAMES_H
|
||||
#define _XKBCOMMON_NAMES_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Predefined names for common modifiers and LEDs.
|
||||
*/
|
||||
|
||||
#define XKB_MOD_NAME_SHIFT "Shift"
|
||||
#define XKB_MOD_NAME_CAPS "Lock"
|
||||
#define XKB_MOD_NAME_CTRL "Control"
|
||||
#define XKB_MOD_NAME_ALT "Mod1"
|
||||
#define XKB_MOD_NAME_NUM "Mod2"
|
||||
#define XKB_MOD_NAME_LOGO "Mod4"
|
||||
|
||||
#define XKB_LED_NAME_CAPS "Caps Lock"
|
||||
#define XKB_LED_NAME_NUM "Num Lock"
|
||||
#define XKB_LED_NAME_SCROLL "Scroll Lock"
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user