Skip to content

Commit

Permalink
Convert the Scheme RelativeDatePeriod lookup table to a std::vector.
Browse files Browse the repository at this point in the history
From a Scheme alist. The vector can be used to find the scheme symbol
as a direct lookup, which isn't possible with an alist, and can be
searched for the Scheme symbol match more quickly than an alist can.
  • Loading branch information
jralls committed Sep 2, 2021
1 parent bed44f4 commit 00c2e99
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 54 deletions.
3 changes: 3 additions & 0 deletions libgnucash/app-utils/gnc-option-date.hpp
Expand Up @@ -73,6 +73,9 @@ enum class RelativeDatePeriod : int
END_ACCOUNTING_PERIOD,
};

constexpr unsigned relative_date_periods =
static_cast<unsigned>(RelativeDatePeriod::END_ACCOUNTING_PERIOD) + 2;

using RelativeDatePeriodVec = std::vector<RelativeDatePeriod>;

bool gnc_relative_date_is_single(RelativeDatePeriod);
Expand Down
223 changes: 173 additions & 50 deletions libgnucash/app-utils/gnc-optiondb.i
Expand Up @@ -427,6 +427,18 @@ gnc_option_test_book_destroy(QofBook* book)
$1 = scm_is_signed_integer($input, INT64_MAX, INT64_MIN);
}

%typemap(in) RelativeDatePeriod (RelativeDatePeriod rdp)
{
if (scm_is_integer($input))
rdp = (RelativeDatePeriod) scm_to_int($input);
else if (scm_is_symbol($input))
rdp = scm_relative_date_get_period($input);
else
rdp = RelativeDatePeriod::TODAY;

$1 = rdp;
}

%typemap(in) RelativeDatePeriodVec& (RelativeDatePeriodVec period_set)
{
auto len = scm_is_true($input) ? scm_to_size_t(scm_length($input)) : 0;
Expand Down Expand Up @@ -626,61 +638,149 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);

%header %{

static std::vector<SCM> reldate_values{};
inline size_t index_of(RelativeDatePeriod per)
{
return static_cast<size_t>(per) + 1;
}

static void init_reldate_values()
{
if (!reldate_values.empty())
return;
std::vector<SCM> tmp (relative_date_periods, SCM_BOOL_F);
using rdp = RelativeDatePeriod;
tmp[index_of(rdp::ABSOLUTE)] =
scm_from_utf8_symbol("absolute");
tmp[index_of(rdp::TODAY)] =
scm_from_utf8_symbol("today");
tmp[index_of(rdp::ONE_WEEK_AGO)] =
scm_from_utf8_symbol("one-week-ago");
tmp[index_of(rdp::ONE_WEEK_AHEAD)] =
scm_from_utf8_symbol("one-week-ahead");
tmp[index_of(rdp::ONE_MONTH_AGO)] =
scm_from_utf8_symbol("one-month-ago");
tmp[index_of(rdp::ONE_MONTH_AHEAD)] =
scm_from_utf8_symbol("one-month-ahead");
tmp[index_of(rdp::THREE_MONTHS_AGO)] =
scm_from_utf8_symbol("three-months-ago");
tmp[index_of(rdp::THREE_MONTHS_AHEAD)] =
scm_from_utf8_symbol("three-months-ahead");
tmp[index_of(rdp::SIX_MONTHS_AGO)] =
scm_from_utf8_symbol("six-months-ago");
tmp[index_of(rdp::SIX_MONTHS_AHEAD)] =
scm_from_utf8_symbol("six-months-ahead");
tmp[index_of(rdp::ONE_YEAR_AGO)] =
scm_from_utf8_symbol("one-year-ago");
tmp[index_of(rdp::ONE_YEAR_AHEAD)] =
scm_from_utf8_symbol("one-year-ahead");
tmp[index_of(rdp::START_THIS_MONTH)] =
scm_from_utf8_symbol("start-this-month");
tmp[index_of(rdp::END_THIS_MONTH)] =
scm_from_utf8_symbol("end-this-month");
tmp[index_of(rdp::START_PREV_MONTH)] =
scm_from_utf8_symbol("start-prev-month");
tmp[index_of(rdp::END_PREV_MONTH)] =
scm_from_utf8_symbol("end-prev-month");
tmp[index_of(rdp::START_NEXT_MONTH)] =
scm_from_utf8_symbol("start-next-month");
tmp[index_of(rdp::END_NEXT_MONTH)] =
scm_from_utf8_symbol("end-next-month");
tmp[index_of(rdp::START_CURRENT_QUARTER)] =
scm_from_utf8_symbol("start-current-quarter");
tmp[index_of(rdp::END_CURRENT_QUARTER)] =
scm_from_utf8_symbol("end-current-quarter");
tmp[index_of(rdp::START_PREV_QUARTER)] =
scm_from_utf8_symbol("start-prev-quarter");
tmp[index_of(rdp::END_PREV_QUARTER)] =
scm_from_utf8_symbol("end-prev-quarter");
tmp[index_of(rdp::START_NEXT_QUARTER)] =
scm_from_utf8_symbol("start-next-quarter");
tmp[index_of(rdp::END_NEXT_QUARTER)] =
scm_from_utf8_symbol("end-next-quarter");
tmp[index_of(rdp::START_CAL_YEAR)] =
scm_from_utf8_symbol("start-cal-year");
tmp[index_of(rdp::END_CAL_YEAR)] =
scm_from_utf8_symbol("end-cal-year");
tmp[index_of(rdp::START_PREV_YEAR)] =
scm_from_utf8_symbol("start-prev-year");
tmp[index_of(rdp::END_PREV_YEAR)] =
scm_from_utf8_symbol("end-prev-year");
tmp[index_of(rdp::START_NEXT_YEAR)] =
scm_from_utf8_symbol("start-next-year");
tmp[index_of(rdp::END_NEXT_YEAR)] =
scm_from_utf8_symbol("end-next-year");
tmp[index_of(rdp::START_ACCOUNTING_PERIOD)] =
scm_from_utf8_symbol("start-accounting-period");
tmp[index_of(rdp::END_ACCOUNTING_PERIOD)] =
scm_from_utf8_symbol("end-accounting-period");
reldate_values = std::move(tmp);
}

inline static RelativeDatePeriod scm_relative_date_get_period(SCM date)
{
static SCM reldate_values = SCM_BOOL_F;

if (scm_is_false(reldate_values))
reldate_values = scm_c_eval_string(
"'((absolute RelativeDatePeriod-ABSOLUTE)"
"(today RelativeDatePeriod-TODAY)"
"(one-week-ago RelativeDatePeriod-ONE-WEEK-AGO)"
"(one-week-ahead RelativeDatePeriod-ONE-WEEK-AHEAD)"
"(one-month-ago RelativeDatePeriod-ONE-MONTH-AGO)"
"(one-month-ahead RelativeDatePeriod-ONE-MONTH-AHEAD)"
"(three-months-ago RelativeDatePeriod-THREE-MONTHS-AGO)"
"(three-months-ahead RelativeDatePeriod-THREE-MONTHS-AHEAD)"
"(six-months-ago RelativeDatePeriod-SIX-MONTHS-AGO)"
"(six-months-ahead RelativeDatePeriod-SIX-MONTHS-AHEAD)"
"(one-year-ago RelativeDatePeriod-ONE-YEAR-AGO)"
"(one-year-ahead RelativeDatePeriod-ONE-YEAR-AHEAD)"
"(start-this-month RelativeDatePeriod-START-THIS-MONTH)"
"(end-this-month RelativeDatePeriod-END-THIS-MONTH)"
"(start-prev-month RelativeDatePeriod-START-PREV-MONTH)"
"(end-prev-month RelativeDatePeriod-END-PREV-MONTH)"
"(start-next-month RelativeDatePeriod-START-NEXT-MONTH)"
"(end-next-month RelativeDatePeriod-END-NEXT-MONTH)"
"(start-current-quarter RelativeDatePeriod-START-CURRENT-QUARTER)"
"(end-current-quarter RelativeDatePeriod-END-CURRENT-QUARTER)"
"(start-prev-quarter RelativeDatePeriod-START-PREV-QUARTER)"
"(end-prev-quarter RelativeDatePeriod-END-PREV-QUARTER)"
"(start-next-quarter RelativeDatePeriod-START-NEXT-QUARTER)"
"(end-next-quarter RelativeDatePeriod-END-NEXT-QUARTER)"
"(start-cal-year RelativeDatePeriod-START-CAL-YEAR)"
"(end-cal-year RelativeDatePeriod-END-CAL-YEAR)"
"(start-prev-year RelativeDatePeriod-START-PREV-YEAR)"
"(end-prev-year RelativeDatePeriod-END-PREV-YEAR)"
"(start-next-year RelativeDatePeriod-START-NEXT-YEAR)"
"(end-next-year RelativeDatePeriod-END-NEXT-YEAR)"
"(start-accounting-period RelativeDatePeriod-START-ACCOUNTING-PERIOD)"
"(end-accounting-period RelativeDatePeriod-END-ACCOUNTING-PERIOD))");

auto reldate_scm{scm_is_pair(date) ? scm_cdr(date) : date};
auto reldate{scm_primitive_eval(scm_assq_ref(reldate_values,
reldate_scm))};
return static_cast<RelativeDatePeriod>(scm_to_int(reldate));
init_reldate_values();
auto reldate_scm{scm_is_pair(date) ? scm_cdr(date) : date};
SCM reldate_val{SCM_BOOL_F};
if (scm_is_procedure(reldate_scm))
reldate_val = scm_call_0(reldate_scm);
if (scm_is_number(reldate_scm))
reldate_val = reldate_scm;
if (scm_is_number(reldate_val))
{
auto reldate_index = scm_to_int(reldate_val);
assert(reldate_index >= static_cast<int>(RelativeDatePeriod::ABSOLUTE) && reldate_index < static_cast<int>(relative_date_periods - 1));
return static_cast<RelativeDatePeriod>(reldate_index);
}
const char* reldate_str;
if (scm_is_symbol(reldate_scm))
reldate_str = scm_to_utf8_string(scm_symbol_to_string(reldate_scm));
else
reldate_str = scm_to_utf8_string(reldate_scm);

auto date_iter =
std::find_if(reldate_values.begin(), reldate_values.end(),
[&reldate_scm](auto val)->bool {
return scm_is_eq(val, reldate_scm) == 1;
});
if (date_iter == reldate_values.end())
return RelativeDatePeriod::ABSOLUTE;
return static_cast<RelativeDatePeriod>(date_iter - reldate_values.begin() - 1);
}

inline static SCM scm_relative_date_from_period(RelativeDatePeriod period)
{
init_reldate_values();
return reldate_values[static_cast<size_t>(period) + 1];
}

inline static bool scm_date_absolute(SCM date)
{
if (scm_is_pair(date))
{
auto car{scm_to_utf8_string(scm_symbol_to_string(scm_car(date)))};
if (strcmp(car, "relative") == 0)
return false;
if (scm_is_symbol(scm_car(date)))
{
auto car{scm_to_utf8_string(scm_symbol_to_string(scm_car(date)))};
auto cdr{scm_cdr(date)};
if (strcmp(car, "relative") == 0)
return false;
if (strcmp(car, "absolute") == 0)
return true;

assert(false);
}
else
{
auto cdr{scm_cdr(date)};
if (scm_is_symbol(cdr))
return false;
if (scm_is_number(cdr))
return true;

assert(false);
}
}
return true;
return (!(scm_is_symbol(date) || scm_is_string(date)));
}

inline static time64 scm_absolute_date_to_time64(SCM date)
Expand Down Expand Up @@ -808,16 +908,39 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
return scm_cons(desig, scm_from_int(val));
}

static SCM
get_scm_value(const GncOptionDateValue& option)
{
if (option.get_period() == RelativeDatePeriod::ABSOLUTE)
return scm_cons(scm_from_utf8_symbol("absolute"),
scm_from_value(option.get_value()));
else
return scm_cons(scm_from_utf8_symbol("relative"),
scm_relative_date_from_period(option.get_period()));
}

static SCM
get_scm_default_value(const GncOptionDateValue& option)
{
if (option.get_default_period() == RelativeDatePeriod::ABSOLUTE)
return scm_cons(scm_from_utf8_symbol("absolute"),
scm_from_value(option.get_default_value()));
else
return scm_cons(scm_from_utf8_symbol("relative"),
scm_relative_date_from_period(option.get_default_period()));
}

template <typename T>
struct is_MultichoiceOrRange
struct is_MultichoiceDateOrRange
{
static constexpr bool value =
is_same_decayed_v<T, GncOptionMultichoiceValue> ||
is_same_decayed_v<T, GncOptionRangeValue<int>>;
is_same_decayed_v<T, GncOptionRangeValue<int>> ||
is_same_decayed_v<T, GncOptionDateValue>;
};

template <typename T>
inline constexpr bool is_MultichoiceOrRange_v = is_MultichoiceOrRange<T>::value;
inline constexpr bool is_MultichoiceDateOrRange_v = is_MultichoiceDateOrRange<T>::value;

template <typename ValueType>
inline SCM return_scm_value(ValueType value)
Expand Down Expand Up @@ -853,7 +976,7 @@ inline SCM return_scm_value(ValueType value)
if (!$self)
return SCM_BOOL_F;
return std::visit([](const auto& option)->SCM {
if constexpr (is_MultichoiceOrRange_v<decltype(option)>)
if constexpr (is_MultichoiceDateOrRange_v<decltype(option)>)
return get_scm_value(option);
auto value{option.get_value()};
return return_scm_value(value);
Expand All @@ -864,7 +987,7 @@ inline SCM return_scm_value(ValueType value)
if (!$self)
return SCM_BOOL_F;
return std::visit([](const auto& option)->SCM {
if constexpr (is_MultichoiceOrRange_v<decltype(option)>)
if constexpr (is_MultichoiceDateOrRange_v<decltype(option)>)
return get_scm_default_value(option);
auto value{option.get_default_value()};
return return_scm_value(value);
Expand Down
8 changes: 4 additions & 4 deletions libgnucash/app-utils/test/test-gnc-optiondb.scm
Expand Up @@ -202,17 +202,17 @@
"baz" "Phony Option"
(RelativeDatePeriod-TODAY)))
(a-time (gnc-dmy2time64 11 07 2019)))
(test-equal (current-time) (gnc-option-value option-db "foo" "bar"))
(test-equal '(relative . today) (gnc-option-value option-db "foo" "bar"))
(gnc-set-option option-db "foo" "bar" a-time)
(test-equal a-time (gnc-option-value option-db "foo" "bar")))
(test-equal `(absolute . ,a-time) (gnc-option-value option-db "foo" "bar")))
(test-end "test-gnc-test-date-option"))

(define (test-gnc-make-date-set-option)
(test-begin "test-gnc-test-date-set-option")
(let* ((option-db (new-gnc-optiondb))
(date-opt (gnc-register-date-option-set
option-db "foo" "bar" "baz" "Phony Option"
`(today
'(today
start-this-month
start-prev-month
start-current-quarter
Expand All @@ -221,7 +221,7 @@
start-cal-year
start-prev-year
start-accounting-period) #t)))
(test-equal (gnc-accounting-period-fiscal-start)
(test-equal '(relative . start-accounting-period)
(gnc-option-value option-db "foo" "bar")))
(test-end "test-gnc-test-date-set-option"))

Expand Down

0 comments on commit 00c2e99

Please sign in to comment.