Created
November 9, 2019 18:06
-
-
Save wpcarro/d2e8d59f16e3792ce392a945cbd7170c to your computer and use it in GitHub Desktop.
Represent integer byte values in a human readable format.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;;; bytes.el --- Working with byte values -*- lexical-binding: t -*- | |
| ;; Author: William Carroll <wpcarro@gmail.com> | |
| ;;; Commentary: | |
| ;; Functions to help with human-readable representations of byte values. | |
| ;; | |
| ;; Usage: | |
| ;; See the test cases for example usage. Or better yet, I should use a type of | |
| ;; structured documentation that would allow me to expose a view into the test | |
| ;; suite here. Is this currently possible in Elisp? | |
| ;; | |
| ;; API: | |
| ;; - serialize :: Integer -> String | |
| ;; | |
| ;; Wish list: | |
| ;; - Rounding: e.g. (bytes (* 1024 1.7)) => "2KB" | |
| ;;; Code: | |
| ;; TODO: Support -ibabyte variants like Gibibyte (GiB). | |
| ;; Ranges: | |
| ;; B: [ 0, 1e3) | |
| ;; KB: [ 1e3, 1e6) | |
| ;; MB: [ 1e6, 1e6) | |
| ;; GB: [ 1e9, 1e12) | |
| ;; TB: [1e12, 1e15) | |
| ;; PB: [1e15, 1e18) | |
| ;; | |
| ;; Note: I'm currently not support exabytes because that causes the integer to | |
| ;; overflow. I imagine a larger integer type may exist, but for now, I'll | |
| ;; treat this as a YAGNI. | |
| (require 'prelude) | |
| (require 'tuple) | |
| (require 'math) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Constants | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (defconst bytes/kb (math/exp 2 10) | |
| "Number of bytes in a kilobyte.") | |
| (defconst bytes/mb (math/exp 2 20) | |
| "Number of bytes in a mb.") | |
| (defconst bytes/gb (math/exp 2 30) | |
| "Number of bytes in a gigabyte.") | |
| (defconst bytes/tb (math/exp 2 40) | |
| "Number of bytes in a terabyte.") | |
| (defconst bytes/pb (math/exp 2 50) | |
| "Number of bytes in a petabyte.") | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Functions | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (defun bytes/classify (x) | |
| "Return unit that closest fits byte count, X." | |
| (prelude/assert (number/positive? x)) | |
| (cond | |
| ((and (>= x 0) (< x bytes/kb)) 'byte) | |
| ((and (>= x bytes/kb) (< x bytes/mb)) 'kilobyte) | |
| ((and (>= x bytes/mb) (< x bytes/gb)) 'megabyte) | |
| ((and (>= x bytes/gb) (< x bytes/tb)) 'gigabyte) | |
| ((and (>= x bytes/tb) (< x bytes/pb)) 'terabyte) | |
| ((and (>= x bytes/pb) (< x bytes/eb)) 'petabyte))) | |
| (defun bytes/to-string (x) | |
| "Convert integer X into a human-readable string." | |
| (let ((base-and-unit | |
| (pcase (bytes/classify x) | |
| ('byte (tuple/from 1 "B")) | |
| ('kilobyte (tuple/from bytes/kb "KB")) | |
| ('megabyte (tuple/from bytes/mb "MB")) | |
| ('gigabyte (tuple/from bytes/gb "GB")) | |
| ('terabyte (tuple/from bytes/tb "TB")) | |
| ('petabyte (tuple/from bytes/pb "PB"))))) | |
| (string/format "%d%s" | |
| (round x (tuple/first base-and-unit)) | |
| (tuple/second base-and-unit)))) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Tests | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (progn | |
| (prelude/assert | |
| (equal "1000B" (bytes/to-string 1000))) | |
| (prelude/assert | |
| (equal "2KB" (bytes/to-string (* 2 bytes/kb)))) | |
| (prelude/assert | |
| (equal "17MB" (bytes/to-string (* 17 bytes/mb)))) | |
| (prelude/assert | |
| (equal "419GB" (bytes/to-string (* 419 bytes/gb)))) | |
| (prelude/assert | |
| (equal "999TB" (bytes/to-string (* 999 bytes/tb)))) | |
| (prelude/assert | |
| (equal "2PB" (bytes/to-string (* 2 bytes/pb))))) | |
| (provide 'bytes) | |
| ;;; bytes.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment