iostream_state_saver.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
  15. #define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
  16. #include <cmath>
  17. #include <cstdint>
  18. #include <ios>
  19. #include <istream>
  20. #include <limits>
  21. #include <ostream>
  22. #include <type_traits>
  23. #include "absl/base/config.h"
  24. #include "absl/meta/type_traits.h"
  25. #include "absl/numeric/int128.h"
  26. namespace absl {
  27. ABSL_NAMESPACE_BEGIN
  28. namespace random_internal {
  29. // The null_state_saver does nothing.
  30. template <typename T>
  31. class null_state_saver {
  32. public:
  33. using stream_type = T;
  34. using flags_type = std::ios_base::fmtflags;
  35. null_state_saver(T&, flags_type) {}
  36. ~null_state_saver() {}
  37. };
  38. // ostream_state_saver is a RAII object to save and restore the common
  39. // basic_ostream flags used when implementing `operator <<()` on any of
  40. // the absl random distributions.
  41. template <typename OStream>
  42. class ostream_state_saver {
  43. public:
  44. using ostream_type = OStream;
  45. using flags_type = std::ios_base::fmtflags;
  46. using fill_type = typename ostream_type::char_type;
  47. using precision_type = std::streamsize;
  48. ostream_state_saver(ostream_type& os, // NOLINT(runtime/references)
  49. flags_type flags, fill_type fill)
  50. : os_(os),
  51. flags_(os.flags(flags)),
  52. fill_(os.fill(fill)),
  53. precision_(os.precision()) {
  54. // Save state in initialized variables.
  55. }
  56. ~ostream_state_saver() {
  57. // Restore saved state.
  58. os_.precision(precision_);
  59. os_.fill(fill_);
  60. os_.flags(flags_);
  61. }
  62. private:
  63. ostream_type& os_;
  64. const flags_type flags_;
  65. const fill_type fill_;
  66. const precision_type precision_;
  67. };
  68. #if defined(__NDK_MAJOR__) && __NDK_MAJOR__ < 16
  69. #define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 1
  70. #else
  71. #define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 0
  72. #endif
  73. template <typename CharT, typename Traits>
  74. ostream_state_saver<std::basic_ostream<CharT, Traits>> make_ostream_state_saver(
  75. std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
  76. std::ios_base::fmtflags flags = std::ios_base::dec | std::ios_base::left |
  77. #if ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT
  78. std::ios_base::fixed |
  79. #endif
  80. std::ios_base::scientific) {
  81. using result_type = ostream_state_saver<std::basic_ostream<CharT, Traits>>;
  82. return result_type(os, flags, os.widen(' '));
  83. }
  84. template <typename T>
  85. typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value,
  86. null_state_saver<T>>
  87. make_ostream_state_saver(T& is, // NOLINT(runtime/references)
  88. std::ios_base::fmtflags flags = std::ios_base::dec) {
  89. using result_type = null_state_saver<T>;
  90. return result_type(is, flags);
  91. }
  92. // stream_precision_helper<type>::kPrecision returns the base 10 precision
  93. // required to stream and reconstruct a real type exact binary value through
  94. // a binary->decimal->binary transition.
  95. template <typename T>
  96. struct stream_precision_helper {
  97. // max_digits10 may be 0 on MSVC; if so, use digits10 + 3.
  98. static constexpr int kPrecision =
  99. (std::numeric_limits<T>::max_digits10 > std::numeric_limits<T>::digits10)
  100. ? std::numeric_limits<T>::max_digits10
  101. : (std::numeric_limits<T>::digits10 + 3);
  102. };
  103. template <>
  104. struct stream_precision_helper<float> {
  105. static constexpr int kPrecision = 9;
  106. };
  107. template <>
  108. struct stream_precision_helper<double> {
  109. static constexpr int kPrecision = 17;
  110. };
  111. template <>
  112. struct stream_precision_helper<long double> {
  113. static constexpr int kPrecision = 36; // assuming fp128
  114. };
  115. // istream_state_saver is a RAII object to save and restore the common
  116. // std::basic_istream<> flags used when implementing `operator >>()` on any of
  117. // the absl random distributions.
  118. template <typename IStream>
  119. class istream_state_saver {
  120. public:
  121. using istream_type = IStream;
  122. using flags_type = std::ios_base::fmtflags;
  123. istream_state_saver(istream_type& is, // NOLINT(runtime/references)
  124. flags_type flags)
  125. : is_(is), flags_(is.flags(flags)) {}
  126. ~istream_state_saver() { is_.flags(flags_); }
  127. private:
  128. istream_type& is_;
  129. flags_type flags_;
  130. };
  131. template <typename CharT, typename Traits>
  132. istream_state_saver<std::basic_istream<CharT, Traits>> make_istream_state_saver(
  133. std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
  134. std::ios_base::fmtflags flags = std::ios_base::dec |
  135. std::ios_base::scientific |
  136. std::ios_base::skipws) {
  137. using result_type = istream_state_saver<std::basic_istream<CharT, Traits>>;
  138. return result_type(is, flags);
  139. }
  140. template <typename T>
  141. typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value,
  142. null_state_saver<T>>
  143. make_istream_state_saver(T& is, // NOLINT(runtime/references)
  144. std::ios_base::fmtflags flags = std::ios_base::dec) {
  145. using result_type = null_state_saver<T>;
  146. return result_type(is, flags);
  147. }
  148. // stream_format_type<T> is a helper struct to convert types which
  149. // basic_iostream cannot output as decimal numbers into types which
  150. // basic_iostream can output as decimal numbers. Specifically:
  151. // * signed/unsigned char-width types are converted to int.
  152. // * TODO(lar): __int128 => uint128, except there is no operator << yet.
  153. //
  154. template <typename T>
  155. struct stream_format_type
  156. : public std::conditional<(sizeof(T) == sizeof(char)), int, T> {};
  157. // stream_u128_helper allows us to write out either absl::uint128 or
  158. // __uint128_t types in the same way, which enables their use as internal
  159. // state of PRNG engines.
  160. template <typename T>
  161. struct stream_u128_helper;
  162. template <>
  163. struct stream_u128_helper<absl::uint128> {
  164. template <typename IStream>
  165. inline absl::uint128 read(IStream& in) {
  166. uint64_t h = 0;
  167. uint64_t l = 0;
  168. in >> h >> l;
  169. return absl::MakeUint128(h, l);
  170. }
  171. template <typename OStream>
  172. inline void write(absl::uint128 val, OStream& out) {
  173. uint64_t h = absl::Uint128High64(val);
  174. uint64_t l = absl::Uint128Low64(val);
  175. out << h << out.fill() << l;
  176. }
  177. };
  178. #ifdef ABSL_HAVE_INTRINSIC_INT128
  179. template <>
  180. struct stream_u128_helper<__uint128_t> {
  181. template <typename IStream>
  182. inline __uint128_t read(IStream& in) {
  183. uint64_t h = 0;
  184. uint64_t l = 0;
  185. in >> h >> l;
  186. return (static_cast<__uint128_t>(h) << 64) | l;
  187. }
  188. template <typename OStream>
  189. inline void write(__uint128_t val, OStream& out) {
  190. uint64_t h = static_cast<uint64_t>(val >> 64u);
  191. uint64_t l = static_cast<uint64_t>(val);
  192. out << h << out.fill() << l;
  193. }
  194. };
  195. #endif
  196. template <typename FloatType, typename IStream>
  197. inline FloatType read_floating_point(IStream& is) {
  198. static_assert(std::is_floating_point<FloatType>::value, "");
  199. FloatType dest;
  200. is >> dest;
  201. // Parsing a double value may report a subnormal value as an error
  202. // despite being able to represent it.
  203. // See https://stackoverflow.com/q/52410931/3286653
  204. // It may also report an underflow when parsing DOUBLE_MIN as an
  205. // ERANGE error, as the parsed value may be smaller than DOUBLE_MIN
  206. // and rounded up.
  207. // See: https://stackoverflow.com/q/42005462
  208. if (is.fail() &&
  209. (std::fabs(dest) == (std::numeric_limits<FloatType>::min)() ||
  210. std::fpclassify(dest) == FP_SUBNORMAL)) {
  211. is.clear(is.rdstate() & (~std::ios_base::failbit));
  212. }
  213. return dest;
  214. }
  215. } // namespace random_internal
  216. ABSL_NAMESPACE_END
  217. } // namespace absl
  218. #endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_