Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 955b6a47 authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Add android::base::ParseByteCount.

Bug: N/A
Test: ran tests
Change-Id: Ib2adcf0a5b9494fcf8259b29974303e8516a9ad9
parent 01ce44b7
Loading
Loading
Loading
Loading
+25 −7
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@


#include <errno.h>
#include <errno.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>


#include <limits>
#include <limits>
#include <string>
#include <string>
@@ -31,14 +32,20 @@ namespace base {
// otherwise valid values will be rejected. Returns boolean success; 'out'
// otherwise valid values will be rejected. Returns boolean success; 'out'
// is untouched if parsing fails.
// is untouched if parsing fails.
template <typename T>
template <typename T>
bool ParseUint(const char* s, T* out,
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
               T max = std::numeric_limits<T>::max()) {
               bool allow_suffixes = false) {
  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
  errno = 0;
  errno = 0;
  char* end;
  char* end;
  unsigned long long int result = strtoull(s, &end, base);
  unsigned long long int result = strtoull(s, &end, base);
  if (errno != 0 || s == end || *end != '\0') {
  if (errno != 0 || end == s) return false;
    return false;
  if (*end != '\0') {
    const char* suffixes = "bkmgtpe";
    const char* suffix;
    if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
#if __clang__  // TODO: win32 still builds with GCC :-(
    if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
#endif
  }
  }
  if (max < result) {
  if (max < result) {
    return false;
    return false;
@@ -49,9 +56,20 @@ bool ParseUint(const char* s, T* out,


// TODO: string_view
// TODO: string_view
template <typename T>
template <typename T>
bool ParseUint(const std::string& s, T* out,
bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
               T max = std::numeric_limits<T>::max()) {
               bool allow_suffixes = false) {
  return ParseUint(s.c_str(), out, max);
  return ParseUint(s.c_str(), out, max, allow_suffixes);
}

template <typename T>
bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
  return ParseUint(s, out, max, true);
}

// TODO: string_view
template <typename T>
bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
  return ParseByteCount(s.c_str(), out, max);
}
}


// Parses the signed decimal integer in the string 's' and sets 'out' to
// Parses the signed decimal integer in the string 's' and sets 'out' to
+41 −0
Original line number Original line Diff line number Diff line
@@ -96,3 +96,44 @@ TEST(parseint, untouched_on_failure) {
  ASSERT_FALSE(android::base::ParseInt("456x", &u));
  ASSERT_FALSE(android::base::ParseInt("456x", &u));
  ASSERT_EQ(123u, u);
  ASSERT_EQ(123u, u);
}
}

TEST(parseint, ParseByteCount) {
  uint64_t i = 0;
  ASSERT_TRUE(android::base::ParseByteCount("123b", &i));
  ASSERT_EQ(123ULL, i);

  ASSERT_TRUE(android::base::ParseByteCount("8k", &i));
  ASSERT_EQ(8ULL * 1024, i);

  ASSERT_TRUE(android::base::ParseByteCount("8M", &i));
  ASSERT_EQ(8ULL * 1024 * 1024, i);

  ASSERT_TRUE(android::base::ParseByteCount("6g", &i));
  ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i);

  ASSERT_TRUE(android::base::ParseByteCount("1T", &i));
  ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i);

  ASSERT_TRUE(android::base::ParseByteCount("2p", &i));
  ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i);

  ASSERT_TRUE(android::base::ParseByteCount("4e", &i));
  ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i);
}

TEST(parseint, ParseByteCount_invalid_suffix) {
  unsigned u;
  ASSERT_FALSE(android::base::ParseByteCount("1x", &u));
}

TEST(parseint, ParseByteCount_overflow) {
  uint64_t u64;
  ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64));

  uint16_t u16;
  ASSERT_TRUE(android::base::ParseByteCount("63k", &u16));
  ASSERT_EQ(63U * 1024, u16);
  ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16));
  ASSERT_EQ(65535U, u16);
  ASSERT_FALSE(android::base::ParseByteCount("65k", &u16));
}