CSVWriter.hpp 6.35 KB
Newer Older
incardon's avatar
incardon committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
 * CSVWriter.hpp
 *
 *  Created on: Dec 15, 2014
 *      Author: Pietro Incardona
 */

#ifndef CSVWRITER_HPP_
#define CSVWRITER_HPP_

#include <iostream>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <fstream>
incardon's avatar
incardon committed
15
#include "util/common.hpp"
incardon's avatar
incardon committed
16
17
18
19
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/for_each.hpp>
#include "csv_multiarray.hpp"
#include "util.hpp"
Pietro Incardona's avatar
Pietro Incardona committed
20
#include "is_csv_writable.hpp"
incardon's avatar
incardon committed
21

Pietro Incardona's avatar
Pietro Incardona committed
22
23
#define CSV_WRITER 0x30000

incardon's avatar
incardon committed
24
25
26
27
28
29
30
31
32
33
34
35
/*! \brief this class is a functor for "for_each" algorithm
 *
 * For each element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the properties of the object
 *
 * \tparam Tobj object
 *
 */

template<typename Tobj>
struct csv_prp
{
incardon's avatar
incardon committed
36
	//! String containing the csv line constructed from an object
incardon's avatar
incardon committed
37
38
	std::stringstream & str;

incardon's avatar
incardon committed
39
	//! Object to write
incardon's avatar
incardon committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
	Tobj & obj;

	/*! \brief Constructor
	 *
	 * Create a vertex properties list
	 *
	 * \param str streamstring
	 * \param obj object to write
	 *
	 */
	csv_prp(std::stringstream & str, Tobj & obj)
	:str(str),obj(obj)
	{
	};

	//! It call the functor for each member
    template<typename T>
    void operator()(T& t)
    {
		// This is the type of the csv column
Pietro Incardona's avatar
Pietro Incardona committed
60
		typedef decltype(obj.template get<T::value>()) col_type;
incardon's avatar
incardon committed
61
62
63

		// Remove the reference from the column type
		typedef typename boost::remove_reference<col_type>::type col_rtype;
Pietro Incardona's avatar
Pietro Incardona committed
64
		typedef typename std::remove_all_extents<col_rtype>::type base_col_rtype;
incardon's avatar
incardon committed
65

Pietro Incardona's avatar
Pietro Incardona committed
66
    	csv_value_str<col_rtype, is_csv_writable<base_col_rtype>::value >(obj.template get<T::value>(),str);
incardon's avatar
incardon committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    }
};

/*! \brief this class is a functor for "for_each" algorithm
 *
 * For each element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the properties of the object
 *
 * \tparam T object
 *
 */

template<typename Tobj, bool attr>
struct csv_col
{
incardon's avatar
incardon committed
82
	//! String containing the colums list as string
incardon's avatar
incardon committed
83
84
	std::stringstream & str;

incardon's avatar
incardon committed
85
86
87
88
89
	/*! \brief Constructor
	 *
	 * \str String where to put the colum list
	 *
	 */
incardon's avatar
incardon committed
90
91
92
93
94
95
96
	csv_col(std::stringstream & str)
	:str(str)
	{
	};

	//! It call the functor for each member
    template<typename T>
Pietro Incardona's avatar
Pietro Incardona committed
97
    inline void operator()(T& t)
incardon's avatar
incardon committed
98
99
    {
		// This is the type of the csv column
Pietro Incardona's avatar
Pietro Incardona committed
100
		typedef typename boost::mpl::at<typename Tobj::type,boost::mpl::int_<T::value>>::type col_type;
incardon's avatar
incardon committed
101

Pietro Incardona's avatar
Pietro Incardona committed
102
    	csv_col_str<col_type>(std::string(Tobj::attributes::name[T::value]),str);
incardon's avatar
incardon committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    }
};

/*! \brief this class is a functor for "for_each" algorithm
 *
 * This class is a functor for "for_each" algorithm. For each
 * element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the vertex
 * properties
 *
 * Specialization when we do not have vertex attributes
 *
 * \tparam G graph type
 *
 */

template<typename Tobj>
struct csv_col<Tobj,false>
{
incardon's avatar
incardon committed
122
	//! String containing the colums list as string
incardon's avatar
incardon committed
123
124
	std::stringstream & str;

incardon's avatar
incardon committed
125
126
127
128
129
	/*! \brief Constructor
	 *
	 * \str String where to put the colum list
	 *
	 */
incardon's avatar
incardon committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	csv_col(std::stringstream & str)
	:str(str)
	{
	};

	//! It call the functor for each member
    template<typename T>
    void operator()(T& t)
    {
		// This is the type of the csv column
		typedef typename boost::fusion::result_of::at_c<typename Tobj::type,T::value>::type col_type;

		// Remove the reference from the column type
		typedef typename boost::remove_reference<col_type>::type col_rtype;

		std::stringstream str2;
		str2 << "column_" << T::value;

		csv_col_str<col_rtype>(str2.str(),str);
    }
};

#define VECTOR 1

/*! \brief CSV Writer
 *
 * It write in CSV format vector of objects living into an N-dimensional space
 *
 * \tparam v_pos Positional vector
 * \tparam v_prp Property vector
 *
 */
template <typename v_pos, typename v_prp, unsigned int impl = VECTOR>
class CSVWriter
{
	/*! \brief Get the colums name (also the positional name)
	 *
	 */
	std::string get_csv_colums()
	{
		std::stringstream str;

		// write positional columns
incardon's avatar
incardon committed
173
		for (size_t i = 0 ; i < v_pos::value_type::dims ; i++)
incardon's avatar
incardon committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
		{
			if (i == 0)
				str << "x[" << i << "]";
			else
				str << "," << "x[" << i << "]";
		}

		// write positional information

		csv_col<typename v_prp::value_type,has_attributes<typename v_prp::value_type>::value> col(str);

		// Iterate through all the vertex and create the vertex list
		boost::mpl::for_each< boost::mpl::range_c<int,0,v_prp::value_type::max_prop> >(col);

		str << "\n";

		return str.str();
	}

	/*! \brief Get the csv data section
	 *
incardon's avatar
incardon committed
195
196
	 * \param vp vector that contain the positional information
	 * \param vpr vector that contain the property information
Pietro Incardona's avatar
Pietro Incardona committed
197
	 * \param offset from where to start
incardon's avatar
incardon committed
198
199
	 *
	 */
Pietro Incardona's avatar
Pietro Incardona committed
200
	std::string get_csv_data(v_pos & vp, v_prp & vpr, size_t offset)
incardon's avatar
incardon committed
201
202
203
204
205
206
207
208
209
210
211
	{
		std::stringstream str;

		// The position and property vector size must match
		if (vp.size() != vpr.size())
		{
			std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " position vector and property vector must have the same size \n";
			return std::string("");
		}

		// Write the data
Pietro Incardona's avatar
Pietro Incardona committed
212
		for (size_t i = offset ; i < vp.size() ; i++)
incardon's avatar
incardon committed
213
214
215
216
217
218
219
220
221
222
		{
			for (size_t j = 0 ; j < v_pos::value_type::dims ; j++)
			{
				if (j == 0)
					str << vp.template get<0>(i)[j];
				else
					str << "," << vp.template get<0>(i)[j];
			}

			// Object to write
Pietro Incardona's avatar
Pietro Incardona committed
223
			auto obj = vpr.get(i);
incardon's avatar
incardon committed
224

Pietro Incardona's avatar
Pietro Incardona committed
225
			csv_prp<decltype(obj)> c_prp(str,obj);
incardon's avatar
incardon committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

			// write the properties to the stream string
			boost::mpl::for_each< boost::mpl::range_c<int,0,v_prp::value_type::max_prop> >(c_prp);

			str << "\n";
		}

		return str.str();
	}

public:

	/*! \brief It write a CSV file
	 *
	 * \tparam prp which properties to output [default = -1 (all)]
	 *
	 * \param file path where to write
incardon's avatar
incardon committed
243
244
	 * \param v positional vector
	 * \param prp properties vector
Pietro Incardona's avatar
Pietro Incardona committed
245
	 * \param offset from where to start to write
incardon's avatar
incardon committed
246
247
	 *
	 */
Pietro Incardona's avatar
Pietro Incardona committed
248
	bool write(std::string file, v_pos & v , v_prp & prp, size_t offset=0)
incardon's avatar
incardon committed
249
250
251
252
253
254
255
256
257
258
	{
		// Header for csv (colums name)
		std::string csv_header;
		// Data point
		std::string point_data;

		// Get csv columns
		csv_header = get_csv_colums();

		// For each property in the vertex type produce a point data
Pietro Incardona's avatar
Pietro Incardona committed
259
		point_data = get_csv_data(v,prp,offset);
incardon's avatar
incardon committed
260
261
262
263
264
265

		// write the file
		std::ofstream ofs(file);

		// Check if the file is open
		if (ofs.is_open() == false)
266
		{std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " cannot create the CSV file: " << file << std::endl;}
incardon's avatar
incardon committed
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

		ofs << csv_header << point_data;

		// Close the file

		ofs.close();

		// Completed succefully
		return true;
	}
};


#endif /* CSVWRITER_HPP_ */