Skip to content
This repository was archived by the owner on Jul 2, 2022. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Tests/Io/PrintfTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <Printf.hpp>

#include <random>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should checkout hsd::random

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but hsd doesn't have random_device


int main() {
std::random_device drng;
std::uniform_int_distribution dist(1, 999);
int num = dist(drng);

static const char* const days[] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday", "Hiddenday", "Nullday"
};

int di = num % 9;
const char* day = days[di];

hsd::xprintf("Hello, User%d!\nYour random day is %s\n", num, day).unwrap();
}
49 changes: 49 additions & 0 deletions cpp/Printf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "Printf.hpp"

#include <cstdio>

#include "String.hpp"
#include "Io.hpp"

using namespace hsd;
Result<void, runtime_error> hsd::xvprintf(const char* fmt, xtuple_iterator tbegin, xtuple_iterator tend) noexcept {
while (*fmt) {
char ch = *fmt++;
if (ch != '%')
std::putchar(ch);
else {
char fch = *fmt++;
if (!fch) {
return runtime_error("\nError: Invalid format string");
}
if (tbegin == tend) {
return runtime_error("\nError: Passed to few arguments");
}
switch (fch) {
case 'd': {
int value = tbegin.getnext<int>().unwrap();
auto s = string::to_string(value);
std::fwrite(s.data(), 1, s.size(), stdout);
break;
}
case 's': {
auto value = tbegin.getnext<const char*>().unwrap();
std::fwrite(value, 1, cstring::length(value), stdout);
break;
}
case 'c': {
char value = tbegin.getnext<char>().unwrap();
std::putchar(value);
break;
}
default: {
return runtime_error("\nError: Invalid format specifier");
}
}
}
}
if (tbegin != tend) {
return runtime_error("\nError: Not all arguments parsed");
}
return {};
}
15 changes: 15 additions & 0 deletions cpp/Printf.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Tuparg.hpp"
#include "Result.hpp"

namespace hsd {
Result<void, runtime_error> xvprintf(const char* fmt, xtuple_iterator tbegin, xtuple_iterator tend) noexcept;

template <typename... Args>
Result<void, runtime_error> xprintf(const char* fmt, Args&&... args) noexcept {
auto targs = make_xtuple(forward<Args>(args)...);
const auto& layout = xtuple_layout<decltype(targs)>::get_layout();
return xvprintf(fmt, layout.begin(targs), layout.end());
}
}
20 changes: 14 additions & 6 deletions cpp/Result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,19 @@ namespace hsd
const char* _err = nullptr;

public:
runtime_error(const char* error)
constexpr runtime_error(const char* error)
: _err{error}
{}

constexpr const char* operator()() const {
return _err;
}
};

// Tags for result construction
struct ok_tag_t {};
struct err_tag_t {};

template < typename Ok, typename Err >
class Result
{
Expand All @@ -90,17 +98,17 @@ namespace hsd
HSD_CONSTEXPR Result& operator=(const Result&) = delete;
HSD_CONSTEXPR Result& operator=(Result&&) = delete;

HSD_CONSTEXPR Result(const Ok& value)
HSD_CONSTEXPR Result(const Ok& value, ok_tag_t = {})
: _ok_data{value}, _initialized{true}
{}

HSD_CONSTEXPR Result(Ok&& value)
HSD_CONSTEXPR Result(Ok&& value, ok_tag_t = {})
: _ok_data{move(value)}, _initialized{true}
{}

template <typename T>
requires (std::is_convertible_v<T, Err>)
HSD_CONSTEXPR Result(T&& value)
HSD_CONSTEXPR Result(T&& value, err_tag_t = {})
: _err_data{forward<T>(value)}, _initialized{false}
{}

Expand Down Expand Up @@ -391,13 +399,13 @@ namespace hsd
constexpr void unwrap_or_default() = delete;
constexpr void unwrap_or() = delete;

HSD_CONSTEXPR Result()
HSD_CONSTEXPR Result(ok_tag_t = {})
: _initialized{true}
{}

template <typename T>
requires (std::is_convertible_v<T, Err>)
HSD_CONSTEXPR Result(T&& value)
HSD_CONSTEXPR Result(T&& value, err_tag_t = {})
: _err_data{forward<Err>(value)}, _initialized{false}
{}

Expand Down
101 changes: 101 additions & 0 deletions cpp/Tuparg.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#pragma once

#include "Types.hpp"
#include "Result.hpp"
#include <cassert>

namespace hsd {
struct xtuple_iterator {
const usize* layout;
void* addr;

template <typename X>
X& getnext_unsafe() {
assert(addr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if addr is nullptr that you really need to use an assert?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more of a safety measure. The program normally shouldn't allow this function to be called with null pointer, but if it gets called (by some other way than getnext), then it's a debugging check, and it should be erased when compiling for release


X* p = reinterpret_cast<X*>(addr);
addr = reinterpret_cast<void*>(
reinterpret_cast<uptr>(addr)
+ *layout
);
if (* ++layout == 0)
addr = nullptr;
return *p;
}

template <typename X>
Result<reference<X>, runtime_error> getnext() {
if (!addr)
return runtime_error("Extracting value past end of the container");
return Result<reference<X>, runtime_error>(getnext_unsafe<X>(), ok_tag_t{});
}

bool operator==(const xtuple_iterator& o) const {
return addr == o.addr;
}

bool operator!=(const xtuple_iterator& o) const {
return addr != o.addr;
}
};

template <typename Tfirst, typename... Trest>
struct xtuple {
Tfirst _first;
xtuple<Trest...> _rest;

xtuple(Tfirst f, Trest... r)
: _first(move(f)), _rest(move(r)...)
{}

consteval static usize get_offset() {
return offsetof(xtuple, _rest);
}
};

template <typename Tfirst>
struct xtuple<Tfirst> {
Tfirst _first;

xtuple(Tfirst f) : _first(move(f)) {}

consteval static usize get_offset() {
return sizeof(xtuple);
}
};

template <typename Tuple>
struct xtuple_layout;

template <typename Tfirst, typename... Trest>
struct xtuple_layout<xtuple<Tfirst, Trest...>> {
using tuple_type = xtuple<Tfirst, Trest...>;
constexpr static usize count = 1 + sizeof...(Trest);

usize data[count + 1];

consteval xtuple_layout() {
assign_layout(data, 0);
data[count] = 0;
}

consteval static void assign_layout(usize* p, usize idx) {
p[idx] = tuple_type::get_offset();
if constexpr (sizeof...(Trest))
xtuple_layout<xtuple<Trest...>>::assign_layout(p, idx+1);
}

static inline xtuple_layout const& get_layout() {
static constinit const xtuple_layout _layout;
return _layout;
}

auto begin(tuple_type& tup) const { return xtuple_iterator{data, &tup._first}; }
auto end() const { return xtuple_iterator{data + count, nullptr}; }
};

template <typename... Args>
auto make_xtuple(Args&&... args) {
return xtuple<remove_reference_t<Args>...>(forward<Args&&>(args)...);
}
}
7 changes: 6 additions & 1 deletion cpp/Types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace hsd
template <>
struct remove_unsigned<unsigned char>
{
using type = char;
using type = signed char;
};

template <>
Expand Down Expand Up @@ -43,6 +43,10 @@ namespace hsd
using usize = decltype(sizeof(int));
using isize = detail::remove_unsigned<usize>::type;

using uptr = usize;
using iptr = isize;
using ptrdiff = isize;

#ifdef HSD_COMPILER_GCC
using u128 = __uint128_t;
using i128 = __int128_t;
Expand All @@ -54,6 +58,7 @@ namespace hsd
using u16 = unsigned short;
using u8 = unsigned char;

using ilong = long;
using i64 = long long;
using i32 = int;
using i16 = short;
Expand Down