{-# LANGUAGE Safe #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
module Data.Quantity (
renderNum,
renderNums,
parseNum,
parseNumInt,
quantifyNum,
quantifyNums,
SizeOpts(..),
binaryOpts,
siOpts
)
where
import safe Data.Char ( toLower )
import safe Data.List (find)
import safe Text.Printf ( printf )
data SizeOpts = SizeOpts { SizeOpts -> Int
base :: Int,
SizeOpts -> Int
powerIncr :: Int,
SizeOpts -> Int
firstPower :: Int,
SizeOpts -> String
suffixes :: String
}
binaryOpts :: SizeOpts
binaryOpts :: SizeOpts
binaryOpts = SizeOpts {base :: Int
base = Int
2,
firstPower :: Int
firstPower = Int
0,
suffixes :: String
suffixes = String
" KMGTPEZY",
powerIncr :: Int
powerIncr = Int
10}
siOpts :: SizeOpts
siOpts :: SizeOpts
siOpts = SizeOpts {base :: Int
base = Int
10,
firstPower :: Int
firstPower = -Int
24,
suffixes :: String
suffixes = String
"yzafpnum kMGTPEZY",
powerIncr :: Int
powerIncr = Int
3}
quantifyNum :: (Ord a, Real a, Floating b, Ord b) => SizeOpts -> a -> (b, Char)
quantifyNum :: forall a b.
(Ord a, Real a, Floating b, Ord b) =>
SizeOpts -> a -> (b, Char)
quantifyNum SizeOpts
opts a
n = (\([b]
x, Char
s) -> (forall a. [a] -> a
head [b]
x, Char
s)) forall a b. (a -> b) -> a -> b
$ forall a b.
(Ord a, Real a, Floating b, Ord b) =>
SizeOpts -> [a] -> ([b], Char)
quantifyNums SizeOpts
opts [a
n]
quantifyNums :: (Ord a, Real a, Floating b, Ord b) => SizeOpts -> [a] -> ([b], Char)
quantifyNums :: forall a b.
(Ord a, Real a, Floating b, Ord b) =>
SizeOpts -> [a] -> ([b], Char)
quantifyNums SizeOpts
_ [] = forall a. HasCallStack => String -> a
error String
"Attempt to use quantifyNums on an empty list"
quantifyNums SizeOpts
opts (a
headnum:[a]
xs) =
(forall a b. (a -> b) -> [a] -> [b]
map (\a
n -> forall {a} {p}. (Real p, Floating a) => p -> a
procnum a
n) (a
headnumforall a. a -> [a] -> [a]
:[a]
xs), Char
suffix)
where number :: Double
number = case forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$ a
headnum of
Double
0 -> Double
1
Double
x -> Double
x
incrList :: [Int]
incrList = forall a b. (a -> b) -> [a] -> [b]
map Int -> Int
idx2pwr [Int
0..forall (t :: * -> *) a. Foldable t => t a -> Int
length (SizeOpts -> String
suffixes SizeOpts
opts) forall a. Num a => a -> a -> a
- Int
1]
incrIdxList :: [(Int, Integer)]
incrIdxList = forall a b. [a] -> [b] -> [(a, b)]
zip [Int]
incrList [Integer
0..]
idx2pwr :: Int -> Int
idx2pwr Int
i = Int
i forall a. Num a => a -> a -> a
* SizeOpts -> Int
powerIncr SizeOpts
opts forall a. Num a => a -> a -> a
+ SizeOpts -> Int
firstPower SizeOpts
opts
finderfunc :: (a, b) -> Bool
finderfunc (a
x, b
_) = (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ SizeOpts -> Int
base SizeOpts
opts) forall a. Floating a => a -> a -> a
** (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x)
forall a. Ord a => a -> a -> Bool
<= (forall a. Num a => a -> a
abs Double
number)
(Int
usedexp, Integer
expidx) =
case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find forall {a} {b}. Integral a => (a, b) -> Bool
finderfunc (forall a. [a] -> [a]
reverse [(Int, Integer)]
incrIdxList) of
Just (Int, Integer)
x -> (Int, Integer)
x
Maybe (Int, Integer)
Nothing -> forall a. [a] -> a
head [(Int, Integer)]
incrIdxList
suffix :: Char
suffix = (SizeOpts -> String
suffixes SizeOpts
opts forall a. [a] -> Int -> a
!! (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
expidx))
procnum :: p -> a
procnum p
n = (forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$ p
n) forall a. Fractional a => a -> a -> a
/
((forall a b. (Integral a, Num b) => a -> b
fromIntegral (SizeOpts -> Int
base SizeOpts
opts) forall a. Floating a => a -> a -> a
** (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
usedexp)))
renderNum :: (Ord a, Real a) =>
SizeOpts
-> Int
-> a
-> String
renderNum :: forall a. (Ord a, Real a) => SizeOpts -> Int -> a -> String
renderNum SizeOpts
opts Int
prec a
number =
(forall r. PrintfType r => String -> r
printf (String
"%." forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
prec forall a. [a] -> [a] -> [a]
++ String
"g") Double
num) forall a. [a] -> [a] -> [a]
++ [Char
suffix]
where (Double
num, Char
suffix) = (forall a b.
(Ord a, Real a, Floating b, Ord b) =>
SizeOpts -> a -> (b, Char)
quantifyNum SizeOpts
opts a
number)::(Double, Char)
renderNums :: (Ord a, Real a) =>
SizeOpts
-> Int
-> [a]
-> [String]
renderNums :: forall a. (Ord a, Real a) => SizeOpts -> Int -> [a] -> [String]
renderNums SizeOpts
opts Int
prec [a]
numbers =
forall a b. (a -> b) -> [a] -> [b]
map forall {t}. PrintfArg t => t -> String
printit [Double]
convnums
where printit :: t -> String
printit t
num =
(forall r. PrintfType r => String -> r
printf (String
"%." forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
prec forall a. [a] -> [a] -> [a]
++ String
"f") t
num) forall a. [a] -> [a] -> [a]
++ [Char
suffix]
([Double]
convnums, Char
suffix) =
(forall a b.
(Ord a, Real a, Floating b, Ord b) =>
SizeOpts -> [a] -> ([b], Char)
quantifyNums SizeOpts
opts [a]
numbers)::([Double], Char)
parseNum :: (Read a, Fractional a) =>
SizeOpts
-> Bool
-> String
-> Either String a
parseNum :: forall a.
(Read a, Fractional a) =>
SizeOpts -> Bool -> String -> Either String a
parseNum SizeOpts
opts Bool
insensitive String
inp =
case forall a. Read a => ReadS a
reads String
inp of
[] -> forall a b. a -> Either a b
Left String
"Couldn't parse numeric component of input"
[(a
num, String
"")] -> forall a b. b -> Either a b
Right a
num
[(a
num, [Char
suffix])] ->
case forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup (Char -> Char
caseTransformer Char
suffix) [(Char, Int)]
suffixMap of
Maybe Int
Nothing -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Unrecognized suffix " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Char
suffix
Just Int
power -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ a
num forall a. Num a => a -> a -> a
* forall a. (Read a, Fractional a) => Int -> a
multiplier Int
power
[(a
_, String
suffix)] -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Multi-character suffix " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
suffix
[(a, String)]
_ -> forall a b. a -> Either a b
Left String
"Multiple parses for input"
where suffixMap :: [(Char, Int)]
suffixMap = forall a b. [a] -> [b] -> [(a, b)]
zip (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
caseTransformer forall b c a. (b -> c) -> (a -> b) -> a -> c
. SizeOpts -> String
suffixes forall a b. (a -> b) -> a -> b
$ SizeOpts
opts)
(forall a. (a -> a) -> a -> [a]
iterate (forall a. Num a => a -> a -> a
+ (SizeOpts -> Int
powerIncr SizeOpts
opts)) (SizeOpts -> Int
firstPower SizeOpts
opts))
caseTransformer :: Char -> Char
caseTransformer Char
x
| Bool
insensitive = Char -> Char
toLower Char
x
| Bool
otherwise = Char
x
multiplier :: (Read a, Fractional a) => Int -> a
multiplier :: forall a. (Read a, Fractional a) => Int -> a
multiplier Int
power =
forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$
forall a b. (Integral a, Num b) => a -> b
fromIntegral (SizeOpts -> Int
base SizeOpts
opts) forall a. Floating a => a -> a -> a
** forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
power
parseNumInt :: (Read a, Integral a) =>
SizeOpts
-> Bool
-> String
-> Either String a
parseNumInt :: forall a.
(Read a, Integral a) =>
SizeOpts -> Bool -> String -> Either String a
parseNumInt SizeOpts
opts Bool
insensitive String
inp =
case (forall a.
(Read a, Fractional a) =>
SizeOpts -> Bool -> String -> Either String a
parseNum SizeOpts
opts Bool
insensitive String
inp)::Either String Double of
Left String
x -> forall a b. a -> Either a b
Left String
x
Right Double
n -> forall a b. b -> Either a b
Right (forall a b. (RealFrac a, Integral b) => a -> b
round Double
n)