1.1 --- a/doc/lgf.dox Mon May 26 13:50:47 2008 +0100
1.2 +++ b/doc/lgf.dox Tue May 27 16:01:20 2008 +0200
1.3 @@ -90,6 +90,9 @@
1.4 caption "LEMON test digraph"
1.5 \endcode
1.6
1.7 +The \e LGF can contain extra sections, but there is no restriction on
1.8 +the format of such sections.
1.9 +
1.10 */
1.11 }
1.12
2.1 --- a/lemon/lgf_reader.h Mon May 26 13:50:47 2008 +0100
2.2 +++ b/lemon/lgf_reader.h Tue May 27 16:01:20 2008 +0200
2.3 @@ -268,6 +268,72 @@
2.4 str = os.str();
2.5 return is;
2.6 }
2.7 +
2.8 + class Section {
2.9 + public:
2.10 + virtual ~Section() {}
2.11 + virtual void process(std::istream& is, int& line_num) = 0;
2.12 + };
2.13 +
2.14 + template <typename Functor>
2.15 + class LineSection : public Section {
2.16 + private:
2.17 +
2.18 + Functor _functor;
2.19 +
2.20 + public:
2.21 +
2.22 + LineSection(const Functor& functor) : _functor(functor) {}
2.23 + virtual ~LineSection() {}
2.24 +
2.25 + virtual void process(std::istream& is, int& line_num) {
2.26 + char c;
2.27 + std::string line;
2.28 + while (is.get(c) && c != '@') {
2.29 + if (c == '\n') {
2.30 + ++line_num;
2.31 + } else if (c == '#') {
2.32 + getline(is, line);
2.33 + ++line_num;
2.34 + } else if (!isWhiteSpace(c)) {
2.35 + is.putback(c);
2.36 + getline(is, line);
2.37 + _functor(line);
2.38 + ++line_num;
2.39 + }
2.40 + }
2.41 + if (is) is.putback(c);
2.42 + else if (is.eof()) is.clear();
2.43 + }
2.44 + };
2.45 +
2.46 + template <typename Functor>
2.47 + class StreamSection : public Section {
2.48 + private:
2.49 +
2.50 + Functor _functor;
2.51 +
2.52 + public:
2.53 +
2.54 + StreamSection(const Functor& functor) : _functor(functor) {}
2.55 + virtual ~StreamSection() {}
2.56 +
2.57 + virtual void process(std::istream& is, int& line_num) {
2.58 + _functor(is, line_num);
2.59 + char c;
2.60 + std::string line;
2.61 + while (is.get(c) && c != '@') {
2.62 + if (c == '\n') {
2.63 + ++line_num;
2.64 + } else if (!isWhiteSpace(c)) {
2.65 + getline(is, line);
2.66 + ++line_num;
2.67 + }
2.68 + }
2.69 + if (is) is.putback(c);
2.70 + else if (is.eof()) is.clear();
2.71 + }
2.72 + };
2.73
2.74 }
2.75
2.76 @@ -282,13 +348,14 @@
2.77 /// reader, and eventually the reading is executed with the \c run()
2.78 /// member function. A map reading rule can be added to the reader
2.79 /// with the \c nodeMap() or \c arcMap() members. An optional
2.80 - /// converter parameter can also be added as a standard functor converting from
2.81 - /// std::string to the value type of the map. If it is set, it will
2.82 - /// determine how the tokens in the file should be is converted to the map's
2.83 - /// value type. If the functor is not set, then a default conversion
2.84 - /// will be used. One map can be read into multiple map objects at the
2.85 - /// same time. The \c attribute(), \c node() and \c arc() functions
2.86 - /// are used to add attribute reading rules.
2.87 + /// converter parameter can also be added as a standard functor
2.88 + /// converting from std::string to the value type of the map. If it
2.89 + /// is set, it will determine how the tokens in the file should be
2.90 + /// is converted to the map's value type. If the functor is not set,
2.91 + /// then a default conversion will be used. One map can be read into
2.92 + /// multiple map objects at the same time. The \c attribute(), \c
2.93 + /// node() and \c arc() functions are used to add attribute reading
2.94 + /// rules.
2.95 ///
2.96 ///\code
2.97 /// DigraphReader<Digraph>(std::cin, digraph).
2.98 @@ -302,9 +369,10 @@
2.99 ///
2.100 /// By default the reader uses the first section in the file of the
2.101 /// proper type. If a section has an optional name, then it can be
2.102 - /// selected for reading by giving an optional name parameter to
2.103 - /// the \c nodes(), \c arcs() or \c attributes()
2.104 - /// functions.
2.105 + /// selected for reading by giving an optional name parameter to the
2.106 + /// \c nodes(), \c arcs() or \c attributes() functions. The readers
2.107 + /// also can load extra sections with the \c sectionLines() and
2.108 + /// sectionStream() functions.
2.109 ///
2.110 /// The \c useNodes() and \c useArcs() functions are used to tell the reader
2.111 /// that the nodes or arcs should not be constructed (added to the
2.112 @@ -356,6 +424,9 @@
2.113 Attributes;
2.114 Attributes _attributes;
2.115
2.116 + typedef std::map<std::string, _reader_bits::Section*> Sections;
2.117 + Sections _sections;
2.118 +
2.119 bool _use_nodes;
2.120 bool _use_arcs;
2.121
2.122 @@ -409,6 +480,8 @@
2.123 _nodes_caption = other._nodes_caption;
2.124 _arcs_caption = other._arcs_caption;
2.125 _attributes_caption = other._attributes_caption;
2.126 +
2.127 + _sections.swap(other._sections);
2.128 }
2.129
2.130 /// \brief Destructor
2.131 @@ -428,6 +501,11 @@
2.132 delete it->second;
2.133 }
2.134
2.135 + for (typename Sections::iterator it = _sections.begin();
2.136 + it != _sections.end(); ++it) {
2.137 + delete it->second;
2.138 + }
2.139 +
2.140 if (local_is) {
2.141 delete _is;
2.142 }
2.143 @@ -574,6 +652,83 @@
2.144
2.145 /// @}
2.146
2.147 + /// \name Section readers
2.148 + /// @{
2.149 +
2.150 + /// \brief Add a section processor with line oriented reading
2.151 + ///
2.152 + /// In the \e LGF file extra sections can be placed, which contain
2.153 + /// any data in arbitrary format. These sections can be read with
2.154 + /// this function line by line. The first parameter is the type
2.155 + /// descriptor of the section, the second is a functor, which
2.156 + /// takes just one \c std::string parameter. At the reading
2.157 + /// process, each line of the section will be given to the functor
2.158 + /// object. However, the empty lines and the comment lines are
2.159 + /// filtered out, and the leading whitespaces are stipped from
2.160 + /// each processed string.
2.161 + ///
2.162 + /// For example let's see a section, which contain several
2.163 + /// integers, which should be inserted into a vector.
2.164 + ///\code
2.165 + /// @numbers
2.166 + /// 12 45 23
2.167 + /// 4
2.168 + /// 23 6
2.169 + ///\endcode
2.170 + ///
2.171 + /// The functor is implemented as an struct:
2.172 + ///\code
2.173 + /// struct NumberSection {
2.174 + /// std::vector<int>& _data;
2.175 + /// NumberSection(std::vector<int>& data) : _data(data) {}
2.176 + /// void operator()(const std::string& line) {
2.177 + /// std::istringstream ls(line);
2.178 + /// int value;
2.179 + /// while (ls >> value) _data.push_back(value);
2.180 + /// }
2.181 + /// };
2.182 + ///
2.183 + /// // ...
2.184 + ///
2.185 + /// reader.sectionLines("numbers", NumberSection(vec));
2.186 + ///\endcode
2.187 + template <typename Functor>
2.188 + DigraphReader& sectionLines(const std::string& type, Functor functor) {
2.189 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
2.190 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
2.191 + "Multiple reading of section.");
2.192 + LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
2.193 + type != "attributes", "Multiple reading of section.");
2.194 + _sections.insert(std::make_pair(type,
2.195 + new _reader_bits::LineSection<Functor>(functor)));
2.196 + return *this;
2.197 + }
2.198 +
2.199 +
2.200 + /// \brief Add a section processor with stream oriented reading
2.201 + ///
2.202 + /// In the \e LGF file extra sections can be placed, which contain
2.203 + /// any data in arbitrary format. These sections can be read
2.204 + /// directly with this function. The first parameter is the type
2.205 + /// of the section, the second is a functor, which takes an \c
2.206 + /// std::istream& and an int& parameter, the latter regard to the
2.207 + /// line number of stream. The functor can read the input while
2.208 + /// the section go on, and the line number should be modified
2.209 + /// accordingly.
2.210 + template <typename Functor>
2.211 + DigraphReader& sectionStream(const std::string& type, Functor functor) {
2.212 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
2.213 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
2.214 + "Multiple reading of section.");
2.215 + LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
2.216 + type != "attributes", "Multiple reading of section.");
2.217 + _sections.insert(std::make_pair(type,
2.218 + new _reader_bits::StreamSection<Functor>(functor)));
2.219 + return *this;
2.220 + }
2.221 +
2.222 + /// @}
2.223 +
2.224 /// \name Using previously constructed node or arc set
2.225 /// @{
2.226
2.227 @@ -929,6 +1084,7 @@
2.228 bool nodes_done = false;
2.229 bool arcs_done = false;
2.230 bool attributes_done = false;
2.231 + std::set<std::string> extra_sections;
2.232
2.233 line_num = 0;
2.234 readLine();
2.235 @@ -962,8 +1118,20 @@
2.236 attributes_done = true;
2.237 }
2.238 } else {
2.239 - readLine();
2.240 - skipSection();
2.241 + if (extra_sections.find(section) != extra_sections.end()) {
2.242 + std::ostringstream msg;
2.243 + msg << "Multiple occurence of section " << section;
2.244 + throw DataFormatError(msg.str().c_str());
2.245 + }
2.246 + Sections::iterator it = _sections.find(section);
2.247 + if (it != _sections.end()) {
2.248 + extra_sections.insert(section);
2.249 + it->second->process(*_is, line_num);
2.250 + readLine();
2.251 + } else {
2.252 + readLine();
2.253 + skipSection();
2.254 + }
2.255 }
2.256 } catch (DataFormatError& error) {
2.257 error.line(line_num);