You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
6.2 KiB

  1. // base/io-funcs.cc
  2. // Copyright 2009-2011 Microsoft Corporation; Saarland University
  3. // See ../../COPYING for clarification regarding multiple authors
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  10. // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  11. // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  12. // MERCHANTABLITY OR NON-INFRINGEMENT.
  13. // See the Apache 2 License for the specific language governing permissions and
  14. // limitations under the License.
  15. #include "base/io-funcs.h"
  16. #include "base/kaldi-math.h"
  17. namespace kaldi {
  18. template <>
  19. void WriteBasicType<bool>(std::ostream& os, bool binary, bool b) {
  20. os << (b ? "T" : "F");
  21. if (!binary) os << " ";
  22. if (os.fail()) KALDI_ERR << "Write failure in WriteBasicType<bool>";
  23. }
  24. template <>
  25. void ReadBasicType<bool>(std::istream& is, bool binary, bool* b) {
  26. KALDI_PARANOID_ASSERT(b != NULL);
  27. if (!binary) is >> std::ws; // eat up whitespace.
  28. char c = is.peek();
  29. if (c == 'T') {
  30. *b = true;
  31. is.get();
  32. } else if (c == 'F') {
  33. *b = false;
  34. is.get();
  35. } else {
  36. KALDI_ERR << "Read failure in ReadBasicType<bool>, file position is "
  37. << is.tellg() << ", next char is " << CharToString(c);
  38. }
  39. }
  40. template <>
  41. void WriteBasicType<float>(std::ostream& os, bool binary, float f) {
  42. if (binary) {
  43. char c = sizeof(f);
  44. os.put(c);
  45. os.write(reinterpret_cast<const char*>(&f), sizeof(f));
  46. } else {
  47. os << f << " ";
  48. }
  49. }
  50. template <>
  51. void WriteBasicType<double>(std::ostream& os, bool binary, double f) {
  52. if (binary) {
  53. char c = sizeof(f);
  54. os.put(c);
  55. os.write(reinterpret_cast<const char*>(&f), sizeof(f));
  56. } else {
  57. os << f << " ";
  58. }
  59. }
  60. template <>
  61. void ReadBasicType<float>(std::istream& is, bool binary, float* f) {
  62. KALDI_PARANOID_ASSERT(f != NULL);
  63. if (binary) {
  64. double d;
  65. int c = is.peek();
  66. if (c == sizeof(*f)) {
  67. is.get();
  68. is.read(reinterpret_cast<char*>(f), sizeof(*f));
  69. } else if (c == sizeof(d)) {
  70. ReadBasicType(is, binary, &d);
  71. *f = d;
  72. } else {
  73. KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek()
  74. << ", at file position " << is.tellg();
  75. }
  76. } else {
  77. is >> *f;
  78. }
  79. if (is.fail()) {
  80. KALDI_ERR << "ReadBasicType: failed to read, at file position "
  81. << is.tellg();
  82. }
  83. }
  84. template <>
  85. void ReadBasicType<double>(std::istream& is, bool binary, double* d) {
  86. KALDI_PARANOID_ASSERT(d != NULL);
  87. if (binary) {
  88. float f;
  89. int c = is.peek();
  90. if (c == sizeof(*d)) {
  91. is.get();
  92. is.read(reinterpret_cast<char*>(d), sizeof(*d));
  93. } else if (c == sizeof(f)) {
  94. ReadBasicType(is, binary, &f);
  95. *d = f;
  96. } else {
  97. KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek()
  98. << ", at file position " << is.tellg();
  99. }
  100. } else {
  101. is >> *d;
  102. }
  103. if (is.fail()) {
  104. KALDI_ERR << "ReadBasicType: failed to read, at file position "
  105. << is.tellg();
  106. }
  107. }
  108. void CheckToken(const char* token) {
  109. if (*token == '\0') KALDI_ERR << "Token is empty (not a valid token)";
  110. const char* orig_token = token;
  111. while (*token != '\0') {
  112. if (::isspace(*token))
  113. KALDI_ERR << "Token is not a valid token (contains space): '"
  114. << orig_token << "'";
  115. token++;
  116. }
  117. }
  118. void WriteToken(std::ostream& os, bool binary, const char* token) {
  119. // binary mode is ignored;
  120. // we use space as termination character in either case.
  121. KALDI_ASSERT(token != NULL);
  122. CheckToken(token); // make sure it's valid (can be read back)
  123. os << token << " ";
  124. if (os.fail()) {
  125. KALDI_ERR << "Write failure in WriteToken.";
  126. }
  127. }
  128. int Peek(std::istream& is, bool binary) {
  129. if (!binary) is >> std::ws; // eat up whitespace.
  130. return is.peek();
  131. }
  132. void WriteToken(std::ostream& os, bool binary, const std::string& token) {
  133. WriteToken(os, binary, token.c_str());
  134. }
  135. void ReadToken(std::istream& is, bool binary, std::string* str) {
  136. KALDI_ASSERT(str != NULL);
  137. if (!binary) is >> std::ws; // consume whitespace.
  138. is >> *str;
  139. if (is.fail()) {
  140. KALDI_ERR << "ReadToken, failed to read token at file position "
  141. << is.tellg();
  142. }
  143. if (!isspace(is.peek())) {
  144. KALDI_ERR << "ReadToken, expected space after token, saw instead "
  145. << CharToString(static_cast<char>(is.peek()))
  146. << ", at file position " << is.tellg();
  147. }
  148. is.get(); // consume the space.
  149. }
  150. int PeekToken(std::istream& is, bool binary) {
  151. if (!binary) is >> std::ws; // consume whitespace.
  152. bool read_bracket;
  153. if (static_cast<char>(is.peek()) == '<') {
  154. read_bracket = true;
  155. is.get();
  156. } else {
  157. read_bracket = false;
  158. }
  159. int ans = is.peek();
  160. if (read_bracket) {
  161. if (!is.unget()) {
  162. // Clear the bad bit. This code can be (and is in fact) reached, since the
  163. // C++ standard does not guarantee that a call to unget() must succeed.
  164. is.clear();
  165. }
  166. }
  167. return ans;
  168. }
  169. void ExpectToken(std::istream& is, bool binary, const char* token) {
  170. int pos_at_start = is.tellg();
  171. KALDI_ASSERT(token != NULL);
  172. CheckToken(token); // make sure it's valid (can be read back)
  173. if (!binary) is >> std::ws; // consume whitespace.
  174. std::string str;
  175. is >> str;
  176. is.get(); // consume the space.
  177. if (is.fail()) {
  178. KALDI_ERR << "Failed to read token [started at file position "
  179. << pos_at_start << "], expected " << token;
  180. }
  181. // The second half of the '&&' expression below is so that if we're expecting
  182. // "<Foo>", we will accept "Foo>" instead. This is so that the model-reading
  183. // code will tolerate errors in PeekToken where is.unget() failed; search for
  184. // is.clear() in PeekToken() for an explanation.
  185. if (strcmp(str.c_str(), token) != 0 &&
  186. !(token[0] == '<' && strcmp(str.c_str(), token + 1) == 0)) {
  187. KALDI_ERR << "Expected token \"" << token << "\", got instead \"" << str
  188. << "\".";
  189. }
  190. }
  191. void ExpectToken(std::istream& is, bool binary, const std::string& token) {
  192. ExpectToken(is, binary, token.c_str());
  193. }
  194. } // end namespace kaldi