Skip to content
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
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# clock (development version)

* The storage mechanism for the duration, sys-time, naive-time, and zoned-time
types has been altered to more correctly represent the full range of values
allowed by the underlying C++ types. This means that if you have serialized
a value of one of these types with an old version of clock, then it will no
longer unserialize correctly going forward.

Technically, rather than storing a variable number of integer vectors
representing ticks, ticks of a day, and ticks of a second, we now always store
values of these types within two double vectors, regardless of the precision.
This simplifies the implementation and allows us to represent the full range
of possible `int64_t` values (#331).

* clock now compiles significantly faster (on a 2018 Intel Mac, it used to take
~70 seconds for a full compilation, and now takes ~25 seconds) (#322).

Expand Down
12 changes: 6 additions & 6 deletions R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -412,16 +412,16 @@ clock_init_utils <- function() {
.Call(`_clock_clock_init_utils`)
}

weekday_add_days_cpp <- function(x, n) {
.Call(`_clock_weekday_add_days_cpp`, x, n)
weekday_add_days_cpp <- function(x, n_fields) {
.Call(`_clock_weekday_add_days_cpp`, x, n_fields)
}

weekday_minus_weekday_cpp <- function(x, y) {
.Call(`_clock_weekday_minus_weekday_cpp`, x, y)
}

weekday_from_time_point_cpp <- function(x) {
.Call(`_clock_weekday_from_time_point_cpp`, x)
weekday_from_time_point_cpp <- function(x_fields) {
.Call(`_clock_weekday_from_time_point_cpp`, x_fields)
}

format_weekday_cpp <- function(x, labels) {
Expand Down Expand Up @@ -452,8 +452,8 @@ as_zoned_sys_time_from_naive_time_cpp <- function(fields, precision_int, zone, n
.Call(`_clock_as_zoned_sys_time_from_naive_time_cpp`, fields, precision_int, zone, nonexistent_string, ambiguous_string)
}

as_zoned_sys_time_from_naive_time_with_reference_cpp <- function(fields, precision_int, zone, nonexistent_string, ambiguous_string, reference) {
.Call(`_clock_as_zoned_sys_time_from_naive_time_with_reference_cpp`, fields, precision_int, zone, nonexistent_string, ambiguous_string, reference)
as_zoned_sys_time_from_naive_time_with_reference_cpp <- function(fields, precision_int, zone, nonexistent_string, ambiguous_string, reference_fields) {
.Call(`_clock_as_zoned_sys_time_from_naive_time_with_reference_cpp`, fields, precision_int, zone, nonexistent_string, ambiguous_string, reference_fields)
}

to_sys_duration_fields_from_sys_seconds_cpp <- function(seconds) {
Expand Down
2 changes: 1 addition & 1 deletion R/date.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ as.Date.clock_calendar <- function(x, ...) {
as.Date.clock_time_point <- function(x, ...) {
names <- clock_rcrd_names(x)
x <- time_point_floor(x, "day")
x <- field_ticks(x)
x <- as_duration(x)
x <- as.double(x)
names(x) <- names
new_date(x)
Expand Down
18 changes: 0 additions & 18 deletions R/duration.R
Original file line number Diff line number Diff line change
Expand Up @@ -1150,21 +1150,3 @@ duration_precision <- function(x) {
duration_precision_attribute <- function(x) {
attr(x, "precision", exact = TRUE)
}

# ------------------------------------------------------------------------------

field_ticks <- function(x) {
# The `ticks` field is the first field of every
# duration / time point / zoned time type, which makes it the field that
# names are on. When extracting the field, we don't ever
# want the names to come with it.
out <- field(x, "ticks")
names(out) <- NULL
out
}
field_ticks_of_day <- function(x) {
field(x, "ticks_of_day")
}
field_ticks_of_second <- function(x) {
field(x, "ticks_of_second")
}
12 changes: 8 additions & 4 deletions src/calendar.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ static
inline
cpp11::writable::list
as_sys_time_from_calendar_impl(const Calendar& x) {
using Duration = typename ClockDuration::chrono_duration;

const r_ssize size = x.size();
ClockDuration out(size);
using Duration = typename ClockDuration::duration;

for (r_ssize i = 0; i < size; ++i) {
if (x.is_na(i)) {
Expand All @@ -108,12 +109,15 @@ as_sys_time_from_calendar_impl(const Calendar& x) {
return out.to_list();
}

template <class Calendar, class ClockDuration>
template <class ClockDuration, class Calendar>
cpp11::writable::list
as_calendar_from_sys_time_impl(const ClockDuration& x) {
as_calendar_from_sys_time_impl(cpp11::list_of<cpp11::doubles>& fields) {
using Duration = typename ClockDuration::chrono_duration;

const ClockDuration x{fields};
const r_ssize size = x.size();

Calendar out(size);
using Duration = typename ClockDuration::duration;

for (r_ssize i = 0; i < size; ++i) {
if (x.is_na(i)) {
Expand Down
168 changes: 84 additions & 84 deletions src/cpp11.cpp

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions src/doubles.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#ifndef CLOCK_DOUBLES_H
#define CLOCK_DOUBLES_H

#include "clock.h"

namespace rclock {

class doubles
{
const cpp11::doubles read_;
cpp11::writable::doubles write_;
bool writable_;
r_ssize size_;

public:
doubles() noexcept;
doubles(const cpp11::doubles& x);
doubles(r_ssize size);

bool is_na(r_ssize i) const noexcept;
r_ssize size() const noexcept;

void assign(double x, r_ssize i);
void assign_na(r_ssize i);

double operator[](r_ssize i) const noexcept;

SEXP sexp() const noexcept;
};

namespace detail {

static const cpp11::doubles empty_doubles = cpp11::doubles{};

} // namespace detail

inline
doubles::doubles() noexcept
: read_(detail::empty_doubles),
writable_(false),
size_(0)
{}

inline
doubles::doubles(const cpp11::doubles& x)
: read_(x),
writable_(false),
size_(x.size())
{}

inline
doubles::doubles(r_ssize size)
: read_(detail::empty_doubles),
write_(cpp11::writable::doubles(size)),
writable_(true),
size_(size)
{}

inline
bool
doubles::is_na(r_ssize i) const noexcept {
return std::isnan(this->operator[](i));
}

inline
r_ssize
doubles::size() const noexcept {
return size_;
}

inline
void
doubles::assign(double x, r_ssize i) {
if (!writable_) {
write_ = cpp11::writable::doubles(read_);
writable_ = true;
}
write_[i] = x;
}

inline
void
doubles::assign_na(r_ssize i) {
return assign(r_dbl_na, i);
}

inline
double
doubles::operator[](r_ssize i) const noexcept {
return writable_ ? write_[i] : read_[i];
}

inline
SEXP
doubles::sexp() const noexcept {
return writable_ ? write_ : read_;
}

} // namespace rclock

#endif
Loading