Tarantool development patches archive
 help / color / mirror / Atom feed
From: Timur Safin via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: "'Oleg Babin'" <olegrok@tarantool.org>, <v.shpilevoy@tarantool.org>
Cc: <tarantool-patches@dev.tarantool.org>
Subject: Re: [Tarantool-patches] [PATCH resend v2 09/11] lua, datetime: time intervals support
Date: Sat, 31 Jul 2021 01:58:52 +0300	[thread overview]
Message-ID: <045901d78596$784a68d0$68df3a70$@tarantool.org> (raw)
In-Reply-To: <ff90fb89-1c85-de43-ecb8-b72068127000@tarantool.org>

Hi there!

: From: Oleg Babin <olegrok@tarantool.org>
: Subject: Re: [Tarantool-patches] [PATCH resend v2 09/11] lua, datetime: time
: intervals support
: 
: Thanks for your patch.
: 
: I wrote several comments below.
: 
: 
: However it makes me think that such approach will work quite slow since
: 
: all functions is implemented in Lua, all arithmetic is in Lua.

I'm not that pessimistic here :) [Given the fact that I'd remove
Out of a loops all handy handlers table creation] But we need
to measure it first. 
: 
: 
...
: > @@ -158,58 +169,146 @@ local DT_EPOCH_1970_OFFSET = 719163LL
: >
: >   local datetime_t = ffi.typeof('struct datetime_t')
: >   local interval_t = ffi.typeof('struct datetime_interval_t')
: > +ffi.cdef [[
: > +    struct t_interval_months {
: > +        int m;
: > +    };
: > +
: > +    struct t_interval_years {
: > +        int y;
: > +    };
: > +]]
: > +local interval_months_t = ffi.typeof('struct t_interval_months')
: > +local interval_years_t = ffi.typeof('struct t_interval_years')
: > +
: > +local function is_interval(o)
: > +    return ffi.istype(interval_t, o) or
: > +           ffi.istype(interval_months_t, o) or
: > +           ffi.istype(interval_years_t, o)
: > +end
: > +
: 
: It will throw for non-cdata values:
: 
: tarantool> ffi.istype(interval_t, o)
: ---
: - error: 'bad argument #1 to ''?'' (C type expected, got nil)'
: ...
: 
: tarantool> ffi.istype(interval_t, 123)
: ---
: - error: 'bad argument #1 to ''?'' (C type expected, got nil)'
: ...

Yes, thanks for pin-pointing it! I've modified it this way to 
avoid such errors:
------------------------------------------------
@@ -182,15 +181,19 @@ local interval_months_t = ffi.typeof('struct t_interval_months')
 local interval_years_t = ffi.typeof('struct t_interval_years')
 
 local function is_interval(o)
-    return ffi.istype(interval_t, o) or
-           ffi.istype(interval_months_t, o) or
-           ffi.istype(interval_years_t, o)
+    return type(o) == 'cdata' and 
+           (ffi.istype(interval_t, o) or
+            ffi.istype(interval_months_t, o) or
+            ffi.istype(interval_years_t, o))
 end
 
 local function is_datetime(o)
-    return ffi.istype(o, datetime_t)
+    return type(o) == 'cdata' and ffi.istype(o, datetime_t)
 end
 
+local function is_date_interval(o)
+    return is_datetime(o) or is_interval(o)
+end
 
 local function interval_new()
     local interval = ffi.new(interval_t)
------------------------------------------------

: > @@ -224,19 +323,123 @@ local function interval_serialize(self)
: >       return { secs = self.secs, nsec = self.nsec }
: >   end
: >
: > +local function local_rd(o)
: > +    return math.floor(tonumber(o.secs / SECS_PER_DAY)) +
: DT_EPOCH_1970_OFFSET
: > +end
: > +
: > +local function local_dt(o)
: > +    return cdt.dt_from_rdn(local_rd(o))
: > +end
: > +
: > +local function _normalize_nsec(secs, nsec)
: > +    if nsec < 0 then
: > +        secs = secs - 1
: > +        nsec = nsec + NANOS_PER_SEC
: > +    elseif nsec >= NANOS_PER_SEC then
: > +        secs = secs + 1
: > +        nsec = nsec - NANOS_PER_SEC
: > +    end
: > +    return secs, nsec
: > +end
: > +
: > +-- addition or subtraction from date/time of a given interval
: > +-- described via table direction should be +1 or -1
: > +local function interval_increment(self, o, direction)
: > +    assert(direction == -1 or direction == 1)
: > +    check_date(self, "interval_increment(date, object, -+1)")
: > +    assert(type(o) == 'table')
: > +
: > +    local ym_updated = false
: > +    local dhms_updated = false
: > +
: > +    local dt = local_dt(self)
: > +    local secs, nsec
: > +    secs, nsec = self.secs, self.nsec
: > +
: > +    for key, value in pairs(o) do
: > +        local handlers = {
: 
: The same as in one previous patch. It's too expensive to recreate table
: and functions for each simple
: 
: action and for each iteration loop.

I've removed creation of a table, which is invariant in the loop, to
outside of loop statement. Let me measure how it much would different
than series of iffs. 

---------------------------------------------------------
@@ -377,52 +382,52 @@ local function interval_increment(self, o, direction)
     local secs, nsec
     secs, nsec = self.secs, self.nsec
 
+    local handlers = {
+        years = function(k, v)
+            check_range(v, {0, 9999}, k)
+            dt = builtin.dt_add_years(dt, direction * v, builtin.DT_LIMIT)
+            ym_updated = true
+        end,
+
+        months = function(k, v)
+            check_range(v, {0, 12}, k)
+            dt = builtin.dt_add_months(dt, direction * v, builtin.DT_LIMIT)
+            ym_updated = true
+        end,
+
+        weeks = function(k, v)
+            check_range(v, {0, 52}, k)
+            secs = secs + direction * 7 * v * SECS_PER_DAY
+            dhms_updated = true
+            dhms_updated = true
+        end,
+
+        days = function(k, v)
+            check_range(v, {0, 31}, k)
+            secs = secs + direction * v * SECS_PER_DAY
+            dhms_updated = true
+        end,
+
+        hours = function(k, v)
+            check_range(v, {0, 23}, k)
+            secs = secs + direction * 60 * 60 * v
+            dhms_updated = true
+        end,
+
+        minutes = function(k, v)
+            check_range(v, {0, 59}, k)
+            secs = secs + direction * 60 * v
+        end,
+
+        seconds = function(k, v)
+            check_range(v, {0, 60}, k)
+            local s, frac = seconds_fraction(v)
+            secs = secs + direction * s
+            nsec = nsec + direction * frac * 1e9 -- convert fraction to nanoseconds
+            dhms_updated = true
+        end,
+    }
     for key, value in pairs(o) do
-        local handlers = {
-            years = function(v)
-                check_range(v, {0, 9999}, key)
-                dt = cdt.dt_add_years(dt, direction * v, cdt.DT_LIMIT)
-                ym_updated = true
-            end,
-
-            months = function(v)
-                check_range(v, {0, 12}, key)
-                dt = cdt.dt_add_months(dt, direction * v, cdt.DT_LIMIT)
-                ym_updated = true
-            end,
-
-            weeks = function(v)
-                check_range(v, {0, 52}, key)
-                secs = secs + direction * 7 * v * SECS_PER_DAY
-                dhms_updated = true
-            end,
-
-            days = function(v)
-                check_range(v, {0, 31}, key)
-                secs = secs + direction * v * SECS_PER_DAY
-                dhms_updated = true
-            end,
-
-            hours = function(v)
-                check_range(v, {0, 23}, key)
-                secs = secs + direction * 60 * 60 * v
-                dhms_updated = true
-            end,
-
-            minutes = function(v)
-                check_range(v, {0, 59}, key)
-                secs = secs + direction * 60 * v
-            end,
-
-            seconds = function(v)
-                check_range(v, {0, 60}, key)
-                local s, frac = seconds_fraction(v)
-                secs = secs + direction * s
-                nsec = nsec + direction * frac * 1e9 -- convert fraction to nanoseconds
-                dhms_updated = true
-            end,
-        }
-        handlers[key](value)
+        handlers[key](key, value)
     end
 
     secs, nsec = _normalize_nsec(secs, nsec)
---------------------------------------------------------

: 
: > +            years = function(v)
: > +                assert(v > 0 and v < 10000)
: > +                dt = cdt.dt_add_years(dt, direction * v, cdt.DT_LIMIT)
: > +                ym_updated = true
: > +            end,
: > +
: > +            months = function(v)
: > +                assert(v > 0 and v < 13 )
: > +                dt = cdt.dt_add_months(dt, direction * v, cdt.DT_LIMIT)
: > +                ym_updated = true
: > +            end,
: > +
: > +            weeks = function(v)
: > +                assert(v > 0 and v < 32)
: > +                secs = secs + direction * 7 * v * SECS_PER_DAY
: > +                dhms_updated = true
: > +            end,
: > +
: > +            days = function(v)
: > +                assert(v > 0 and v < 32)
: > +                secs = secs + direction * v * SECS_PER_DAY
: > +                dhms_updated = true
: > +            end,
: > +
: > +            hours = function(v)
: > +                assert(v >= 0 and v < 24)
: > +                secs = secs + direction * 60 * 60 * v
: > +                dhms_updated = true
: > +            end,
: > +
: > +            minutes = function(v)
: > +                assert(v >= 0 and v < 60)
: > +                secs = secs + direction * 60 * v
: > +            end,
: > +
: > +            seconds = function(v)
: > +                assert(v >= 0 and v < 61)
: > +                local s, frac
: > +                frac = v % 1
: > +                if frac > 0 then
: > +                    s = v - (v % 1)
: > +                else
: > +                    s = v
: > +                end
: > +                secs = secs + direction * s
: > +                nsec = nsec + direction * frac * 1e9 -- convert fraction
: to nanoseconds
: > +                dhms_updated = true
: > +            end,
: > +        }
: > +        handlers[key](value)
: > +    end
: > +
: > +    secs, nsec = _normalize_nsec(secs, nsec)
: > +
: > +    -- .days, .hours, .minutes, .seconds
: > +    if dhms_updated then
: > +        self.secs = secs
: > +        self.nsec = nsec
: > +    end
: > +
: > +    -- .years, .months updated
: > +    if ym_updated then
: > +        self.secs = (cdt.dt_rdn(dt) - DT_EPOCH_1970_OFFSET) *
: SECS_PER_DAY +
: > +                    secs % SECS_PER_DAY
: > +    end
: > +
: > +    return self
: > +end
: > +

: 
: tarantool> return require('datetime').now() + 1
: ---
: - error: '[string "return require(''datetime'').now() + 1"]:1: Usage:
: datetime:__add(interval)'
: ...
: 
: 
: Looks a bit confusing. User doesn't know about metamethods.

Partially agreed. Though I assume that users of this code will 
be educated enough. But in any case, what would be your suggested
error message here? 

Thanks,
Timur


  reply	other threads:[~2021-07-30 22:58 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-28 10:34 [Tarantool-patches] [PATCH resend v2 00/11] Initial datetime support Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 01/11] build: add Christian Hansen c-dt to the build Timur Safin via Tarantool-patches
2021-07-29 23:40   ` Vladislav Shpilevoy via Tarantool-patches
2021-07-31  9:22     ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 02/11] lua: built-in module datetime Timur Safin via Tarantool-patches
2021-07-29 18:55   ` Oleg Babin via Tarantool-patches
2021-07-30 19:00     ` Timur Safin via Tarantool-patches
2021-07-31  6:29       ` Oleg Babin via Tarantool-patches
2021-07-31 16:51         ` Timur Safin via Tarantool-patches
2021-07-29 23:36   ` Vladislav Shpilevoy via Tarantool-patches
2021-07-30 15:39     ` Timur Safin via Tarantool-patches
2021-08-01 17:01       ` Vladislav Shpilevoy via Tarantool-patches
2021-08-01 20:23         ` Timur Safin via Tarantool-patches
2021-08-04 23:57           ` Vladislav Shpilevoy via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 03/11] lua, datetime: datetime tests Timur Safin via Tarantool-patches
2021-07-29 18:55   ` Oleg Babin via Tarantool-patches
2021-07-30 20:45     ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 04/11] lua, datetime: display datetime Timur Safin via Tarantool-patches
2021-07-29 18:55   ` Oleg Babin via Tarantool-patches
2021-07-30 21:48     ` Timur Safin via Tarantool-patches
2021-07-31  6:29       ` Oleg Babin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 05/11] box, datetime: add messagepack support for datetime Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 06/11] box, datetime: datetime comparison for indices Timur Safin via Tarantool-patches
2021-07-29 18:56   ` Oleg Babin via Tarantool-patches
2021-07-30 22:18     ` Timur Safin via Tarantool-patches
2021-07-31  6:30       ` Oleg Babin via Tarantool-patches
2021-07-31  9:31         ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 07/11] lua, datetime: proper datetime encoding Timur Safin via Tarantool-patches
2021-07-29 18:57   ` Oleg Babin via Tarantool-patches
2021-07-30 22:20     ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 08/11] lua, datetime: calculated attributes for datetimes Timur Safin via Tarantool-patches
2021-07-29 18:57   ` Oleg Babin via Tarantool-patches
2021-07-30 22:30     ` Timur Safin via Tarantool-patches
2021-07-31  6:31       ` Oleg Babin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 09/11] lua, datetime: time intervals support Timur Safin via Tarantool-patches
2021-07-29 18:58   ` Oleg Babin via Tarantool-patches
2021-07-30 22:58     ` Timur Safin via Tarantool-patches [this message]
2021-07-31  6:31       ` Oleg Babin via Tarantool-patches
2021-07-31  9:20         ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 10/11] lua, datetime: unixtime, timestamp setters in datetime.lua Timur Safin via Tarantool-patches
2021-07-29 18:58   ` Oleg Babin via Tarantool-patches
2021-07-30 23:11     ` Timur Safin via Tarantool-patches
2021-07-31  6:31       ` Oleg Babin via Tarantool-patches
2021-07-31  9:54         ` Timur Safin via Tarantool-patches
2021-07-28 10:34 ` [Tarantool-patches] [PATCH resend v2 11/11] datetime: changelog for datetime module Timur Safin via Tarantool-patches
2021-07-29 18:55 ` [Tarantool-patches] [PATCH resend v2 00/11] Initial datetime support Oleg Babin via Tarantool-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='045901d78596$784a68d0$68df3a70$@tarantool.org' \
    --to=tarantool-patches@dev.tarantool.org \
    --cc=olegrok@tarantool.org \
    --cc=tsafin@tarantool.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH resend v2 09/11] lua, datetime: time intervals support' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox