// util/kaldi-holder-inl.h
// Copyright 2009-2011 Microsoft Corporation
// 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_UTIL_KALDI_HOLDER_INL_H_
#define KALDI_UTIL_KALDI_HOLDER_INL_H_
#include <algorithm>
#include "util/kaldi-io.h"
#include "util/text-utils.h"
#include "matrix/kaldi-matrix.h"
namespace kaldi {
/// \addtogroup holders
/// @{
// KaldiObjectHolder is valid only for Kaldi objects with
// copy constructors, default constructors, and "normal"
// Kaldi Write and Read functions. E.g. it works for
// Matrix and Vector.
template<class KaldiType> class KaldiObjectHolder {
public:
typedef KaldiType T;
KaldiObjectHolder(): t_(NULL) { }
static bool Write(std::ostream &os, bool binary, const T &t) {
InitKaldiOutputStream(os, binary); // Puts binary header if binary mode.
try {
t.Write(os, binary);
return os.good();
} catch (const std::exception &e) {
KALDI_WARN << "Exception caught writing Table object: " << e.what();
if (!IsKaldiError(e.what())) { std::cerr << e.what(); }
return false; // Write failure.
}
}
void Clear() {
if (t_) {
delete t_;
t_ = NULL;
}
}
// Reads into the holder.
bool Read(std::istream &is) {
if (t_) delete t_;
t_ = new T;
// Don't want any existing state to complicate the read functioN: get new object.
bool is_binary;
if (!InitKaldiInputStream(is, &is_binary)) {
KALDI_WARN << "Reading Table object, failed reading binary header\n";
return false;
}
try {
t_->Read(is, is_binary);
return true;
} catch (std::exception &e) {
KALDI_WARN << "Exception caught reading Table object ";
if (!IsKaldiError(e.what())) { std::cerr << e.what(); }
delete t_;
t_ = NULL;
return false;
}
}
// Kaldi objects always have the stream open in binary mode for
// reading.
static bool IsReadInBinary() { return true; }
const T &Value() const {
// code error if !t_.
if (!t_) KALDI_ERR << "KaldiObjectHolder::Value() called wrongly.";
return *t_;
}
~KaldiObjectHolder() { if (t_) delete t_; }
private:
KALDI_DISALLOW_COPY_AND_ASSIGN(KaldiObjectHolder);
T *t_;
};
// BasicHolder is valid for float, double, bool, and integer
// types. There will be a compile time error otherwise, because
// we make sure that the {Write, Read}BasicType functions do not
// get instantiated for other types.
template<class BasicType> class BasicHolder {
public:
typedef BasicType T;
BasicHolder(): t_(static_cast<T>(-1)) { }
static bool Write(std::ostream &os, bool binary, const T &t) {
InitKaldiOutputStream(os, binary); // Puts binary header if binary mode.
try {
WriteBasicType(os, binary, t);
if (!binary) os << '\n'; // Makes output format more readable and
// easier to manipulate.
return os.good();
} catch (const std::exception &e) {
KALDI_WARN << "Exception caught writing Table object: " << e.what();
if (!IsKaldiError(e.what())) { std::cerr << e.what(); }
return false; // Write failure.
}
}
void Clear() { }
// Reads into the holder.
bool Read(std::istream &is) {
bool is_binary;
if (!InitKaldiInputStream(is, &is_binary)) {
KALDI_WARN << "Reading Table object [integer type], failed reading binary header\n";
return false;
}
try {
int c;
if (!is_binary) { // This is to catch errors, the class would work without it..
// Eat up any whitespace and make sure it's not newline.
while (isspace((c = is.peek())) && c != static_cast<int>('\n')) is.get();
if (is.peek() == '\n') {
KALDI_WARN << "Found newline but expected basic type.";
return false; // This is just to catch a more-
// likely-than average type of error (empty line before the token), since
// ReadBasicType will eat it up.
}
}
ReadBasicType(is, is_binary, &t_);
if (!is_binary) { // This is to catch errors, the class would work without it..
// make sure there is a newline.
while (isspace((c = is.peek())) && c != static_cast<int>('\n')) is.get();
if (is.peek() != '\n') {
KALDI_WARN << "BasicHolder::Read, expected newline, got "
<< CharToString(is.peek()) << ", position " << is.tellg();
return false;
}
is.get(); // Consume the newline.
}
return true;
} catch (std::exception &e) {
KALDI_WARN << "Exception caught reading Table object";
if (!IsKaldiError(e.what())) { std::cerr << e.what(); }
return false;
}
}
// Objects read/written with the Kaldi I/O functions always have the stream
// open in binary mode for reading.
static bool IsReadInBinary() { return true; }
const T &Value() const {
return t_;
}
~BasicHolder() { }
private:
KALDI_DISALLOW_COPY_AND_AS