mirror of
https://github.com/aportelli/LatAnalyze.git
synced 2025-06-17 14:57:05 +01:00
reintegration of LatCore & folder restructuration
This commit is contained in:
212
lib/Io/AsciiFile.cpp
Normal file
212
lib/Io/AsciiFile.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* AsciiFile.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/AsciiFile.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
/******************************************************************************
|
||||
* AsciiFile implementation *
|
||||
******************************************************************************/
|
||||
// AsciiParserState constructor ////////////////////////////////////////////////
|
||||
AsciiFile::AsciiParserState::AsciiParserState(istream *stream, string *name,
|
||||
IoDataTable *data)
|
||||
: ParserState<IoDataTable>(stream, name, data)
|
||||
{
|
||||
initScanner();
|
||||
}
|
||||
|
||||
// AsciiParserState destructor /////////////////////////////////////////////////
|
||||
AsciiFile::AsciiParserState::~AsciiParserState(void)
|
||||
{
|
||||
destroyScanner();
|
||||
}
|
||||
|
||||
// constructor /////////////////////////////////////////////////////////////////
|
||||
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)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
const auto defaultPrec = fileStream_.precision(defaultDoublePrec);
|
||||
|
||||
checkWritability();
|
||||
isParsed_ = false;
|
||||
fileStream_ << "#L latan_begin mat " << name << endl;
|
||||
fileStream_ << m.cols() << endl;
|
||||
fileStream_ << scientific << m << endl;
|
||||
fileStream_ << "#L latan_end mat " << endl;
|
||||
fileStream_.precision(defaultPrec);
|
||||
}
|
||||
|
||||
void AsciiFile::save(const DSample &ds, const std::string &name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
checkWritability();
|
||||
isParsed_ = false;
|
||||
fileStream_ << "#L latan_begin rs_sample " << name << endl;
|
||||
fileStream_ << ds.size() << endl;
|
||||
save(ds.matrix(), name + "_data");
|
||||
fileStream_ << "#L latan_end rs_sample " << endl;
|
||||
}
|
||||
|
||||
void AsciiFile::save(const DMatSample &ms, const std::string &name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
checkWritability();
|
||||
isParsed_ = false;
|
||||
fileStream_ << "#L latan_begin rs_sample " << name << endl;
|
||||
fileStream_ << ms.size() << endl;
|
||||
save(ms[central], name + "_C");
|
||||
for (Index i = 0; i < ms.size(); ++i)
|
||||
{
|
||||
save(ms[i], name + "_S_" + strFrom(i));
|
||||
}
|
||||
fileStream_ << "#L latan_end rs_sample " << endl;
|
||||
}
|
||||
|
||||
// read first name ////////////////////////////////////////////////////////////
|
||||
string AsciiFile::getFirstName(void)
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
// 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<ios_base::openmode>(0);
|
||||
|
||||
name_ = name;
|
||||
mode_ = mode;
|
||||
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;
|
||||
}
|
||||
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) and (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 '" + name_ + "' is 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;
|
||||
}
|
92
lib/Io/AsciiFile.hpp
Normal file
92
lib/Io/AsciiFile.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* AsciiFile.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_AsciiFile_hpp_
|
||||
#define Latan_AsciiFile_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/File.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/Statistics/MatSample.hpp>
|
||||
#include <LatAnalyze/Core/ParserState.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* ASCII datafile class *
|
||||
******************************************************************************/
|
||||
class AsciiFile: public File
|
||||
{
|
||||
public:
|
||||
class AsciiParserState: public ParserState<IoDataTable>
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
AsciiParserState(std::istream *stream, std::string *name,
|
||||
IoDataTable *data);
|
||||
// destructor
|
||||
virtual ~AsciiParserState(void);
|
||||
// first element reference
|
||||
bool isFirst;
|
||||
std::string first;
|
||||
// parsing buffers
|
||||
int intBuf;
|
||||
DSample dSampleBuf;
|
||||
DMatSample dMatSampleBuf;
|
||||
std::queue<DMat> dMatQueue;
|
||||
std::queue<double> doubleQueue;
|
||||
private:
|
||||
// allocation/deallocation functions defined in IoAsciiLexer.lpp
|
||||
virtual void initScanner(void);
|
||||
virtual void destroyScanner(void);
|
||||
};
|
||||
public:
|
||||
// constructors
|
||||
AsciiFile(void) = default;
|
||||
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 DSample &ds, const std::string &name);
|
||||
virtual void save(const DMatSample &ms, const std::string &name);
|
||||
// read first name
|
||||
virtual std::string getFirstName(void);
|
||||
// tests
|
||||
virtual bool isOpen(void) const;
|
||||
// IO
|
||||
virtual void close(void);
|
||||
virtual void open(const std::string &name, const unsigned int mode);
|
||||
public:
|
||||
// default ASCII precision
|
||||
static const unsigned int defaultDoublePrec = 15;
|
||||
private:
|
||||
// IO
|
||||
virtual std::string load(const std::string &name = "");
|
||||
// parser
|
||||
void parse(void);
|
||||
private:
|
||||
std::fstream fileStream_;
|
||||
bool isParsed_{false};
|
||||
std::unique_ptr<AsciiParserState> state_{nullptr};
|
||||
};
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_AsciiFile_hpp_
|
91
lib/Io/AsciiLexer.lpp
Normal file
91
lib/Io/AsciiLexer.lpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* AsciiLexer.lpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
%option reentrant
|
||||
%option prefix="_Ascii_"
|
||||
%option bison-bridge
|
||||
%option bison-locations
|
||||
%option noyywrap
|
||||
%option yylineno
|
||||
|
||||
%{
|
||||
#include <LatAnalyze/Io/AsciiFile.hpp>
|
||||
#include "AsciiParser.hpp"
|
||||
|
||||
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<long int>(yytext); RETTOK(INT);}
|
||||
{FLOAT} {yylval->val_double = strTo<double>(yytext); RETTOK(FLOAT);}
|
||||
({ALPHA}|{DIGIT})+ {strcpy(yylval->val_str,yytext); RETTOK(ID);}
|
||||
<MARK>latan_begin {BEGIN(TYPE); RETTOK(OPEN);}
|
||||
<MARK>latan_end {BEGIN(TYPE); RETTOK(CLOSE);}
|
||||
<TYPE>mat {BEGIN(INITIAL); RETTOK(MAT);}
|
||||
<TYPE>rs_sample {BEGIN(INITIAL); RETTOK(SAMPLE);}
|
||||
<TYPE>rg_state {BEGIN(INITIAL); RETTOK(RG_STATE);}
|
||||
<*>\r*\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);
|
||||
}
|
183
lib/Io/AsciiParser.ypp
Normal file
183
lib/Io/AsciiParser.ypp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* AsciiParser.ypp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/AsciiFile.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/Statistics/MatSample.hpp>
|
||||
|
||||
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
|
||||
{
|
||||
long int val_int;
|
||||
double val_double;
|
||||
char val_char;
|
||||
char val_str[256];
|
||||
}
|
||||
|
||||
%token <val_char> ERR
|
||||
%token <val_double> FLOAT
|
||||
%token <val_int> INT
|
||||
%token <val_str> ID
|
||||
%token OPEN CLOSE MAT SAMPLE RG_STATE
|
||||
|
||||
%type <val_str> mat matsample dsample
|
||||
|
||||
%{
|
||||
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();
|
||||
}
|
||||
| dsample
|
||||
{
|
||||
TEST_FIRST($1);
|
||||
(*state->data)[$1].reset(new DSample(state->dSampleBuf));
|
||||
}
|
||||
| matsample
|
||||
{
|
||||
TEST_FIRST($1);
|
||||
(*state->data)[$1].reset(new DMatSample(state->dMatSampleBuf));
|
||||
}
|
||||
;
|
||||
|
||||
mat:
|
||||
OPEN MAT ID INT floats CLOSE MAT
|
||||
{
|
||||
const unsigned int nRow = state->doubleQueue.size()/$4, nCol = $4;
|
||||
Index i, j, r = 0;
|
||||
|
||||
if (state->doubleQueue.size() != nRow*nCol)
|
||||
{
|
||||
LATAN_ERROR(Size, "matrix '" + *state->streamName + ":" + $3 +
|
||||
"' 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($$, $3);
|
||||
}
|
||||
;
|
||||
|
||||
dsample:
|
||||
OPEN SAMPLE ID INT mat CLOSE SAMPLE
|
||||
{
|
||||
const unsigned int nSample = $4, os = DMatSample::offset;
|
||||
|
||||
DMat &m = state->dMatQueue.front();
|
||||
if (m.rows() != nSample + os)
|
||||
{
|
||||
LATAN_ERROR(Size, "double sample '" + *state->streamName + ":"
|
||||
+ $3 + "' has a wrong size");
|
||||
}
|
||||
if (m.cols() != 1)
|
||||
{
|
||||
LATAN_ERROR(Size, "double sample '" + *state->streamName + ":"
|
||||
+ $3 + "' is not stored as a column vector");
|
||||
}
|
||||
state->dSampleBuf = m.array();
|
||||
state->dMatQueue.pop();
|
||||
strcpy($$, $3);
|
||||
}
|
||||
;
|
||||
|
||||
matsample:
|
||||
OPEN SAMPLE ID INT mat mats CLOSE SAMPLE
|
||||
{
|
||||
const unsigned int nSample = $4, os = DMatSample::offset;
|
||||
|
||||
if (state->dMatQueue.size() != nSample + os)
|
||||
{
|
||||
LATAN_ERROR(Size, "matrix sample '" + *state->streamName + ":"
|
||||
+ $3 + "' has a wrong size");
|
||||
}
|
||||
state->dMatSampleBuf.resize(nSample);
|
||||
state->dMatSampleBuf[central] = state->dMatQueue.front();
|
||||
state->dMatQueue.pop();
|
||||
for (unsigned int i = 0; i < nSample; ++i)
|
||||
{
|
||||
state->dMatSampleBuf[i] = state->dMatQueue.front();
|
||||
state->dMatQueue.pop();
|
||||
}
|
||||
strcpy($$, $3);
|
||||
}
|
||||
;
|
||||
|
||||
mats:
|
||||
mats mat
|
||||
| mat
|
||||
;
|
||||
|
||||
floats:
|
||||
floats FLOAT {state->doubleQueue.push($2);}
|
||||
| floats INT {state->doubleQueue.push(static_cast<double>($2));}
|
||||
| FLOAT {state->doubleQueue.push($1);}
|
||||
| INT {state->doubleQueue.push(static_cast<double>($1));}
|
||||
;
|
81
lib/Io/BinReader.cpp
Normal file
81
lib/Io/BinReader.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* BinReader.cpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/BinReader.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
#if (defined __GNUC__)||(defined __clang__)
|
||||
#pragma GCC diagnostic ignored "-Wunreachable-code"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
BinIO::BinIO(string msg, string loc)
|
||||
: runtime_error("Binary reader error: " + msg + " (" + loc + ")")
|
||||
{}
|
||||
|
||||
/******************************************************************************
|
||||
* BinReader implementation *
|
||||
******************************************************************************/
|
||||
// constructor /////////////////////////////////////////////////////////////////
|
||||
BinReader::BinReader(const string fileName, const uint32_t endianness,
|
||||
const bool isColMaj)
|
||||
{
|
||||
open(fileName, endianness, isColMaj);
|
||||
}
|
||||
|
||||
// I/O /////////////////////////////////////////////////////////////////////////
|
||||
void BinReader::open(const string fileName, const uint32_t endianness,
|
||||
const bool isColMaj)
|
||||
{
|
||||
fileName_ = fileName;
|
||||
endianness_ = endianness;
|
||||
isColMaj_ = isColMaj;
|
||||
file_.reset(new ifstream(fileName_, ios::in|ios::binary|ios::ate));
|
||||
if (!file_->is_open())
|
||||
{
|
||||
LATAN_ERROR(Io, "impossible to open file '" + fileName_ + "'");
|
||||
}
|
||||
size_ = static_cast<size_t>(file_->tellg());
|
||||
file_->seekg(0, ios::beg);
|
||||
}
|
||||
|
||||
void BinReader::close(void)
|
||||
{
|
||||
file_.reset(nullptr);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string BinReader::read(void)
|
||||
{
|
||||
std::string s;
|
||||
char c = 'a';
|
||||
|
||||
while (c != '\n')
|
||||
{
|
||||
c = read<char>();
|
||||
if (c != '\n')
|
||||
{
|
||||
s.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
196
lib/Io/BinReader.hpp
Normal file
196
lib/Io/BinReader.hpp
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* BinReader.hpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LatAnalyze_BinReader_hpp_
|
||||
#define LatAnalyze_BinReader_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
// I/O exception
|
||||
class BinIO: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
BinIO(std::string msg, std::string loc);
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Byte manipulation utilities *
|
||||
******************************************************************************/
|
||||
class Endianness
|
||||
{
|
||||
public:
|
||||
enum: uint32_t
|
||||
{
|
||||
little = 0x00000001,
|
||||
big = 0x01000000,
|
||||
unknown = 0xffffffff
|
||||
};
|
||||
};
|
||||
|
||||
class ByteManip
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t getHostEndianness(void)
|
||||
{
|
||||
return ((0xffffffff & 1) == Endianness::little) ? Endianness::little
|
||||
: (((0xffffffff & 1) == Endianness::big) ? Endianness::big
|
||||
: Endianness::unknown);
|
||||
}
|
||||
template <typename T>
|
||||
static T swapBytes(const T);
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* template implementation *
|
||||
******************************************************************************/
|
||||
template <typename T>
|
||||
T ByteManip::swapBytes(const T u)
|
||||
{
|
||||
static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");
|
||||
|
||||
union
|
||||
{
|
||||
T u;
|
||||
unsigned char u8[sizeof(T)];
|
||||
} source, dest;
|
||||
|
||||
source.u = u;
|
||||
for (size_t k = 0; k < sizeof(T); ++k)
|
||||
{
|
||||
dest.u8[k] = source.u8[sizeof(T) - k - 1];
|
||||
}
|
||||
|
||||
return dest.u;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Utility to read binary files *
|
||||
******************************************************************************/
|
||||
class BinReader
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
BinReader(void) = default;
|
||||
BinReader(const std::string fileName,
|
||||
const uint32_t endianness = ByteManip::getHostEndianness(),
|
||||
const bool isColMaj = false);
|
||||
// destructor
|
||||
virtual ~BinReader(void) = default;
|
||||
// I/O
|
||||
void open(const std::string fileName,
|
||||
const uint32_t endianness = ByteManip::getHostEndianness(),
|
||||
const bool isColMaj = false);
|
||||
void close(void);
|
||||
template <typename T>
|
||||
void read(T *pt, Index size);
|
||||
template <typename T>
|
||||
T read(void);
|
||||
template <typename T>
|
||||
MatBase<T> read(const Index nRow, const Index nCol);
|
||||
private:
|
||||
std::unique_ptr<std::ifstream> file_{nullptr};
|
||||
std::string fileName_;
|
||||
size_t size_;
|
||||
uint32_t endianness_;
|
||||
bool isColMaj_;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* template implementation *
|
||||
******************************************************************************/
|
||||
template <typename T>
|
||||
void BinReader::read(T *pt, Index n)
|
||||
{
|
||||
if (file_ != nullptr)
|
||||
{
|
||||
file_->read(reinterpret_cast<char *>(pt),
|
||||
static_cast<long>(sizeof(T))*n);
|
||||
if (endianness_ != ByteManip::getHostEndianness())
|
||||
{
|
||||
for (Index i = 0; i < n; ++i)
|
||||
{
|
||||
pt[i] = ByteManip::swapBytes(pt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "file is not opened");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T BinReader::read(void)
|
||||
{
|
||||
T x;
|
||||
|
||||
if (file_ != nullptr)
|
||||
{
|
||||
read(&x, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "file is not opened");
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string BinReader::read(void);
|
||||
|
||||
template <typename T>
|
||||
MatBase<T> BinReader::read(const Index nRow, const Index nCol)
|
||||
{
|
||||
MatBase<T> m;
|
||||
|
||||
// Eigen matrices use column-major ordering
|
||||
if (isColMaj_)
|
||||
{
|
||||
m.resize(nRow, nCol);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.resize(nCol, nRow);
|
||||
}
|
||||
if (file_ != nullptr)
|
||||
{
|
||||
read(m.data(), nRow*nCol);
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "file is not opened");
|
||||
}
|
||||
if (isColMaj_)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m.transpose();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // LatAnalyze_BinReader_hpp_
|
64
lib/Io/File.cpp
Normal file
64
lib/Io/File.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* File.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/File.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
/******************************************************************************
|
||||
* File implementation *
|
||||
******************************************************************************/
|
||||
// constructors ////////////////////////////////////////////////////////////////
|
||||
File::File(const string &name, const unsigned int mode)
|
||||
: name_(name)
|
||||
, mode_(mode)
|
||||
{}
|
||||
|
||||
// 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)
|
||||
{
|
||||
data_.clear();
|
||||
}
|
||||
|
||||
void File::checkWritability(void)
|
||||
{
|
||||
if (!((mode_ & Mode::write) or (mode_ & Mode::append)) or !isOpen())
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is not writable");
|
||||
}
|
||||
}
|
123
lib/Io/File.hpp
Normal file
123
lib/Io/File.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* File.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_File_hpp_
|
||||
#define Latan_File_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/IoObject.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/Statistics/MatSample.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Abstract datafile class *
|
||||
******************************************************************************/
|
||||
typedef std::unordered_map<std::string, std::unique_ptr<IoObject>> IoDataTable;
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
class Mode
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
null = 0,
|
||||
write = 1 << 0,
|
||||
read = 1 << 1,
|
||||
append = 1 << 2
|
||||
};
|
||||
};
|
||||
public:
|
||||
// constructors
|
||||
File(void) = default;
|
||||
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 <typename IoT>
|
||||
const IoT & read(const std::string &name = "");
|
||||
virtual void save(const DMat &m, const std::string &name) = 0;
|
||||
virtual void save(const DSample &ds, const std::string &name) = 0;
|
||||
virtual void save(const DMatSample &ms, const std::string &name) = 0;
|
||||
// read first name
|
||||
virtual std::string getFirstName(void) = 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;
|
||||
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 <typename IoT>
|
||||
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_{Mode::null};
|
||||
IoDataTable data_;
|
||||
};
|
||||
|
||||
// Template implementations
|
||||
template <typename IoT>
|
||||
const IoT& File::read(const std::string &name)
|
||||
{
|
||||
std::string dataName;
|
||||
|
||||
dataName = load(name);
|
||||
|
||||
return getData<IoT>(dataName);
|
||||
}
|
||||
|
||||
template <typename IoT>
|
||||
const IoT& File::getData(const std::string &name) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return dynamic_cast<const IoT &>(*(data_.at(name)));
|
||||
}
|
||||
catch(std::out_of_range)
|
||||
{
|
||||
LATAN_ERROR(Definition, "no data with name '" + name + "' in file "
|
||||
+ name_);
|
||||
}
|
||||
catch(std::bad_cast)
|
||||
{
|
||||
LATAN_ERROR(Definition, "data with name '" + name + "' in file "
|
||||
+ name_ + " does not have type '" + typeid(IoT).name()
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif
|
355
lib/Io/Hdf5File.cpp
Normal file
355
lib/Io/Hdf5File.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Hdf5File.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli, Matt Spraggs
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/Hdf5File.hpp>
|
||||
#include <LatAnalyze/Io/IoObject.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
#ifndef H5_NO_NAMESPACE
|
||||
using namespace H5NS;
|
||||
#endif
|
||||
|
||||
constexpr unsigned int maxGroupNameSize = 1024u;
|
||||
|
||||
const short dMatType = static_cast<short>(IoObject::IoType::dMat);
|
||||
const short dSampleType = static_cast<short>(IoObject::IoType::dSample);
|
||||
const short dMatSampleType = static_cast<short>(IoObject::IoType::dMatSample);
|
||||
|
||||
/******************************************************************************
|
||||
* Hdf5File implementation *
|
||||
******************************************************************************/
|
||||
// constructors ////////////////////////////////////////////////////////////////
|
||||
Hdf5File::Hdf5File(void)
|
||||
{}
|
||||
|
||||
Hdf5File::Hdf5File(const std::string &name, const unsigned int mode)
|
||||
{
|
||||
open(name, mode);
|
||||
}
|
||||
|
||||
// destructor //////////////////////////////////////////////////////////////////
|
||||
Hdf5File::~Hdf5File(void)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
// access //////////////////////////////////////////////////////////////////////
|
||||
void Hdf5File::save(const DMat &m, const string &name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
Group group;
|
||||
Attribute attr;
|
||||
DataSet dataset;
|
||||
hsize_t dim[2] = {static_cast<hsize_t>(m.rows()),
|
||||
static_cast<hsize_t>(m.cols())};
|
||||
hsize_t attrDim = 1;
|
||||
DataSpace dataSpace(2, dim), attrSpace(1, &attrDim);
|
||||
|
||||
group = h5File_->createGroup(name.c_str() + nameOffset(name));
|
||||
attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace);
|
||||
attr.write(PredType::NATIVE_SHORT, &dMatType);
|
||||
dataset = group.createDataSet("data", PredType::NATIVE_DOUBLE, dataSpace);
|
||||
dataset.write(m.data(), PredType::NATIVE_DOUBLE);
|
||||
}
|
||||
|
||||
void Hdf5File::save(const DSample &ds, const string &name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
Group group;
|
||||
Attribute attr;
|
||||
DataSet dataset;
|
||||
hsize_t dim = static_cast<hsize_t>(ds.size() + 1);
|
||||
hsize_t attrDim = 1;
|
||||
DataSpace dataSpace(1, &dim), attrSpace(1, &attrDim);
|
||||
const long int nSample = ds.size();
|
||||
|
||||
group = h5File_->createGroup(name.c_str() + nameOffset(name));
|
||||
attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace);
|
||||
attr.write(PredType::NATIVE_SHORT, &dSampleType);
|
||||
attr = group.createAttribute("nSample", PredType::NATIVE_LONG, attrSpace);
|
||||
attr.write(PredType::NATIVE_LONG, &nSample);
|
||||
dataset = group.createDataSet("data", PredType::NATIVE_DOUBLE, dataSpace);
|
||||
dataset.write(ds.data(), PredType::NATIVE_DOUBLE);
|
||||
}
|
||||
|
||||
void Hdf5File::save(const DMatSample &ms, const string &name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "trying to save data with an empty name");
|
||||
}
|
||||
|
||||
Group group;
|
||||
Attribute attr;
|
||||
DataSet dataset;
|
||||
hsize_t dim[2] = {static_cast<hsize_t>(ms[central].rows()),
|
||||
static_cast<hsize_t>(ms[central].cols())};
|
||||
hsize_t attrDim = 1;
|
||||
DataSpace dataSpace(2, dim), attrSpace(1, &attrDim);
|
||||
const long int nSample = ms.size();
|
||||
string datasetName;
|
||||
|
||||
group = h5File_->createGroup(name.c_str() + nameOffset(name));
|
||||
attr = group.createAttribute("type", PredType::NATIVE_SHORT, attrSpace);
|
||||
attr.write(PredType::NATIVE_SHORT, &dMatSampleType);
|
||||
attr = group.createAttribute("nSample", PredType::NATIVE_LONG, attrSpace);
|
||||
attr.write(PredType::NATIVE_LONG, &nSample);
|
||||
FOR_STAT_ARRAY(ms, s)
|
||||
{
|
||||
datasetName = (s == central) ? "data_C" : ("data_S_" + strFrom(s));
|
||||
dataset = group.createDataSet(datasetName.c_str(),
|
||||
PredType::NATIVE_DOUBLE,
|
||||
dataSpace);
|
||||
dataset.write(ms[s].data(), PredType::NATIVE_DOUBLE);
|
||||
}
|
||||
}
|
||||
|
||||
// read first name ////////////////////////////////////////////////////////////
|
||||
string Hdf5File::getFirstName(void)
|
||||
{
|
||||
return getFirstGroupName();
|
||||
}
|
||||
|
||||
// tests ///////////////////////////////////////////////////////////////////////
|
||||
bool Hdf5File::isOpen(void) const
|
||||
{
|
||||
return (h5File_ != nullptr);
|
||||
}
|
||||
|
||||
// check names for forbidden characters ////////////////////////////////////////
|
||||
size_t Hdf5File::nameOffset(const string &name)
|
||||
{
|
||||
size_t ret = 0;
|
||||
string badChars = "/";
|
||||
|
||||
for (auto c : badChars)
|
||||
{
|
||||
size_t pos = name.rfind(c);
|
||||
|
||||
if (pos != string::npos and pos > ret)
|
||||
{
|
||||
ret = pos;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// IO //////////////////////////////////////////////////////////////////////////
|
||||
void Hdf5File::close(void)
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
h5File_->close();
|
||||
}
|
||||
h5File_.reset(nullptr);
|
||||
name_ = "";
|
||||
mode_ = Mode::null;
|
||||
deleteData();
|
||||
}
|
||||
|
||||
void Hdf5File::open(const string &name, const unsigned int mode)
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
LATAN_ERROR(Io, "file already opened with name '" + name_ + "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int h5Mode = 0;
|
||||
|
||||
name_ = name;
|
||||
mode_ = mode;
|
||||
|
||||
if (mode & Mode::write)
|
||||
{
|
||||
h5Mode |= H5F_ACC_TRUNC;
|
||||
}
|
||||
if (mode & Mode::read)
|
||||
{
|
||||
h5Mode |= H5F_ACC_RDONLY;
|
||||
}
|
||||
if (mode & Mode::append)
|
||||
{
|
||||
h5Mode |= H5F_ACC_RDWR|H5F_ACC_CREAT;
|
||||
}
|
||||
h5File_.reset(new H5File(name_.c_str(), h5Mode));
|
||||
}
|
||||
}
|
||||
|
||||
string Hdf5File::getFirstGroupName(void)
|
||||
{
|
||||
string res;
|
||||
|
||||
if ((mode_ & Mode::read) and (isOpen()))
|
||||
{
|
||||
auto firstGroupName = [](hid_t loc_id, const char *name, void *fname)
|
||||
{
|
||||
H5G_stat_t statbuf;
|
||||
|
||||
H5Gget_objinfo(loc_id, name, 0, &statbuf);
|
||||
if ((statbuf.type == H5G_GROUP) and (strlen((char *)fname) == 0))
|
||||
{
|
||||
strncpy((char *)fname, name, maxGroupNameSize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
char groupName[maxGroupNameSize] = "";
|
||||
|
||||
h5File_->iterateElems("/", nullptr, firstGroupName, groupName);
|
||||
res = groupName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is not opened in read mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is not opened");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Hdf5File::load(DMat &m, const DataSet &d)
|
||||
{
|
||||
DataSpace dataspace;
|
||||
hsize_t dim[2];
|
||||
|
||||
dataspace = d.getSpace();
|
||||
dataspace.getSimpleExtentDims(dim);
|
||||
m.resize(dim[0], dim[1]);
|
||||
d.read(m.data(), PredType::NATIVE_DOUBLE);
|
||||
}
|
||||
|
||||
void Hdf5File::load(DSample &ds, const DataSet &d)
|
||||
{
|
||||
DataSpace dataspace;
|
||||
hsize_t dim[1];
|
||||
|
||||
dataspace = d.getSpace();
|
||||
dataspace.getSimpleExtentDims(dim);
|
||||
ds.resize(dim[0] - 1);
|
||||
d.read(ds.data(), PredType::NATIVE_DOUBLE);
|
||||
}
|
||||
|
||||
string Hdf5File::load(const string &name)
|
||||
{
|
||||
if ((mode_ & Mode::read) and (isOpen()))
|
||||
{
|
||||
string groupName;
|
||||
Group group;
|
||||
Attribute attribute;
|
||||
DataSet dataset;
|
||||
IoObject::IoType type;
|
||||
|
||||
groupName = (name.empty()) ? getFirstGroupName() : name;
|
||||
if (groupName.empty())
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is empty");
|
||||
}
|
||||
group = h5File_->openGroup(groupName.c_str());
|
||||
attribute = group.openAttribute("type");
|
||||
attribute.read(PredType::NATIVE_SHORT, &type);
|
||||
switch (type)
|
||||
{
|
||||
case IoObject::IoType::dMat:
|
||||
{
|
||||
DMat *pt = new DMat;
|
||||
|
||||
data_[groupName].reset(pt);
|
||||
dataset = group.openDataSet("data");
|
||||
load(*pt, dataset);
|
||||
break;
|
||||
}
|
||||
case IoObject::IoType::dSample:
|
||||
{
|
||||
DSample *pt = new DSample;
|
||||
|
||||
data_[groupName].reset(pt);
|
||||
dataset = group.openDataSet("data");
|
||||
load(*pt, dataset);
|
||||
break;
|
||||
}
|
||||
case IoObject::IoType::dMatSample:
|
||||
{
|
||||
DMatSample *pt = new DMatSample;
|
||||
long int nSample;
|
||||
|
||||
data_[groupName].reset(pt);
|
||||
attribute = group.openAttribute("nSample");
|
||||
attribute.read(PredType::NATIVE_LONG, &nSample);
|
||||
pt->resize(nSample);
|
||||
FOR_STAT_ARRAY(*pt, s)
|
||||
{
|
||||
if (s == central)
|
||||
{
|
||||
dataset = group.openDataSet("data_C");
|
||||
}
|
||||
else
|
||||
{
|
||||
dataset =
|
||||
group.openDataSet(("data_S_" + strFrom(s)).c_str());
|
||||
}
|
||||
load((*pt)[s], dataset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LATAN_ERROR(Io, "unknown data type ("
|
||||
+ strFrom(static_cast<int>(type)) + ") "
|
||||
" (" + name_ + ":" + groupName + ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return groupName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is not opened in read mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "file '" + name_ + "' is not opened");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
73
lib/Io/Hdf5File.hpp
Normal file
73
lib/Io/Hdf5File.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Hdf5File.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli, Matt Spraggs
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Hdf5File_hpp_
|
||||
#define Latan_Hdf5File_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/File.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/Statistics/MatSample.hpp>
|
||||
#include <H5Cpp.h>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
#ifndef H5_NO_NAMESPACE
|
||||
#define H5NS H5
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* HDF5 datafile class *
|
||||
******************************************************************************/
|
||||
class Hdf5File: public File
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
Hdf5File(void);
|
||||
Hdf5File(const std::string &name, const unsigned int mode);
|
||||
// destructor
|
||||
virtual ~Hdf5File(void);
|
||||
// access
|
||||
virtual void save(const DMat &m, const std::string &name);
|
||||
virtual void save(const DSample &ds, const std::string &name);
|
||||
virtual void save(const DMatSample &ms, const std::string &name);
|
||||
// read first name
|
||||
virtual std::string getFirstName(void);
|
||||
// tests
|
||||
virtual bool isOpen(void) const;
|
||||
// IO
|
||||
virtual void close(void);
|
||||
virtual void open(const std::string &name, const unsigned int mode);
|
||||
private:
|
||||
// IO
|
||||
std::string getFirstGroupName(void);
|
||||
virtual std::string load(const std::string &name = "");
|
||||
void load(DMat &m, const H5NS::DataSet &d);
|
||||
void load(DSample &ds, const H5NS::DataSet &d);
|
||||
void load(DMatSample &s, const H5NS::DataSet &d);
|
||||
// check name for forbidden characters
|
||||
static size_t nameOffset(const std::string &name);
|
||||
private:
|
||||
// file name
|
||||
std::unique_ptr<H5NS::H5File> h5File_{nullptr};
|
||||
};
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Hdf5File_hpp_
|
51
lib/Io/Io.cpp
Normal file
51
lib/Io/Io.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Io.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/Io.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
#include <LatAnalyze/Io/AsciiFile.hpp>
|
||||
#include <LatAnalyze/Io/Hdf5File.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
string Io::getFirstName(const string &fileName)
|
||||
{
|
||||
std::unique_ptr<File> file = open(fileName);
|
||||
|
||||
return file->getFirstName();
|
||||
}
|
||||
|
||||
unique_ptr<File> Io::open(const std::string &fileName, const unsigned int mode)
|
||||
{
|
||||
string ext = extension(fileName);
|
||||
|
||||
if ((ext == "dat") or (ext == "sample") or (ext == "seed"))
|
||||
{
|
||||
return unique_ptr<File>(new AsciiFile(fileName, mode));
|
||||
}
|
||||
else if (ext == "h5")
|
||||
{
|
||||
return unique_ptr<File>(new Hdf5File(fileName, mode));
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Io, "unknown file extension '" + ext + "'");
|
||||
}
|
||||
}
|
100
lib/Io/Io.hpp
Normal file
100
lib/Io/Io.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Io.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Io_hpp_
|
||||
#define Latan_Io_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/File.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Static IO functions *
|
||||
******************************************************************************/
|
||||
class Io
|
||||
{
|
||||
public:
|
||||
template <typename IoT, typename FileType>
|
||||
static IoT load(const std::string &fileName, const std::string &name = "");
|
||||
template <typename IoT>
|
||||
static IoT load(const std::string &fileName, const std::string &name = "");
|
||||
template <typename IoT, typename FileType>
|
||||
static void save(const IoT &data, const std::string &fileName,
|
||||
const unsigned int mode = File::Mode::write,
|
||||
const std::string &name = "");
|
||||
template <typename IoT>
|
||||
static void save(const IoT &data, const std::string &fileName,
|
||||
const unsigned int mode = File::Mode::write,
|
||||
const std::string &name = "");
|
||||
template <typename FileType>
|
||||
static std::string getFirstName(const std::string &fileName);
|
||||
static std::string getFirstName(const std::string &fileName);
|
||||
static std::unique_ptr<File> open(const std::string &fileName,
|
||||
const unsigned int mode = File::Mode::read);
|
||||
};
|
||||
|
||||
// template implementation /////////////////////////////////////////////////////
|
||||
template <typename IoT, typename FileType>
|
||||
IoT Io::load(const std::string &fileName, const std::string &name)
|
||||
{
|
||||
FileType file(fileName, File::Mode::read);
|
||||
|
||||
return file.template read<IoT>(name);
|
||||
}
|
||||
|
||||
template <typename IoT>
|
||||
IoT Io::load(const std::string &fileName, const std::string &name)
|
||||
{
|
||||
std::unique_ptr<File> file = open(fileName);
|
||||
|
||||
return file->read<IoT>(name);
|
||||
}
|
||||
|
||||
template <typename IoT, typename FileType>
|
||||
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.save(data, realName);
|
||||
}
|
||||
|
||||
template <typename IoT>
|
||||
void Io::save(const IoT &data, const std::string &fileName,
|
||||
const unsigned int mode, const std::string &name)
|
||||
{
|
||||
std::unique_ptr<File> file = open(fileName, mode);
|
||||
std::string realName = (name.empty()) ? fileName : name;
|
||||
|
||||
file->save(data, realName);
|
||||
}
|
||||
|
||||
template <typename FileType>
|
||||
std::string Io::getFirstName(const std::string &fileName)
|
||||
{
|
||||
FileType file(fileName, File::Mode::read);
|
||||
|
||||
return file.getFirstName();
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Io_hpp_
|
50
lib/Io/IoObject.hpp
Normal file
50
lib/Io/IoObject.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* IoObject.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_IoObject_hpp_
|
||||
#define Latan_IoObject_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Abstract class for IO objects *
|
||||
******************************************************************************/
|
||||
class IoObject
|
||||
{
|
||||
public:
|
||||
// conserve order for datafile retro-compatibility!
|
||||
enum class IoType: short int
|
||||
{
|
||||
noType = 0,
|
||||
dMat = 1,
|
||||
dMatSample = 2,
|
||||
dSample = 3
|
||||
};
|
||||
public:
|
||||
// destructor
|
||||
virtual ~IoObject(void) = default;
|
||||
// access
|
||||
virtual IoType getType(void) const = 0;
|
||||
};
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_IoObject_hpp_
|
2791
lib/Io/Xml/tinyxml2.cpp
Normal file
2791
lib/Io/Xml/tinyxml2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2272
lib/Io/Xml/tinyxml2.hpp
Normal file
2272
lib/Io/Xml/tinyxml2.hpp
Normal file
File diff suppressed because it is too large
Load Diff
84
lib/Io/XmlReader.cpp
Normal file
84
lib/Io/XmlReader.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* XmlReader.cpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2013 - 2014 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Io/XmlReader.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
XmlParsing::XmlParsing(string msg, string loc)
|
||||
: runtime_error("XML reader error: " + msg + " (" + loc + ")")
|
||||
{}
|
||||
|
||||
/******************************************************************************
|
||||
* XmlReader implementation *
|
||||
******************************************************************************/
|
||||
// constructor /////////////////////////////////////////////////////////////////
|
||||
XmlReader::XmlReader(const string &fileName)
|
||||
{
|
||||
open(fileName);
|
||||
}
|
||||
|
||||
// IO //////////////////////////////////////////////////////////////////////////
|
||||
void XmlReader::open(const string &fileName)
|
||||
{
|
||||
name_ = fileName;
|
||||
doc_.LoadFile(name_.c_str());
|
||||
if (doc_.Error())
|
||||
{
|
||||
string errMsg;
|
||||
|
||||
if (doc_.ErrorStr())
|
||||
{
|
||||
errMsg = doc_.ErrorStr();
|
||||
}
|
||||
LATAN_ERROR(Io, "cannot open file " + fileName + " [tinyxml2 code "
|
||||
+ strFrom(doc_.ErrorID()) + ": " + errMsg + "]");
|
||||
}
|
||||
root_ = doc_.RootElement();
|
||||
}
|
||||
|
||||
// XML structure access ////////////////////////////////////////////////////////
|
||||
const XmlNode * XmlReader::getNextNode(const XmlNode *node,
|
||||
const string &nodeName)
|
||||
{
|
||||
const char *pt = (nodeName.empty()) ? nullptr : nodeName.c_str();
|
||||
|
||||
if (node)
|
||||
{
|
||||
return node->NextSiblingElement(pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const XmlNode * XmlReader::getNextSameNode(const XmlNode *node)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
return getNextNode(node, node->Name());
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
235
lib/Io/XmlReader.hpp
Normal file
235
lib/Io/XmlReader.hpp
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* XmlReader.hpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2013 - 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LatAnalyze_XmlReader_hpp_
|
||||
#define LatAnalyze_XmlReader_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#include <LatAnalyze/Io/Xml/tinyxml2.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
// parsing exception
|
||||
class XmlParsing: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
XmlParsing(std::string msg, std::string loc);
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* XML parameter file reader *
|
||||
******************************************************************************/
|
||||
typedef tinyxml2::XMLElement XmlNode;
|
||||
|
||||
class XmlReader
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
XmlReader(void) = default;
|
||||
explicit XmlReader(const std::string &fileName);
|
||||
// destructor
|
||||
virtual ~XmlReader(void) = default;
|
||||
// IO
|
||||
void open(const std::string &fileName);
|
||||
// XML structure access
|
||||
template <typename... Strs>
|
||||
static const XmlNode * getFirstNode(const XmlNode *startNode,
|
||||
const std::string &nodeName,
|
||||
Strs... nodeNames);
|
||||
template <typename... Strs>
|
||||
const XmlNode * getFirstNode(const std::string &nodeName,
|
||||
Strs... nodeNames) const;
|
||||
static const XmlNode * getNextNode(const XmlNode *node,
|
||||
const std::string &nodeName = "");
|
||||
static const XmlNode * getNextSameNode(const XmlNode *node);
|
||||
template <typename T>
|
||||
static T getValue(const XmlNode *node);
|
||||
template <typename T, typename... Strs>
|
||||
static T getFirstValue(const XmlNode *startNode,
|
||||
const std::string &nodeName, Strs... nodeNames);
|
||||
template <typename T, typename... Strs>
|
||||
T getFirstValue(const std::string &nodeName, Strs... nodeNames) const;
|
||||
template <typename T, typename... Strs>
|
||||
static std::vector<T> getAllValues(const XmlNode *startNode,
|
||||
const std::string &nodeName,
|
||||
Strs... nodeNames);
|
||||
template <typename T, typename... Strs>
|
||||
std::vector<T> getAllValues(const std::string &nodeName,
|
||||
Strs... nodeNames) const;
|
||||
// XML structure test
|
||||
template <typename... Strs>
|
||||
static bool hasNode(const XmlNode *startNode, const std::string &nodeName,
|
||||
Strs... nodeNames);
|
||||
template <typename... Strs>
|
||||
bool hasNode(const std::string &nodeName, Strs... nodeNames) const;
|
||||
private:
|
||||
std::string name_;
|
||||
tinyxml2::XMLDocument doc_;
|
||||
XmlNode *root_{nullptr};
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* XmlReader template implementation *
|
||||
******************************************************************************/
|
||||
// XML structure access ////////////////////////////////////////////////////////
|
||||
template <typename... Strs>
|
||||
const XmlNode * XmlReader::getFirstNode(const XmlNode *startNode,
|
||||
const std::string &nodeName,
|
||||
Strs... nodeNames)
|
||||
{
|
||||
static_assert(static_or<std::is_assignable<std::string, Strs>::value...>::value,
|
||||
"getFirstNode arguments are not compatible with std::string");
|
||||
|
||||
const unsigned int nName = sizeof...(nodeNames) + 1;
|
||||
const std::string name[] = {nodeName, nodeNames...};
|
||||
const XmlNode *node = startNode;
|
||||
|
||||
if (!node)
|
||||
{
|
||||
LATAN_ERROR(Io, "root node is null, no XML file opened");
|
||||
}
|
||||
for (unsigned int i = 0; i < nName; ++i)
|
||||
{
|
||||
node = node->FirstChildElement(name[i].c_str());
|
||||
if (!node)
|
||||
{
|
||||
LATAN_ERROR(Io, "XML node " + name[i] + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
template <typename... Strs>
|
||||
const XmlNode * XmlReader::getFirstNode(const std::string &nodeName,
|
||||
Strs... nodeNames) const
|
||||
{
|
||||
if (!root_)
|
||||
{
|
||||
LATAN_ERROR(Io, "root node is null, no XML file opened");
|
||||
}
|
||||
|
||||
return getFirstNode(root_, nodeName, nodeNames...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T XmlReader::getValue(const XmlNode *node)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
if (node->GetText())
|
||||
{
|
||||
return Latan::strTo<T>(node->GetText());
|
||||
}
|
||||
else
|
||||
{
|
||||
return T();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Strs>
|
||||
T XmlReader::getFirstValue(const XmlNode *startNode,
|
||||
const std::string &nodeName, Strs... nodeNames)
|
||||
{
|
||||
const XmlNode *node = getFirstNode(startNode, nodeName, nodeNames...);
|
||||
|
||||
return getValue<T>(node);
|
||||
}
|
||||
|
||||
template <typename T, typename... Strs>
|
||||
T XmlReader::getFirstValue(const std::string &nodeName, Strs... nodeNames) const
|
||||
{
|
||||
return getFirstValue<T>(root_, nodeName, nodeNames...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Strs>
|
||||
std::vector<T> XmlReader::getAllValues(const XmlNode *startNode,
|
||||
const std::string &nodeName,
|
||||
Strs... nodeNames)
|
||||
{
|
||||
const XmlNode *node = getFirstNode(startNode, nodeName, nodeNames...);
|
||||
std::vector<T> value;
|
||||
|
||||
while (node)
|
||||
{
|
||||
value.push_back(getValue<T>(node));
|
||||
node = getNextSameNode(node);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename... Strs>
|
||||
std::vector<T> XmlReader::getAllValues(const std::string &nodeName,
|
||||
Strs... nodeNames) const
|
||||
{
|
||||
return getAllValues<T>(root_, nodeName, nodeNames...);
|
||||
}
|
||||
|
||||
// XML structure test //////////////////////////////////////////////////////////
|
||||
template <typename... Strs>
|
||||
bool XmlReader::hasNode(const XmlNode *startNode, const std::string &nodeName,
|
||||
Strs... nodeNames)
|
||||
{
|
||||
static_assert(static_or<std::is_assignable<std::string, Strs>::value...>::value,
|
||||
"hasNode arguments are not compatible with std::string");
|
||||
|
||||
const unsigned int nName = sizeof...(nodeNames) + 1;
|
||||
const std::string name[] = {nodeName, nodeNames...};
|
||||
const XmlNode *node = startNode;
|
||||
|
||||
if (!node)
|
||||
{
|
||||
LATAN_ERROR(Io, "root node is null, no XML file opened");
|
||||
}
|
||||
for (unsigned int i = 0; i < nName; ++i)
|
||||
{
|
||||
node = node->FirstChildElement(name[i].c_str());
|
||||
if (!node)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename... Strs>
|
||||
bool XmlReader::hasNode(const std::string &nodeName, Strs... nodeNames) const
|
||||
{
|
||||
if (!root_)
|
||||
{
|
||||
LATAN_ERROR(Io, "root node is null, no XML file opened");
|
||||
}
|
||||
|
||||
return hasNode(root_, nodeName, nodeNames...);
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // LatAnalyze_XmlReader_hpp_
|
Reference in New Issue
Block a user