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.
219 lines
6.2 KiB
219 lines
6.2 KiB
// base/io-funcs.cc
|
|
|
|
// Copyright 2009-2011 Microsoft Corporation; Saarland University
|
|
|
|
// See ../../COPYING for clarification regarding multiple authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
// MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
// See the Apache 2 License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "base/io-funcs.h"
|
|
#include "base/kaldi-math.h"
|
|
|
|
namespace kaldi {
|
|
|
|
template<>
|
|
void WriteBasicType<bool>(std::ostream &os, bool binary, bool b) {
|
|
os << (b ? "T":"F");
|
|
if (!binary) os << " ";
|
|
if (os.fail())
|
|
KALDI_ERR << "Write failure in WriteBasicType<bool>";
|
|
}
|
|
|
|
template<>
|
|
void ReadBasicType<bool>(std::istream &is, bool binary, bool *b) {
|
|
KALDI_PARANOID_ASSERT(b != NULL);
|
|
if (!binary) is >> std::ws; // eat up whitespace.
|
|
char c = is.peek();
|
|
if (c == 'T') {
|
|
*b = true;
|
|
is.get();
|
|
} else if (c == 'F') {
|
|
*b = false;
|
|
is.get();
|
|
} else {
|
|
KALDI_ERR << "Read failure in ReadBasicType<bool>, file position is "
|
|
<< is.tellg() << ", next char is " << CharToString(c);
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void WriteBasicType<float>(std::ostream &os, bool binary, float f) {
|
|
if (binary) {
|
|
char c = sizeof(f);
|
|
os.put(c);
|
|
os.write(reinterpret_cast<const char *>(&f), sizeof(f));
|
|
} else {
|
|
os << f << " ";
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void WriteBasicType<double>(std::ostream &os, bool binary, double f) {
|
|
if (binary) {
|
|
char c = sizeof(f);
|
|
os.put(c);
|
|
os.write(reinterpret_cast<const char *>(&f), sizeof(f));
|
|
} else {
|
|
os << f << " ";
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void ReadBasicType<float>(std::istream &is, bool binary, float *f) {
|
|
KALDI_PARANOID_ASSERT(f != NULL);
|
|
if (binary) {
|
|
double d;
|
|
int c = is.peek();
|
|
if (c == sizeof(*f)) {
|
|
is.get();
|
|
is.read(reinterpret_cast<char*>(f), sizeof(*f));
|
|
} else if (c == sizeof(d)) {
|
|
ReadBasicType(is, binary, &d);
|
|
*f = d;
|
|
} else {
|
|
KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek()
|
|
<< ", at file position " << is.tellg();
|
|
}
|
|
} else {
|
|
is >> *f;
|
|
}
|
|
if (is.fail()) {
|
|
KALDI_ERR << "ReadBasicType: failed to read, at file position "
|
|
<< is.tellg();
|
|
}
|
|
}
|
|
|
|
template<>
|
|
void ReadBasicType<double>(std::istream &is, bool binary, double *d) {
|
|
KALDI_PARANOID_ASSERT(d != NULL);
|
|
if (binary) {
|
|
float f;
|
|
int c = is.peek();
|
|
if (c == sizeof(*d)) {
|
|
is.get();
|
|
is.read(reinterpret_cast<char*>(d), sizeof(*d));
|
|
} else if (c == sizeof(f)) {
|
|
ReadBasicType(is, binary, &f);
|
|
*d = f;
|
|
} else {
|
|
KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek()
|
|
<< ", at file position " << is.tellg();
|
|
}
|
|
} else {
|
|
is >> *d;
|
|
}
|
|
if (is.fail()) {
|
|
KALDI_ERR << "ReadBasicType: failed to read, at file position "
|
|
<< is.tellg();
|
|
}
|
|
}
|
|
|
|
void CheckToken(const char *token) {
|
|
if (*token == '\0')
|
|
KALDI_ERR << "Token is empty (not a valid token)";
|
|
const char *orig_token = token;
|
|
while (*token != '\0') {
|
|
if (::isspace(*token))
|
|
KALDI_ERR << "Token is not a valid token (contains space): '"
|
|
<< orig_token << "'";
|
|
token++;
|
|
}
|
|
}
|
|
|
|
void WriteToken(std::ostream &os, bool binary, const char *token) {
|
|
// binary mode is ignored;
|
|
// we use space as termination character in either case.
|
|
KALDI_ASSERT(token != NULL);
|
|
CheckToken(token); // make sure it's valid (can be read back)
|
|
os << token << " ";
|
|
if (os.fail()) {
|
|
KALDI_ERR << "Write failure in WriteToken.";
|
|
}
|
|
}
|
|
|
|
int Peek(std::istream &is, bool binary) {
|
|
if (!binary) is >> std::ws; // eat up whitespace.
|
|
return is.peek();
|
|
}
|
|
|
|
void WriteToken(std::ostream &os, bool binary, const std::string & token) {
|
|
WriteToken(os, binary, token.c_str());
|
|
}
|
|
|
|
void ReadToken(std::istream &is, bool binary, std::string *str) {
|
|
KALDI_ASSERT(str != NULL);
|
|
if (!binary) is >> std::ws; // consume whitespace.
|
|
is >> *str;
|
|
if (is.fail()) {
|
|
KALDI_ERR << "ReadToken, failed to read token at file position "
|
|
<< is.tellg();
|
|
}
|
|
if (!isspace(is.peek())) {
|
|
KALDI_ERR << "ReadToken, expected space after token, saw instead "
|
|
<< CharToString(static_cast<char>(is.peek()))
|
|
<< ", at file position " << is.tellg();
|
|
}
|
|
is.get(); // consume the space.
|
|
}
|
|
|
|
int PeekToken(std::istream &is, bool binary) {
|
|
if (!binary) is >> std::ws; // consume whitespace.
|
|
bool read_bracket;
|
|
if (static_cast<char>(is.peek()) == '<') {
|
|
read_bracket = true;
|
|
is.get();
|
|
} else {
|
|
read_bracket = false;
|
|
}
|
|
int ans = is.peek();
|
|
if (read_bracket) {
|
|
if (!is.unget()) {
|
|
// Clear the bad bit. This code can be (and is in fact) reached, since the
|
|
// C++ standard does not guarantee that a call to unget() must succeed.
|
|
is.clear();
|
|
}
|
|
}
|
|
return ans;
|
|
}
|
|
|
|
|
|
void ExpectToken(std::istream &is, bool binary, const char *token) {
|
|
int pos_at_start = is.tellg();
|
|
KALDI_ASSERT(token != NULL);
|
|
CheckToken(token); // make sure it's valid (can be read back)
|
|
if (!binary) is >> std::ws; // consume whitespace.
|
|
std::string str;
|
|
is >> str;
|
|
is.get(); // consume the space.
|
|
if (is.fail()) {
|
|
KALDI_ERR << "Failed to read token [started at file position "
|
|
<< pos_at_start << "], expected " << token;
|
|
}
|
|
// The second half of the '&&' expression below is so that if we're expecting
|
|
// "<Foo>", we will accept "Foo>" instead. This is so that the model-reading
|
|
// code will tolerate errors in PeekToken where is.unget() failed; search for
|
|
// is.clear() in PeekToken() for an explanation.
|
|
if (strcmp(str.c_str(), token) != 0 &&
|
|
!(token[0] == '<' && strcmp(str.c_str(), token + 1) == 0)) {
|
|
KALDI_ERR << "Expected token \"" << token << "\", got instead \""
|
|
<< str <<"\".";
|
|
}
|
|
}
|
|
|
|
void ExpectToken(std::istream &is, bool binary, const std::string &token) {
|
|
ExpectToken(is, binary, token.c_str());
|
|
}
|
|
|
|
} // end namespace kaldi
|