summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorCharles Blake <cblake@csail.mit.edu>2015-08-09 06:58:36 -0400
committerCharles Blake <cblake@csail.mit.edu>2015-08-09 06:58:36 -0400
commit9c3c48a6d0b89447e2f2efac953bce34a2b96fa8 (patch)
tree577c4cb15baead3a22fd4e11588d1bb6fd134330 /lib
parent26f7a53d4a526b6305a2bca3d28c3c5eb9cfa297 (diff)
parent34ca9dd5861d5504bbbeb71469318c8c8caba6d7 (diff)
downloadNim-9c3c48a6d0b89447e2f2efac953bce34a2b96fa8.tar.gz
Merge ../Nim into devel
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/collections/tables.nim8
-rw-r--r--lib/pure/json.nim24
-rw-r--r--lib/pure/times.nim126
-rw-r--r--lib/pure/unittest.nim2
-rw-r--r--lib/system.nim7
5 files changed, 148 insertions, 19 deletions
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index ec0d9623f..be6b755ed 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -226,6 +226,10 @@ proc `$`*[A, B](t: Table[A, B]): string =
   ## The `$` operator for hash tables.
   dollarImpl()
 
+proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = t[].hasKey(key)
+
 template equalsImpl() =
   if s.counter == t.counter:
     # different insertion orders mean different 'data' seqs, so we have
@@ -293,10 +297,6 @@ proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
   ## returns true iff `key` is in the table, otherwise inserts `value`.
   t[].hasKeyOrPut(key, val)
 
-proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
-  ## returns true iff `key` is in the table `t`.
-  result = t[].hasKey(key)
-
 proc contains*[A, B](t: TableRef[A, B], key: A): bool =
   ## alias of `hasKey` for use with the `in` operator.
   return hasKey[A, B](t, key)
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 49915b7e9..540a1a8eb 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -608,29 +608,29 @@ proc newJArray*(): JsonNode =
 proc getStr*(n: JsonNode, default: string = ""): string =
   ## Retrieves the string value of a `JString JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JString``.
-  if n.kind != JString: return default
+  ## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil.
+  if n.isNil or n.kind != JString: return default
   else: return n.str
 
 proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
   ## Retrieves the int value of a `JInt JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JInt``.
-  if n.kind != JInt: return default
+  ## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
+  if n.isNil or n.kind != JInt: return default
   else: return n.num
 
 proc getFNum*(n: JsonNode, default: float = 0.0): float =
   ## Retrieves the float value of a `JFloat JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JFloat``.
-  if n.kind != JFloat: return default
+  ## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil.
+  if n.isNil or n.kind != JFloat: return default
   else: return n.fnum
 
 proc getBVal*(n: JsonNode, default: bool = false): bool =
   ## Retrieves the bool value of a `JBool JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JBool``.
-  if n.kind != JBool: return default
+  ## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
+  if n.isNil or n.kind != JBool: return default
   else: return n.bval
 
 proc getFields*(n: JsonNode,
@@ -638,15 +638,15 @@ proc getFields*(n: JsonNode,
         seq[tuple[key: string, val: JsonNode]] =
   ## Retrieves the key, value pairs of a `JObject JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JObject``.
-  if n.kind != JObject: return default
+  ## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
+  if n.isNil or n.kind != JObject: return default
   else: return n.fields
 
 proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
   ## Retrieves the int value of a `JArray JsonNode`.
   ##
-  ## Returns ``default`` if ``n`` is not a ``JArray``.
-  if n.kind != JArray: return default
+  ## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil.
+  if n.isNil or n.kind != JArray: return default
   else: return n.elems
 
 proc `%`*(s: string): JsonNode =
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 78629af71..d9abbed1a 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -1052,6 +1052,117 @@ proc parse*(value, layout: string): TimeInfo =
   info.weekday = getLocalTime(timeInfoToTime(info)).weekday
   return info
 
+# Leap year calculations are adapted from:
+# from http://www.codeproject.com/Articles/7358/Ultra-fast-Algorithms-for-Working-with-Leap-Years
+# The dayOfTheWeek procs are adapated from:
+# from http://stason.org/TULARC/society/calendars/2-5-What-day-of-the-week-was-2-August-1953.html
+
+# Note: for leap years, start date is assumed to be 1 AD.
+# counts the number of leap years up to January 1st of a given year.
+# Keep in mind that if specified year is a leap year, the leap day
+# has not happened before January 1st of that year.
+proc countLeapYears(yearSpan: int): int =
+  (((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1)/400)).int
+
+proc countDays(yearSpan: int): int =
+  (yearSpan - 1) * 365 + countLeapYears(yearSpan)
+
+proc countYears(daySpan: int): int =
+  # counts the number of years spanned by a given number of days.
+  ((daySpan - countLeapYears(daySpan div 365)) div 365)
+
+proc countYearsAndDays(daySpan: int): tuple[years: int, days: int] =
+  # counts the number of years spanned by a given number of days and the remainder as days.
+  let days = daySpan - countLeapYears(daySpan div 365)
+  result.years = days div 365
+  result.days = days mod 365
+
+const
+  secondsInMin = 60
+  secondsInHour = 60*60
+  secondsInDay = 60*60*24
+  epochStartYear = 1970
+
+proc getDayOfWeek*(day, month, year: int): WeekDay =
+  ## Returns the day of the week enum from day, month and year.
+  # Day & month start from one.
+  let
+    a = (14 - month) div 12
+    y = year - a
+    m = month + (12*a) - 2
+    d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
+  # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
+  # for the WeekDay type.
+  if d == 0: return dSun
+  result = (d-1).WeekDay
+
+proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
+  ## Returns the day of the week enum from day, month and year, according to the Julian calender.
+  # Day & month start from one.
+  let
+    a = (14 - month) div 12
+    y = year - a
+    m = month + (12*a) - 2
+    d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
+  result = d.WeekDay
+
+proc timeToTimeInfo*(t: Time): TimeInfo =
+  ## Converts a Time to TimeInfo.
+  let
+    daysSinceEpoch = t.int div secondsInDay
+    (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
+    daySeconds = t.int mod secondsInDay
+
+    y = yearsSinceEpoch + epochStartYear
+
+  var
+    mon = mJan
+    days = daysRemaining
+    daysInMonth = getDaysInMonth(mon, y)
+
+  # calculate month and day remainder
+  while days > daysInMonth and mon <= mDec:
+    days -= daysInMonth
+    mon.inc
+    daysInMonth = getDaysInMonth(mon, y)
+
+  let
+    yd = daysRemaining
+    m = mon  # month is zero indexed enum
+    md = days
+    # NB: month is zero indexed but dayOfWeek expects 1 indexed.
+    wd = getDayOfWeek(days, mon.int + 1, y).Weekday
+    h = daySeconds div secondsInHour + 1
+    mi = (daySeconds mod secondsInHour) div secondsInMin
+    s = daySeconds mod secondsInMin
+  result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
+
+proc timetoTimeInterval*(t: Time): TimeInterval =
+  ## Converts a Time to a TimeInterval.
+  var
+    daysSinceEpoch = t.int div secondsInDay
+    (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
+    daySeconds = t.int mod secondsInDay
+
+  result.years = yearsSinceEpoch + epochStartYear
+
+  var
+    mon = mJan
+    days = daysRemaining
+    daysInMonth = getDaysInMonth(mon, result.years)
+
+  # calculate month and day remainder
+  while days > daysInMonth and mon <= mDec:
+    days -= daysInMonth
+    mon.inc
+    daysInMonth = getDaysInMonth(mon, result.years)
+
+  result.months = mon.int + 1 # month is 1 indexed int
+  result.days = days
+  result.hours = daySeconds div secondsInHour + 1
+  result.minutes = (daySeconds mod secondsInHour) div secondsInMin
+  result.seconds = daySeconds mod secondsInMin
+  # Milliseconds not available from Time
 
 when isMainModule:
   # $ date --date='@2147483647'
@@ -1137,3 +1248,18 @@ when isMainModule:
   assert "15:04:00" in $s.parse(f)
   when not defined(testing):
     echo "Kitchen: " & $s.parse(f)
+    var ti = timeToTimeInfo(getTime())
+    echo "Todays date after decoding: ", ti
+    var tint = timeToTimeInterval(getTime())
+    echo "Todays date after decoding to interval: ", tint
+  # checking dayOfWeek matches known days
+  assert getDayOfWeek(21, 9, 1900) == dFri
+  assert getDayOfWeek(1, 1, 1970) == dThu
+  assert getDayOfWeek(21, 9, 1970) == dMon
+  assert getDayOfWeek(1, 1, 2000) == dSat
+  assert getDayOfWeek(1, 1, 2021) == dFri
+  # Julian tests
+  assert getDayOfWeekJulian(21, 9, 1900) == dFri
+  assert getDayOfWeekJulian(21, 9, 1970) == dMon
+  assert getDayOfWeekJulian(1, 1, 2000) == dSat
+  assert getDayOfWeekJulian(1, 1, 2021) == dFri
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index c459023a9..064937ad8 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -285,7 +285,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
 
     result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
 
-template require*(conditions: stmt): stmt {.immediate, dirty.} =
+template require*(conditions: stmt): stmt {.immediate.} =
   ## Same as `check` except any failed test causes the program to quit
   ## immediately. Any teardown statements are not executed and the failed
   ## test output is not generated.
diff --git a/lib/system.nim b/lib/system.nim
index e5cae1336..7dae074f3 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -188,7 +188,7 @@ proc new*(T: typedesc): auto =
   ## reference to it as result value.
   ##
   ## When ``T`` is a ref type then the resulting type will be ``T``,
-  ## otherwise it will be ``ref T``. 
+  ## otherwise it will be ``ref T``.
   when (T is ref):
       var r: T
   else:
@@ -577,6 +577,9 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
   ## that one never needs to know ``x``'s size. As a special semantic rule,
   ## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
 
+when defined(nimtypedescfixed):
+  proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
+
 proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
   ## unary ``<`` that can be used for nice looking excluding ranges:
   ##
@@ -1500,7 +1503,7 @@ when not defined(nimrodVM):
       ## containing zero, so it is somewhat safer than ``createU``.
       ## The allocated memory belongs to its allocating thread!
       ## Use `createShared` to allocate from a shared heap.
-      cast[ptr T](alloc0(T.sizeof * size))
+      cast[ptr T](alloc0(sizeof(T) * size))
     proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
                                                            benign.}
       ## grows or shrinks a given memory block. If p is **nil** then a new