| ... | ... |
@@ -268,6 +268,72 @@ |
| 268 | 268 |
str = os.str(); |
| 269 | 269 |
return is; |
| 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 |
|
| 272 | 338 |
} |
| 273 | 339 |
|
| ... | ... |
@@ -282,13 +348,14 @@ |
| 282 | 348 |
/// reader, and eventually the reading is executed with the \c run() |
| 283 | 349 |
/// member function. A map reading rule can be added to the reader |
| 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 |
/// |
| 293 | 360 |
///\code |
| 294 | 361 |
/// DigraphReader<Digraph>(std::cin, digraph). |
| ... | ... |
@@ -302,9 +369,10 @@ |
| 302 | 369 |
/// |
| 303 | 370 |
/// By default the reader uses the first section in the file of the |
| 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 |
/// |
| 309 | 377 |
/// The \c useNodes() and \c useArcs() functions are used to tell the reader |
| 310 | 378 |
/// that the nodes or arcs should not be constructed (added to the |
| ... | ... |
@@ -356,6 +424,9 @@ |
| 356 | 424 |
Attributes; |
| 357 | 425 |
Attributes _attributes; |
| 358 | 426 |
|
| 427 |
typedef std::map<std::string, _reader_bits::Section*> Sections; |
|
| 428 |
Sections _sections; |
|
| 429 |
|
|
| 359 | 430 |
bool _use_nodes; |
| 360 | 431 |
bool _use_arcs; |
| 361 | 432 |
|
| ... | ... |
@@ -409,6 +480,8 @@ |
| 409 | 480 |
_nodes_caption = other._nodes_caption; |
| 410 | 481 |
_arcs_caption = other._arcs_caption; |
| 411 | 482 |
_attributes_caption = other._attributes_caption; |
| 483 |
|
|
| 484 |
_sections.swap(other._sections); |
|
| 412 | 485 |
} |
| 413 | 486 |
|
| 414 | 487 |
/// \brief Destructor |
| ... | ... |
@@ -428,6 +501,11 @@ |
| 428 | 501 |
delete it->second; |
| 429 | 502 |
} |
| 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) {
|
| 432 | 510 |
delete _is; |
| 433 | 511 |
} |
| ... | ... |
@@ -574,6 +652,83 @@ |
| 574 | 652 |
|
| 575 | 653 |
/// @} |
| 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 |
| 578 | 733 |
/// @{
|
| 579 | 734 |
|
| ... | ... |
@@ -929,6 +1084,7 @@ |
| 929 | 1084 |
bool nodes_done = false; |
| 930 | 1085 |
bool arcs_done = false; |
| 931 | 1086 |
bool attributes_done = false; |
| 1087 |
std::set<std::string> extra_sections; |
|
| 932 | 1088 |
|
| 933 | 1089 |
line_num = 0; |
| 934 | 1090 |
readLine(); |
| ... | ... |
@@ -962,8 +1118,20 @@ |
| 962 | 1118 |
attributes_done = true; |
| 963 | 1119 |
} |
| 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 |
} |
| 968 | 1136 |
} catch (DataFormatError& error) {
|
| 969 | 1137 |
error.line(line_num); |
0 comments (0 inline)