A toolkit for working with phylogenetic data.
v0.22.1
indexed_newick_reader.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include <cassert>
34 #include <stdexcept>
35 
36 namespace genesis {
37 namespace tree {
38 
39 // =================================================================================================
40 // Settings
41 // =================================================================================================
42 
43 IndexedAttributeTreeNewickReaderPlugin& IndexedAttributeTreeNewickReaderPlugin::add_attribute(
44  Source source,
45  size_t index,
46  Target target,
47  std::string const& target_key
48 ) {
49  indexed_attributes_.push_back({ source, index, target, target_key, "", false });
50  return *this;
51 }
52 
53 IndexedAttributeTreeNewickReaderPlugin& IndexedAttributeTreeNewickReaderPlugin::add_attribute(
54  Source source,
55  size_t index,
56  Target target,
57  std::string const& target_key,
58  std::string const& default_value
59 ) {
60  indexed_attributes_.push_back({ source, index, target, target_key, default_value, true });
61  return *this;
62 }
63 
64 IndexedAttributeTreeNewickReaderPlugin& IndexedAttributeTreeNewickReaderPlugin::add_catch_all(
65  Source source,
66  Target target,
67  std::string const& target_key_prefix
68 ) {
69  catch_all_attributes_.push_back({ source, 0, target, target_key_prefix, "", false });
70  return *this;
71 }
72 
73 IndexedAttributeTreeNewickReaderPlugin& IndexedAttributeTreeNewickReaderPlugin::add_catch_all(
74  Target target
75 ) {
76  add_catch_all( Source::kComment, target, "comment_" );
77  add_catch_all( Source::kTag, target, "tag_" );
78  add_catch_all( Source::kValue, target, "value_" );
79  return *this;
80 }
81 
82 void IndexedAttributeTreeNewickReaderPlugin::clear()
83 {
84  indexed_attributes_.clear();
85  catch_all_attributes_.clear();
86 }
87 
88 // =================================================================================================
89 // Plugin Functions
90 // =================================================================================================
91 
92 void IndexedAttributeTreeNewickReaderPlugin::element_to_node(
93  NewickBrokerElement const& element,
94  TreeNode& node
95 ) const {
96  auto& attributes = node.data<AttributeTreeNodeData>().attributes;
97  process_indexed_attributes_( element, attributes, Target::kNode );
98  process_catch_all_attributes_( element, attributes, Target::kNode );
99 }
100 
101 void IndexedAttributeTreeNewickReaderPlugin::element_to_edge(
102  NewickBrokerElement const& element,
103  TreeEdge& edge
104 ) const {
105  auto& attributes = edge.data<AttributeTreeEdgeData>().attributes;
106  process_indexed_attributes_( element, attributes, Target::kEdge );
107  process_catch_all_attributes_( element, attributes, Target::kEdge );
108 }
109 
110 void IndexedAttributeTreeNewickReaderPlugin::register_with( NewickReader& reader ) const
111 {
112  // Set node data creation function.
113  reader.create_node_data_plugin = []( TreeNode& node ){
114  node.reset_data( AttributeTreeNodeData::create() );
115  };
116 
117  // Set edge data creation function.
118  reader.create_edge_data_plugin = []( TreeEdge& edge ){
119  edge.reset_data( AttributeTreeEdgeData::create() );
120  };
121 
122  // Add node manipulation functions.
123  reader.element_to_node_plugins.push_back(
124  [&]( NewickBrokerElement const& element, TreeNode& node ) {
125  element_to_node( element, node );
126  }
127  );
128 
129  // Add edge manipulation functions.
130  reader.element_to_edge_plugins.push_back(
131  [&]( NewickBrokerElement const& element, TreeEdge& edge ) {
132  element_to_edge( element, edge );
133  }
134  );
135 }
136 
137 // =================================================================================================
138 // Internal Functions
139 // =================================================================================================
140 
141 std::vector<std::string> const& IndexedAttributeTreeNewickReaderPlugin::get_attribute_source_(
142  NewickBrokerElement const& element,
143  Source source
144 ) const {
145  switch( source ) {
146  case Source::kValue: {
147  return element.values;
148  }
149  case Source::kComment: {
150  return element.comments;
151  }
152  case Source::kTag: {
153  return element.tags;
154  }
155  default: {
156  // This can only happen if we misuse the enum.
157  throw std::runtime_error( "Invalid source type for indexed attribute." );
158  }
159  }
160 
161  // Make compiler happy. Need to do something here.
162  throw std::runtime_error( "Invalid source type for indexed attribute." );
163 }
164 
165 void IndexedAttributeTreeNewickReaderPlugin::process_indexed_attributes_(
166  NewickBrokerElement const& element,
167  AttributeTreeMap& attributes,
168  Target target
169 ) const {
170  // Process indexed attributes...
171  for( auto const& attrs : indexed_attributes_ ) {
172 
173  // ... but only if they are for our target.
174  if( attrs.target != target ) {
175  continue;
176  }
177 
178  // Find the correct source element.
179  auto const& src = get_attribute_source_( element, attrs.source );
180 
181  // Add the value at the index to the attribute map, or use default if index invalid.
182  if( attrs.index < src.size() ) {
183  attributes[ attrs.target_key ] = src[ attrs.index ];
184  } else if( attrs.use_default ) {
185  attributes[ attrs.target_key ] = attrs.default_value;
186  }
187  }
188 }
189 
190 void IndexedAttributeTreeNewickReaderPlugin::process_catch_all_attributes_(
191  NewickBrokerElement const& element,
192  AttributeTreeMap& attributes,
193  Target target
194 ) const {
195  // Process catch all attributes...
196  for( auto const& attrs : catch_all_attributes_ ) {
197 
198  // ... but only if they are for our target.
199  if( attrs.target != target ) {
200  continue;
201  }
202 
203  // Find the correct source element.
204  auto const& src = get_attribute_source_( element, attrs.source );
205 
206  // Add all source attributes to the target map.
207  size_t cnt = 0;
208  for( auto const& elem : src ) {
209  attributes[ attrs.target_key + std::to_string( cnt ) ] = elem;
210  ++cnt;
211  }
212  }
213 }
214 
215 } // namespace tree
216 } // namespace genesis
Source
Select which kind of Newick data to take, i.e., either comments, values, or tags. ...
static std::unique_ptr< AttributeTreeEdgeData > create()
static std::unique_ptr< AttributeTreeNodeData > create()
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
std::string to_string(T const &v)
Return a string representation of a given value.
Definition: string.hpp:384
Store data at the attributes map of an AttributeTreeEdge.
Store data at the attributes map of an AttributeTreeNode.
Target
Select where to store the data, i.e., at Nodes or Edges of the Tree.
Take data from Newick comments, i.e., [something].
std::map< std::string, std::string > AttributeTreeMap
Alias for the map type used by an AttributeTree.