//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.
This commit is contained in:
@@ -2,7 +2,7 @@ function(tv2hv_target target)
|
|||||||
target_compile_definitions(${target} PRIVATE "$<$<CONFIG:DEBUG>:TV2HV_DEBUG>")
|
target_compile_definitions(${target} PRIVATE "$<$<CONFIG:DEBUG>:TV2HV_DEBUG>")
|
||||||
#target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR})
|
#target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR})
|
||||||
target_compile_features(${target} PRIVATE cxx_std_23)
|
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()
|
endfunction()
|
||||||
|
|
||||||
function(_tv2hv_set_alternate_linker)
|
function(_tv2hv_set_alternate_linker)
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
add_executable(tv2hv
|
add_executable(tv2hv
|
||||||
|
|
||||||
|
|
||||||
|
# utility code
|
||||||
|
utils/error.cpp
|
||||||
|
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
19
src/kvm/vm.hpp
Normal file
19
src/kvm/vm.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include <utils/types.hpp>
|
||||||
|
#include <utils/error.hpp>
|
||||||
|
|
||||||
|
namespace kvm {
|
||||||
|
|
||||||
|
class CPU;
|
||||||
|
|
||||||
|
class VM {
|
||||||
|
/// The primary vCPU.
|
||||||
|
util::Ref<CPU> vcpu;
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Creates a new VM instance.
|
||||||
|
static util::ErrorOr<util::Ref<VM>> create();
|
||||||
|
|
||||||
|
// TODO: more stuff
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
16
src/utils/error.cpp
Normal file
16
src/utils/error.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <cstring>
|
||||||
|
#include <utils/error.hpp>
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
82
src/utils/error.hpp
Normal file
82
src/utils/error.hpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <optional>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
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<class ...Args>
|
||||||
|
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 T>
|
||||||
|
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<T>(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isError() const {
|
||||||
|
return std::holds_alternative<Error>(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Error& err() const {
|
||||||
|
return std::get<Error>(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& value() {
|
||||||
|
return std::get<T>(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& value() const {
|
||||||
|
return std::get<T>(variant);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class ErrorOr<void> {
|
||||||
|
std::optional<Error> error;
|
||||||
|
public:
|
||||||
|
ErrorOr() = default;
|
||||||
|
ErrorOr(const Error& error)
|
||||||
|
: error(error) {}
|
||||||
|
|
||||||
|
bool isError() const {
|
||||||
|
return error.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Error& err() const {
|
||||||
|
return error.value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
59
src/utils/types.hpp
Normal file
59
src/utils/types.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
//! Core types and includes
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include <base/assert.hpp>
|
||||||
|
|
||||||
|
// 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 <class T>
|
||||||
|
constexpr void Unused(T t) {
|
||||||
|
static_cast<void>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using Ref = std::shared_ptr<T>;
|
||||||
|
|
||||||
|
template <class T, class Deleter = std::default_delete<T>>
|
||||||
|
using Unique = std::unique_ptr<T, Deleter>;
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct OverloadVisitor : Ts... {
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Ts>
|
||||||
|
OverloadVisitor(Ts...) -> OverloadVisitor<Ts...>;
|
||||||
|
|
||||||
|
template <class T, auto* Free>
|
||||||
|
struct UniqueCDeleter {
|
||||||
|
constexpr void operator()(T* ptr) {
|
||||||
|
if(ptr)
|
||||||
|
Free(reinterpret_cast<void*>(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 <class T, auto Free = std::free>
|
||||||
|
using CUnique = Unique<T, UniqueCDeleter<T, Free>>;
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
Reference in New Issue
Block a user