Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F25854582
CSVReader.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
9 KB
Referenced Files
None
Subscribers
None
CSVReader.hpp
View Options
//===-- rosa/support/csv/CSVReader.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVReader.hpp
///
/// \authors David Juhasz (david.juhasz@tuwien.ac.at), Edwin Willegger (edwin.willegger@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facitilities to read CSV files.
///
/// \note The implementation is based on the solution at
/// https://stackoverflow.com/a/1120224
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_CSV_CSVREADER_HPP
#define ROSA_SUPPORT_CSV_CSVREADER_HPP
#include
"rosa/support/debug.hpp"
#include
"rosa/support/sequence.hpp"
#include
<istream>
#include
<sstream>
#include
<vector>
#include
<map>
#include
<algorithm>
#include
<set>
namespace
rosa
{
namespace
csv
{
/// Indicating it the CSV file contains any header or not
enum
class
HeaderInformation
{
HasHeader
,
HasNoHeader
};
/// Anonymous namespace providing implementation details for
/// \c rosa::csv::CSVIterator, consider it private.
namespace
{
/// Provides facility for parsing one value from a string.
///
/// \tparam T type of value to parse
/// \tparam IsSignedInt if \p T is a signed integral type, always use default
/// \tparam IsUnsignedInt if \p T is an unsigned integral type, always use
/// default
/// \tparam IsFloat if \p T is a floating-point type, always use default
/// \tparam IsString if \p T is \c std::string, always use default
///
/// \note Specializations of this struct are provided for arithmentic types
/// and \c std::string.
template
<
typename
T
,
bool
IsSignedInt
=
(
std
::
is_integral
<
T
>::
value
&&
std
::
is_signed
<
T
>::
value
),
bool
IsUnsignedInt
=
(
std
::
is_integral
<
T
>::
value
&&
std
::
is_unsigned
<
T
>::
value
),
bool
IsFloat
=
std
::
is_floating_point
<
T
>::
value
,
bool
IsString
=
std
::
is_same
<
T
,
std
::
string
>::
value
>
struct
ValueParser
{
///
///
/// \param Cell the \c std::string to parse
///
/// \return the parsed value
///
/// \note The function silently fails if cannot parse \p Cell for type \p T.
static
T
parse
(
const
std
::
string
&
Cell
)
noexcept
;
};
template
<
typename
T
>
struct
ValueParser
<
T
,
true
,
false
,
false
,
false
>
{
STATIC_ASSERT
((
std
::
is_integral
<
T
>::
value
&&
std
::
is_signed
<
T
>::
value
),
"wrong type"
);
// Sanity check.
static
T
parse
(
const
std
::
string
&
Cell
)
noexcept
{
return
static_cast
<
T
>
(
std
::
stoll
(
Cell
));
}
};
template
<
typename
T
>
struct
ValueParser
<
T
,
false
,
true
,
false
,
false
>
{
STATIC_ASSERT
((
std
::
is_integral
<
T
>::
value
&&
std
::
is_unsigned
<
T
>::
value
),
"wrong type"
);
// Sanity check.
static
T
parse
(
const
std
::
string
&
Cell
)
noexcept
{
return
static_cast
<
T
>
(
std
::
stoull
(
Cell
));
}
};
template
<
typename
T
>
struct
ValueParser
<
T
,
false
,
false
,
true
,
false
>
{
STATIC_ASSERT
((
std
::
is_floating_point
<
T
>::
value
),
"wrong type"
);
// Sanity check.
static
T
parse
(
const
std
::
string
&
Cell
)
noexcept
{
return
static_cast
<
T
>
(
std
::
stold
(
Cell
));
}
};
template
<
typename
T
>
struct
ValueParser
<
T
,
false
,
false
,
false
,
true
>
{
STATIC_ASSERT
((
std
::
is_same
<
T
,
std
::
string
>::
value
),
"wrong type"
);
// Sanity check.
static
T
parse
(
const
std
::
string
&
Cell
)
noexcept
{
return
Cell
;
}
};
/// Parses and stores entries from a row of CSV data.
///
/// \tparam Ts types of values to parse and store, i.e. entries in the row
///
/// \note The implementation relies on \c rosa::csv::CSVRowParser, which is
/// implemented only for `arithmetic` types -- signed and unsigned integral
/// and floating-point types -- and for \c std::string. Those are the valid
/// values for \p Ts.
template
<
typename
...
Ts
>
class
CSVRow
{
private
:
/// Parses a given row of CSV data into \c CSVRow::Data.
///
/// \ CSVRow::Data is filled with values parsed from \p LineStream. Entries
/// in the line are to be separated by commas, the character `,`.
///
/// \note Parsed values are silently converted to types \p Ts.
///
/// \note Parsing silently fails if values do not match \p Ts.
///
/// \tparam S0 indices to access tuple elements.
///
/// \param [in,out] LineStream the line to parse
///
/// \note The last argument is used only to get \p S0, the actual value of
/// the parameter is ignored.
template
<
size_t
...
S0
>
void
parseRow
(
std
::
stringstream
&
LineStream
,
Seq
<
S0
...
>
)
{
STATIC_ASSERT
(
sizeof
...(
Ts
)
==
sizeof
...(
S0
),
"Not matching template arguments."
);
std
::
string
Cell
;
// Get fields and parse the values into the proper element of the tuple
// one by one in a fold expression.
((
std
::
getline
(
LineStream
,
Cell
,
','
),
std
::
get
<
S0
>
(
Data
)
=
ValueParser
<
Ts
>::
parse
(
Cell
)),
...);
}
public
:
/// Parses and stores one row of CSV data.
///
/// The function reads one line from \p Str and parses it into
/// \c rosa::csv::CSVRow::Data using \c rosa::csv::CSVRowParser.
///
/// \param [in,out] Str input stream of a CSV file
void
readNextRow
(
std
::
istream
&
Str
)
{
std
::
string
Line
;
std
::
getline
(
Str
,
Line
);
std
::
stringstream
LineStream
(
Line
);
parseRow
(
LineStream
,
seq_t
<
sizeof
...(
Ts
)
>
());
}
/// Gives a constant references for the \c std::tuple containing the values
/// read by \p this object.
///
/// \return \c CSVRow::Data
const
std
::
tuple
<
Ts
...
>
&
tuple
(
void
)
const
noexcept
{
return
Data
;
}
private
:
std
::
tuple
<
Ts
...
>
Data
;
///< Stores parsed entries
};
/// Reads a row of CSV data into \c rosa::csv::CSVRow.
///
/// The next line is read from \p Str by calling
/// \c rosa::csv::CSVRow::readNextRow on \p Data.
///
/// \tparam Ts type of values to read from the row
///
/// \note The CSV file should contain a line with fields matching \p Ts...
///
/// \param [in,out] Str input stream of a CSV file
/// \param [in,out] Data object to read the next line into
///
/// \return \p Str after reading one line from it
template
<
typename
...
Ts
>
std
::
istream
&
operator
>>
(
std
::
istream
&
Str
,
CSVRow
<
Ts
...
>
&
Data
)
{
Data
.
readNextRow
(
Str
);
return
Str
;
}
}
// End namespace
/// Provides `InputIterator` features for iterating over a CSV file.
///
/// The iterator parses rows into `std::tuple` values and iterates over the
/// file row by row.
///
/// \tparam Ts types of values stored in one row of the CSV file
///
/// \note The iterator expects each row to consists of fields matching \p Ts.
///
/// \note The implementation relies on \c rosa::csv::CSVRow, which in turn
/// relies on \c rosa::csv::CSVRowParser, which is implemented only for
/// `arithmetic` types -- signed and unsigned integral types and floating-point
/// types -- and for \c std::string. Those are the valid values for \p Ts
template
<
typename
...
Ts
>
class
CSVIterator
{
public
:
/// \defgroup CSVIteratorTypedefs Typedefs of rosa::csv::CSVIterator
///
/// Standard `typedef`s for iterators.
///
///@{
typedef
std
::
input_iterator_tag
iterator_category
;
///< Category of the iterator.
typedef
std
::
tuple
<
Ts
...
>
value_type
;
///< Type of values iterated over.
typedef
std
::
size_t
difference_type
;
///< Type to identify distance.
typedef
std
::
tuple
<
Ts
...
>
*
pointer
;
///< Pointer to the type iterated over.
typedef
std
::
tuple
<
Ts
...
>
&
reference
;
///< Reference to the type iterated over.
///@}
/// Creates a new instance.
///
/// \param [in,out] S input stream to iterate over
CSVIterator
(
std
::
istream
&
S
)
:
Str
(
S
.
good
()
?
&
S
:
nullptr
),
Row
()
{
// \c rosa::csv::CSVIterator::Row is initialized empty so the first
// incrementation here will read the first row.
++
(
*
this
);
}
/// Creates an empty new instance.
CSVIterator
(
void
)
noexcept
:
Str
(
nullptr
)
{}
/// Pre-increment operator.
///
/// The implementation reads the next row. If the end of the input stream is
/// reached, the operator becomes empty and has no further effect.
///
/// \return \p this object after incrementing it.
CSVIterator
&
operator
++
()
{
if
(
Str
)
{
if
(
!
((
*
Str
)
>>
Row
))
{
Str
=
nullptr
;
}
}
return
*
this
;
}
/// Post-increment operator.
///
/// The implementation uses the pre-increment operator and returns a copy of
/// the original state of \p this object.
///
/// \return \p this object before incrementing it.
CSVIterator
operator
++
(
int
)
{
CSVIterator
Tmp
(
*
this
);
++
(
*
this
);
return
Tmp
;
}
/// Returns a constant reference to the current entry.
///
/// \note Should not dereference the iterator when it is empty.
///
/// \return constant reference to the current entry.
const
std
::
tuple
<
Ts
...
>
&
operator
*
(
void
)
const
noexcept
{
return
Row
.
tuple
();
}
/// Returns a constant pointer to the current entry.
///
/// \note Should not dereference the iterator when it is empty.
///
/// \return constant pointer to the current entry.
const
std
::
tuple
<
Ts
...
>
*
operator
->
(
void
)
const
noexcept
{
return
&
Row
.
tuple
();
}
/// Tells if \p this object is equal to another one.
///
/// Two \c rosa::csv::CSVReader instances are equal if and only if they are
/// the same or both are empty.
///
/// \param RHS other object to compare to
///
/// \return whether \p this object is equal with \p RHS
bool
operator
==
(
const
CSVIterator
&
RHS
)
const
noexcept
{
return
((
this
==
&
RHS
)
||
((
this
->
Str
==
nullptr
)
&&
(
RHS
.
Str
==
nullptr
)));
}
/// Tells if \p this object is not equal to another one.
///
/// \see rosa::csv::CSVReader::operator==
///
/// \param RHS other object to compare to
///
/// \return whether \p this object is not equal with \p RHS.
bool
operator
!=
(
const
CSVIterator
&
RHS
)
const
noexcept
{
return
!
((
*
this
)
==
RHS
);
}
private
:
std
::
istream
*
Str
;
///< Input stream of a CSV file to iterate over.
CSVRow
<
Ts
...
>
Row
;
///< Content of the current row.
};
}
// End namespace csv
}
// End namespace rosa
#endif
// ROSA_SUPPORT_CSV_CSVREADER_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, Aug 29, 1:16 PM (4 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
376178
Default Alt Text
CSVReader.hpp (9 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment