string_utils.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #pragma once
  2. #include <sstream>
  3. #include <stdexcept>
  4. #include <string>
  5. namespace c10 {
  6. // to_string, stoi and stod implementation for Android related stuff.
  7. // Note(jiayq): Do not use the CAFFE2_TESTONLY_FORCE_STD_STRING_TEST macro
  8. // outside testing code that lives under common_test.cc
  9. #if defined(__ANDROID__) || defined(CAFFE2_TESTONLY_FORCE_STD_STRING_TEST)
  10. #define CAFFE2_TESTONLY_WE_ARE_USING_CUSTOM_STRING_FUNCTIONS 1
  11. template <typename T>
  12. std::string to_string(T value) {
  13. std::ostringstream os;
  14. os << value;
  15. return os.str();
  16. }
  17. inline int stoi(const std::string& str, std::size_t* pos = 0) {
  18. std::stringstream ss;
  19. int n = 0;
  20. ss << str;
  21. ss >> n;
  22. if (ss.fail()) {
  23. // To mimic `std::stoi` and to avoid including `Exception.h`, throw
  24. // `std::invalid_argument`.
  25. // We can't easily detect out-of-range, so we don't use `std::out_of_range`.
  26. throw std::invalid_argument("Not an integer");
  27. }
  28. if (pos) {
  29. if (ss.tellg() == std::streampos(-1)) {
  30. *pos = str.size();
  31. } else {
  32. *pos = ss.tellg();
  33. }
  34. }
  35. return n;
  36. }
  37. inline uint64_t stoull(const std::string& str) {
  38. std::stringstream ss;
  39. uint64_t n = 0;
  40. ss << str;
  41. ss >> n;
  42. if (ss.fail()) {
  43. // To mimic `std::stoull` and to avoid including `Exception.h`, throw
  44. // `std::invalid_argument`.
  45. // We can't easily detect out-of-range, so we don't use `std::out_of_range`.
  46. throw std::invalid_argument("Not an unsigned 64-bit integer");
  47. }
  48. return n;
  49. }
  50. inline double stod(const std::string& str, std::size_t* pos = 0) {
  51. std::stringstream ss;
  52. ss << str;
  53. double val = 0;
  54. ss >> val;
  55. if (ss.fail()) {
  56. // To mimic `std::stod` and to avoid including `Exception.h`, throw
  57. // `std::invalid_argument`.
  58. // We can't easily detect out-of-range, so we don't use `std::out_of_range`.
  59. throw std::invalid_argument("Not a double-precision floating point number");
  60. }
  61. if (pos) {
  62. if (ss.tellg() == std::streampos(-1)) {
  63. *pos = str.size();
  64. } else {
  65. *pos = ss.tellg();
  66. }
  67. }
  68. return val;
  69. }
  70. inline long long stoll(const std::string& str, std::size_t* pos = 0) {
  71. // std::stoll doesn't exist in our Android environment, we need to implement
  72. // it ourselves.
  73. std::stringstream ss;
  74. ss << str;
  75. long long result = 0;
  76. ss >> result;
  77. if (ss.fail()) {
  78. // To mimic `std::stoll` and to avoid including `Exception.h`, throw
  79. // `std::invalid_argument`.
  80. // We can't easily detect out-of-range, so we don't use `std::out_of_range`.
  81. throw std::invalid_argument("Not a long long integer");
  82. }
  83. if (pos) {
  84. if (ss.tellg() == std::streampos(-1)) {
  85. *pos = str.size();
  86. } else {
  87. *pos = ss.tellg();
  88. }
  89. }
  90. return result;
  91. }
  92. inline long long stoll(const std::string& str, size_t pos, int base) {
  93. // std::stoll doesn't exist in our Android environment, we need to implement
  94. // it ourselves.
  95. std::stringstream ss;
  96. if (str.size() > 0 && str.at(0) == '0') {
  97. if (str.size() > 1 && (str.at(1) == 'x' || str.at(1) == 'X')) {
  98. ss << std::hex << str;
  99. } else {
  100. ss << std::oct << str;
  101. }
  102. } else {
  103. ss << str;
  104. }
  105. long long result = 0;
  106. ss >> result;
  107. if (ss.fail()) {
  108. // To mimic `std::stoll` and to avoid including `Exception.h`, throw
  109. // `std::invalid_argument`.
  110. // We can't easily detect out-of-range, so we don't use `std::out_of_range`.
  111. throw std::invalid_argument("Not a long long integer");
  112. }
  113. return result;
  114. }
  115. #else
  116. #define CAFFE2_TESTONLY_WE_ARE_USING_CUSTOM_STRING_FUNCTIONS 0
  117. using std::stod;
  118. using std::stoi;
  119. using std::stoll;
  120. using std::stoull;
  121. using std::to_string;
  122. #endif // defined(__ANDROID__) || defined(CAFFE2_FORCE_STD_STRING_FALLBACK_TEST)
  123. } // namespace c10
  124. #if defined(__ANDROID__) && __ANDROID_API__ < 21 && defined(__GLIBCXX__)
  125. #include <cstdlib>
  126. // std::strtoll isn't available on Android NDK platform < 21 when building
  127. // with libstdc++, so bring the global version into std.
  128. namespace std {
  129. using ::strtoll;
  130. }
  131. #endif