content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  module Util.PrettyPrint
    ( renderNumWithUnit
    , renderPercent
    , renderIncrease
    , renderNum
    , renderInt
    , renderBytes
    , renderBytesString
    ) where
  
  import Data.Text (Text)
  import qualified Data.Text as Text
  import Text.Printf
  import TextShow
  
  renderNumWithUnit :: Text -> Double -> Text
  renderNumWithUnit unit num = renderNum num <> " " <> unit
  
  -- | Render a fraction as a percentage
  renderPercent :: Double -> Double -> Text
  renderPercent x y
    | y == 0     = "Infinite"
    | otherwise  = Text.pack $ printf (printf "%%.%df%%%%" precision) frac
    where
      frac = x / y * 100
      -- Make sure we always have enough signifigant digits
      precision = max 0 $ ceiling (negate $ logBase 10 frac) + 2 :: Int
  
  -- | Render an increase as either a percent or times
  renderIncrease :: Double -> Double -> Text
  renderIncrease x y
    | y == 0    = "Infinite"
    | frac < 2  = renderPercent (x - y) y
    | frac < 10 = Text.pack $ printf "%.2fx" frac
    | otherwise = showt (round frac :: Int) <> "x"
    where
      frac = x / y
  
  renderNum :: Double -> Text
  renderNum num
    | num < 10 = Text.pack $ printf "%.2f" num
    | otherwise = renderInt $ round num
  
  renderInt :: Int -> Text
  renderInt num
    | num < 1000 = showt num
    | num < 1000000 = showt (num `div` 1000) <> "k"
    | otherwise = showt (num `div` 1000000) <> "M"
  
  renderBytes :: Int -> Text
  renderBytes b = Text.pack $ renderBytesString b
  
  renderBytesString :: Int -> String
  renderBytesString b
   | b' > gb = printf "%.2f GiB" (b' / gb)
   | b' > mb = printf "%.2f MiB" (b' / mb)
   | b' > kb = printf "%.2f kiB" (b' / kb)
   | otherwise = printf "%d bytes" (fromIntegral b :: Integer)
   where
    kb, mb, gb :: Double
    kb = 1024
    mb = 1024*kb
    gb = 1024*mb
    b' = fromIntegral b :: Double
  