From 3c75084e28f668688914ef6398393bcba8196177 Mon Sep 17 00:00:00 2001 From: Joshua Saxby Date: Tue, 14 Sep 2021 09:27:53 +0100 Subject: [PATCH] Tidy up for initial release - spruced up docs - added Fixed::MIN() and Fixed::MAX() constant-like functions for min and max range of type, along with tests for them. - added todo-list in docs --- Doxyfile | 2 +- README.md | 62 ++----------------------------- sxpsxfp/include/sxpsxfp/Fixed.hpp | 35 +++++++++++++++-- tests/static_checks.cpp | 16 ++++++++ 4 files changed, 52 insertions(+), 63 deletions(-) diff --git a/Doxyfile b/Doxyfile index 288447e..e77b2a1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -44,7 +44,7 @@ PROJECT_NUMBER = $(TAG_NAME) # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "Lazy-evaluated type-wrapper for numeric types in C++" +PROJECT_BRIEF = "More convenient fixed-point arithmetic for the Sony PlayStation" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff --git a/README.md b/README.md index 68e9a8a..0d818cb 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,4 @@ -# CPP20-Cross-Platform-Template -A template for a cross-platform C++20 project including modern CMake, unit-testing with Catch, cross-platform CI and release builds using using Github Actions. +# SxPsxFp +More convenient fixed-point arithmetic for the Sony PlayStation -## What's included -- CMake C++20 project skeleton, with strict warning flags enabled when using GCC or Clang. -- Usage of modern CMake practices for setting project-wide compiler options, etc. in a target-focused way. -- Properly exported CMake project that can be used by other CMake projects with minimal effort (no hand-written `FindMyProject.cmake` files) -- Unit testing using [Catch2](https://github.com/catchorg/Catch2), with automatic test discovery integration with CTest. -- Github Actions config files supporting building and running tests on Linux, macOS and Windows using the following compilers: - - Linux: GCC-10, Clang-10 - - macOS: GCC-10, Clang-12 - - Windows: MSVC 2019 -- Building Releases on each platform when a Github Release is published, uploading these as build Artifacts. -- Doxygen config file with tweaks from the default config settings to provide a few more graphs (usage, caller/callee relationships) than are enabled by default. - -> **Note** There's also a Travis-CI build config for a cross-platform build of similar structure to the Github Actions builds, however this is no longer maintained as Travis-CI has been found to not support more recent versions of CMake on all platforms. - -## Usage -1. Click the Use this template button at the top of this page to create your own new copy of this template -2. Fill in the project details on the next page as you desire -3. Once you've got your new project produced from this template, make changes in the following files: - - `CMakeLists.txt`, `project/CMakeLists.txt`, `project/src/CMakeLists.txt`, `tests/CMakeLists.txt`: - - Replace all instances of `PROJECT`, `project` and `Project` with your project's name, capitalised or uncapitalised as appropriate - - `Doxyfile`: - - Change the `PROJECT_NAME` and `INPUT` settings to your project's name. - - `project`: - - Rename this directory to the name of your project. - - **Choose a Software License for your code** if it is open-source and you want other people to be able to use it with ease! - - This _project template_ is placed into the public domain, but you may want to use a different license for your own projects that you create from this template. Here is the public domain dedication text for this project: - - ``` - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - 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 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. - - For more information, please refer to - ``` -4. Enjoy! - -> The above instructions are the bare minimum required to get your own project based on this template off of the ground. You'll almost certainly want to change more things in `Doxyfile` and definitely `README.md`, but that should be well within the capabilities of a developer and also beyond the scope of this guide. +- [sxpsxfp](@ref com::saxbophone::sxpsxfp) API reference diff --git a/sxpsxfp/include/sxpsxfp/Fixed.hpp b/sxpsxfp/include/sxpsxfp/Fixed.hpp index 5af01d4..55a2498 100644 --- a/sxpsxfp/include/sxpsxfp/Fixed.hpp +++ b/sxpsxfp/include/sxpsxfp/Fixed.hpp @@ -23,6 +23,10 @@ #include #endif +/** + * @todo Consider shortening the namespace name to its last component + * @todo Consider choosing a more intuitive name than @b sxpsxfp + */ namespace com::saxbophone::sxpsxfp { class Fixed; // forward-declaration to allow declaration of user-defined literals @@ -60,6 +64,7 @@ namespace com::saxbophone::sxpsxfp { * point arithmetic and allows arithmetic operations to be done on these * instances directly, handling the additional arithmetic for emulating * fixed-point internally. + * @todo Document constants */ class Fixed { public: @@ -72,6 +77,15 @@ namespace com::saxbophone::sxpsxfp { static constexpr UnderlyingType DECIMAL_MIN = -(1 << Fixed::DECIMAL_BITS); static constexpr double FRACTIONAL_MAX = Fixed::DECIMAL_MAX + (1.0 - Fixed::FRACTIONAL_STEP); static constexpr double FRACTIONAL_MIN = Fixed::DECIMAL_MIN - (1.0 - Fixed::FRACTIONAL_STEP); + + static constexpr Fixed MAX() { + return Fixed((UnderlyingType)2147483647); + } + + static constexpr Fixed MIN() { + return Fixed((UnderlyingType)-2147483648); + } + /** * @brief Default constructor, creates a Fixed instance with value `0.0_fx` */ @@ -93,6 +107,9 @@ namespace com::saxbophone::sxpsxfp { * @note Not recommended to use this outside of constexpr contexts * where avoidable on the PlayStation, as the console has no hardware * floating point support, so slow software floats will be used. + * @todo Consider adding a single-precision `float` version of this + * methodfor faster emulation when doing runtime conversions on the + * PlayStation and `double` precision is not needed. */ constexpr Fixed(double value) { double scaled = value * Fixed::SCALE; @@ -111,9 +128,9 @@ namespace com::saxbophone::sxpsxfp { * @warning Don't use this for converting raw fixed-point integers to Fixed. * Use Fixed::Fixed(UnderlyingType) for that. * @see Fixed::Fixed(UnderlyingType) + * @todo Check for overflow? No exceptions on the PS1... */ static constexpr Fixed from_integer(int value) { - // TODO: Check for overflow? No exceptions on the PS1... return Fixed(value << Fixed::FRACTION_BITS); } /** @@ -202,9 +219,14 @@ namespace com::saxbophone::sxpsxfp { } /** * @brief Compound assignment multiplication operator + * @todo Investigate performance impact of compiler-generated 64-bit + * multiplication emulation on 32-bit MIPS. If poor performance, + * consider utilising Lameguy64's suggested implementation using inline + * assembly to take advantage of the R3000's 64-bit double-word multiply + * feature. */ constexpr Fixed& operator *=(const Fixed& rhs) { - // XXX: no int64_t on PS1, needs rewrite to run on that platform + // XXX: no int64_t on PS1, software emulation kicks in automatically int64_t result = (int64_t)this->_raw_value * rhs._raw_value; // shift back down this->_raw_value = (UnderlyingType)(result / Fixed::SCALE); @@ -212,6 +234,7 @@ namespace com::saxbophone::sxpsxfp { } /** * @brief Compound assignment integer multiplication operator + * @todo Investigate overflow? */ constexpr Fixed& operator *=(const UnderlyingType& rhs) { this->_raw_value *= rhs; @@ -219,15 +242,21 @@ namespace com::saxbophone::sxpsxfp { } /** * @brief Compound assignment division operator + * @todo Investigate performance impact of compiler-generated 64-bit + * multiplication emulation on 32-bit MIPS. If poor performance, + * consider utilising Lameguy64's suggested implementation using inline + * assembly to take advantage of the R3000's 64-bit double-word multiply + * feature. */ constexpr Fixed& operator /=(const Fixed& rhs) { - // XXX: no int64_t on PS1, needs rewrite to run on that platform + // XXX: no int64_t on PS1, software emulation kicks in automatically int64_t scaled = (int64_t)this->_raw_value * Fixed::SCALE; this->_raw_value = (UnderlyingType)(scaled / rhs._raw_value); return *this; } /** * @brief Compound assignment integer division operator + * @todo Investigate overflow? */ constexpr Fixed& operator /=(const UnderlyingType& rhs) { this->_raw_value /= rhs; diff --git a/tests/static_checks.cpp b/tests/static_checks.cpp index 190697e..3a0e566 100644 --- a/tests/static_checks.cpp +++ b/tests/static_checks.cpp @@ -53,6 +53,22 @@ TEST_CASE("Fixed::FRACTIONAL_MIN == Fixed::DECIMAL_MIN - (1 - Fixed::FRACTIONAL_ STATIC_REQUIRE(Fixed::FRACTIONAL_MIN == Fixed::DECIMAL_MIN - (1.0 - Fixed::FRACTIONAL_STEP)); } +TEST_CASE("Fixed::MAX() == Max 32-bit signed integer") { + STATIC_REQUIRE(Fixed::MAX() == Fixed(INT_MAX)); +} + +TEST_CASE("Fixed::MIN() == Min 32-bit signed integer") { + STATIC_REQUIRE(Fixed::MIN() == Fixed(INT_MIN)); +} + +TEST_CASE("typeof(Fixed::MAX()) == Fixed") { + STATIC_REQUIRE(std::is_same_v); +} + +TEST_CASE("typeof(Fixed::MIN()) == Fixed") { + STATIC_REQUIRE(std::is_same_v); +} + TEST_CASE("typeof(Fixed + Fixed) == Fixed") { Fixed x = {}, y = {}; STATIC_REQUIRE(std::is_same_v);