Compare commits

...
35 Commits
Author SHA1 Message Date
Riyyi 243442a3b6 Format: Fill float printing with '0's until the precision 2024-09-07 16:57:18 +02:00
Riyyi d5bf50715e System: Add missing include 2024-08-25 13:21:03 +02:00
Riyyi 8520952235 Meta: Add type compare is() function 2024-04-29 13:31:38 +02:00
Riyyi 526948874a Macro: Add string concat macro function 2023-12-03 20:13:58 +01:00
Riyyi c8e4ae884e Format: Improve the double formatting implementation 2023-11-26 10:33:56 +01:00
Riyyi 07c9f9959d Util: Fix singleton resource cleanup 2022-10-05 12:39:29 +02:00
Riyyi 9000d1d968 CMake: Populate list of required include directories for library targets
PUBLIC items will populate the INTERFACE_INCLUDE_DIRECTORIES property of
<target>. This property is a list of public include directories
requirements for a library.

Targets may populate this property to publish the include directories
required to compile against the headers for the target.
2022-09-28 14:32:23 +02:00
Riyyi 50fe09ee56 Util: Fix reading binary files 2022-09-26 02:40:32 +02:00
Riyyi 6cd2fe4e9a Util: Add ArgParser::parse overload for C legacy 2022-09-25 22:41:35 +02:00
Riyyi 703be90792 Util: Revert allow setting instance pointer manually
This is unnecessary as the allocation + placement new works.
2022-09-25 21:40:21 +02:00
Riyyi da9fb1ed0f Util: Allow setting instance pointer manually, ex: in constructor 2022-09-25 20:51:33 +02:00
Riyyi d6f378b6bc Json: Add support for float, deduplicate code 2022-09-25 01:45:23 +02:00
Riyyi e592ee7fd4 Util: Add length() and raw() functions to File class 2022-09-23 01:00:01 +02:00
Riyyi 8e2e1a13df Format: Add support for unsigned char 2022-09-22 14:26:13 +02:00
Riyyi afdd0f8b45 Format: Fix left shift operator log messages 2022-09-22 11:50:53 +02:00
Riyyi 93af096d68 Util: Set singleton instance pointer early 2022-09-21 23:20:19 +02:00
Riyyi 228e290b94 Json: Add support for more integral types 2022-09-21 17:24:38 +02:00
Riyyi cacd3ca8fd Doc: Add link to format specification and previous development locations 2022-09-20 15:11:01 +02:00
Riyyi 953df138c0 CMake: Automatically build tests during standalone compilation 2022-09-16 20:45:59 +02:00
Riyyi f3e49d8f74 CMake: Link instead of recompile 2022-09-16 20:45:39 +02:00
Riyyi 3b7d8d1e4a CMake: Allow for shared library compilation 2022-09-16 20:44:53 +02:00
Riyyi d3de1fb635 Macro: Add define for bit shifts 2022-08-31 21:30:30 +02:00
Riyyi f31f7feb5e Test: Silence compiler warning about signed int literal being too big 2022-08-24 22:07:49 +02:00
Riyyi 7093b5ad3d Json: Remove redundant width specifier to silence compiler warning 2022-08-24 21:46:55 +02:00
Riyyi 145c7e44a2 Format: Silence compiler warning about switch statement fall through 2022-08-24 21:46:49 +02:00
Riyyi 29406fac1f Meta: Dont try to lint files that are being deleted 2022-08-24 21:22:49 +02:00
Riyyi 27489c6cb4 Format: Re-add using statement to Formatter 2022-08-23 16:47:36 +02:00
Riyyi a83615083d Format: Allow user-defined types in Parser 2022-08-23 16:41:27 +02:00
Riyyi febb89be9c Format: Add using statement to Formatter 2022-08-23 15:24:48 +02:00
Riyyi bbeab2efd0 Format: Flush file stream just in case 2022-08-23 15:23:06 +02:00
Riyyi 0448e01f0a Meta: Allow single line short case labels in .clang-format 2022-08-22 12:50:47 +02:00
Riyyi 94eb1dd173 Util: Fix function source check, to prevent infinite recursion 2022-08-20 02:20:44 +02:00
Riyyi f7157feddf Util: Prefer string_view as function parameter in File class 2022-08-20 02:20:02 +02:00
Riyyi b5e55f13d3 Meta: Print commit hook scripts via function 2022-08-19 02:45:30 +02:00
Riyyi 054980e0f2 Meta: Add feature to temporary clear unstaged files in lint-ci.sh 2022-08-19 02:27:34 +02:00
26 changed files with 298 additions and 96 deletions
+1
View File
@@ -14,6 +14,7 @@ AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: Yes
+13 -11
View File
@@ -4,8 +4,13 @@
# Set project name
set(PROJECT "ruc")
# Unit tests
option(RUC_BUILD_TESTS "Build the RUC test programs" ON)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(RUC_STANDALONE TRUE)
endif()
# Options
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(RUC_BUILD_TESTS "Build the RUC test programs" ${RUC_STANDALONE})
# ------------------------------------------
@@ -55,8 +60,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Define library source files
file(GLOB_RECURSE LIBRARY_SOURCES "src/*.cpp")
add_library(${PROJECT} STATIC ${LIBRARY_SOURCES})
target_include_directories(${PROJECT} PRIVATE
add_library(${PROJECT} ${LIBRARY_SOURCES})
target_include_directories(${PROJECT} PUBLIC
"src")
# ------------------------------------------
@@ -65,8 +70,8 @@ target_include_directories(${PROJECT} PRIVATE
# Define source files
file(GLOB TEST_LIBRARY_SOURCES "test/*.cpp" "src/ruc/timer.cpp")
add_library(${PROJECT}-test STATIC ${TEST_LIBRARY_SOURCES})
target_include_directories(${PROJECT}-test PRIVATE
add_library(${PROJECT}-test ${TEST_LIBRARY_SOURCES})
target_include_directories(${PROJECT}-test PUBLIC
"src"
"test")
@@ -75,11 +80,8 @@ target_include_directories(${PROJECT}-test PRIVATE
if (RUC_BUILD_TESTS)
# Define test source files
file(GLOB_RECURSE TEST_SOURCES "test/*.cpp")
set(TEST_SOURCES ${TEST_SOURCES} ${LIBRARY_SOURCES})
file(GLOB_RECURSE TEST_SOURCES "test/unit/*.cpp")
add_executable(${PROJECT}-unit-test ${TEST_SOURCES})
target_include_directories(${PROJECT}-unit-test PRIVATE
"src"
"test")
target_link_libraries(${PROJECT}-unit-test ruc ruc-test)
endif()
+6
View File
@@ -9,3 +9,9 @@ Utility library for C++.
- Formatting library
- JSON parsing
- Unit test macros
** Formatting library
The format specification has been heavily inspired by the ~{fmt}~ library, most of the [[https://fmt.dev/latest/syntax.html#format-specification-mini-language][mini-language]] is supported.
*Note*: Development was previously done at: [[https://github.com/riyyi/manafiles/tree/6f0e3d6063ab75ad81899135689569e440ddb813/src/util][manafiles/src/util]] and [[https://github.com/riyyi/manafiles/tree/6f0e3d6063ab75ad81899135689569e440ddb813/test][manafiles/test]].
+26 -11
View File
@@ -7,22 +7,37 @@
b="$(tput bold)"
red="$(tput setf 4)"
yellow="$(tput setf 6)"
blue="$(tput setf 1)"
green="$(tput setf 2)"
n="$(tput sgr0)"
if [ ! -d ".git" ]; then
echo "${b}${red}Error:${n} please run this script from the project root" >&2
exit 1
echo "${b}${red}Error:${n} please run this script from the project root" >&2
exit 1
fi
# Temporary clear unstaged files from the repository to pass the diff checker
unstaged="$(git --no-pager diff --name-only)"
if [ -n "$unstaged" ]; then
patch=".git/patch-$(date +%s)"
echo "[${yellow}WARNING${n}]: Stashing unstaged files to $patch"
git --no-pager diff > "$patch"
git restore .
remove() {
git apply "$patch"
rm -rf "${patch:?}"
echo "[${blue}INFO${n}]: Restored changes from $patch"
}
trap remove EXIT HUP INT TERM
fi
# Get the path from the project root to the script
subDir="$(dirname -- "$0")"
# Get all files staged for commit
files="$(git --no-pager diff --cached --name-only)"
green="$(tput setf 2)"
red="$(tput setf 4)"
nc="$(tput sgr0)"
files="$(git --no-pager diff --cached --name-only --diff-filter=d)"
failures=0
@@ -33,9 +48,9 @@ lint-shell-script.sh
for linter in $linters; do
echo "Running $subDir/$linter"
if "$subDir/$linter" "$files"; then
echo "[${green}PASS${nc}]: $subDir/$linter"
echo "[${green}PASS${n}]: $subDir/$linter"
else
echo "[${red}FAIL${nc}]: $subDir/$linter"
echo "[${red}FAIL${n}]: $subDir/$linter"
failures=$(( failures + 1 ))
fi
done
@@ -43,9 +58,9 @@ done
echo "Running $subDir/lint-clang-format.sh"
# shellcheck disable=SC2086
if "$subDir/lint-clang-format.sh" "$files" && git diff --exit-code $files; then
echo "[${green}PASS${nc}]: $subDir/lint-clang-format.sh"
echo "[${green}PASS${n}]: $subDir/lint-clang-format.sh"
else
echo "[${red}FAIL${nc}]: $subDir/lint-clang-format.sh"
echo "[${red}FAIL${n}]: $subDir/lint-clang-format.sh"
failures=$(( failures + 1 ))
fi
+13 -11
View File
@@ -5,13 +5,17 @@
# ------------------------------------------
b="$(tput bold)"
red="$(tput setf 4)"
n="$(tput sgr0)"
error() {
b="$(tput bold)"
red="$(tput setf 4)"
n="$(tput sgr0)"
echo "${b}${red}Error:${n} $1" >&2
exit 1
}
if [ ! -d ".git" ]; then
echo "${b}${red}Error:${n} please run this script from the project root" >&2
exit 1
error "please run this script from the project root"
fi
formatter=false
@@ -20,16 +24,14 @@ if command -v clang-format-11 >/dev/null 2>&1; then
elif command -v clang-format >/dev/null 2>&1; then
formatter="clang-format"
if ! "$formatter" --version | awk '{ if (substr($NF, 1, index($NF, ".") - 1) < 11) exit 1; }'; then
echo "You are using '$("${CLANG_FORMAT}" --version)', which appears to not be clang-format 11 or later."
exit 1
error "you are using '$("${formatter}" --version)', which appears to not be clang-format 11 or later."
fi
else
echo "clang-format-11 is not available, but C++ files need linting!"
echo "Either skip this script, or install clang-format-11."
exit 1
error "clang-format-11 is not available, but C++ files need linting!
Either skip this script, or install clang-format-11."
fi
files="${1:-$(git --no-pager diff --cached --name-only)}"
files="${1:-$(git --no-pager diff --cached --name-only --diff-filter=d)}"
files="$(echo "$files" | grep -E '\.(cpp|h)$')"
if [ -z "$files" ]; then
+12 -9
View File
@@ -5,22 +5,25 @@
# ------------------------------------------
b="$(tput bold)"
red="$(tput setf 4)"
n="$(tput sgr0)"
error() {
b="$(tput bold)"
red="$(tput setf 4)"
n="$(tput sgr0)"
echo "${b}${red}Error:${n} $1" >&2
exit 1
}
if [ ! -d ".git" ]; then
echo "${b}${red}Error:${n} please run this script from the project root" >&2
exit 1
error "please run this script from the project root"
fi
if ! command -v shellcheck > /dev/null 2>&1; then
echo "shellcheck is not available, but shell script files need linting!"
echo "Either skip this script, or install shellcheck."
exit 1
error "shellcheck is not available, but shell-script files need linting!
Either skip this script, or install shellcheck."
fi
files="${1:-$(git --no-pager diff --cached --name-only)}"
files="${1:-$(git --no-pager diff --cached --name-only --diff-filter=d)}"
files="$(echo "$files" | grep -E '\.sh$')"
if [ -z "$files" ]; then
+5
View File
@@ -259,6 +259,11 @@ bool ArgParser::parseArgument(std::string_view argument)
}
bool ArgParser::parse(int argc, const char* argv[])
{
return parse(argc, const_cast<char**>(argv));
}
bool ArgParser::parse(int argc, char* argv[])
{
bool result = true;
+1
View File
@@ -63,6 +63,7 @@ public:
};
bool parse(int argc, const char* argv[]);
bool parse(int argc, char* argv[]);
void addOption(Option&& option);
void addOption(bool& value, char shortName, const char* longName, const char* usageString, const char* manString);
+44 -13
View File
@@ -6,27 +6,25 @@
#include <cstdint> // int32_t
#include <filesystem>
#include <fstream> // ifstream, ios, ofstream
#include <memory> // make_unique
#include <fstream> // std::ifstream, std::ofstream
#include <memory> // std::make_shared, std::make_unique, std::shared_ptr
#include <string>
#include <string_view>
#include "ruc/file.h"
#include "ruc/meta/assert.h"
namespace ruc {
File::File(const std::string& path)
File::File(std::string_view path)
: m_path(path)
{
// Create input stream object and open file
std::ifstream file(path, std::ios::in);
std::ifstream file(path.data());
VERIFY(file.is_open(), "failed to open file: '{}'", path);
// Get length of the file
file.seekg(0, std::ios::end);
int32_t size = file.tellg();
file.seekg(0, std::ios::beg);
VERIFY(size != -1, "failed to read file length: '{}', path");
int32_t size = File::length(path, file);
// Allocate memory filled with zeros
auto buffer = std::make_unique<char[]>(size);
@@ -44,15 +42,48 @@ File::~File()
// -----------------------------------------
File File::create(const std::string& path)
File File::create(std::string_view path)
{
if (!std::filesystem::exists(path)) {
std::ofstream { path };
std::ofstream { path.data() };
}
return File(path);
}
int32_t File::length(std::string_view path, std::ifstream& file)
{
file.seekg(0, std::ios::end);
int32_t length = file.tellg();
file.seekg(0, std::ios::beg);
VERIFY(length != -1, "failed to read file length: '{}'", path);
return length;
}
// FIXME: Deduplicate code with constructor, this broke binary files only
std::shared_ptr<char[]> File::raw(std::string_view path)
{
// Create input stream object and open file
std::ifstream file(path.data());
VERIFY(file.is_open(), "failed to open file: '{}'", path);
// Get length of the file
int32_t size = File::length(path, file);
// Allocate memory filled with zeros
auto buffer = std::make_shared<char[]>(size + 1);
// Fill buffer with file contents
file.read(buffer.get(), size);
file.close();
// Null termination
buffer[size] = '\0';
return buffer;
}
// -----------------------------------------
void File::clear()
@@ -60,14 +91,14 @@ void File::clear()
m_data.clear();
}
File& File::append(const std::string& data)
File& File::append(std::string_view data)
{
m_data.append(data);
return *this;
}
File& File::replace(size_t index, size_t length, const std::string& data)
File& File::replace(size_t index, size_t length, std::string_view data)
{
m_data.replace(index, length, data);
@@ -77,7 +108,7 @@ File& File::replace(size_t index, size_t length, const std::string& data)
File& File::flush()
{
// Create output stream object and open file
std::ofstream file(m_path, std::ios::out | std::ios::trunc);
std::ofstream file(m_path.data(), std::ios::out | std::ios::trunc);
VERIFY(file.is_open(), "failed to open file: '{}'", m_path);
// Write data to disk
+11 -6
View File
@@ -6,28 +6,33 @@
#pragma once
#include <cstdint> // int32_t
#include <memory> // std::shared_ptr
#include <string>
#include <string_view>
namespace ruc {
class File {
public:
File(const std::string& path);
File(std::string_view path);
virtual ~File();
static File create(const std::string& path);
static File create(std::string_view path);
static int32_t length(std::string_view path, std::ifstream& file);
static std::shared_ptr<char[]> raw(std::string_view path);
void clear();
File& append(const std::string& data);
File& replace(size_t index, size_t length, const std::string& data);
File& append(std::string_view data);
File& replace(size_t index, size_t length, std::string_view data);
File& flush();
const char* c_str() const { return m_data.c_str(); }
const std::string& data() const { return m_data; }
const std::string& path() const { return m_path; }
std::string_view path() const { return m_path; }
private:
std::string m_path;
std::string_view m_path;
std::string m_data;
};
+47 -8
View File
@@ -5,6 +5,7 @@
*/
#include <algorithm> // min
#include <charconv> // std::to_chars
#include <cstddef> // size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <iomanip> // setprecision
@@ -178,15 +179,53 @@ void Builder::putI64(int64_t value,
void Builder::putF64(double number, uint8_t precision) const
{
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<double>::digits10));
char buffer[512];
auto conversion = std::to_chars(buffer, buffer + sizeof(buffer), number);
auto converted = std::string(buffer, conversion.ptr - buffer);
std::stringstream stream;
stream
<< std::fixed << std::setprecision(precision)
<< number
<< std::defaultfloat << std::setprecision(6);
std::string string = stream.str();
m_builder << string;
size_t dot = converted.find('.');
size_t length = dot + precision + 1;
// There is no number behind the decimal point
if (dot == std::string::npos) {
if (precision > 0) {
converted += '.' + std::string(precision, '0');
}
m_builder << converted;
return;
}
// If there are less numbers behind the decimal point than the precision
if (converted.length() < length) {
converted += std::string(length - converted.length(), '0');
m_builder << converted;
return;
}
// Only round if there are more numbers behind the decimal point than the precision,
// or the number that comes after the maximum precision is higher than 4
if (converted.length() > length && converted[length] > '4') {
for (size_t i = length - 1; i >= 0 && i < converted.length(); --i) {
if (converted[i] == '.') {
continue;
}
if (converted[i] < '9') { // Overflow stops here
converted[i]++;
break;
}
converted[i] = '0';
}
}
// Cut off the characters after the requested precision
if (converted.length() > length) {
size_t last_included_number = converted.find_last_not_of("0", length - 1);
// If precision is zero, also cut off the '.', otherwise include the '0' after the '.'
size_t last_character_is_dot_offset = (converted[last_included_number] == '.') ? (precision > 0 ? 1 : -1) : 0;
converted = converted.substr(0, last_included_number + last_character_is_dot_offset + 1);
}
m_builder << converted;
}
void Builder::putString(std::string_view string, char fill, Align align, size_t width) const
+5
View File
@@ -81,6 +81,11 @@ void Formatter<const char*>::format(Builder& builder, const char* value) const
value != nullptr ? std::string_view { value, strlen(value) } : "nullptr");
}
void Formatter<const unsigned char*>::format(Builder& builder, const unsigned char* value) const
{
return Formatter<const char*>::format(builder, reinterpret_cast<const char*>(value));
}
// Pointer
void Formatter<std::nullptr_t>::format(Builder& builder, std::nullptr_t) const
+21 -2
View File
@@ -108,9 +108,11 @@ struct Formatter<T> {
uint8_t base = 0;
bool uppercase = false;
switch (specifier.type) {
case PresentationType::Binary:
base = 2;
break;
case PresentationType::BinaryUppercase:
uppercase = true;
case PresentationType::Binary:
base = 2;
break;
case PresentationType::Octal:
@@ -120,9 +122,11 @@ struct Formatter<T> {
case PresentationType::Decimal:
base = 10;
break;
case PresentationType::Hex:
base = 16;
break;
case PresentationType::HexUppercase:
uppercase = true;
case PresentationType::Hex:
base = 16;
break;
default:
@@ -195,6 +199,19 @@ template<size_t N>
struct Formatter<char[N]> : Formatter<const char*> {
};
template<>
struct Formatter<const unsigned char*> : Formatter<const char*> {
void format(Builder& builder, const unsigned char* value) const;
};
template<>
struct Formatter<unsigned char*> : Formatter<const unsigned char*> {
};
template<size_t N>
struct Formatter<unsigned char[N]> : Formatter<const unsigned char*> {
};
// Pointer
template<typename T>
@@ -314,6 +331,8 @@ struct Formatter<Specifier> : Formatter<std::nullptr_t> {
} // namespace ruc::format
using ruc::format::Formatter;
#if 0
TODO:
+2 -1
View File
@@ -70,7 +70,8 @@ private:
template<typename T>
const LogOperatorStyle& operator<<(const LogOperatorStyle& logOperatorStyle, const T& value)
{
_format(const_cast<LogOperatorStyle&>(logOperatorStyle).builder(), value);
Formatter<T> formatter;
formatter.format(const_cast<LogOperatorStyle&>(logOperatorStyle).builder(), value);
return logOperatorStyle;
}
+2
View File
@@ -411,6 +411,8 @@ constexpr void Parser::checkSpecifierType(const Specifier& specifier, ParameterT
case ParameterType::Container:
checkSpecifierContainerType(specifier);
break;
case ParameterType::UserDefined:
break;
default:
VERIFY_NOT_REACHED();
}
+1
View File
@@ -32,6 +32,7 @@ public:
String,
Pointer,
Container,
UserDefined,
};
Parser(std::string_view format, size_t parameterCount);
+2 -1
View File
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: MIT
*/
#include <cstdio> // FILE, fputs, stdout, stderr
#include <cstdio> // FILE, fflush, fputs, stdout, stderr
#include <iomanip> // setprecision
#include <ios> // defaultfloat, fixed
#include <sstream> // stringstream
@@ -22,6 +22,7 @@ void variadicPrint(FILE* file, std::string_view format, TypeErasedParameters& pa
std::string string = stream.str();
fputs(string.c_str(), file);
fflush(file);
}
// -----------------------------------------
+8 -6
View File
@@ -7,7 +7,8 @@
#pragma once
#include <algorithm> // transform
#include <cstddef> // nullptr_t
#include <cstddef> // nullptr_t, size_t
#include <cstdint> // int32_t, int64_t, uint32_t
#include <map>
#include <string>
#include <unordered_map>
@@ -17,6 +18,7 @@
#include "ruc/json/array.h"
#include "ruc/json/object.h"
#include "ruc/meta/assert.h"
#include "ruc/meta/concepts.h"
#include "ruc/meta/odr.h"
namespace ruc::json {
@@ -44,15 +46,15 @@ void fromJson(const Json& json, bool& boolean)
boolean = json.asBool();
}
template<typename Json>
void fromJson(const Json& json, int& number)
template<typename Json, Integral T>
void fromJson(const Json& json, T& number)
{
VERIFY(json.type() == Json::Type::Number);
number = (int)json.asDouble();
number = static_cast<T>(json.asDouble());
}
template<typename Json>
void fromJson(const Json& json, double& number)
template<typename Json, FloatingPoint T>
void fromJson(const Json& json, T& number)
{
VERIFY(json.type() == Json::Type::Number);
number = json.asDouble();
+1 -1
View File
@@ -266,7 +266,7 @@ Value Parser::consumeString()
break;
default:
char buffer[7];
sprintf(buffer, "\\u%0.4X", character);
sprintf(buffer, "\\u%.4X", character);
return std::string(buffer);
break;
}
+9 -8
View File
@@ -6,8 +6,8 @@
#pragma once
#include <cassert> // assert
#include <cstddef> // nullptr_t
#include <cstddef> // nullptr_t, size_t
#include <cstdint> // int32_t, int64_t, uint32_t
#include <map>
#include <string>
#include <unordered_map>
@@ -15,6 +15,7 @@
#include "ruc/json/array.h"
#include "ruc/json/object.h"
#include "ruc/meta/concepts.h"
#include "ruc/meta/odr.h"
namespace ruc::json {
@@ -30,20 +31,20 @@ struct jsonConstructor {
json.m_value.boolean = boolean;
}
template<typename Json>
static void construct(Json& json, int number)
template<typename Json, Integral T>
static void construct(Json& json, T number)
{
json.destroy();
json.m_type = Json::Type::Number;
json.m_value.number = (double)number;
json.m_value.number = static_cast<double>(number);
}
template<typename Json>
static void construct(Json& json, double number)
template<typename Json, FloatingPoint T>
static void construct(Json& json, T number)
{
json.destroy();
json.m_type = Json::Type::Number;
json.m_value.number = number;
json.m_value.number = static_cast<double>(number);
}
template<typename Json>
+2 -2
View File
@@ -71,8 +71,8 @@ inline void __assertion_failed(const char* assertion, const char* file, uint32_t
fprintf(stderr, ": ");
// Cant use the formatting library to print asserts caused by the formatting library
std::string_view functionString = function;
if (functionString.find("ruc::format::") != std::string_view::npos
&& functionString.find("ruc::GenericLexer::") != std::string_view::npos) {
if (functionString.find("ruc::format::") == std::string_view::npos
&& functionString.find("ruc::GenericLexer::") == std::string_view::npos) {
std::string message;
formatTo(message, parameters...);
fprintf(stderr, "%s", message.c_str());
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#define BIT(x) (1 << x)
#define CONCAT_IMPL(a, b) a##b
#define CONCAT(a, b) CONCAT_IMPL(a, b)
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <typeinfo>
template<typename T, typename U>
inline bool is(U& input)
{
if constexpr (requires { input.template fastIs<T>(); }) {
return input.template fastIs<T>();
}
return typeid(input) == typeid(T);
}
template<typename T, typename U>
inline bool is(U* input)
{
return input && is<T>(*input);
}
// References:
// - serenity/AK/TypeCasts.h
// - serenity/Userland/Libraries/LibJS/AST.h
+14 -4
View File
@@ -6,7 +6,9 @@
#pragma once
#include <cassert>
#include <cstdlib> // free, malloc
#include "meta/assert.h"
namespace ruc {
@@ -16,7 +18,10 @@ public:
static inline T& the()
{
if (s_instance == nullptr) {
s_instance = new T { s {} };
// Allocate memory for this instance
s_instance = static_cast<T*>(malloc(sizeof(T)));
// Call the constructor using "placement new"
new (s_instance) T { s {} };
}
return *s_instance;
@@ -24,10 +29,15 @@ public:
static inline void destroy()
{
if (s_instance) {
delete s_instance;
if (!s_instance) {
return;
}
// Call the destructor
s_instance->~T();
// Deallocate memory
free(static_cast<void*>(s_instance));
s_instance = nullptr;
}
+1
View File
@@ -1,3 +1,4 @@
#include <algorithm> // std::sort, std::unique
#include <cerrno> // errno, EAGAIN, EINTR
#include <cstddef> // size_t
#include <cstdio> // perror, ssize_t
+10 -2
View File
@@ -55,7 +55,7 @@ TEST_CASE(FormatIntegral)
result = format("{}", u32);
EXPECT_EQ(result, "4294967295");
size_t u64 = 18446744073709551615; // long unsigned int
size_t u64 = 18446744073709551615u; // long unsigned int
result = format("{}", u64);
EXPECT_EQ(result, "18446744073709551615");
}
@@ -109,6 +109,14 @@ TEST_CASE(FormatString)
result = format("{}", cString);
EXPECT_EQ(result, "C string");
const unsigned char unsignedCharArray[] = "µnsïgned çhãr";
result = format("{}", unsignedCharArray);
EXPECT_EQ(result, "µnsïgned çhãr");
const unsigned char* unsignedCharPointer = &unsignedCharArray[0];
result = format("{}", unsignedCharPointer);
EXPECT_EQ(result, "µnsïgned çhãr");
std::string string = "string";
result = format("{}", string);
EXPECT_EQ(result, "string");
@@ -513,5 +521,5 @@ TEST_CASE(FormatContainers)
}
// Local Variables:
// lsp-in-cpp-project-cache: nil
// lsp-in-cpp-project-cache: (nil)
// End: