summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-bytesize/bytesize.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2022-07-12 08:32:20 +0100
committerLibravatar GitHub <noreply@github.com>2022-07-12 08:32:20 +0100
commit6934ae378ab5743da80a5995fc74d167502187b1 (patch)
tree6e3f58498158f1e844504961338eadb18f5a590e /vendor/codeberg.org/gruf/go-bytesize/bytesize.go
parent[performance] Add new index to fix slow web profile queries (#706) (diff)
downloadgotosocial-6934ae378ab5743da80a5995fc74d167502187b1.tar.xz
[chore] improved router logging, recovery and error handling (#705)
* move panic recovery to logging middleware, improve logging + panic recovery logic Signed-off-by: kim <grufwub@gmail.com> * remove dead code Signed-off-by: kim <grufwub@gmail.com> * remove skip paths code Signed-off-by: kim <grufwub@gmail.com> * re-enable log quoting Signed-off-by: kim <grufwub@gmail.com> * use human-friendly bytesize in logging body size Signed-off-by: kim <grufwub@gmail.com> * only disable quoting in debug builds Signed-off-by: kim <grufwub@gmail.com> * use logrus level instead of debug.DEBUG() to enable/disable quoting Signed-off-by: kim <grufwub@gmail.com> * shutup linter Signed-off-by: kim <grufwub@gmail.com> * fix instance tests Signed-off-by: kim <grufwub@gmail.com> * fix gin test contexts created with missing engine HTML renderer Signed-off-by: kim <grufwub@gmail.com> * add note regarding not logging query parameters Signed-off-by: kim <grufwub@gmail.com> * better explain 'DisableQuoting' logic Signed-off-by: kim <grufwub@gmail.com> * add license text Signed-off-by: kim <grufwub@gmail.com>
Diffstat (limited to 'vendor/codeberg.org/gruf/go-bytesize/bytesize.go')
-rw-r--r--vendor/codeberg.org/gruf/go-bytesize/bytesize.go306
1 files changed, 306 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-bytesize/bytesize.go b/vendor/codeberg.org/gruf/go-bytesize/bytesize.go
new file mode 100644
index 000000000..c2fedc8d7
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-bytesize/bytesize.go
@@ -0,0 +1,306 @@
+package bytesize
+
+import (
+ "errors"
+ "math/bits"
+ "unsafe"
+)
+
+var (
+ // ErrInvalidUnit is returned when an invalid IEC/SI is provided.
+ ErrInvalidUnit = errors.New("bytesize: invalid unit")
+
+ // ErrInvalidFormat is returned when an invalid size value is provided.
+ ErrInvalidFormat = errors.New("bytesize: invalid format")
+
+ // bunits are the binary unit chars.
+ units = `kMGTPE`
+
+ // iecpows is a precomputed table of 1024^n.
+ iecpows = [...]float64{
+ float64(1024), // KiB
+ float64(1024 * 1024), // MiB
+ float64(1024 * 1024 * 1024), // GiB
+ float64(1024 * 1024 * 1024 * 1024), // TiB
+ float64(1024 * 1024 * 1024 * 1024 * 1024), // PiB
+ float64(1024 * 1024 * 1024 * 1024 * 1024 * 1024), // EiB
+ }
+
+ // sipows is a precomputed table of 1000^n.
+ sipows = [...]float64{
+ float64(1e3), // KB
+ float64(1e6), // MB
+ float64(1e9), // GB
+ float64(1e12), // TB
+ float64(1e15), // PB
+ float64(1e18), // EB
+ }
+
+ // bvals is a precomputed table of IEC unit values.
+ iecvals = [...]uint64{
+ 'k': 1024,
+ 'K': 1024,
+ 'M': 1024 * 1024,
+ 'G': 1024 * 1024 * 1024,
+ 'T': 1024 * 1024 * 1024 * 1024,
+ 'P': 1024 * 1024 * 1024 * 1024 * 1024,
+ 'E': 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
+ }
+
+ // sivals is a precomputed table of SI unit values.
+ sivals = [...]uint64{
+ // ASCII numbers _aren't_ valid SI unit values,
+ // BUT if the space containing a possible unit
+ // char is checked with this table -- it is valid
+ // to provide no unit char so unit=1 works.
+ '0': 1,
+ '1': 1,
+ '2': 1,
+ '3': 1,
+ '4': 1,
+ '5': 1,
+ '6': 1,
+ '7': 1,
+ '8': 1,
+ '9': 1,
+
+ 'k': 1e3,
+ 'M': 1e6,
+ 'G': 1e9,
+ 'T': 1e12,
+ 'P': 1e15,
+ 'E': 1e18,
+ }
+)
+
+// Size is a casting for uint64 types that provides formatting
+// methods for byte sizes in both IEC and SI units.
+type Size uint64
+
+// ParseSize will parse a valid Size from given string. Both IEC and SI units are supported.
+func ParseSize(s string) (Size, error) {
+ // Parse units from string
+ unit, l, err := parseUnit(s)
+ if err != nil {
+ return 0, err
+ }
+
+ // Parse remaining string as float
+ f, n, err := atof64(s[:l])
+ if err != nil || n != l {
+ return 0, ErrInvalidFormat
+ }
+
+ return Size(uint64(f) * unit), nil
+}
+
+// AppendFormat defaults to using Size.AppendFormatIEC().
+func (sz Size) AppendFormat(dst []byte) []byte {
+ return sz.AppendFormatIEC(dst) // default
+}
+
+// AppendFormatSI will append SI formatted size to 'dst'.
+func (sz Size) AppendFormatSI(dst []byte) []byte {
+ if uint64(sz) < 1000 {
+ dst = itoa(dst, uint64(sz))
+ dst = append(dst, 'B')
+ return dst
+ } // above is fast-path, .appendFormat() is outlined
+ return sz.appendFormat(dst, 1000, &sipows, "B")
+}
+
+// AppendFormatIEC will append IEC formatted size to 'dst'.
+func (sz Size) AppendFormatIEC(dst []byte) []byte {
+ if uint64(sz) < 1024 {
+ dst = itoa(dst, uint64(sz))
+ dst = append(dst, 'B')
+ return dst
+ } // above is fast-path, .appendFormat() is outlined
+ return sz.appendFormat(dst, 1024, &iecpows, "iB")
+}
+
+// appendFormat will append formatted Size to 'dst', depending on base, powers table and single unit suffix.
+func (sz Size) appendFormat(dst []byte, base uint64, pows *[6]float64, sunit string) []byte {
+ const min = 0.75
+
+ // Larger number: get value of
+ // i / unit size. We have a 'min'
+ // threshold after which we prefer
+ // using the unit 1 down
+ n := bits.Len64(uint64(sz)) / 10
+ f := float64(sz) / pows[n-1]
+ if f < min {
+ f *= float64(base)
+ n--
+ }
+
+ // Append formatted float with units
+ dst = ftoa(dst, f)
+ dst = append(dst, units[n-1])
+ dst = append(dst, sunit...)
+ return dst
+}
+
+// StringSI returns an SI unit string format of Size.
+func (sz Size) StringSI() string {
+ b := sz.AppendFormatSI(make([]byte, 0, 6))
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// StringIEC returns an IEC unit string format of Size.
+func (sz Size) StringIEC() string {
+ b := sz.AppendFormatIEC(make([]byte, 0, 7))
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// String returns a string format of Size, defaults to IEC unit format.
+func (sz Size) String() string {
+ return sz.StringIEC()
+}
+
+// parseUnit will parse the byte size unit from string 's'.
+func parseUnit(s string) (uint64, int, error) {
+ var isIEC bool
+
+ // Check for string
+ if len(s) < 1 {
+ return 0, 0, ErrInvalidFormat
+ }
+
+ // Strip 'byte' unit suffix
+ if l := len(s) - 1; s[l] == 'B' {
+ s = s[:l]
+
+ // Check str remains
+ if len(s) < 1 {
+ return 0, 0, ErrInvalidFormat
+ }
+ }
+
+ // Strip IEC binary unit suffix
+ if l := len(s) - 1; s[l] == 'i' {
+ s = s[:l]
+ isIEC = true
+
+ // Check str remains
+ if len(s) < 1 {
+ return 0, 0, ErrInvalidFormat
+ }
+ }
+
+ // Location of unit char.
+ l := len(s) - 1
+
+ var unit uint64
+ switch c := int(s[l]); {
+ // Determine IEC unit in use
+ case isIEC && c < len(iecvals):
+ unit = iecvals[c]
+ if unit == 0 {
+ return 0, 0, ErrInvalidUnit
+ }
+
+ // Determine SI unit in use
+ case c < len(sivals):
+ unit = sivals[c]
+ switch unit {
+ case 0:
+ return 0, 0, ErrInvalidUnit
+ case 1:
+ l++
+ }
+ }
+
+ return unit, l, nil
+}
+
+// ftoa appends string formatted 'f' to 'dst', assumed < ~800.
+func ftoa(dst []byte, f float64) []byte {
+ switch i := uint64(f); {
+ // Append with 2 d.p.
+ case i < 10:
+ f *= 10
+
+ // Calculate next dec. value
+ d1 := uint8(uint64(f) % 10)
+
+ f *= 10
+
+ // Calculate next dec. value
+ d2 := uint8(uint64(f) % 10)
+
+ // Round the final value
+ if uint64(f*10)%10 > 4 {
+ d2++
+
+ // Overflow, incr 'd1'
+ if d2 == 10 {
+ d2 = 0
+ d1++
+
+ // Overflow, incr 'i'
+ if d1 == 10 {
+ d1 = 0
+ i++
+ }
+ }
+ }
+
+ // Append decimal value
+ dst = itoa(dst, i)
+ dst = append(dst,
+ '.',
+ '0'+d1,
+ '0'+d2,
+ )
+
+ // Append with 1 d.p.
+ case i < 100:
+ f *= 10
+
+ // Calculate next dec. value
+ d1 := uint8(uint64(f) % 10)
+
+ // Round the final value
+ if uint64(f*10)%10 > 4 {
+ d1++
+
+ // Overflow, incr 'i'
+ if d1 == 10 {
+ d1 = 0
+ i++
+ }
+ }
+
+ // Append decimal value
+ dst = itoa(dst, i)
+ dst = append(dst, '.', '0'+d1)
+
+ // No decimal places
+ default:
+ dst = itoa(dst, i)
+ }
+
+ return dst
+}
+
+// itoa appends string formatted 'i' to 'dst'.
+func itoa(dst []byte, i uint64) []byte {
+ // Assemble int in reverse order.
+ var b [4]byte
+ bp := len(b) - 1
+
+ // Append integer
+ for i >= 10 {
+ q := i / 10
+ b[bp] = byte('0' + i - q*10)
+ bp--
+ i = q
+ } // i < 10
+ b[bp] = byte('0' + i)
+
+ return append(dst, b[bp:]...)
+}
+
+//go:linkname atof64 strconv.atof64
+func atof64(string) (float64, int, error)