[forensics] Add class for storage sizes

We have commonly relied on variable names to enforce sizes for storage,
like with crashpad::CrashReportDatabase. This works, but is brittle and
easy to mess up. Having a class that couples the scalar quantity with
its associated units will make future uses of storage sizes easier and
less prone to errors.

Bug: 47137

Change-Id: If6a58625e38b972c6f3915ad4db5eea38faaea6d
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/404803
Commit-Queue: Alex Pankhurst <pankhurst@google.com>
Testability-Review: Alex Pankhurst <pankhurst@google.com>
Testability-Review: Francois Rousseau <frousseau@google.com>
Reviewed-by: Francois Rousseau <frousseau@google.com>
diff --git a/src/developer/forensics/utils/BUILD.gn b/src/developer/forensics/utils/BUILD.gn
index fdeb5f5..88c65e3 100644
--- a/src/developer/forensics/utils/BUILD.gn
+++ b/src/developer/forensics/utils/BUILD.gn
@@ -79,6 +79,10 @@
   sources = [ "sized_data.h" ]
 }
 
+source_set("storage_size") {
+  sources = [ "storage_size.h" ]
+}
+
 source_set("time") {
   sources = [
     "time.cc",
diff --git a/src/developer/forensics/utils/storage_size.h b/src/developer/forensics/utils/storage_size.h
new file mode 100644
index 0000000..c84a72f
--- /dev/null
+++ b/src/developer/forensics/utils/storage_size.h
@@ -0,0 +1,85 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_DEVELOPER_FORENSICS_UTILS_STORAGE_SIZE_H_
+#define SRC_DEVELOPER_FORENSICS_UTILS_STORAGE_SIZE_H_
+
+#include <cstdint>
+
+namespace forensics {
+
+// Size class for storage mediums, like files, with associated methods to convert between bytes,
+// kilobytes, megabytes, and gigabytes.
+//
+// Note: This class draws heavily from zx::duration, but unlike zx::duration it does nothing to
+// prevent integer under/over flow and should be used with caution.
+class StorageSize final {
+ public:
+  explicit constexpr StorageSize(uint64_t bytes) : bytes_(bytes) {}
+
+  static constexpr StorageSize Bytes(uint64_t bytes) { return StorageSize(bytes); }
+  static constexpr StorageSize Kilobytes(uint64_t kilobytes) {
+    return StorageSize(kilobytes << 10);
+  }
+  static constexpr StorageSize Megabytes(uint64_t megabytes) {
+    return StorageSize(megabytes << 20);
+  }
+  static constexpr StorageSize Gigabytes(uint64_t gigabytes) {
+    return StorageSize(gigabytes << 30);
+  }
+
+  constexpr uint64_t Get() const { return bytes_; }
+
+  constexpr StorageSize operator+(StorageSize other) const {
+    return StorageSize(bytes_ + other.bytes_);
+  }
+
+  constexpr StorageSize operator-(StorageSize other) const {
+    return StorageSize(bytes_ - other.bytes_);
+  }
+
+  constexpr StorageSize operator*(uint64_t scalar) const { return StorageSize(bytes_ * scalar); }
+
+  constexpr uint64_t operator/(StorageSize other) const { return bytes_ / other.bytes_; }
+  constexpr StorageSize operator/(uint64_t scalar) const { return StorageSize(bytes_ / scalar); }
+
+  constexpr StorageSize& operator+=(StorageSize other) {
+    bytes_ += other.bytes_;
+    return *this;
+  }
+
+  constexpr StorageSize& operator-=(StorageSize other) {
+    bytes_ -= other.bytes_;
+    return *this;
+  }
+
+  constexpr StorageSize& operator*=(uint64_t scalar) {
+    bytes_ *= scalar;
+    return *this;
+  }
+
+  constexpr StorageSize& operator/=(uint64_t scalar) {
+    bytes_ /= scalar;
+    return *this;
+  }
+
+  constexpr bool operator==(StorageSize other) const { return bytes_ == other.bytes_; }
+  constexpr bool operator!=(StorageSize other) const { return bytes_ != other.bytes_; }
+  constexpr bool operator<(StorageSize other) const { return bytes_ < other.bytes_; }
+  constexpr bool operator<=(StorageSize other) const { return bytes_ <= other.bytes_; }
+  constexpr bool operator>(StorageSize other) const { return bytes_ > other.bytes_; }
+  constexpr bool operator>=(StorageSize other) const { return bytes_ >= other.bytes_; }
+
+  constexpr uint64_t ToBytes() const { return bytes_; }
+  constexpr uint64_t ToKilobytes() const { return bytes_ >> 10; }
+  constexpr uint64_t ToMegabytes() const { return bytes_ >> 20; }
+  constexpr uint64_t ToGigabytes() const { return bytes_ >> 30; }
+
+ private:
+  uint64_t bytes_{0};
+};
+
+}  // namespace forensics
+
+#endif  // SRC_DEVELOPER_FORENSICS_UTILS_STORAGE_SIZE_H_