gravatar
deba@inf.elte.hu
deba@inf.elte.hu
Section reader for DigraphReader
0 2 0
default
2 files changed with 183 insertions and 12 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
... ...
@@ -87,10 +87,13 @@
87 87
 @attributes
88 88
 source 1
89 89
 target 3
90 90
 caption "LEMON test digraph"
91 91
\endcode
92 92

	
93
The \e LGF can contain extra sections, but there is no restriction on
94
the format of such sections.
95

	
93 96
*/
94 97
}
95 98

	
96 99
//  LocalWords:  whitespace whitespaces
Ignore white space 12 line context
... ...
@@ -265,12 +265,78 @@
265 265
	  is.putback(c);
266 266
	}
267 267
      }
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

	
274 340
  /// \ingroup lemon_io
275 341
  ///  
276 342
  /// \brief LGF reader for directed graphs
... ...
@@ -279,19 +345,20 @@
279 345
  ///
280 346
  /// The reading method does a batch processing. The user creates a
281 347
  /// reader object, then various reading rules can be added to the
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
  /// are used to add attribute reading rules.
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).
295 362
  ///       nodeMap("coordinates", coord_map).
296 363
  ///       arcMap("capacity", cap_map).
297 364
  ///       node("source", src).
... ...
@@ -299,15 +366,16 @@
299 366
  ///       attribute("caption", caption).
300 367
  ///       run();
301 368
  ///\endcode
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
  /// functions.
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
311 379
  /// graph) during the reading, but instead the label map of the items
312 380
  /// are given as a parameter of these functions. An
313 381
  /// application of these function is multipass reading, which is
... ...
@@ -353,12 +421,15 @@
353 421
    ArcMaps _arc_maps;
354 422

	
355 423
    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
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

	
362 433
    int line_num;
363 434
    std::istringstream line;
364 435

	
... ...
@@ -406,12 +477,14 @@
406 477
      _arc_maps.swap(other._arc_maps);
407 478
      _attributes.swap(other._attributes);
408 479

	
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
415 488
    ~DigraphReader() {
416 489
      for (typename NodeMaps::iterator it = _node_maps.begin(); 
417 490
	   it != _node_maps.end(); ++it) {
... ...
@@ -425,12 +498,17 @@
425 498

	
426 499
      for (typename Attributes::iterator it = _attributes.begin(); 
427 500
	   it != _attributes.end(); ++it) {
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
      }
434 512

	
435 513
    }
436 514

	
... ...
@@ -571,12 +649,89 @@
571 649
      _attributes_caption = caption;
572 650
      return *this;
573 651
    }
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

	
580 735
    /// \brief Use previously constructed node set
581 736
    ///
582 737
    /// Use previously constructed node set, and specify the node
... ...
@@ -926,12 +1081,13 @@
926 1081
      
927 1082
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
928 1083
      
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();
935 1091

	
936 1092
      while (readSuccess()) {
937 1093
	skipSection();
... ...
@@ -959,14 +1115,26 @@
959 1115
	  } else if (section == "attributes" && !attributes_done) {
960 1116
	    if (_attributes_caption.empty() || _attributes_caption == caption) {
961 1117
	      readAttributes();
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);
970 1138
	  throw;
971 1139
	}	
972 1140
      }
0 comments (0 inline)