Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for std::chrono::duration in tables and action arguments #449

Merged
merged 1 commit into from
Jul 6, 2023
Merged
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
170 changes: 170 additions & 0 deletions libraries/psio/include/psio/chrono.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#pragma once

#include <psio/fracpack.hpp>

#include <chrono>

namespace psio
{

template <typename Rep, typename Period>
struct is_packable<std::chrono::duration<Rep, Period>> : std::bool_constant<true>
{
using is_p = is_packable<Rep>;
using T = std::chrono::duration<Rep, Period>;

static constexpr uint32_t fixed_size = is_p::fixed_size;
static constexpr bool is_variable_size = is_p::is_variable_size;
static constexpr bool is_optional = is_p::is_optional;
static constexpr bool supports_0_offset = is_p::supports_0_offset;

static bool has_value(const T& value) { return is_p::has_value(value.count()); }
template <bool Verify>
static bool has_value(const char* src, uint32_t pos, uint32_t end_pos)
{
return is_p::template has_value<Verify>(src, pos, end_pos);
}

template <bool Unpack, typename F>
static bool unpack_impl(F&& f, T* value)
{
if constexpr (Unpack)
{
Rep tmp;
bool result = f(&tmp);
*value = T{tmp};
return result;
}
else
{
return f((Rep*)nullptr);
}
}

template <typename S>
static void pack(const T& value, S& stream)
{
return is_p::pack(value.count(), stream);
}

static bool is_empty_container(const T& value)
{
return is_p::is_empty_container(value.count());
}
static bool is_empty_container(const char* src, uint32_t pos, uint32_t end_pos)
{
return is_p::is_empty_container(src, pos, end_pos);
}

template <typename S>
static void embedded_fixed_pack(const T& value, S& stream)
{
return is_p::embedded_fixed_pack(value.count(), stream);
}

template <typename S>
static void embedded_fixed_repack(const T& value,
uint32_t fixed_pos,
uint32_t heap_pos,
S& stream)
{
return is_p::embedded_fixed_repack(value.count(), fixed_pos, heap_pos, stream);
}

template <typename S>
static void embedded_variable_pack(const T& value, S& stream)
{
return is_p::embedded_variable_pack(value.count(), stream);
}

template <bool Unpack, bool Verify>
[[nodiscard]] static bool unpack(T* value,
bool& has_unknown,
bool& known_end,
const char* src,
uint32_t& pos,
uint32_t end_pos)
{
auto orig_pos = pos;
bool result = unpack_impl<Unpack>(
[&](Rep* value) {
return is_p::template unpack<Unpack, Verify>(value, has_unknown, known_end, src,
pos, end_pos);
},
value);
if constexpr (Verify && (PackableValidatedObject<T> || PackableValidatedView<T>))
{
return result && user_validate<Unpack, false>(value, src, orig_pos);
}
return result;
}

template <bool Unpack, bool Verify>
[[nodiscard]] static bool embedded_variable_unpack(T* value,
bool& has_unknown,
bool& known_end,
const char* src,
uint32_t& fixed_pos,
uint32_t end_fixed_pos,
uint32_t& heap_pos,
uint32_t end_heap_pos)
{
auto orig_pos = fixed_pos;
bool result = unpack_impl<Unpack>(
[&](Rep* value)
{
return is_p::template embedded_variable_unpack<Unpack, Verify>(
value, has_unknown, known_end, src, fixed_pos, end_fixed_pos, heap_pos,
end_heap_pos);
},
value);
if constexpr (Verify && (PackableValidatedObject<T> || PackableValidatedView<T>))
{
return result && user_validate<Unpack, true>(value, src, orig_pos);
}
return result;
}

template <bool Unpack, bool Verify>
[[nodiscard]] static bool embedded_unpack(T* value,
bool& has_unknown,
bool& known_end,
const char* src,
uint32_t& fixed_pos,
uint32_t end_fixed_pos,
uint32_t& heap_pos,
uint32_t end_heap_pos)
{
auto orig_pos = fixed_pos;
bool result = unpack_impl<Unpack>(
[&](Rep* value)
{
return is_p::template embedded_unpack<Unpack, Verify>(value, has_unknown, known_end,
src, fixed_pos, end_fixed_pos,
heap_pos, end_heap_pos);
},
value);
if constexpr (Verify && (PackableValidatedObject<T> || PackableValidatedView<T>))
{
return result && user_validate < Unpack,
!is_optional && is_variable_size > (value, src, orig_pos);
}
return result;
}
};

template <typename Rep, typename Period, typename Stream>
void to_json(const std::chrono::duration<Rep, Period>& obj, Stream& stream)
{
to_json(obj.count(), stream);
}

template <typename Rep, typename Period, typename Stream>
void from_json(std::chrono::duration<Rep, Period>& obj, Stream& stream)
{
Rep tmp;
from_json(tmp, stream);
obj = std::chrono::duration<Rep, Period>(tmp);
}

} // namespace psio
10 changes: 10 additions & 0 deletions libraries/psio/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ if(DEFINED IS_NATIVE)
benchmark.cpp
# crypto.cpp
test_fracpack.cpp
test_bool.cpp
test_char.cpp
test_int8.cpp
test_int16.cpp
test_int32.cpp
test_int64.cpp
test_float.cpp
test_struct.cpp
test_std_array.cpp
test_chrono.cpp
test_view.cpp
)
target_link_libraries(psio-tests psio catch2 Threads::Threads )
Expand Down
6 changes: 6 additions & 0 deletions libraries/psio/tests/test_bool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "test_fracpack.hpp"

TEST_CASE("roundtrip bool")
{
test<bool>({false, true});
}
6 changes: 6 additions & 0 deletions libraries/psio/tests/test_char.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "test_fracpack.hpp"

TEST_CASE("roundtrip char")
{
test<char>({'a', 'b', 'c'});
}
10 changes: 10 additions & 0 deletions libraries/psio/tests/test_chrono.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <psio/chrono.hpp>

#include "test_fracpack.hpp"

TEST_CASE("chrono")
{
test<std::chrono::nanoseconds>({std::chrono::nanoseconds(0), std::chrono::nanoseconds(1),
std::chrono::nanoseconds::min(),
std::chrono::nanoseconds::max()});
}
21 changes: 21 additions & 0 deletions libraries/psio/tests/test_float.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "test_fracpack.hpp"

TEST_CASE("roudtrip float/double")
{
test<float>({std::copysign(std::numeric_limits<float>::quiet_NaN(), -1.0f),
std::copysign(std::numeric_limits<float>::signaling_NaN(), -1.0f),
-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::max(),
-std::numeric_limits<float>::min(), -std::numeric_limits<float>::denorm_min(), -1,
-0.0f, std::numeric_limits<float>::min(), 0, 1,
std::numeric_limits<float>::denorm_min(), std::numeric_limits<float>::max(),
std::numeric_limits<float>::infinity(), std::numeric_limits<float>::signaling_NaN(),
std::numeric_limits<float>::quiet_NaN()});
test<double>(
{std::copysign(std::numeric_limits<double>::quiet_NaN(), -1.0),
std::copysign(std::numeric_limits<double>::signaling_NaN(), -1.0),
-std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::max(),
-std::numeric_limits<double>::min(), -std::numeric_limits<double>::denorm_min(), -1, -0.0,
std::numeric_limits<double>::min(), 0, 1, std::numeric_limits<double>::denorm_min(),
std::numeric_limits<double>::max(), std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::signaling_NaN(), std::numeric_limits<double>::quiet_NaN()});
}
Loading
Loading