From 157fda5445938edbe577b5dbcc2f4ffb63cb56f9 Mon Sep 17 00:00:00 2001 From: Antonin Portelli Date: Thu, 20 Feb 2014 23:52:45 +0000 Subject: [PATCH] simplification of IO interface --- examples/exMat.cpp | 2 +- examples/exRand.cpp | 6 +- latan/AsciiFile.cpp | 193 ++++++++++++++++++++++++++++++++++++++++++ latan/AsciiFile.hpp | 87 +++++++++++++++++++ latan/AsciiLexer.lpp | 95 +++++++++++++++++++++ latan/AsciiParser.ypp | 188 ++++++++++++++++++++++++++++++++++++++++ latan/Dataset.hpp | 45 +++++----- latan/File.cpp | 75 ++++++++++++++++ latan/File.hpp | 161 +++++++++++++++++++++++++++++++++++ latan/IoObject.hpp | 4 +- latan/Makefile.am | 12 +-- latan/RandGen.cpp | 21 +++-- latan/RandGen.hpp | 31 ++++--- utils/resample.cpp | 12 +-- utils/sample_read.cpp | 5 +- 15 files changed, 870 insertions(+), 67 deletions(-) create mode 100644 latan/AsciiFile.cpp create mode 100644 latan/AsciiFile.hpp create mode 100644 latan/AsciiLexer.lpp create mode 100644 latan/AsciiParser.ypp create mode 100644 latan/File.cpp create mode 100644 latan/File.hpp diff --git a/examples/exMat.cpp b/examples/exMat.cpp index 02609d0..45d95e2 100644 --- a/examples/exMat.cpp +++ b/examples/exMat.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/examples/exRand.cpp b/examples/exRand.cpp index 2229aaa..c50bfec 100644 --- a/examples/exRand.cpp +++ b/examples/exRand.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using namespace std; @@ -11,7 +11,7 @@ const string stateFileName = "exRand.seed"; int main(void) { - RandGen::State state; + RandGenState state; RandGen gen[2]; AsciiFile stateFile(stateFileName, File::Mode::write|File::Mode::read); @@ -31,7 +31,7 @@ int main(void) } cout << "-- setting up another generator from '" << stateFileName << "'..." << endl; - gen[1].setState(stateFile.read("exRand")); + gen[1].setState(stateFile.read("exRand")); cout << "-- generating a " << seqLength << " steps random sequence..." << endl; for (int i = 0; i < seqLength; ++i) diff --git a/latan/AsciiFile.cpp b/latan/AsciiFile.cpp new file mode 100644 index 0000000..61a965e --- /dev/null +++ b/latan/AsciiFile.cpp @@ -0,0 +1,193 @@ +/* + * AsciiFile.cpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#include +#include + +using namespace std; +using namespace Latan; + +/****************************************************************************** + * AsciiFile implementation * + ******************************************************************************/ +// AsciiParserState constructor //////////////////////////////////////////////// +AsciiFile::AsciiParserState::AsciiParserState(istream *stream, string *name, + IoDataTable *data) +: ParserState(stream, name, data) +{ + initScanner(); +} + +// AsciiParserState destructor ///////////////////////////////////////////////// +AsciiFile::AsciiParserState::~AsciiParserState(void) +{ + destroyScanner(); +} + +// constructor ///////////////////////////////////////////////////////////////// +AsciiFile::AsciiFile(void) +: File(), fileStream_() +, isParsed_(false) +, state_(nullptr) +{} + +AsciiFile::AsciiFile(const string &name, const unsigned int mode) +{ + open(name, mode); +} + +// destructor ////////////////////////////////////////////////////////////////// +AsciiFile::~AsciiFile(void) +{ + close(); +} + +// access ////////////////////////////////////////////////////////////////////// +void AsciiFile::save(const DMat &m, const std::string &name) +{ + checkWritability(); + isParsed_ = false; + fileStream_ << "#L latan_begin mat " << name << endl; + fileStream_ << m.cols() << endl; + fileStream_ << scientific << m << endl; + fileStream_ << "#L latan_end mat " << endl; +} + +void AsciiFile::save(const DMatSample &s, const std::string &name) +{ + checkWritability(); + isParsed_ = false; + fileStream_ << "#L latan_begin rs_sample " << name << endl; + fileStream_ << s.size() << endl; + save(s[central], name + "_C"); + for (int i = 0; i < static_cast(s.size()); ++i) + { + save(s[i], name + "_S_" + strFrom(i)); + } + fileStream_ << "#L latan_end rs_sample " << endl; +} + +void AsciiFile::save(const RandGenState &state, const std::string &name) +{ + checkWritability(); + isParsed_ = false; + fileStream_ << "#L latan_begin rg_state " << name << endl; + fileStream_ << state << endl; + fileStream_ << "#L latan_end rg_state " << endl; +} + +// tests /////////////////////////////////////////////////////////////////////// +bool AsciiFile::isOpen() const +{ + return fileStream_.is_open(); +} + +// IO ////////////////////////////////////////////////////////////////////////// +void AsciiFile::close(void) +{ + state_.reset(); + if (isOpen()) + { + fileStream_.close(); + } + name_ = ""; + mode_ = Mode::null; + isParsed_ = false; + deleteData(); +} + +void AsciiFile::open(const string &name, const unsigned int mode) +{ + if (isOpen()) + { + LATAN_ERROR(Io, "file already opened with name '" + name_ + "'"); + } + else + { + ios_base::openmode stdMode = static_cast(0); + + if (mode & Mode::write) + { + stdMode |= ios::out|ios::trunc; + } + if (mode & Mode::read) + { + stdMode |= ios::in; + } + if (mode & Mode::append) + { + stdMode |= ios::out|ios::app; + } + name_ = name; + mode_ = mode; + isParsed_ = false; + fileStream_.open(name_.c_str(), stdMode); + if (mode_ & Mode::read) + { + state_.reset(new AsciiParserState(&fileStream_, &name_, &data_)); + } + else + { + state_.reset(); + } + } +} + +std::string AsciiFile::load(const string &name) +{ + if ((mode_ & Mode::read)&&(isOpen())) + { + if (!isParsed_) + { + state_->isFirst = true; + parse(); + } + if (name.empty()) + { + return state_->first; + } + else + { + return name; + } + } + else + { + if (isOpen()) + { + LATAN_ERROR(Io, "file '" + name_ + "' is not opened in read mode"); + } + else + { + LATAN_ERROR(Io, "file not opened"); + } + } +} + +// parser ////////////////////////////////////////////////////////////////////// + +//// Bison/Flex parser declaration +int _Ascii_parse(AsciiFile::AsciiParserState *state); + +void AsciiFile::parse() +{ + fileStream_.seekg(0); + _Ascii_parse(state_.get()); + isParsed_ = true; +} diff --git a/latan/AsciiFile.hpp b/latan/AsciiFile.hpp new file mode 100644 index 0000000..6bb8559 --- /dev/null +++ b/latan/AsciiFile.hpp @@ -0,0 +1,87 @@ +/* + * AsciiFile.hpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#ifndef Latan_AsciiFile_hpp_ +#define Latan_AsciiFile_hpp_ + +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE + +/****************************************************************************** + * ASCII datafile class * + ******************************************************************************/ +class AsciiFile: public File +{ +public: + class AsciiParserState: public ParserState + { + public: + // constructor + explicit AsciiParserState(std::istream *stream, std::string *name, + IoDataTable *data); + // destructor + virtual ~AsciiParserState(void); + // first element reference + bool isFirst; + std::string first; + // parsing buffers + RandGenState stateBuf; + DMatSample dMatSampleBuf; + std::queue dMatQueue; + std::queue doubleQueue; + std::queue intQueue; + private: + // allocation/deallocation functions defined in IoAsciiLexer.lpp + virtual void initScanner(void); + virtual void destroyScanner(void); + }; +public: + // constructors + AsciiFile(void); + AsciiFile(const std::string &name, const unsigned int mode); + // destructor + virtual ~AsciiFile(void); + // access + virtual void save(const DMat &m, const std::string &name); + virtual void save(const DMatSample &s, const std::string &name); + virtual void save(const RandGenState &state, const std::string &name); + // tests + virtual bool isOpen(void) const; + // IO + virtual void close(void); + virtual void open(const std::string &name, const unsigned int mode); +private: + // IO + virtual std::string load(const std::string &name = ""); + // parser + void parse(void); +private: + std::fstream fileStream_; + bool isParsed_; + std::unique_ptr state_; +}; + +END_NAMESPACE + +#endif // Latan_AsciiFile_hpp_ diff --git a/latan/AsciiLexer.lpp b/latan/AsciiLexer.lpp new file mode 100644 index 0000000..8e91f24 --- /dev/null +++ b/latan/AsciiLexer.lpp @@ -0,0 +1,95 @@ +/* + * IoAsciiLexer.lpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +%option reentrant +%option prefix="_Ascii_" +%option bison-bridge +%option bison-locations +%option noyywrap +%option yylineno + +%{ + #include + #include + #include + #pragma GCC diagnostic ignored "-Wsign-compare" + #pragma GCC diagnostic ignored "-Wunused-function" + #pragma GCC diagnostic ignored "-Wunused-parameter" + + using namespace std; + using namespace Latan; + + #define YY_EXTRA_TYPE AsciiFile::AsciiParserState* + #define YY_USER_ACTION \ + yylloc->first_line = yylloc->last_line = yylineno;\ + yylloc->first_column = yylloc->last_column + 1;\ + yylloc->last_column = yylloc->first_column + yyleng - 1; + + #define YY_INPUT(buf, result, max_size) \ + { \ + (*yyextra->stream).read(buf,max_size);\ + result = (*yyextra->stream).gcount();\ + } + + #define YY_DEBUG 0 + #if (YY_DEBUG == 1) + #define RETTOK(tok) cout << #tok << "(" << yytext << ")" << endl; return tok + #else + #define RETTOK(tok) return tok + #endif +%} + +DIGIT [0-9] +ALPHA [a-zA-Z_\-] +SIGN \+|- +EXP e|E +INT {SIGN}?{DIGIT}+ +FLOAT {SIGN}?(({DIGIT}+\.{DIGIT}*)|({DIGIT}*\.{DIGIT}+))({EXP}{SIGN}?{INT}+)? +LMARK #L +BLANK [ \t] + +%x MARK TYPE + +%% + +{LMARK} {BEGIN(MARK);} +{INT} {yylval->val_int = strTo(yytext); RETTOK(INT);} +{FLOAT} {yylval->val_double = strTo(yytext); RETTOK(FLOAT);} +({ALPHA}|{DIGIT})+ {strcpy(yylval->val_str,yytext); RETTOK(ID);} +latan_begin {BEGIN(TYPE); RETTOK(OPEN);} +latan_end {BEGIN(TYPE); RETTOK(CLOSE);} +mat {BEGIN(INITIAL); RETTOK(MAT);} +rs_sample {BEGIN(INITIAL); RETTOK(SAMPLE);} +rg_state {BEGIN(INITIAL); RETTOK(RG_STATE);} +<*>\n {yylloc->last_column = 0;} +<*>[ \t] +<*>. {yylval->val_char = yytext[0]; RETTOK(ERR);} + +%% + +void AsciiFile::AsciiParserState::initScanner() +{ + yylex_init(&scanner); + yyset_extra(this, scanner); +} + +void AsciiFile::AsciiParserState::destroyScanner() +{ + yylex_destroy(scanner); +} diff --git a/latan/AsciiParser.ypp b/latan/AsciiParser.ypp new file mode 100644 index 0000000..6665caa --- /dev/null +++ b/latan/AsciiParser.ypp @@ -0,0 +1,188 @@ +/* + * IoAsciiParser.ypp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +%{ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + using namespace std; + using namespace Latan; + + #define TEST_FIRST(name) \ + if (state->isFirst)\ + {\ + state->first = (name);\ + state->isFirst = false;\ + } +%} + +%pure-parser +%name-prefix="_Ascii_" +%locations +%defines +%error-verbose +%parse-param { Latan::AsciiFile::AsciiParserState* state } +%initial-action {yylloc.last_column = 0;} +%lex-param { void* scanner } + +%union +{ + int val_int; + double val_double; + char val_char; + char val_str[256]; +} + +%token ERR +%token FLOAT +%token INT +%token ID +%token OPEN CLOSE MAT SAMPLE RG_STATE + +%type mat sample rg_state + +%{ + int _Ascii_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner); + + void _Ascii_error(YYLTYPE* locp, AsciiFile::AsciiParserState* state, + const char* err) + { + stringstream buf; + + buf << *state->streamName << ":" << locp->first_line << ":"\ + << locp->first_column << ": " << err; + LATAN_ERROR(Parsing, buf.str()); + } + + #define scanner state->scanner +%} + +%% + +datas: + /* empty string */ + | datas data + ; + +data: + mat + { + TEST_FIRST($1); + (*state->data)[$1].reset(new DMat(state->dMatQueue.front())); + state->dMatQueue.pop(); + } + | sample + { + TEST_FIRST($1); + (*state->data)[$1].reset(new DMatSample(state->dMatSampleBuf)); + } + | rg_state + { + TEST_FIRST($1); + (*state->data)[$1].reset(new RandGenState(state->stateBuf)); + } + ; + +mat: + OPEN MAT ID INT floats CLOSE MAT + { + const unsigned int nRow = state->doubleQueue.size()/$INT, nCol = $INT; + int i, j, r = 0; + + if (state->doubleQueue.size() != nRow*nCol) + { + LATAN_ERROR(Size, "matrix '" + *state->streamName + ":" + $ID + + "' has a wrong size"); + } + + state->dMatQueue.push(DMat(nRow, nCol)); + while (!state->doubleQueue.empty()) + { + j = r % nCol; + i = (r - j)/nCol; + state->dMatQueue.back()(i, j) = state->doubleQueue.front(); + state->doubleQueue.pop(); + r++; + } + strcpy($$, $ID); + } + ; + +sample: + OPEN SAMPLE ID INT mats CLOSE SAMPLE + { + const unsigned int nSample = $INT + 1; + + if (state->dMatQueue.size() != nSample) + { + LATAN_ERROR(Size, "sample '" + *state->streamName + ":" + $ID + + "' has a wrong size"); + } + state->dMatSampleBuf.resize(nSample); + state->dMatSampleBuf[central] = state->dMatQueue.front(); + state->dMatQueue.pop(); + for (int i = 0; i < $INT; ++i) + { + state->dMatSampleBuf[i] = state->dMatQueue.front(); + state->dMatQueue.pop(); + } + strcpy($$, $ID); + } + +rg_state: + OPEN RG_STATE ID ints CLOSE RG_STATE + { + if (state->intQueue.size() != RLXG_STATE_SIZE) + { + LATAN_ERROR(Size, "random generator state '" + *state->streamName + + ":" + $ID + "' has a wrong size"); + } + for (unsigned int i = 0; i < RLXG_STATE_SIZE; ++i) + { + state->stateBuf[i] = state->intQueue.front(); + state->intQueue.pop(); + } + strcpy($$, $ID); + } + ; + +mats: + mats mat + | mat + ; + +floats: + floats FLOAT {state->doubleQueue.push($FLOAT);} + | floats INT {state->doubleQueue.push(static_cast($INT));} + | FLOAT {state->doubleQueue.push($FLOAT);} + | INT {state->doubleQueue.push(static_cast($INT));} + ; + +ints: + ints INT {state->intQueue.push($INT);} + | INT {state->intQueue.push($INT);} + ; diff --git a/latan/Dataset.hpp b/latan/Dataset.hpp index fd3844f..336137c 100644 --- a/latan/Dataset.hpp +++ b/latan/Dataset.hpp @@ -21,7 +21,7 @@ #define Latan_Dataset_hpp_ #include -#include +#include #include #include #include @@ -32,7 +32,7 @@ BEGIN_NAMESPACE /****************************************************************************** * Dataset class * ******************************************************************************/ -template +template class Dataset: public StatArray { private: @@ -41,40 +41,43 @@ public: // constructors using Base::Base; Dataset(void); + template Dataset(const std::string &listFileName, const std::string &dataName); // destructor virtual ~Dataset(void) = default; // IO + template void load(const std::string &listFileName, const std::string &dataName); // resampling Sample bootstrapMean(const unsigned int nSample, RandGen& generator); private: // mean from pointer vector for resampling void ptVectorMean(T &m, const std::vector &v); -private: - FileType file_; }; /****************************************************************************** * Dataset template implementation * ******************************************************************************/ // constructor ///////////////////////////////////////////////////////////////// -template -Dataset::Dataset(void) +template +Dataset::Dataset(void) {} -template -Dataset::Dataset(const std::string &listFileName, - const std::string &dataName) +template +template +Dataset::Dataset(const std::string &listFileName, + const std::string &dataName) { - load(listFileName, dataName); + load(listFileName, dataName); } // IO ////////////////////////////////////////////////////////////////////////// -template -void Dataset::load(const std::string &listFileName, - const std::string &dataName) +template +template +void Dataset::load(const std::string &listFileName, + const std::string &dataName) { + FileType file; std::ifstream listFile; char dataFileNameBuf[MAX_PATH_LENGTH]; std::vector dataFileName; @@ -92,16 +95,16 @@ void Dataset::load(const std::string &listFileName, this->resize(dataFileName.size()); for (unsigned int i = 0; i < dataFileName.size(); ++i) { - file_.open(dataFileName[i], File::Mode::read); - (*this)[i] = file_.template read(dataName); - file_.close(); + file.open(dataFileName[i], File::Mode::read); + (*this)[i] = file.template read(dataName); + file.close(); } } // resampling ////////////////////////////////////////////////////////////////// -template -Sample Dataset::bootstrapMean(const unsigned int nSample, - RandGen& generator) +template +Sample Dataset::bootstrapMean(const unsigned int nSample, + RandGen& generator) { unsigned int nData = this->size(); std::vector data(nData); @@ -124,8 +127,8 @@ Sample Dataset::bootstrapMean(const unsigned int nSample, return s; } -template -void Dataset::ptVectorMean(T &m, const std::vector &v) +template +void Dataset::ptVectorMean(T &m, const std::vector &v) { if (v.size()) { diff --git a/latan/File.cpp b/latan/File.cpp new file mode 100644 index 0000000..105edd3 --- /dev/null +++ b/latan/File.cpp @@ -0,0 +1,75 @@ +/* + * File.cpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#include +#include + +using namespace std; +using namespace Latan; + +/****************************************************************************** + * File implementation * + ******************************************************************************/ +// constructors //////////////////////////////////////////////////////////////// +File::File(void) +: name_("") +, mode_(Mode::null) +, data_() +{} + +File::File(const string &name, const unsigned int mode) +: name_(name) +, mode_(mode) +, data_() +{} + +// destructor ////////////////////////////////////////////////////////////////// +File::~File(void) +{ + deleteData(); +} + +// access ////////////////////////////////////////////////////////////////////// +const string & File::getName(void) const +{ + return name_; +} + +unsigned int File::getMode(void) const +{ + return mode_; +} + +// internal functions ////////////////////////////////////////////////////////// +void File::deleteData(void) +{ + for (auto &i : data_) + { + i.second.reset(); + } + data_.clear(); +} + +void File::checkWritability(void) +{ + if (!((mode_ & Mode::write)||(mode_ & Mode::append))||!isOpen()) + { + LATAN_ERROR(Io, "file '" + name_ + "' is not writable"); + } +} diff --git a/latan/File.hpp b/latan/File.hpp new file mode 100644 index 0000000..4975b4b --- /dev/null +++ b/latan/File.hpp @@ -0,0 +1,161 @@ +/* + * File.hpp, part of LatAnalyze 3 + * + * Copyright (C) 2013 - 2014 Antonin Portelli + * + * LatAnalyze 3 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LatAnalyze 3 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LatAnalyze 3. If not, see . + */ + +#ifndef Latan_Io_hpp_ +#define Latan_Io_hpp_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE + +// forward declaration of IO types +class DMat; +class DMatSample; +class RandGen; +class RandGenState; + +/****************************************************************************** + * Abstract datafile class * + ******************************************************************************/ +typedef std::unordered_map> IoDataTable; + +class File +{ +public: + class Mode + { + public: + enum + { + null = 0, + write = 1 << 0, + read = 1 << 1, + append = 1 << 2 + }; + }; +public: + // constructors + File(void); + File(const std::string &name, const unsigned int mode); + // destructor + virtual ~File(void); + // access + const std::string & getName(void) const; + unsigned int getMode(void) const; + template + const IoT & read(const std::string &name = ""); + virtual void save(const DMat &m, const std::string &name) = 0; + virtual void save(const DMatSample &state, const std::string &name) = 0; + virtual void save(const RandGenState &state, const std::string &name) = 0; + // tests + virtual bool isOpen(void) const = 0; + // IO + virtual void close(void) = 0; + virtual void open(const std::string &name, const unsigned int mode) = 0; + // static IO functions + +protected: + // access + void setName(const std::string &name); + void setMode(const unsigned int mode); + // data access + void deleteData(void); + // error checking + void checkWritability(void); +private: + // data access + template + const IoT& getData(const std::string &name = "") const; + // IO + virtual std::string load(const std::string &name = "") = 0; +protected: + std::string name_; + unsigned int mode_; + IoDataTable data_; +}; + +// Template implementations +template +const IoT& File::read(const std::string &name) +{ + std::string dataName; + + dataName = load(name); + + return getData(dataName); +} + +template +const IoT& File::getData(const std::string &name) const +{ + try + { + return dynamic_cast(*(data_.at(name))); + } + catch(std::out_of_range) + { + LATAN_ERROR(Definition, "no data with name '" + name + "' in file " + + name_); + } +} + +/****************************************************************************** + * Static IO functions * + ******************************************************************************/ +class Io +{ +public: + template + static IoT load(const std::string &fileName, const std::string &name = ""); + template + static void save(const IoT &data, const std::string &fileName, + const unsigned int mode = File::Mode::append, + const std::string &name = ""); +}; + +// template implementation ///////////////////////////////////////////////////// +template +IoT Io::load(const std::string &fileName, const std::string &name) +{ + FileType file(fileName, File::Mode::read); + + return file.template read(name); +} + +template +void Io::save(const IoT &data, const std::string &fileName, + const unsigned int mode, const std::string &name) +{ + FileType file(fileName, mode); + std::string realName = (name.empty()) ? fileName : name; + + file.template save(data, realName); +} + +END_NAMESPACE + +#endif diff --git a/latan/IoObject.hpp b/latan/IoObject.hpp index d376fa0..2912023 100644 --- a/latan/IoObject.hpp +++ b/latan/IoObject.hpp @@ -24,7 +24,9 @@ BEGIN_NAMESPACE -// Abstract base for IO objects +/****************************************************************************** + * Abstract class for IO objects * + ******************************************************************************/ class IoObject { public: diff --git a/latan/Makefile.am b/latan/Makefile.am index 2055b1f..373ada5 100644 --- a/latan/Makefile.am +++ b/latan/Makefile.am @@ -20,19 +20,20 @@ AM_YFLAGS = -d include eigen_files.mk nobase_dist_pkginclude_HEADERS = $(eigen_files) -BUILT_SOURCES = IoAsciiParser.hpp MathParser.hpp +BUILT_SOURCES = AsciiParser.hpp MathParser.hpp lib_LTLIBRARIES = liblatan.la liblatan_la_SOURCES = \ + AsciiFile.cpp \ + AsciiParser.ypp \ + AsciiLexer.lpp \ CompiledFunction.cpp\ Exceptions.cpp \ Function.cpp \ Global.cpp \ includes.hpp \ - Io.cpp \ - IoAsciiParser.ypp \ - IoAsciiLexer.lpp \ + File.cpp \ Mat.cpp \ Math.cpp \ MathInterpreter.cpp \ @@ -45,11 +46,12 @@ liblatan_la_SOURCES = \ ../config.h liblatan_ladir = $(pkgincludedir) liblatan_la_HEADERS = \ + AsciiFile.hpp \ CompiledFunction.hpp\ Dataset.hpp \ Function.hpp \ Global.hpp \ - Io.hpp \ + File.hpp \ IoObject.hpp \ Mat.hpp \ Math.hpp \ diff --git a/latan/RandGen.cpp b/latan/RandGen.cpp index 5ba31a7..0517b08 100644 --- a/latan/RandGen.cpp +++ b/latan/RandGen.cpp @@ -28,18 +28,17 @@ using namespace std; using namespace Latan; /****************************************************************************** - * RandGen implementation * + * RandGenState implementation * ******************************************************************************/ -// State constructor /////////////////////////////////////////////////////////// -RandGen::State::State(void) -{} - -// State IO type /////////////////////////////////////////////////////////////// -IoObject::IoType RandGen::State::getType(void) const +// IO type /////////////////////////////////////////////////////////////// +IoObject::IoType RandGenState::getType(void) const { return IoType::rgState; } +/****************************************************************************** + * RandGen implementation * + ******************************************************************************/ // RanLxd implementation /////////////////////////////////////////////////////// RandGen::RanLxd::RanLxd(void) : init(0) @@ -640,22 +639,22 @@ RandGen::RandGen(const int seed) generator_.rlxd_init(RLXD_LEVEL, seed); } -RandGen::RandGen(const State &state) +RandGen::RandGen(const RandGenState &state) { setState(state); } // state management //////////////////////////////////////////////////////////// -RandGen::State RandGen::getState(void) const +RandGenState RandGen::getState(void) const { - State state; + RandGenState state; generator_.rlxd_get(state.data()); return state; } -void RandGen::setState(const State &state) +void RandGen::setState(const RandGenState &state) { generator_.rlxd_reset(state.data()); } diff --git a/latan/RandGen.hpp b/latan/RandGen.hpp index 84cef25..c144fbc 100644 --- a/latan/RandGen.hpp +++ b/latan/RandGen.hpp @@ -27,25 +27,24 @@ BEGIN_NAMESPACE +class RandGenState: public Eigen::Array, + public IoObject +{ +private: + typedef Eigen::Array Base; +public: + // destructor + virtual ~RandGenState(void) = default; + // IO type + IoType getType(void) const; +}; + /****************************************************************************** * Random generator class * ******************************************************************************/ class RandGen { -public: - class State: public Eigen::Array, public IoObject - { - private: - typedef Eigen::Array Base; - public: - // constructor - State(void); - // destructor - virtual ~State(void) = default; - // IO type - IoType getType(void) const; - }; private: // Martin Luescher's ranlxd generator interface class RanLxd @@ -85,12 +84,12 @@ public: // constructors RandGen(void); RandGen(const int seed); - RandGen(const State &state); + RandGen(const RandGenState &state); // destructor virtual ~RandGen(void) = default; // state management - State getState(void) const; - void setState(const State &state); + RandGenState getState(void) const; + void setState(const RandGenState &state); // generators double uniform(const double a = 0.0, const double b = 1.0); double discreteUniform(const unsigned int n); diff --git a/utils/resample.cpp b/utils/resample.cpp index f477a56..b8eb838 100644 --- a/utils/resample.cpp +++ b/utils/resample.cpp @@ -1,8 +1,8 @@ #include #include #include +#include #include -#include #ifndef DEF_NSAMPLE #define DEF_NSAMPLE 100u @@ -60,25 +60,25 @@ int main(int argc, char *argv[]) usage(cmdName); } - Dataset dataset; + Dataset dataset; DMatSample s; RandGen g; if (!stateFileName.empty()) { AsciiFile f(stateFileName, File::Mode::read); - g.setState(f.read()); + g.setState(f.read()); } cout << "-- loading data from manifest '" << manFileName << "'..." << endl; - dataset.load(manFileName, name); + dataset.load(manFileName, name); s = dataset.bootstrapMean(nSample, g); cout << scientific; cout << "central value:\n" << s[central] << endl; cout << "standard deviation:\n" << s.variance().cwiseSqrt() << endl; if (!outFileName.empty()) { - AsciiFile f(outFileName, File::Mode::write); - f.save(s, manFileName + "_" + name); + Io::save(s, outFileName, File::Mode::write, + manFileName + "_" + name); } return EXIT_SUCCESS; diff --git a/utils/sample_read.cpp b/utils/sample_read.cpp index 6e6fae0..125a1f4 100644 --- a/utils/sample_read.cpp +++ b/utils/sample_read.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace std; using namespace Latan; @@ -13,10 +13,9 @@ int main(int argc, char *argv[]) } string fileName = argv[1]; - AsciiFile f(fileName, File::Mode::read); cout << "-- loading sample from '" << fileName << "'..." << endl; - const DMatSample &s = f.read(); + const DMatSample &s = Io::load(fileName); cout << scientific; cout << "central value:\n" << s[central] << endl; cout << "standard deviation:\n" << s.variance().cwiseSqrt() << endl;