... | ... |
@@ -270,2 +270,68 @@ |
270 | 270 |
} |
271 |
|
|
272 |
class Section { |
|
273 |
public: |
|
274 |
virtual ~Section() {} |
|
275 |
virtual void process(std::istream& is, int& line_num) = 0; |
|
276 |
}; |
|
277 |
|
|
278 |
template <typename Functor> |
|
279 |
class LineSection : public Section { |
|
280 |
private: |
|
281 |
|
|
282 |
Functor _functor; |
|
283 |
|
|
284 |
public: |
|
285 |
|
|
286 |
LineSection(const Functor& functor) : _functor(functor) {} |
|
287 |
virtual ~LineSection() {} |
|
288 |
|
|
289 |
virtual void process(std::istream& is, int& line_num) { |
|
290 |
char c; |
|
291 |
std::string line; |
|
292 |
while (is.get(c) && c != '@') { |
|
293 |
if (c == '\n') { |
|
294 |
++line_num; |
|
295 |
} else if (c == '#') { |
|
296 |
getline(is, line); |
|
297 |
++line_num; |
|
298 |
} else if (!isWhiteSpace(c)) { |
|
299 |
is.putback(c); |
|
300 |
getline(is, line); |
|
301 |
_functor(line); |
|
302 |
++line_num; |
|
303 |
} |
|
304 |
} |
|
305 |
if (is) is.putback(c); |
|
306 |
else if (is.eof()) is.clear(); |
|
307 |
} |
|
308 |
}; |
|
309 |
|
|
310 |
template <typename Functor> |
|
311 |
class StreamSection : public Section { |
|
312 |
private: |
|
313 |
|
|
314 |
Functor _functor; |
|
315 |
|
|
316 |
public: |
|
317 |
|
|
318 |
StreamSection(const Functor& functor) : _functor(functor) {} |
|
319 |
virtual ~StreamSection() {} |
|
320 |
|
|
321 |
virtual void process(std::istream& is, int& line_num) { |
|
322 |
_functor(is, line_num); |
|
323 |
char c; |
|
324 |
std::string line; |
|
325 |
while (is.get(c) && c != '@') { |
|
326 |
if (c == '\n') { |
|
327 |
++line_num; |
|
328 |
} else if (!isWhiteSpace(c)) { |
|
329 |
getline(is, line); |
|
330 |
++line_num; |
|
331 |
} |
|
332 |
} |
|
333 |
if (is) is.putback(c); |
|
334 |
else if (is.eof()) is.clear(); |
|
335 |
} |
|
336 |
}; |
|
271 | 337 |
|
... | ... |
@@ -284,9 +350,10 @@ |
284 | 350 |
/// with the \c nodeMap() or \c arcMap() members. An optional |
285 |
/// converter parameter can also be added as a standard functor converting from |
|
286 |
/// std::string to the value type of the map. If it is set, it will |
|
287 |
/// determine how the tokens in the file should be is converted to the map's |
|
288 |
/// value type. If the functor is not set, then a default conversion |
|
289 |
/// will be used. One map can be read into multiple map objects at the |
|
290 |
/// same time. The \c attribute(), \c node() and \c arc() functions |
|
291 |
/// |
|
351 |
/// converter parameter can also be added as a standard functor |
|
352 |
/// converting from std::string to the value type of the map. If it |
|
353 |
/// is set, it will determine how the tokens in the file should be |
|
354 |
/// is converted to the map's value type. If the functor is not set, |
|
355 |
/// then a default conversion will be used. One map can be read into |
|
356 |
/// multiple map objects at the same time. The \c attribute(), \c |
|
357 |
/// node() and \c arc() functions are used to add attribute reading |
|
358 |
/// rules. |
|
292 | 359 |
/// |
... | ... |
@@ -304,5 +371,6 @@ |
304 | 371 |
/// proper type. If a section has an optional name, then it can be |
305 |
/// selected for reading by giving an optional name parameter to |
|
306 |
/// the \c nodes(), \c arcs() or \c attributes() |
|
307 |
/// |
|
372 |
/// selected for reading by giving an optional name parameter to the |
|
373 |
/// \c nodes(), \c arcs() or \c attributes() functions. The readers |
|
374 |
/// also can load extra sections with the \c sectionLines() and |
|
375 |
/// sectionStream() functions. |
|
308 | 376 |
/// |
... | ... |
@@ -358,2 +426,5 @@ |
358 | 426 |
|
427 |
typedef std::map<std::string, _reader_bits::Section*> Sections; |
|
428 |
Sections _sections; |
|
429 |
|
|
359 | 430 |
bool _use_nodes; |
... | ... |
@@ -411,2 +482,4 @@ |
411 | 482 |
_attributes_caption = other._attributes_caption; |
483 |
|
|
484 |
_sections.swap(other._sections); |
|
412 | 485 |
} |
... | ... |
@@ -430,2 +503,7 @@ |
430 | 503 |
|
504 |
for (typename Sections::iterator it = _sections.begin(); |
|
505 |
it != _sections.end(); ++it) { |
|
506 |
delete it->second; |
|
507 |
} |
|
508 |
|
|
431 | 509 |
if (local_is) { |
... | ... |
@@ -576,2 +654,79 @@ |
576 | 654 |
|
655 |
/// \name Section readers |
|
656 |
/// @{ |
|
657 |
|
|
658 |
/// \brief Add a section processor with line oriented reading |
|
659 |
/// |
|
660 |
/// In the \e LGF file extra sections can be placed, which contain |
|
661 |
/// any data in arbitrary format. These sections can be read with |
|
662 |
/// this function line by line. The first parameter is the type |
|
663 |
/// descriptor of the section, the second is a functor, which |
|
664 |
/// takes just one \c std::string parameter. At the reading |
|
665 |
/// process, each line of the section will be given to the functor |
|
666 |
/// object. However, the empty lines and the comment lines are |
|
667 |
/// filtered out, and the leading whitespaces are stipped from |
|
668 |
/// each processed string. |
|
669 |
/// |
|
670 |
/// For example let's see a section, which contain several |
|
671 |
/// integers, which should be inserted into a vector. |
|
672 |
///\code |
|
673 |
/// @numbers |
|
674 |
/// 12 45 23 |
|
675 |
/// 4 |
|
676 |
/// 23 6 |
|
677 |
///\endcode |
|
678 |
/// |
|
679 |
/// The functor is implemented as an struct: |
|
680 |
///\code |
|
681 |
/// struct NumberSection { |
|
682 |
/// std::vector<int>& _data; |
|
683 |
/// NumberSection(std::vector<int>& data) : _data(data) {} |
|
684 |
/// void operator()(const std::string& line) { |
|
685 |
/// std::istringstream ls(line); |
|
686 |
/// int value; |
|
687 |
/// while (ls >> value) _data.push_back(value); |
|
688 |
/// } |
|
689 |
/// }; |
|
690 |
/// |
|
691 |
/// // ... |
|
692 |
/// |
|
693 |
/// reader.sectionLines("numbers", NumberSection(vec)); |
|
694 |
///\endcode |
|
695 |
template <typename Functor> |
|
696 |
DigraphReader& sectionLines(const std::string& type, Functor functor) { |
|
697 |
LEMON_ASSERT(!type.empty(), "Type is not empty."); |
|
698 |
LEMON_ASSERT(_sections.find(type) == _sections.end(), |
|
699 |
"Multiple reading of section."); |
|
700 |
LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" && |
|
701 |
type != "attributes", "Multiple reading of section."); |
|
702 |
_sections.insert(std::make_pair(type, |
|
703 |
new _reader_bits::LineSection<Functor>(functor))); |
|
704 |
return *this; |
|
705 |
} |
|
706 |
|
|
707 |
|
|
708 |
/// \brief Add a section processor with stream oriented reading |
|
709 |
/// |
|
710 |
/// In the \e LGF file extra sections can be placed, which contain |
|
711 |
/// any data in arbitrary format. These sections can be read |
|
712 |
/// directly with this function. The first parameter is the type |
|
713 |
/// of the section, the second is a functor, which takes an \c |
|
714 |
/// std::istream& and an int& parameter, the latter regard to the |
|
715 |
/// line number of stream. The functor can read the input while |
|
716 |
/// the section go on, and the line number should be modified |
|
717 |
/// accordingly. |
|
718 |
template <typename Functor> |
|
719 |
DigraphReader& sectionStream(const std::string& type, Functor functor) { |
|
720 |
LEMON_ASSERT(!type.empty(), "Type is not empty."); |
|
721 |
LEMON_ASSERT(_sections.find(type) == _sections.end(), |
|
722 |
"Multiple reading of section."); |
|
723 |
LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" && |
|
724 |
type != "attributes", "Multiple reading of section."); |
|
725 |
_sections.insert(std::make_pair(type, |
|
726 |
new _reader_bits::StreamSection<Functor>(functor))); |
|
727 |
return *this; |
|
728 |
} |
|
729 |
|
|
730 |
/// @} |
|
731 |
|
|
577 | 732 |
/// \name Using previously constructed node or arc set |
... | ... |
@@ -931,2 +1086,3 @@ |
931 | 1086 |
bool attributes_done = false; |
1087 |
std::set<std::string> extra_sections; |
|
932 | 1088 |
|
... | ... |
@@ -964,4 +1120,16 @@ |
964 | 1120 |
} else { |
965 |
readLine(); |
|
966 |
skipSection(); |
|
1121 |
if (extra_sections.find(section) != extra_sections.end()) { |
|
1122 |
std::ostringstream msg; |
|
1123 |
msg << "Multiple occurence of section " << section; |
|
1124 |
throw DataFormatError(msg.str().c_str()); |
|
1125 |
} |
|
1126 |
Sections::iterator it = _sections.find(section); |
|
1127 |
if (it != _sections.end()) { |
|
1128 |
extra_sections.insert(section); |
|
1129 |
it->second->process(*_is, line_num); |
|
1130 |
readLine(); |
|
1131 |
} else { |
|
1132 |
readLine(); |
|
1133 |
skipSection(); |
|
1134 |
} |
|
967 | 1135 |
} |
0 comments (0 inline)