From c6e21288756907fc4f8005dd588882cda8612e8a Mon Sep 17 00:00:00 2001 From: modeco80 Date: Sun, 15 Feb 2026 10:56:05 -0500 Subject: [PATCH] //utils: Add some scaffolding code Error is.. well, an error. Unlike std::error_code, or etc, we use a string so that code can attach its own context. It's not perfect, but it's better than error categories, and that's good enough. A early idea for the api of kvm::VM is provided, but I'm not attached to it. --- cmake/ProjectFuncs.cmake | 2 +- src/CMakeLists.txt | 4 ++ src/kvm/vm.hpp | 19 ++++++++++ src/utils/error.cpp | 16 ++++++++ src/utils/error.hpp | 82 ++++++++++++++++++++++++++++++++++++++++ src/utils/types.hpp | 59 +++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/kvm/vm.hpp create mode 100644 src/utils/error.cpp create mode 100644 src/utils/error.hpp create mode 100644 src/utils/types.hpp diff --git a/cmake/ProjectFuncs.cmake b/cmake/ProjectFuncs.cmake index 85092f5..1653a9f 100644 --- a/cmake/ProjectFuncs.cmake +++ b/cmake/ProjectFuncs.cmake @@ -2,7 +2,7 @@ function(tv2hv_target target) target_compile_definitions(${target} PRIVATE "$<$:TV2HV_DEBUG>") #target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_features(${target} PRIVATE cxx_std_23) - target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}/src/lib ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}) endfunction() function(_tv2hv_set_alternate_linker) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f2aef0..605f0ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,9 @@ add_executable(tv2hv + + # utility code + utils/error.cpp + main.cpp ) diff --git a/src/kvm/vm.hpp b/src/kvm/vm.hpp new file mode 100644 index 0000000..37c42f4 --- /dev/null +++ b/src/kvm/vm.hpp @@ -0,0 +1,19 @@ +#include +#include + +namespace kvm { + + class CPU; + + class VM { + /// The primary vCPU. + util::Ref vcpu; + public: + + /// Creates a new VM instance. + static util::ErrorOr> create(); + + // TODO: more stuff + }; + +} diff --git a/src/utils/error.cpp b/src/utils/error.cpp new file mode 100644 index 0000000..8d8120f --- /dev/null +++ b/src/utils/error.cpp @@ -0,0 +1,16 @@ +#include +#include + +namespace util { + + Error Error::vFormat(const std::string_view formatString, std::format_args args) { + return Error(std::vformat(formatString, args)); + } + + Error Error::systemError() { + char errBuffer[128]{}; + auto* pStr = strerror_r(errno, &errBuffer[0], sizeof(errBuffer)); + return Error::format("System error: {}", std::string_view(pStr)); + } + +} diff --git a/src/utils/error.hpp b/src/utils/error.hpp new file mode 100644 index 0000000..765d0b7 --- /dev/null +++ b/src/utils/error.hpp @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include + +namespace util { + + /// An error. + class Error { + std::string msg; + + static Error vFormat(const std::string_view formatString, std::format_args args); + + public: + explicit Error(const std::string& message) + : msg(message) {} + + template + static constexpr auto format(const std::string_view formatString, Args... args) { + return vFormat(formatString, std::make_format_args(args...)); + } + + /// Formats a system error. + static Error systemError(); + + const char* message() const { return msg.c_str(); } + }; + + /// A type which can store either an error or a value. + template + class ErrorOr { + std::variant< + Error, + T + > variant; + public: + constexpr ErrorOr(const Error& error) + : variant(error) {} + + constexpr ErrorOr(const T& value) + : variant(value) {} + + bool isValue() const { + return std::holds_alternative(variant); + } + + bool isError() const { + return std::holds_alternative(variant); + } + + const Error& err() const { + return std::get(variant); + } + + T& value() { + return std::get(variant); + } + + T& value() const { + return std::get(variant); + } + }; + + template<> + class ErrorOr { + std::optional error; + public: + ErrorOr() = default; + ErrorOr(const Error& error) + : error(error) {} + + bool isError() const { + return error.has_value(); + } + + const Error& err() const { + return error.value(); + } + }; + +} diff --git a/src/utils/types.hpp b/src/utils/types.hpp new file mode 100644 index 0000000..597a48b --- /dev/null +++ b/src/utils/types.hpp @@ -0,0 +1,59 @@ +//! Core types and includes +#pragma once + +#include +#include +#include + +#include + +// these are in the global namespace since most libraries +// won't try defining anything like this in the global namespace +// (and I'd like these types to be used globally a lot more anyways) +using u8 = std::uint8_t; +using i8 = std::int8_t; +using u16 = std::uint16_t; +using i16 = std::int16_t; +using u32 = std::uint32_t; +using i32 = std::int32_t; +using u64 = std::uint64_t; +using i64 = std::int64_t; +using usize = std::size_t; +using isize = std::intptr_t; + +namespace util { + + template + constexpr void Unused(T t) { + static_cast(t); + } + + template + using Ref = std::shared_ptr; + + template > + using Unique = std::unique_ptr; + + template + struct OverloadVisitor : Ts... { + using Ts::operator()...; + }; + + template + OverloadVisitor(Ts...) -> OverloadVisitor; + + template + struct UniqueCDeleter { + constexpr void operator()(T* ptr) { + if(ptr) + Free(reinterpret_cast(ptr)); + } + }; + + /// Use this for wrapping a C-allocated memory block. The defaults here assume + /// you're wrapping data allocated by malloc(), however, any deallocator pattern + /// is supported by the UniqueCDeleter. + template + using CUnique = Unique>; + +} // namespace base