Skip to content

Commit

Permalink
Merge pull request #449 from gofractally/fracpack-chrono
Browse files Browse the repository at this point in the history
Add support for std::chrono::duration.
  • Loading branch information
swatanabe authored Jul 6, 2023
2 parents fdeac6f + bea7a4f commit 5a725ea
Show file tree
Hide file tree
Showing 14 changed files with 781 additions and 543 deletions.
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

0 comments on commit 5a725ea

Please sign in to comment.