-- | Text builder helpers.
--
-- Code for printing numbers in 3 or 4 characters adapted from `tasty-bench`:
--   https://github.com/Bodigrim/tasty-bench/blob/412ae68dbd9582e0b19ff5f2c7f9ead25e104cce/Test/Tasty/Bench.hs#L795
module ParkBench.Internal.Builder
  ( Builder,
    build,
    bytes4,
    char,
    chars,
    Builder.decimal,
    double,
    double4,
    ParkBench.Internal.Builder.empty,
    nanos3,
    nanos4,
    ParkBench.Internal.Builder.null,
    percentage,
    sepBy,
    text,
    word3,
  )
where

import qualified Data.List as List
import qualified Data.Text.Lazy as LazyText
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as Builder
import qualified Data.Text.Lazy.Builder.Int as Builder (decimal)
import qualified Data.Text.Lazy.Builder.RealFloat as Builder
import ParkBench.Internal.Prelude

build :: Builder -> Text
build :: Builder -> Text
build =
  Text -> Text
LazyText.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
Builder.toLazyText

-- | Render nanoseconds, trying to fit into 4 characters.
bytes4 :: Double -> Builder
bytes4 :: Double -> Builder
bytes4 Double
b
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
0.5 = Builder
ParkBench.Internal.Builder.empty
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
995 = Int -> Double -> Builder
double Int
0 Double
b forall a. Semigroup a => a -> a -> a
<> Builder
" b"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
9_950 = Int -> Double -> Builder
double Int
2 Double
kb forall a. Semigroup a => a -> a -> a
<> Builder
" kb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
99_500 = Int -> Double -> Builder
double Int
1 Double
kb forall a. Semigroup a => a -> a -> a
<> Builder
" kb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
995_000 = Int -> Double -> Builder
double Int
0 Double
kb forall a. Semigroup a => a -> a -> a
<> Builder
" kb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
9_950_000 = Int -> Double -> Builder
double Int
2 Double
mb forall a. Semigroup a => a -> a -> a
<> Builder
" mb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
99_500_000 = Int -> Double -> Builder
double Int
1 Double
mb forall a. Semigroup a => a -> a -> a
<> Builder
" mb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
995_000_000 = Int -> Double -> Builder
double Int
0 Double
mb forall a. Semigroup a => a -> a -> a
<> Builder
" mb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
9_950_000_000 = Int -> Double -> Builder
double Int
2 Double
gb forall a. Semigroup a => a -> a -> a
<> Builder
" gb"
  | Double
b forall a. Ord a => a -> a -> Bool
< Double
99_500_000_000 = Int -> Double -> Builder
double Int
1 Double
gb forall a. Semigroup a => a -> a -> a
<> Builder
" gb"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
gb forall a. Semigroup a => a -> a -> a
<> Builder
" gb"
  where
    kb :: Double
kb = Double
b forall a. Fractional a => a -> a -> a
/ Double
1_000
    mb :: Double
mb = Double
b forall a. Fractional a => a -> a -> a
/ Double
1_000_000
    gb :: Double
gb = Double
b forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000

char :: Char -> Builder
char :: Char -> Builder
char =
  Char -> Builder
Builder.singleton
{-# INLINE char #-}

chars :: Int -> Char -> Builder
chars :: Int -> Char -> Builder
chars Int
n =
  forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> a -> [a]
replicate Int
n forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Builder
Builder.singleton

double :: Int -> Double -> Builder
double :: Int -> Double -> Builder
double Int
i =
  forall a. RealFloat a => FPFormat -> Maybe Int -> a -> Builder
Builder.formatRealFloat FPFormat
Builder.Fixed (forall a. a -> Maybe a
Just Int
i)

-- | Render a double, trying to fit into 4 characters.
double4 :: Double -> Builder
double4 :: Double -> Builder
double4 Double
n
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
0.005 = Builder
ParkBench.Internal.Builder.empty
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
9.95 = Int -> Double -> Builder
double Int
2 Double
n
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
99.5 = Int -> Double -> Builder
double Int
1 Double
n
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
995 = Int -> Double -> Builder
double Int
0 Double
n
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
9_950 = Int -> Double -> Builder
double Int
1 Double
k forall a. Semigroup a => a -> a -> a
<> Builder
"k"
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
995_000 = Int -> Double -> Builder
double Int
0 Double
k forall a. Semigroup a => a -> a -> a
<> Builder
"k"
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
9_950_000 = Int -> Double -> Builder
double Int
1 Double
m forall a. Semigroup a => a -> a -> a
<> Builder
"m"
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
995_000_000 = Int -> Double -> Builder
double Int
0 Double
m forall a. Semigroup a => a -> a -> a
<> Builder
"m"
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
9_950_000_000 = Int -> Double -> Builder
double Int
1 Double
b forall a. Semigroup a => a -> a -> a
<> Builder
"b"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
n forall a. Semigroup a => a -> a -> a
<> Builder
"b"
  where
    a :: Double
a = forall a. Num a => a -> a
abs Double
n
    k :: Double
k = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000
    m :: Double
m = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000_000
    b :: Double
b = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000

empty :: Builder
empty :: Builder
empty =
  forall a. Monoid a => a
mempty
{-# INLINE empty #-}

-- | Render nanoseconds, trying to fit into 3 characters.
nanos3 :: Rational -> Builder
nanos3 :: Rational -> Builder
nanos3 (Rational -> Double
r2d -> Double
ns)
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
0.5 = Builder
ParkBench.Internal.Builder.empty
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995 = Int -> Double -> Builder
double Int
0 Double
ns forall a. Semigroup a => a -> a -> a
<> Builder
" ns"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950 = Int -> Double -> Builder
double Int
1 Double
us forall a. Semigroup a => a -> a -> a
<> Builder
" µs"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995_000 = Int -> Double -> Builder
double Int
0 Double
us forall a. Semigroup a => a -> a -> a
<> Builder
" µs"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950_000 = Int -> Double -> Builder
double Int
1 Double
ms forall a. Semigroup a => a -> a -> a
<> Builder
" ms"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995_000_000 = Int -> Double -> Builder
double Int
0 Double
ms forall a. Semigroup a => a -> a -> a
<> Builder
" ms"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950_000_000 = Int -> Double -> Builder
double Int
1 Double
s forall a. Semigroup a => a -> a -> a
<> Builder
" s"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
s forall a. Semigroup a => a -> a -> a
<> Builder
" s"
  where
    us :: Double
us = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000
    ms :: Double
ms = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000_000
    s :: Double
s = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000

-- | Render nanoseconds, trying to fit into 4 characters.
nanos4 :: Double -> Builder
nanos4 :: Double -> Builder
nanos4 Double
ns
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
0.5 = Builder
ParkBench.Internal.Builder.empty
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995 = Int -> Double -> Builder
double Int
0 Double
ns forall a. Semigroup a => a -> a -> a
<> Builder
" ns"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950 = Int -> Double -> Builder
double Int
2 Double
us forall a. Semigroup a => a -> a -> a
<> Builder
" µs"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
99_500 = Int -> Double -> Builder
double Int
1 Double
us forall a. Semigroup a => a -> a -> a
<> Builder
" µs"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995_000 = Int -> Double -> Builder
double Int
0 Double
us forall a. Semigroup a => a -> a -> a
<> Builder
" µs"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950_000 = Int -> Double -> Builder
double Int
2 Double
ms forall a. Semigroup a => a -> a -> a
<> Builder
" ms"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
99_500_000 = Int -> Double -> Builder
double Int
1 Double
ms forall a. Semigroup a => a -> a -> a
<> Builder
" ms"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
995_000_000 = Int -> Double -> Builder
double Int
0 Double
ms forall a. Semigroup a => a -> a -> a
<> Builder
" ms"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
9_950_000_000 = Int -> Double -> Builder
double Int
2 Double
s forall a. Semigroup a => a -> a -> a
<> Builder
" s"
  | Double
ns forall a. Ord a => a -> a -> Bool
< Double
99_500_000_000 = Int -> Double -> Builder
double Int
1 Double
s forall a. Semigroup a => a -> a -> a
<> Builder
" s"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
s forall a. Semigroup a => a -> a -> a
<> Builder
" s"
  where
    us :: Double
us = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000
    ms :: Double
ms = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000_000
    s :: Double
s = Double
ns forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000

-- | /O(n)/.
null :: Builder -> Bool
null :: Builder -> Bool
null =
  Text -> Bool
LazyText.null forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
Builder.toLazyText

percentage :: Double -> Builder
percentage :: Double -> Builder
percentage ((forall a. Num a => a -> a -> a
* Double
100) -> Double
n)
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
5 forall a. Fractional a => a -> a -> a
/ Double
1000 = Builder
ParkBench.Internal.Builder.empty
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
995 forall a. Fractional a => a -> a -> a
/ Double
100 = Int -> Double -> Builder
double Int
2 Double
n forall a. Semigroup a => a -> a -> a
<> Builder
"%"
  | Double
a forall a. Ord a => a -> a -> Bool
< Double
100 = Int -> Double -> Builder
double Int
1 Double
n forall a. Semigroup a => a -> a -> a
<> Builder
"%"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
n forall a. Semigroup a => a -> a -> a
<> Builder
"%"
  where
    a :: Double
a = forall a. Num a => a -> a
abs Double
n

sepBy :: [Builder] -> Builder -> Builder
sepBy :: [Builder] -> Builder -> Builder
sepBy [Builder]
xs Builder
x =
  forall a. Monoid a => [a] -> a
mconcat (forall a. a -> [a] -> [a]
List.intersperse Builder
x [Builder]
xs)

text :: Text -> Builder
text :: Text -> Builder
text =
  Text -> Builder
Builder.fromText
{-# INLINE text #-}

-- | Render a word, trying to fit into 3 characters.
word3 :: Word64 -> Builder
word3 :: Word64 -> Builder
word3 (Word64 -> Double
w2d -> Double
n)
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
995 = Int -> Double -> Builder
double Int
0 Double
n
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
9_950 = Int -> Double -> Builder
double Int
1 Double
k forall a. Semigroup a => a -> a -> a
<> Builder
"k"
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
995_000 = Int -> Double -> Builder
double Int
0 Double
k forall a. Semigroup a => a -> a -> a
<> Builder
"k"
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
9_950_000 = Int -> Double -> Builder
double Int
1 Double
m forall a. Semigroup a => a -> a -> a
<> Builder
"m"
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
995_000_000 = Int -> Double -> Builder
double Int
0 Double
m forall a. Semigroup a => a -> a -> a
<> Builder
"m"
  | Double
n forall a. Ord a => a -> a -> Bool
< Double
9_950_000_000 = Int -> Double -> Builder
double Int
1 Double
b forall a. Semigroup a => a -> a -> a
<> Builder
"b"
  | Bool
otherwise = Int -> Double -> Builder
double Int
0 Double
b forall a. Semigroup a => a -> a -> a
<> Builder
"b"
  where
    k :: Double
k = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000
    m :: Double
m = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000_000
    b :: Double
b = Double
n forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000