diff --git a/CMakeLists.txt b/CMakeLists.txt index 4271823..7110dab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,8 +75,9 @@ add_library(fennec STATIC # MEMORY =============================================================================================================== include/fennec/memory/new.h source/memory/new.cpp - include/fennec/memory/allocator.h include/fennec/memory/common.h + include/fennec/memory/allocator.h + include/fennec/memory/memory.h include/fennec/memory/pointers.h include/fennec/memory/ptr_traits.h @@ -118,15 +119,17 @@ add_library(fennec STATIC # FPROC ================================================================================================================ # Strings + include/fennec/fproc/strings/cstring.h + include/fennec/fproc/strings/locale.h include/fennec/fproc/strings/string.h include/fennec/fproc/strings/detail/__ctype.h - include/fennec/fproc/strings/cstring.h - include/fennec/fproc/strings/locale.h - include/fennec/fproc/io/file.h - source/fproc/io/file.cpp - include/fennec/fproc/filesystem/path.h - include/fennec/memory/memory.h + + # IO + include/fennec/fproc/io/file.h source/fproc/io/file.cpp + include/fennec/fproc/io/common.h + source/fproc/io/common.cpp + ) # add metaprogramming templates as a dependency and also force documentation to be generated when fennec is compiled diff --git a/PLANNING.md b/PLANNING.md index 5160077..0abf3c0 100644 --- a/PLANNING.md +++ b/PLANNING.md @@ -63,7 +63,7 @@ This however can be achieved using events at different stages of those engines t - 2D Physics (`physics2d`) - 2D & 3D Audio (`audio`) -### Security Ramblings: +### 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 @@ -85,7 +85,7 @@ This issue can be solved using `fopen("", "w+")`, however this specific be 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 +`'+'` 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 @@ -99,6 +99,38 @@ debugging it, and testing for vulnerabilities. As stated above, this implementat 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. + +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 am considering encryption for archives, but there likely is not much of a point. @@ -186,6 +218,10 @@ fennec should be able to use Doxygen and LaTeX externally. Consider including bi - Spreadsheets & Tables - ODS - CSV + - Audio Formats + - MP3 + - WAV + - AAC - Graphics Formats - Textures - BMP @@ -200,6 +236,11 @@ fennec should be able to use Doxygen and LaTeX externally. Consider including bi - Models - FBX - Wavefront OBJ + - Video Formats + - MP4 + - AVI + - MPG + - MOV **TODO LATER** * Compilation (`fproc/code`) diff --git a/README.md b/README.md index 95a8f2d..2f0797d 100644 --- a/README.md +++ b/README.md @@ -65,24 +65,24 @@ fennec Standards: called `detail`. Helper functions should be documented with C-Style comments, however it is not necessary to provide Doxygen documentation. - - **DO NOT USE C++ EXCEPTIONS** they will not be supported because they are shit. No, I won't elaborate.[[1]](#f1) + - **DO NOT USE C++ EXCEPTIONS** they will not be supported because they are shit. No, I won't elaborate.[[1]](#f1) * Most behaviours should be type independent. Specifically interactions with the core systems of the engine.

-[1] Okay, I will elaborate. If we were to use the exception paradigm for all erroneous behaviour, we couldn't - guarantee that the state will not be corrupted when an exception is thrown. The behaviour afterward is - undefined because of this, and we also don't really know when, how, or where that exception will be handled. - The assertion paradigm is better at handling this because you are defining erroneous behaviour in the code and how - it is handled. In a debug build we can immediately halt the program, we don't care about the state afterward, only - beforehand. Now for a release build, this is first and foremost a game engine, so we want to crash as gracefully as - possible, prevent data loss, and get some debug information for it. fennec defines its own `assert` macro to - be used, defining a hook in the private version of the function. This hook is used to clean up any state information - within the engine and may be used to send immediate events to listeners so that outside functionality may decide - how to handle the impending crash. In Debug Mode there is nothing that can be done to stop the crash, as soon as the branch - finishes, `abort()` will be called. +[1] Okay, I will elaborate. If we were to use the exception paradigm for all erroneous behaviour, we couldn't + guarantee that the state will not be corrupted when an exception is thrown. The behaviour afterward is + undefined because of this, and we also don't really know when, how, or where that exception will be handled. + The assertion paradigm is better at handling this because you are defining erroneous behaviour in the code and how + it is handled. In a debug build we can immediately halt the program, we don't care about the state afterward, only + beforehand. Now for a release build, this is first and foremost a game engine, so we want to crash as gracefully as + possible, prevent data loss, and get some debug information for it. fennec defines its own `assert` macro to + be used, defining a hook in the private version of the function. This hook is used to clean up any state information + within the engine and may be used to send immediate events to listeners so that outside functionality may decide + how to handle the impending crash. In Debug Mode there is nothing that can be done to stop the crash, as soon + as the branch finishes, `abort()` will be called.
@@ -199,6 +199,44 @@ information displayed is correct. ## Usage + +### Licensing + +The following statement is not legal advice, nor is it legally binding, and nor does it change the terms of the license. + +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. + +I encourage those who wish to commercialize derivative works crowdfund rather than use a sales model. I also ask +that you kindly support me as a developer, I will set up a Buy Me a Coffee link at some point. + +GPLv3 is bound by fair use; here is the clause, 17 U.S. Code § 107: + +``` +107. Limitations on exclusive rights: Fair use + +Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by +reproduction in copies or phonorecords or by any other means specified by that section, for purposes such as criticism, +comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an +infringement of copyright. In determining whether the use made of a work in any particular case is a fair use the +factors to be considered shall include— + + (1) the purpose and character of the use, including whether such use is of a commercial nature or is for nonprofit + educational purposes; + (2) the nature of the copyrighted work; + (3) the amount and substantiality of the portion used in relation to the copyrighted work as a whole; and + (4) the effect of the use upon the potential market for or value of the copyrighted work. + +The fact that a work is unpublished shall not itself bar a finding of fair use if such finding is made upon +consideration of all the above factors. +``` + +If you have any questions or concerns, please seek legal council. If you believe someone else has violated the terms +of this license, please contact me at [mslockbo@gmail.com](mailto:mslockbo@gmail.com). +

@@ -207,5 +245,5 @@ information displayed is correct. There are some principles to keep in mind when contributing to fennec. -1. You must follow the style guide provided by the [GNU Coding Standard](https://www.gnu.org/prep/standards/html_node/Writing-C.html). -2. Any changes must allow all projects to be forward compatible with newer engine verisons. + 1. You must follow the [standards provided above](#coding-standards). + 2. Any changes must allow all projects to be forward compatible with newer engine versions. diff --git a/include/fennec/fproc/io/common.h b/include/fennec/fproc/io/common.h new file mode 100644 index 0000000..fe7917f --- /dev/null +++ b/include/fennec/fproc/io/common.h @@ -0,0 +1,31 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#ifndef FENNEC_FPROC_IO_COMMON_H +#define FENNEC_FPROC_IO_COMMON_H + +#include + +namespace fennec +{ + +string getcwd(); + +} + +#endif // FENNEC_FPROC_IO_COMMON_H diff --git a/include/fennec/fproc/io/file.h b/include/fennec/fproc/io/file.h index a8e6cf9..d9ab2c7 100644 --- a/include/fennec/fproc/io/file.h +++ b/include/fennec/fproc/io/file.h @@ -21,7 +21,6 @@ #include #include -#include struct FILE; @@ -32,10 +31,10 @@ namespace fennec /// \brief Mode flags for opening a file enum fmode : uint8_t { - read = 0b00000001 -, write = 0b00000010 -, append = 0b00000100 -, no_overwrite = 0b00001000 + read = 0b00000001 +, write = 0b00000010 +, append = 0b00000100 +, noexists = 0b00001000 }; class file @@ -50,7 +49,8 @@ public: /// \param mode the flags for opening the file file(const cstring& path, fmode mode); file(const string& path, fmode mode); - file(const path& path, fmode mode); + + file(file&& file); file(const file&) = delete; @@ -59,7 +59,6 @@ public: void open(const cstring& filename, fmode mode); void open(const string& filename, fmode mode); - void open(const path& filename, fmode mode); void close(); void commit(); @@ -89,6 +88,8 @@ public: private: FILE* _handle; + string _path; + fmode _mode; }; } diff --git a/include/fennec/fproc/strings/cstring.h b/include/fennec/fproc/strings/cstring.h index 44c8233..4ac4588 100644 --- a/include/fennec/fproc/strings/cstring.h +++ b/include/fennec/fproc/strings/cstring.h @@ -24,6 +24,8 @@ #include +#include + namespace fennec { diff --git a/include/fennec/fproc/strings/string.h b/include/fennec/fproc/strings/string.h index 70e2eca..6470080 100644 --- a/include/fennec/fproc/strings/string.h +++ b/include/fennec/fproc/strings/string.h @@ -42,7 +42,7 @@ using string = _string<>; /// \brief Struct for wrapping c-style strings /// /// \details behaviour guarantees that the underlying string is null-terminated -template> +template struct _string { public: @@ -120,7 +120,6 @@ public: /// \param i the index to access /// \returns a reference to the character constexpr char& operator[](int i) { - assertd(i >= 0 && i < size(), "Array Out of Bounds"); return _str[i]; } @@ -284,7 +283,7 @@ public: /// \param str the string to copy /// \returns a reference to `this` constexpr string& operator=(const string& str) { - if (str.size() > size()) string::resize(str.size()); + if (str.size() > size()) resize(str.size()); fennec::memcpy(_str, str, str.size()); _str[str.size()] = '\0'; return *this; diff --git a/include/fennec/lang/assert.h b/include/fennec/lang/assert.h index 49f8a6b..d72eb8a 100644 --- a/include/fennec/lang/assert.h +++ b/include/fennec/lang/assert.h @@ -65,7 +65,7 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); -extern void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc); +void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* desc); // flagged unlikely to optimize branch prediction #define assert(expression, description) \ diff --git a/include/fennec/lang/detail/__int.h b/include/fennec/lang/detail/__int.h index bcd0c54..3caed33 100644 --- a/include/fennec/lang/detail/__int.h +++ b/include/fennec/lang/detail/__int.h @@ -28,6 +28,7 @@ #pragma push_macro("__cplusplus") #undef __cplusplus +#include #include #pragma pop_macro("__cplusplus") diff --git a/include/fennec/lang/detail/__numeric_transforms.h b/include/fennec/lang/detail/__numeric_transforms.h index 5e7e743..69a840e 100644 --- a/include/fennec/lang/detail/__numeric_transforms.h +++ b/include/fennec/lang/detail/__numeric_transforms.h @@ -28,7 +28,7 @@ namespace fennec namespace detail { -template struct __make_unsigned : undefined_t {}; +template struct __make_unsigned : type_transform {}; template<> struct __make_unsigned : type_transform {}; template<> struct __make_unsigned : type_transform {}; @@ -43,7 +43,7 @@ template<> struct __make_unsigned : type_transform {}; template<> struct __make_unsigned : type_transform {}; -template struct __make_signed : undefined_t {}; +template struct __make_signed : type_transform {}; template<> struct __make_signed : type_transform {}; template<> struct __make_signed : type_transform {}; diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 9039f6e..10c04e7 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -191,6 +191,14 @@ # define FENNEC_HAS_BUILTIN_IS_FINAL 0 #endif +// Inconsistent with dynamic intrinsics, requires a massive table for static intrinsics +#if __has_builtin(__is_fundamental) +# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 1 +# define FENNEC_BUILTIN_IS_FUNDAMENTAL(arg) __is_fundamental(arg) +#else +# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 0 +#endif + // Inconsistent without intrinsics #if __has_builtin(__is_polymorphic) # define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 1 diff --git a/include/fennec/lang/type_traits.h b/include/fennec/lang/type_traits.h index bbe40b2..b6450e8 100644 --- a/include/fennec/lang/type_traits.h +++ b/include/fennec/lang/type_traits.h @@ -288,6 +288,21 @@ template struct is_arithmetic /// \tparam T type to check template constexpr bool_t is_arithmetic_v = is_arithmetic::value; + +// fennec::is_fundamental ============================================================================================== + +/// +/// \brief check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t +/// \tparam T type to check +template struct is_fundamental + : bool_constant || is_void_v || is_null_pointer_v>{}; + +/// +/// \brief shorthand for ```is_fundamental::value``` +/// \tparam T type to check +template constexpr bool_t is_fundamental_v = is_fundamental::value; + + // fennec::is_same ===================================================================================================== /// @@ -306,7 +321,7 @@ template struct is_same : true_type {}; /// \tparam T type to check template constexpr bool_t is_same_v = is_same {}; -// fennec::can_convert ================================================================================================= +// fennec::is_convertible ============================================================================================== /// /// \brief check if type `T0` can be converted `T1` diff --git a/include/fennec/lang/types.h b/include/fennec/lang/types.h index 73a694d..5d9d019 100644 --- a/include/fennec/lang/types.h +++ b/include/fennec/lang/types.h @@ -203,6 +203,8 @@ #include +#include + namespace fennec { // Basic Types ========================================================================================================= @@ -253,12 +255,7 @@ namespace fennec template using void_t = void; ///< \brief Void type used for SFINAE /// @} -} -#include - -namespace fennec -{ // Sized Arithmetic Types ============================================================================================== diff --git a/include/fennec/math/common.h b/include/fennec/math/common.h index 90ce364..6eff4eb 100644 --- a/include/fennec/math/common.h +++ b/include/fennec/math/common.h @@ -271,6 +271,8 @@ #include +#include + #include #if _MSC_VER @@ -462,7 +464,7 @@ constexpr vector trunc(const vector& x) { /// \param x input value template constexpr genType roundEven(genType x) { - static const genType e = std::numeric_limits::epsilon(); + static const genType e = numeric_limits::epsilon(); int I = static_cast(x); genType i = static_cast(I); genType f = x - i; diff --git a/include/fennec/memory/allocator.h b/include/fennec/memory/allocator.h index 564a82d..451a240 100644 --- a/include/fennec/memory/allocator.h +++ b/include/fennec/memory/allocator.h @@ -1,4 +1,4 @@ -2// ===================================================================================================================== +// ===================================================================================================================== // fennec, a free and open source game engine // Copyright (C) 2025 Medusa Slockbower // @@ -33,15 +33,22 @@ #define FENNEC_MEMORY_ALLOCATOR_H #include +#include #include #include #include #include +#include #include +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wchanges-meaning" +#endif + namespace fennec { @@ -177,14 +184,92 @@ public: } /// \brief Allocate a block of memory large enough to hold `n` elements of type `T` - constexpr T* allocate(size_t n) { - return ::operator new(n * sizeof(T)); + constexpr T* allocate(size_t n) { + return static_cast(::operator new(n * sizeof(T))); + } + + /// \brief Allocate a block of memory large enough to hold `n` elements of type `T` + constexpr T* allocate(size_t n, align_t align) { + return static_cast(::operator new(n * sizeof(T), align)); } /// \brief Deallocate a block of memory with type `T` constexpr void deallocate(T* ptr) { return ::operator delete(ptr); } + + /// \brief Deallocate a block of memory with type `T` + constexpr void deallocate(T* ptr, align_t align) { + return ::operator delete(ptr, align); + } +}; + + +/// +/// \brief Allocator implementation, uses `new` and `delete` operators. +/// \tparam T The data type to allocate +template +class allocator +{ +public: + /// \brief Alias for the data type used for metaprogramming + using value_t = T; + + /// \brief Metaprogramming utility to rebind an allocator to a different data type + template using rebind = allocator; + + /// \brief Default Constructor + constexpr allocator() = default; + + /// \brief Default Destructor + constexpr ~allocator() = default; + + /// \brief Copy Constructor + constexpr allocator(const allocator&) = default; + + /// \brief Copy Assignment + constexpr allocator& operator=(const allocator&) = default; + + + /// \brief Equality operator + constexpr bool_t operator==(const allocator&) { + return true; + } + + /// \brief Inequality operator + constexpr bool_t operator!=(const allocator&) { + return false; + } + + /// \brief Equality operator for allocators of same type but with different data type + template constexpr bool_t operator==(const allocator&) { + return true; + } + + /// \brief Inequality operator for allocators of same type but with different data type + template constexpr bool_t operator!=(const allocator&) { + return true; + } + + /// \brief Allocate a block of memory large enough to hold `n` elements of type `T` + constexpr T* allocate(size_t n) { + return static_cast(::operator new[](n * sizeof(T))); + } + + /// \brief Allocate a block of memory large enough to hold `n` elements of type `T` + constexpr T* allocate(size_t n, align_t align) { + return static_cast(::operator new[](n * sizeof(T), align)); + } + + /// \brief Deallocate a block of memory with type `T` + constexpr void deallocate(T* ptr) { + return ::operator delete[](ptr); + } + + /// \brief Deallocate a block of memory with type `T` + constexpr void deallocate(T* ptr, align_t align) { + return ::operator delete[](ptr, align); + } }; @@ -211,6 +296,9 @@ public: /// \brief diff type definition for ptr_traits using diff_t = ptrdiff_t; + + // Cosntructors ======================================================================================================== + /// /// \brief Default Constructor, initializes internal data to `null` and the capacity to `0` constexpr allocation() noexcept @@ -235,6 +323,24 @@ public: fennec::memcpy(_data, data, n); } + /// + /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes + /// \param n The number of elements of type `T` to allocate for + constexpr allocation(size_t n, align_t align) noexcept + : _data(nullptr), _capacity(0), _alignment(zero()) { + allocate(n, align); + } + + /// + /// \brief Buffer Copy Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes. + /// Then, the contents of data are copied into the allocation. + /// \param data the buffer to copy + /// \param n the number of elements + constexpr allocation(const T* data, size_t n, align_t align) + : allocation(n, align) { + fennec::memcpy(_data, data, n); + } + /// /// \brief Allocator Constructor /// \param alloc The allocation object to copy. @@ -268,6 +374,30 @@ public: fennec::memcpy(_data, data, n); } + /// + /// \brief Sized Allocator Constructor + /// \param n The number of elements of type `T` to allocate for + /// \param alloc The allocation object to copy. + /// + /// \details This constructor should be used when the type `AllocT` needs internal data. + constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept + : _alloc(alloc), _data(nullptr), _capacity(0), _alignment(zero()) { + allocate(n, align); + } + + /// + /// \brief Buffer Copy Allocator Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes. + /// Then, the contents of data are copied into the allocation. + /// \param data the buffer to copy + /// \param n the number of elements + /// \param alloc The allocation object to copy. + /// + /// \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); + } + /// /// \brief Copy Constructor, creates an allocation of equal size and performs a byte-wise copy /// \param alloc The allocation to copy @@ -292,6 +422,9 @@ public: if (_data) _alloc.deallocate(_data); } + + // Assignment ========================================================================================================== + /// /// \brief Copy Assignment Operator /// \param alloc the allocation to copy @@ -319,37 +452,45 @@ public: return *this; } + + // Allocation and Deallocation ========================================================================================= + /// /// \brief Allocate a block of memory for the allocation. /// 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 allocate(size_t n) noexcept { - if (_data) { - _alloc.deallocate(_data); - } + constexpr void allocate(size_t n, align_t align = zero()) noexcept { + deallocate(); - _data = _alloc.allocate(_capacity = n); + if (_alignment != zero()) { + _data = _alloc.allocate(_capacity = n, _alignment = align); + } else { + _data = _alloc.allocate(_capacity = n); + } } /// /// \brief Release the block of memory. - constexpr void release() noexcept - { + constexpr void deallocate() noexcept { if (_data) { - _alloc.deallocate(_data); + if (_alignment != zero()) { + _alloc.deallocate(_data, _alignment); + } else { + _alloc.deallocate(_data); + } } _data = nullptr; _capacity = 0; + _alignment = zero(); } /// /// \brief Reallocate the block with a new size. /// Contents are copied to the new allocation. - constexpr void reallocate(size_t n) noexcept - { + constexpr void reallocate(size_t n, align_t align = zero()) noexcept { if (_data == nullptr) { - return _alloc.allocate(_capacity = n); + allocate(n, align); } value_t* old = _data; @@ -359,6 +500,27 @@ public: _capacity = n; } + + // Access ============================================================================================================== + + constexpr value_t& operator[](size_t i) { + assertd(i < size(), "Array Out of Bounds"); + return _data[i]; + } + + constexpr const value_t operator[](size_t i) const requires requires { is_fundamental_v == true; } { + assertd(i < size(), "Array Out of Bounds"); + return _data[i]; + } + + constexpr const value_t& operator[](size_t i) const requires requires { is_fundamental_v == false; } { + assertd(i < size(), "Array Out of Bounds"); + return _data[i]; + } + + +// Modification ======================================================================================================== + /// /// \brief Clear the block of memory, setting all bytes to 0. constexpr void clear() noexcept { @@ -387,11 +549,16 @@ public: } private: - alloc_t _alloc; // Allocator object - value_t* _data; // Handle for the memory block - size_t _capacity; // Capacity of the memory block in elements. + alloc_t _alloc; // Allocator object + value_t* _data; // Handle for the memory block + size_t _capacity; // Capacity of the memory block in elements. + align_t _alignment; // Alignment information }; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } #endif // FENNEC_MEMORY_ALLOCATOR_H diff --git a/include/fennec/memory/detail/__ptr_traits.h b/include/fennec/memory/detail/__ptr_traits.h index f313c83..a56388b 100644 --- a/include/fennec/memory/detail/__ptr_traits.h +++ b/include/fennec/memory/detail/__ptr_traits.h @@ -36,7 +36,7 @@ struct __ptr_get_element : first_element { }; // Default case, return th // overload for types that have a member `ClassT::element_t` template requires requires { typename ClassT::element_t; } -struct __ptr_get_element { using type = typename ClassT::element_t; }; +struct __ptr_get_element { using type = typename ClassT::element_t; }; // helper for generating `pointer_to` template> diff --git a/include/fennec/memory/detail/__string.h b/include/fennec/memory/detail/__string.h index 5bf33d2..95dd55a 100644 --- a/include/fennec/memory/detail/__string.h +++ b/include/fennec/memory/detail/__string.h @@ -19,10 +19,6 @@ #ifndef FENNEC_MEMORY_DETAIL_MEMORY_H #define FENNEC_MEMORY_DETAIL_MEMORY_H -#include - - - // deprecated, switched to ISO C implementation // see https://git.mslockbo.org/mslockbo/fennec/src/commit/0eeb7ae3cff9d78e98dc5d9fc09bcb98b10986b9 for previous // implementation @@ -39,6 +35,7 @@ #pragma push_macro("__cplusplus") #undef __cplusplus #include +#include #pragma pop_macro("__cplusplus") #if __GNUC__ diff --git a/include/fennec/memory/new.h b/include/fennec/memory/new.h index 8be7ce9..8b67bd9 100644 --- a/include/fennec/memory/new.h +++ b/include/fennec/memory/new.h @@ -49,6 +49,10 @@ struct nothrow_t explicit nothrow_t() noexcept { } }; +/// +/// \returns the page size for the current environment +size_t pagesize(); + template void construct(TypeT* ptr) { ptr->TypeT(); } @@ -71,4 +75,31 @@ template void destruct(TypeT* ptr) { } +void* operator new (fennec::size_t size); +void* operator new[](fennec::size_t size); +void* operator new (fennec::size_t size, const fennec::nothrow_t&); +void* operator new[](fennec::size_t size, const fennec::nothrow_t&); +void* operator new (fennec::size_t size, fennec::align_t align); +void* operator new[](fennec::size_t size, fennec::align_t align); +void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&); +void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&); + + +void operator delete (void* ptr) noexcept; +void operator delete[](void* ptr) noexcept; +void operator delete (void* ptr, fennec::size_t) noexcept; +void operator delete[](void* ptr, fennec::size_t) noexcept; +void operator delete (void* ptr, const fennec::nothrow_t&) noexcept; +void operator delete[](void* ptr, const fennec::nothrow_t&) noexcept; +void operator delete (void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept; +void operator delete[](void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept; + +void operator delete (void* ptr, fennec::align_t) noexcept; +void operator delete[](void* ptr, fennec::align_t) noexcept; +void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept; +void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept; +void operator delete (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept; +void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept; + + #endif // FENNEC_MEMORY_NEW_H diff --git a/source/fproc/io/common.cpp b/source/fproc/io/common.cpp new file mode 100644 index 0000000..6efa02f --- /dev/null +++ b/source/fproc/io/common.cpp @@ -0,0 +1,56 @@ +// ===================================================================================================================== +// 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 . +// ===================================================================================================================== + +#include + +#ifdef _WIN32 + +namespace fennec +{ + +string getcwd() { + char cstr[MAX_PATH]; + if (GetCurrentDirectory(sizeof(str), str) == 0) { + return string(""); + } + string result(cstr); + return result; +} + +} + +#else + +#include +#include + +namespace fennec +{ + +string getcwd() { + char cstr[PATH_MAX]; + if (::getcwd(cstr, sizeof(cstr)) == NULL) { + return string(""); + } + string result(cstr); + return result; +} + +#endif + +} diff --git a/source/fproc/io/file.cpp b/source/fproc/io/file.cpp index da6d3a1..fcd29a9 100644 --- a/source/fproc/io/file.cpp +++ b/source/fproc/io/file.cpp @@ -14,4 +14,4 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// ===================================================================================================================== +// ===================================================================================================================== \ No newline at end of file diff --git a/source/lang/assert.cpp b/source/lang/assert.cpp index bfd33b2..31756f5 100644 --- a/source/lang/assert.cpp +++ b/source/lang/assert.cpp @@ -20,7 +20,7 @@ using assert_handler = void (*)(const char *, const char *, int , const char *); -extern void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description); +void __assert_callback(const char* expression, const char* file, int line, const char* function, const char* description); void __assert_impl(const char* expression, const char* file, int line, const char* function, const char* description) { diff --git a/source/memory/new.cpp b/source/memory/new.cpp index 495d722..5919201 100644 --- a/source/memory/new.cpp +++ b/source/memory/new.cpp @@ -28,16 +28,14 @@ #else -// Allocation functions -inline void* operator new (fennec::size_t size) { return ::malloc(size); } -inline void* operator new[](fennec::size_t size) { return ::malloc(size); } -inline void* operator new (fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } -inline void* operator new[](fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } - -// Aligned allocation & deallocation functions +// Windows does not define ISO C aligned allocation functions #ifdef _WIN32 inline void operator delete (void* ptr) noexcept { _aligned_free(ptr); } inline void operator delete[](void* ptr) noexcept { _aligned_free(ptr); } +inline void operator delete (void* ptr, fennec::align_t) noexcept { ::_aligned_free(ptr); } +inline void operator delete[](void* ptr, fennec::align_t) noexcept { ::_aligned_free(ptr); } +inline void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::_aligned_free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::_aligned_free(ptr); } inline void operator delete (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { _aligned_free(ptr); } inline void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { _aligned_free(ptr); } @@ -45,9 +43,15 @@ inline void* operator new (fennec::size_t size, fennec::align_t align) inline void* operator new[](fennec::size_t size, fennec::align_t align) { return _aligned_malloc(static_cast(align), size); } inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast(align), size); } inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return _aligned_malloc(static_cast(align), size); } + #else + inline void operator delete (void* ptr) noexcept { ::free(ptr); } inline void operator delete[](void* ptr) noexcept { ::free(ptr); } +inline void operator delete (void* ptr, fennec::align_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::align_t) noexcept { ::free(ptr); } +inline void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } inline void operator delete (void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } inline void operator delete[](void* ptr, fennec::align_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } @@ -55,22 +59,54 @@ inline void* operator new (fennec::size_t size, fennec::align_t align) inline void* operator new[](fennec::size_t size, fennec::align_t align) { return ::aligned_alloc(static_cast(align), size); } inline void* operator new (fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast(align), size); } inline void* operator new[](fennec::size_t size, fennec::align_t align, const fennec::nothrow_t&) { return ::aligned_alloc(static_cast(align), size); } + #endif -// Aligned deallocation functions -inline void operator delete (void* ptr, fennec::align_t) noexcept { ::free(ptr); } -inline void operator delete[](void* ptr, fennec::align_t) noexcept { ::free(ptr); } +// Allocation functions +inline void* operator new (fennec::size_t size) { return ::malloc(size); } +inline void* operator new[](fennec::size_t size) { return ::malloc(size); } +inline void* operator new (fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } +inline void* operator new[](fennec::size_t size, const fennec::nothrow_t&) { return ::malloc(size); } -// Sized deallocation functions -inline void operator delete (void* ptr, fennec::size_t) noexcept { ::free(ptr); } -inline void operator delete[](void* ptr, fennec::size_t) noexcept { ::free(ptr); } -inline void operator delete (void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } -inline void operator delete[](void* ptr, fennec::size_t, fennec::align_t) noexcept { ::free(ptr); } - -// Non-throwing deallocation functions +// Deallocation Functions +inline void operator delete (void* ptr, fennec::size_t) noexcept { ::free(ptr); } +inline void operator delete[](void* ptr, fennec::size_t) noexcept { ::free(ptr); } inline void operator delete (void* ptr, const fennec::nothrow_t&) noexcept { ::free(ptr); } inline void operator delete[](void* ptr, const fennec::nothrow_t&) noexcept { ::free(ptr); } inline void operator delete (void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } inline void operator delete[](void* ptr, fennec::size_t, const fennec::nothrow_t&) noexcept { ::free(ptr); } -#endif \ No newline at end of file + +// Platform specific code +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +namespace fennec +{ + + size_T pagesize() { + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + return sysInfo.dwPageSize; + } + +} + +#else + +#include + +namespace fennec +{ + + size_t pagesize() { + return sysconf(_SC_PAGESIZE); + } + +} + +#endif + +#endif