Skip to content

Commit

Permalink
Merge pull request #2 from Yardanico/opt
Browse files Browse the repository at this point in the history
Optimize and simplify code
  • Loading branch information
bichanna authored Mar 30, 2022
2 parents 73287fe + 82799bc commit e672ef5
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 42 deletions.
41 changes: 20 additions & 21 deletions src/millie.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import millie/utils
import strutils, strformat, math
import std/[strutils, math]

const units = @[
const units = [
"", # nothing...
"K", # thousand
"M", # million
Expand All @@ -10,46 +10,45 @@ const units = @[
"P", # quadrillion
]

## Converts big numbers to what's pleasant to see (an adorable, little girl, perhaps?)

proc millify*(
value: int64,
value: SomeNumber,
precision: int = 1,
lowercase: bool = false,
space: bool = false,
): string =
## Converts big numbers to what's pleasant to see (an adorable, little girl, perhaps?)

# validate if `vaue` can be parsed or not
var val: SomeNumber = parseNum(value)
# preallocate the resulting string
result = newStringOfCap(10)

# `prefix` will be used later when assembling
let prefix: string = if val < 0: "-" else: ""
var val = float(value)

# add a negative prefix if needed
if val < 0: result.add '-'

# only work with positive numbers for easiness
val = val.abs()

# keep dividing the input value by the digit grouping base (1000)
# until the number and the unit index are found.
var unitIndex: int = 0
proc disposableFunc(res: float) =
var unitIndex = 0
divideTillEnd(val):
val = res
unitIndex += 1
divideTillEnd(val, disposableFunc)

# The number is too big for Millie to handle. So,
# Millie just returns it as is.
if len(units) <= unitIndex: return $value

# round the decimal number up to the desired precision
var rounded: SomeNumber = roundTo(val, precision)
var formatted: string
if rounded.ceil() == rounded: formatted = $rounded.ceil().float.int else: formatted = $rounded

# get the appropriate unit for the value
let unit: string = if len(units) > unitIndex: units[unitIndex] else: ""
let suffix: string = if not lowercase: unit else: unit.toLower()

let rounded = val.round(precision)
let ceil = rounded.ceil()
result.add if ceil == rounded: $ceil.int else: $rounded

# add a space if the user specified to do so
let spaceStr = if space: " " else: ""
if space: result.add ' '

return fmt"{prefix}{formatted}{spaceStr}{suffix}"
# get the appropriate unit for the value
let unit = units[unitIndex]
result.add if not lowercase: unit else: unit.toLower()
29 changes: 8 additions & 21 deletions src/millie/utils.nim
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
import strutils, strformat, math

## parseNum ensures the value is a number (double)
## returns the parsed value.
proc parseNum*(value: SomeNumber): float =
var val: float

try: val = parseFloat($value)
except ValueError: raise newException(ValueError, fmt"Input value must be a number, not '{value}'")

return val

## roundTo rounds a number up to a specified precision and returns it
proc roundTo*(value: SomeNumber, precision: int): SomeNumber = return parseFloat($value).round(precision)

## divideTillEnd divides and calls the passed function until `res` is less than 0.
proc divideTillEnd*(value: SomeNumber, fun: proc (res: float)) =
var denom = 1000;
template divideTillEnd*(value: SomeNumber, code: untyped) =
## divideTillEnd divides the value and executes the passed code
## until `res` is less than 1.
let vals = value # save the value
var denom = 1000
while true:
var res = value / denom.toFloat
var res {.inject.} = vals / denom.toFloat
if res < 1: break

fun(res)
code

denom *= 1000
denom *= 1000

0 comments on commit e672ef5

Please sign in to comment.