diff options
author | Charles Blake <cblake@csail.mit.edu> | 2015-08-09 06:58:36 -0400 |
---|---|---|
committer | Charles Blake <cblake@csail.mit.edu> | 2015-08-09 06:58:36 -0400 |
commit | 9c3c48a6d0b89447e2f2efac953bce34a2b96fa8 (patch) | |
tree | 577c4cb15baead3a22fd4e11588d1bb6fd134330 /lib | |
parent | 26f7a53d4a526b6305a2bca3d28c3c5eb9cfa297 (diff) | |
parent | 34ca9dd5861d5504bbbeb71469318c8c8caba6d7 (diff) | |
download | Nim-9c3c48a6d0b89447e2f2efac953bce34a2b96fa8.tar.gz |
Merge ../Nim into devel
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/collections/tables.nim | 8 | ||||
-rw-r--r-- | lib/pure/json.nim | 24 | ||||
-rw-r--r-- | lib/pure/times.nim | 126 | ||||
-rw-r--r-- | lib/pure/unittest.nim | 2 | ||||
-rw-r--r-- | lib/system.nim | 7 |
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 |