Compare commits
31
Commits
94eb1dd173
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
243442a3b6 | ||
|
|
d5bf50715e | ||
|
|
8520952235 | ||
|
|
526948874a | ||
|
|
c8e4ae884e | ||
|
|
07c9f9959d | ||
|
|
9000d1d968 | ||
|
|
50fe09ee56 | ||
|
|
6cd2fe4e9a | ||
|
|
703be90792 | ||
|
|
da9fb1ed0f | ||
|
|
d6f378b6bc | ||
|
|
e592ee7fd4 | ||
|
|
8e2e1a13df | ||
|
|
afdd0f8b45 | ||
|
|
93af096d68 | ||
|
|
228e290b94 | ||
|
|
cacd3ca8fd | ||
|
|
953df138c0 | ||
|
|
f3e49d8f74 | ||
|
|
3b7d8d1e4a | ||
|
|
d3de1fb635 | ||
|
|
f31f7feb5e | ||
|
|
7093b5ad3d | ||
|
|
145c7e44a2 | ||
|
|
29406fac1f | ||
|
|
27489c6cb4 | ||
|
|
a83615083d | ||
|
|
febb89be9c | ||
|
|
bbeab2efd0 | ||
|
|
0448e01f0a |
@@ -14,6 +14,7 @@ AlignTrailingComments: true
|
|||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: true
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortLambdasOnASingleLine: All
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
|||||||
+13
-11
@@ -4,8 +4,13 @@
|
|||||||
# Set project name
|
# Set project name
|
||||||
set(PROJECT "ruc")
|
set(PROJECT "ruc")
|
||||||
|
|
||||||
# Unit tests
|
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
option(RUC_BUILD_TESTS "Build the RUC test programs" ON)
|
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
|
# Define library source files
|
||||||
file(GLOB_RECURSE LIBRARY_SOURCES "src/*.cpp")
|
file(GLOB_RECURSE LIBRARY_SOURCES "src/*.cpp")
|
||||||
|
|
||||||
add_library(${PROJECT} STATIC ${LIBRARY_SOURCES})
|
add_library(${PROJECT} ${LIBRARY_SOURCES})
|
||||||
target_include_directories(${PROJECT} PRIVATE
|
target_include_directories(${PROJECT} PUBLIC
|
||||||
"src")
|
"src")
|
||||||
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
@@ -65,8 +70,8 @@ target_include_directories(${PROJECT} PRIVATE
|
|||||||
# Define source files
|
# Define source files
|
||||||
file(GLOB TEST_LIBRARY_SOURCES "test/*.cpp" "src/ruc/timer.cpp")
|
file(GLOB TEST_LIBRARY_SOURCES "test/*.cpp" "src/ruc/timer.cpp")
|
||||||
|
|
||||||
add_library(${PROJECT}-test STATIC ${TEST_LIBRARY_SOURCES})
|
add_library(${PROJECT}-test ${TEST_LIBRARY_SOURCES})
|
||||||
target_include_directories(${PROJECT}-test PRIVATE
|
target_include_directories(${PROJECT}-test PUBLIC
|
||||||
"src"
|
"src"
|
||||||
"test")
|
"test")
|
||||||
|
|
||||||
@@ -75,11 +80,8 @@ target_include_directories(${PROJECT}-test PRIVATE
|
|||||||
|
|
||||||
if (RUC_BUILD_TESTS)
|
if (RUC_BUILD_TESTS)
|
||||||
# Define test source files
|
# Define test source files
|
||||||
file(GLOB_RECURSE TEST_SOURCES "test/*.cpp")
|
file(GLOB_RECURSE TEST_SOURCES "test/unit/*.cpp")
|
||||||
set(TEST_SOURCES ${TEST_SOURCES} ${LIBRARY_SOURCES})
|
|
||||||
|
|
||||||
add_executable(${PROJECT}-unit-test ${TEST_SOURCES})
|
add_executable(${PROJECT}-unit-test ${TEST_SOURCES})
|
||||||
target_include_directories(${PROJECT}-unit-test PRIVATE
|
target_link_libraries(${PROJECT}-unit-test ruc ruc-test)
|
||||||
"src"
|
|
||||||
"test")
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -9,3 +9,9 @@ Utility library for C++.
|
|||||||
- Formatting library
|
- Formatting library
|
||||||
- JSON parsing
|
- JSON parsing
|
||||||
- Unit test macros
|
- 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]].
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ fi
|
|||||||
subDir="$(dirname -- "$0")"
|
subDir="$(dirname -- "$0")"
|
||||||
|
|
||||||
# Get all files staged for commit
|
# Get all files staged for commit
|
||||||
files="$(git --no-pager diff --cached --name-only)"
|
files="$(git --no-pager diff --cached --name-only --diff-filter=d)"
|
||||||
|
|
||||||
failures=0
|
failures=0
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ else
|
|||||||
Either skip this script, or install clang-format-11."
|
Either skip this script, or install clang-format-11."
|
||||||
fi
|
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)$')"
|
files="$(echo "$files" | grep -E '\.(cpp|h)$')"
|
||||||
|
|
||||||
if [ -z "$files" ]; then
|
if [ -z "$files" ]; then
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ if ! command -v shellcheck > /dev/null 2>&1; then
|
|||||||
Either skip this script, or install shellcheck."
|
Either skip this script, or install shellcheck."
|
||||||
fi
|
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$')"
|
files="$(echo "$files" | grep -E '\.sh$')"
|
||||||
|
|
||||||
if [ -z "$files" ]; then
|
if [ -z "$files" ]; then
|
||||||
|
|||||||
@@ -259,6 +259,11 @@ bool ArgParser::parseArgument(std::string_view argument)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ArgParser::parse(int argc, const char* argv[])
|
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;
|
bool result = true;
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool parse(int argc, const char* argv[]);
|
bool parse(int argc, const char* argv[]);
|
||||||
|
bool parse(int argc, char* argv[]);
|
||||||
|
|
||||||
void addOption(Option&& option);
|
void addOption(Option&& option);
|
||||||
void addOption(bool& value, char shortName, const char* longName, const char* usageString, const char* manString);
|
void addOption(bool& value, char shortName, const char* longName, const char* usageString, const char* manString);
|
||||||
|
|||||||
+37
-7
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
#include <cstdint> // int32_t
|
#include <cstdint> // int32_t
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream> // ifstream, ios, ofstream
|
#include <fstream> // std::ifstream, std::ofstream
|
||||||
#include <memory> // make_unique
|
#include <memory> // std::make_shared, std::make_unique, std::shared_ptr
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -20,14 +20,11 @@ File::File(std::string_view path)
|
|||||||
: m_path(path)
|
: m_path(path)
|
||||||
{
|
{
|
||||||
// Create input stream object and open file
|
// Create input stream object and open file
|
||||||
std::ifstream file(path.data(), std::ios::in);
|
std::ifstream file(path.data());
|
||||||
VERIFY(file.is_open(), "failed to open file: '{}'", path);
|
VERIFY(file.is_open(), "failed to open file: '{}'", path);
|
||||||
|
|
||||||
// Get length of the file
|
// Get length of the file
|
||||||
file.seekg(0, std::ios::end);
|
int32_t size = File::length(path, file);
|
||||||
int32_t size = file.tellg();
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
VERIFY(size != -1, "failed to read file length: '{}'", path);
|
|
||||||
|
|
||||||
// Allocate memory filled with zeros
|
// Allocate memory filled with zeros
|
||||||
auto buffer = std::make_unique<char[]>(size);
|
auto buffer = std::make_unique<char[]>(size);
|
||||||
@@ -54,6 +51,39 @@ File File::create(std::string_view path)
|
|||||||
return File(path);
|
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()
|
void File::clear()
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // int32_t
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -17,6 +19,8 @@ public:
|
|||||||
virtual ~File();
|
virtual ~File();
|
||||||
|
|
||||||
static File create(std::string_view 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();
|
void clear();
|
||||||
File& append(std::string_view data);
|
File& append(std::string_view data);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm> // min
|
#include <algorithm> // min
|
||||||
|
#include <charconv> // std::to_chars
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
#include <iomanip> // setprecision
|
#include <iomanip> // setprecision
|
||||||
@@ -178,15 +179,53 @@ void Builder::putI64(int64_t value,
|
|||||||
|
|
||||||
void Builder::putF64(double number, uint8_t precision) const
|
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;
|
size_t dot = converted.find('.');
|
||||||
stream
|
size_t length = dot + precision + 1;
|
||||||
<< std::fixed << std::setprecision(precision)
|
|
||||||
<< number
|
// There is no number behind the decimal point
|
||||||
<< std::defaultfloat << std::setprecision(6);
|
if (dot == std::string::npos) {
|
||||||
std::string string = stream.str();
|
if (precision > 0) {
|
||||||
m_builder << string;
|
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
|
void Builder::putString(std::string_view string, char fill, Align align, size_t width) const
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ void Formatter<const char*>::format(Builder& builder, const char* value) const
|
|||||||
value != nullptr ? std::string_view { value, strlen(value) } : "nullptr");
|
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
|
// Pointer
|
||||||
|
|
||||||
void Formatter<std::nullptr_t>::format(Builder& builder, std::nullptr_t) const
|
void Formatter<std::nullptr_t>::format(Builder& builder, std::nullptr_t) const
|
||||||
|
|||||||
@@ -108,9 +108,11 @@ struct Formatter<T> {
|
|||||||
uint8_t base = 0;
|
uint8_t base = 0;
|
||||||
bool uppercase = false;
|
bool uppercase = false;
|
||||||
switch (specifier.type) {
|
switch (specifier.type) {
|
||||||
|
case PresentationType::Binary:
|
||||||
|
base = 2;
|
||||||
|
break;
|
||||||
case PresentationType::BinaryUppercase:
|
case PresentationType::BinaryUppercase:
|
||||||
uppercase = true;
|
uppercase = true;
|
||||||
case PresentationType::Binary:
|
|
||||||
base = 2;
|
base = 2;
|
||||||
break;
|
break;
|
||||||
case PresentationType::Octal:
|
case PresentationType::Octal:
|
||||||
@@ -120,9 +122,11 @@ struct Formatter<T> {
|
|||||||
case PresentationType::Decimal:
|
case PresentationType::Decimal:
|
||||||
base = 10;
|
base = 10;
|
||||||
break;
|
break;
|
||||||
|
case PresentationType::Hex:
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
case PresentationType::HexUppercase:
|
case PresentationType::HexUppercase:
|
||||||
uppercase = true;
|
uppercase = true;
|
||||||
case PresentationType::Hex:
|
|
||||||
base = 16;
|
base = 16;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -195,6 +199,19 @@ template<size_t N>
|
|||||||
struct Formatter<char[N]> : Formatter<const char*> {
|
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
|
// Pointer
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -314,6 +331,8 @@ struct Formatter<Specifier> : Formatter<std::nullptr_t> {
|
|||||||
|
|
||||||
} // namespace ruc::format
|
} // namespace ruc::format
|
||||||
|
|
||||||
|
using ruc::format::Formatter;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ private:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
const LogOperatorStyle& operator<<(const LogOperatorStyle& logOperatorStyle, const T& value)
|
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;
|
return logOperatorStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -411,6 +411,8 @@ constexpr void Parser::checkSpecifierType(const Specifier& specifier, ParameterT
|
|||||||
case ParameterType::Container:
|
case ParameterType::Container:
|
||||||
checkSpecifierContainerType(specifier);
|
checkSpecifierContainerType(specifier);
|
||||||
break;
|
break;
|
||||||
|
case ParameterType::UserDefined:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
String,
|
String,
|
||||||
Pointer,
|
Pointer,
|
||||||
Container,
|
Container,
|
||||||
|
UserDefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser(std::string_view format, size_t parameterCount);
|
Parser(std::string_view format, size_t parameterCount);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdio> // FILE, fputs, stdout, stderr
|
#include <cstdio> // FILE, fflush, fputs, stdout, stderr
|
||||||
#include <iomanip> // setprecision
|
#include <iomanip> // setprecision
|
||||||
#include <ios> // defaultfloat, fixed
|
#include <ios> // defaultfloat, fixed
|
||||||
#include <sstream> // stringstream
|
#include <sstream> // stringstream
|
||||||
@@ -22,6 +22,7 @@ void variadicPrint(FILE* file, std::string_view format, TypeErasedParameters& pa
|
|||||||
|
|
||||||
std::string string = stream.str();
|
std::string string = stream.str();
|
||||||
fputs(string.c_str(), file);
|
fputs(string.c_str(), file);
|
||||||
|
fflush(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm> // transform
|
#include <algorithm> // transform
|
||||||
#include <cstddef> // nullptr_t
|
#include <cstddef> // nullptr_t, size_t
|
||||||
|
#include <cstdint> // int32_t, int64_t, uint32_t
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
#include "ruc/json/array.h"
|
#include "ruc/json/array.h"
|
||||||
#include "ruc/json/object.h"
|
#include "ruc/json/object.h"
|
||||||
#include "ruc/meta/assert.h"
|
#include "ruc/meta/assert.h"
|
||||||
|
#include "ruc/meta/concepts.h"
|
||||||
#include "ruc/meta/odr.h"
|
#include "ruc/meta/odr.h"
|
||||||
|
|
||||||
namespace ruc::json {
|
namespace ruc::json {
|
||||||
@@ -44,15 +46,15 @@ void fromJson(const Json& json, bool& boolean)
|
|||||||
boolean = json.asBool();
|
boolean = json.asBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Json>
|
template<typename Json, Integral T>
|
||||||
void fromJson(const Json& json, int& number)
|
void fromJson(const Json& json, T& number)
|
||||||
{
|
{
|
||||||
VERIFY(json.type() == Json::Type::Number);
|
VERIFY(json.type() == Json::Type::Number);
|
||||||
number = (int)json.asDouble();
|
number = static_cast<T>(json.asDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Json>
|
template<typename Json, FloatingPoint T>
|
||||||
void fromJson(const Json& json, double& number)
|
void fromJson(const Json& json, T& number)
|
||||||
{
|
{
|
||||||
VERIFY(json.type() == Json::Type::Number);
|
VERIFY(json.type() == Json::Type::Number);
|
||||||
number = json.asDouble();
|
number = json.asDouble();
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ Value Parser::consumeString()
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
char buffer[7];
|
char buffer[7];
|
||||||
sprintf(buffer, "\\u%0.4X", character);
|
sprintf(buffer, "\\u%.4X", character);
|
||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cassert> // assert
|
#include <cstddef> // nullptr_t, size_t
|
||||||
#include <cstddef> // nullptr_t
|
#include <cstdint> // int32_t, int64_t, uint32_t
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "ruc/json/array.h"
|
#include "ruc/json/array.h"
|
||||||
#include "ruc/json/object.h"
|
#include "ruc/json/object.h"
|
||||||
|
#include "ruc/meta/concepts.h"
|
||||||
#include "ruc/meta/odr.h"
|
#include "ruc/meta/odr.h"
|
||||||
|
|
||||||
namespace ruc::json {
|
namespace ruc::json {
|
||||||
@@ -30,20 +31,20 @@ struct jsonConstructor {
|
|||||||
json.m_value.boolean = boolean;
|
json.m_value.boolean = boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Json>
|
template<typename Json, Integral T>
|
||||||
static void construct(Json& json, int number)
|
static void construct(Json& json, T number)
|
||||||
{
|
{
|
||||||
json.destroy();
|
json.destroy();
|
||||||
json.m_type = Json::Type::Number;
|
json.m_type = Json::Type::Number;
|
||||||
json.m_value.number = (double)number;
|
json.m_value.number = static_cast<double>(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Json>
|
template<typename Json, FloatingPoint T>
|
||||||
static void construct(Json& json, double number)
|
static void construct(Json& json, T number)
|
||||||
{
|
{
|
||||||
json.destroy();
|
json.destroy();
|
||||||
json.m_type = Json::Type::Number;
|
json.m_type = Json::Type::Number;
|
||||||
json.m_value.number = number;
|
json.m_value.number = static_cast<double>(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Json>
|
template<typename Json>
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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
@@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cassert>
|
#include <cstdlib> // free, malloc
|
||||||
|
|
||||||
|
#include "meta/assert.h"
|
||||||
|
|
||||||
namespace ruc {
|
namespace ruc {
|
||||||
|
|
||||||
@@ -16,7 +18,10 @@ public:
|
|||||||
static inline T& the()
|
static inline T& the()
|
||||||
{
|
{
|
||||||
if (s_instance == nullptr) {
|
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;
|
return *s_instance;
|
||||||
@@ -24,10 +29,15 @@ public:
|
|||||||
|
|
||||||
static inline void destroy()
|
static inline void destroy()
|
||||||
{
|
{
|
||||||
if (s_instance) {
|
if (!s_instance) {
|
||||||
delete s_instance;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
s_instance->~T();
|
||||||
|
// Deallocate memory
|
||||||
|
free(static_cast<void*>(s_instance));
|
||||||
|
|
||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <algorithm> // std::sort, std::unique
|
||||||
#include <cerrno> // errno, EAGAIN, EINTR
|
#include <cerrno> // errno, EAGAIN, EINTR
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdio> // perror, ssize_t
|
#include <cstdio> // perror, ssize_t
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ TEST_CASE(FormatIntegral)
|
|||||||
result = format("{}", u32);
|
result = format("{}", u32);
|
||||||
EXPECT_EQ(result, "4294967295");
|
EXPECT_EQ(result, "4294967295");
|
||||||
|
|
||||||
size_t u64 = 18446744073709551615; // long unsigned int
|
size_t u64 = 18446744073709551615u; // long unsigned int
|
||||||
result = format("{}", u64);
|
result = format("{}", u64);
|
||||||
EXPECT_EQ(result, "18446744073709551615");
|
EXPECT_EQ(result, "18446744073709551615");
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,14 @@ TEST_CASE(FormatString)
|
|||||||
result = format("{}", cString);
|
result = format("{}", cString);
|
||||||
EXPECT_EQ(result, "C string");
|
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";
|
std::string string = "string";
|
||||||
result = format("{}", string);
|
result = format("{}", string);
|
||||||
EXPECT_EQ(result, "string");
|
EXPECT_EQ(result, "string");
|
||||||
@@ -513,5 +521,5 @@ TEST_CASE(FormatContainers)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// lsp-in-cpp-project-cache: nil
|
// lsp-in-cpp-project-cache: (nil)
|
||||||
// End:
|
// End:
|
||||||
|
|||||||
Reference in New Issue
Block a user