|
|
// base/io-funcs-inl.h
// Copyright 2009-2011 Microsoft Corporation; Saarland University;
// Jan Silovsky; Yanmin Qian;
// Johns Hopkins University (Author: Daniel Povey)
// 2016 Xiaohui Zhang
// 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.
#ifndef KALDI_BASE_IO_FUNCS_INL_H_
#define KALDI_BASE_IO_FUNCS_INL_H_ 1
// Do not include this file directly. It is included by base/io-funcs.h
#include <limits>
#include <utility>
#include <vector>
namespace kaldi {
// Template that covers integers.
template <class T> void WriteBasicType(std::ostream& os, bool binary, T t) { // Compile time assertion that this is not called with a wrong type.
KALDI_ASSERT_IS_INTEGER_TYPE(T); if (binary) { char len_c = (std::numeric_limits<T>::is_signed ? 1 : -1) * static_cast<char>(sizeof(t)); os.put(len_c); os.write(reinterpret_cast<const char*>(&t), sizeof(t)); } else { if (sizeof(t) == 1) os << static_cast<int16>(t) << " "; else os << t << " "; } if (os.fail()) { KALDI_ERR << "Write failure in WriteBasicType."; } }
// Template that covers integers.
template <class T> inline void ReadBasicType(std::istream& is, bool binary, T* t) { KALDI_PARANOID_ASSERT(t != NULL); // Compile time assertion that this is not called with a wrong type.
KALDI_ASSERT_IS_INTEGER_TYPE(T); if (binary) { int len_c_in = is.get(); if (len_c_in == -1) KALDI_ERR << "ReadBasicType: encountered end of stream."; char len_c = static_cast<char>(len_c_in), len_c_expected = (std::numeric_limits<T>::is_signed ? 1 : -1) * static_cast<char>(sizeof(*t)); if (len_c != len_c_expected) { KALDI_ERR << "ReadBasicType: did not get expected integer type, " << static_cast<int>(len_c) << " vs. " << static_cast<int>(len_c_expected) << ". You can change this code to successfully" << " read it later, if needed."; // insert code here to read "wrong" type. Might have a switch statement.
} is.read(reinterpret_cast<char*>(t), sizeof(*t)); } else { if (sizeof(*t) == 1) { int16 i; is >> i; *t = i; } else { is >> *t; } } if (is.fail()) { KALDI_ERR << "Read failure in ReadBasicType, file position is " << is.tellg() << ", next char is " << is.peek(); } }
// Template that covers integers.
template <class T> inline void WriteIntegerPairVector(std::ostream& os, bool binary, const std::vector<std::pair<T, T> >& v) { // Compile time assertion that this is not called with a wrong type.
KALDI_ASSERT_IS_INTEGER_TYPE(T); if (binary) { char sz = sizeof(T); // this is currently just a check.
os.write(&sz, 1); int32 vecsz = static_cast<int32>(v.size()); KALDI_ASSERT((size_t)vecsz == v.size()); os.write(reinterpret_cast<const char*>(&vecsz), sizeof(vecsz)); if (vecsz != 0) { os.write(reinterpret_cast<const char*>(&(v[0])), sizeof(T) * vecsz * 2); } } else { // focus here is on prettiness of text form rather than
// efficiency of reading-in.
// reading-in is dominated by low-level operations anyway:
// for efficiency use binary.
os << "[ "; typename std::vector<std::pair<T, T> >::const_iterator iter = v.begin(), end = v.end(); for (; iter != end; ++iter) { if (sizeof(T) == 1) os << static_cast<int16>(iter->first) << ',' << static_cast<int16>(iter->second) << ' '; else os << iter->first << ',' << iter->second << ' '; } os << "]\n"; } if (os.fail()) { KALDI_ERR << "Write failure in WriteIntegerPairVector."; } }
// Template that covers integers.
template <class T> inline void ReadIntegerPairVector(std::istream& is, bool binary, std::vector<std::pair<T, T> >* v) { KALDI_ASSERT_IS_INTEGER_TYPE(T); KALDI_ASSERT(v != NULL); if (binary) { int sz = is.peek(); if (sz == sizeof(T)) { is.get(); } else { // this is currently just a check.
KALDI_ERR << "ReadIntegerPairVector: expected to see type of size " << sizeof(T) << ", saw instead " << sz << ", at file position " << is.tellg(); } int32 vecsz; is.read(reinterpret_cast<char*>(&vecsz), sizeof(vecsz)); if (is.fail() || vecsz < 0) goto bad; v->resize(vecsz); if (vecsz > 0) { is.read(reinterpret_cast<char*>(&((*v)[0])), sizeof(T) * vecsz * 2); } } else { std::vector<std::pair<T, T> > tmp_v; // use temporary so v doesn't use
// extra memory due to resizing.
is >> std::ws; if (is.peek() != static_cast<int>('[')) { KALDI_ERR << "ReadIntegerPairVector: expected to see [, saw " << is.peek() << ", at file position " << is.tellg(); } is.get(); // consume the '['.
is >> std::ws; // consume whitespace.
while (is.peek() != static_cast<int>(']')) { if (sizeof(T) == 1) { // read/write chars as numbers.
int16 next_t1, next_t2; is >> next_t1; if (is.fail()) goto bad; if (is.peek() != static_cast<int>(',')) KALDI_ERR << "ReadIntegerPairVector: expected to see ',', saw " << is.peek() << ", at file position " << is.tellg(); is.get(); // consume the ','.
is >> next_t2 >> std::ws; if (is.fail()) goto bad; else tmp_v.push_back(std::make_pair((T)next_t1, (T)next_t2)); } else { T next_t1, next_t2; is >> next_t1; if (is.fail()) goto bad; if (is.peek() != static_cast<int>(',')) KALDI_ERR << "ReadIntegerPairVector: expected to see ',', saw " << is.peek() << ", at file position " << is.tellg(); is.get(); // consume the ','.
is >> next_t2 >> std::ws; if (is.fail()) goto bad; else tmp_v.push_back(std::pair<T, T>(next_t1, next_t2)); } } is.get(); // get the final ']'.
*v = tmp_v; // could use std::swap to use less temporary memory, but this
// uses less permanent memory.
} if (!is.fail()) return; bad: KALDI_ERR << "ReadIntegerPairVector: read failure at file position " << is.tellg(); }
template <class T> inline void WriteIntegerVector(std::ostream& os, bool binary, const std::vector<T>& v) { // Compile time assertion that this is not called with a wrong type.
KALDI_ASSERT_IS_INTEGER_TYPE(T); if (binary) { char sz = sizeof(T); // this is currently just a check.
os.write(&sz, 1); int32 vecsz = static_cast<int32>(v.size()); KALDI_ASSERT((size_t)vecsz == v.size()); os.write(reinterpret_cast<const char*>(&vecsz), sizeof(vecsz)); if (vecsz != 0) { os.write(reinterpret_cast<const char*>(&(v[0])), sizeof(T) * vecsz); } } else { // focus here is on prettiness of text form rather than
// efficiency of reading-in.
// reading-in is dominated by low-level operations anyway:
// for efficiency use binary.
os << "[ "; typename std::vector<T>::const_iterator iter = v.begin(), end = v.end(); for (; iter != end; ++iter) { if (sizeof(T) == 1) os << static_cast<int16>(*iter) << " "; else os << *iter << " "; } os << "]\n"; } if (os.fail()) { KALDI_ERR << "Write failure in WriteIntegerVector."; } }
template <class T> inline void ReadIntegerVector(std::istream& is, bool binary, std::vector<T>* v) { KALDI_ASSERT_IS_INTEGER_TYPE(T); KALDI_ASSERT(v != NULL); if (binary) { int sz = is.peek(); if (sz == sizeof(T)) { is.get(); } else { // this is currently just a check.
KALDI_ERR << "ReadIntegerVector: expected to see type of size " << sizeof(T) << ", saw instead " << sz << ", at file position " << is.tellg(); } int32 vecsz; is.read(reinterpret_cast<char*>(&vecsz), sizeof(vecsz)); if (is.fail() || vecsz < 0) goto bad; v->resize(vecsz); if (vecsz > 0) { is.read(reinterpret_cast<char*>(&((*v)[0])), sizeof(T) * vecsz); } } else { std::vector<T> tmp_v; // use temporary so v doesn't use extra memory
// due to resizing.
is >> std::ws; if (is.peek() != static_cast<int>('[')) { KALDI_ERR << "ReadIntegerVector: expected to see [, saw " << is.peek() << ", at file position " << is.tellg(); } is.get(); // consume the '['.
is >> std::ws; // consume whitespace.
while (is.peek() != static_cast<int>(']')) { if (sizeof(T) == 1) { // read/write chars as numbers.
int16 next_t; is >> next_t >> std::ws; if (is.fail()) goto bad; else tmp_v.push_back((T)next_t); } else { T next_t; is >> next_t >> std::ws; if (is.fail()) goto bad; else tmp_v.push_back(next_t); } } is.get(); // get the final ']'.
*v = tmp_v; // could use std::swap to use less temporary memory, but this
// uses less permanent memory.
} if (!is.fail()) return; bad: KALDI_ERR << "ReadIntegerVector: read failure at file position " << is.tellg(); }
// Initialize an opened stream for writing by writing an optional binary
// header and modifying the floating-point precision.
inline void InitKaldiOutputStream(std::ostream& os, bool binary) { // This does not throw exceptions (does not check for errors).
if (binary) { os.put('\0'); os.put('B'); } // Note, in non-binary mode we may at some point want to mess with
// the precision a bit.
// 7 is a bit more than the precision of float..
if (os.precision() < 7) os.precision(7); }
/// Initialize an opened stream for reading by detecting the binary header and
// setting the "binary" value appropriately.
inline bool InitKaldiInputStream(std::istream& is, bool* binary) { // Sets the 'binary' variable.
// Throws exception in the very unusual situation that stream
// starts with '\0' but not then 'B'.
if (is.peek() == '\0') { // seems to be binary
is.get(); if (is.peek() != 'B') { return false; } is.get(); *binary = true; return true; } else { *binary = false; return true; } }
} // end namespace kaldi.
#endif // KALDI_BASE_IO_FUNCS_INL_H_
|