A toolkit for working with phylogenetic data.
v0.22.1
taxonomy.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2018 Lucas Czech and HITS gGmbH
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 
34 
35 #include <algorithm>
36 #include <stdexcept>
37 
38 namespace genesis {
39 namespace taxonomy {
40 
41 // =================================================================================================
42 // Constructors and Rule of Five
43 // =================================================================================================
44 
46  : children_( other.children_ )
47 {
48  reset_parent_pointers_( nullptr );
49 }
50 
52  : children_( std::move( other.children_ ))
53 {
54  reset_parent_pointers_( nullptr );
55 }
56 
58 {
59  children_ = other.children_;
60  reset_parent_pointers_( nullptr );
61  return *this;
62 }
63 
65 {
66  children_ = std::move( other.children_ );
67  reset_parent_pointers_( nullptr );
68  return *this;
69 }
70 
74 void swap( Taxonomy& lhs, Taxonomy& rhs )
75 {
76  using std::swap;
77  swap( lhs.children_, rhs.children_ );
78 }
79 
80 // =================================================================================================
81 // Accessors
82 // =================================================================================================
83 
84 size_t Taxonomy::size() const
85 {
86  return children_.size();
87 }
88 
89 bool Taxonomy::has_child ( std::string name ) const
90 {
91  return children_.end() != std::find_if(
92  children_.begin(),
93  children_.end(),
94  [ &name ] ( Taxon const& r ) {
95  return r.name() == name;
96  }
97  );
98 }
99 
100 Taxon const& Taxonomy::get_child ( std::string name ) const
101 {
102  for( auto const& c : children_ ) {
103  if( c.name() == name ) {
104  return c;
105  }
106  }
107  throw std::runtime_error( "Taxon has no child named '" + name + "'." );
108 }
109 
110 Taxon& Taxonomy::get_child ( std::string name )
111 {
112  for( auto& c : children_ ) {
113  if( c.name() == name ) {
114  return c;
115  }
116  }
117  throw std::runtime_error( "Taxon has no child named '" + name + "'." );
118 }
119 
120 Taxon const& Taxonomy::operator [] ( std::string name ) const
121 {
122  return get_child( name );
123 }
124 
125 Taxon& Taxonomy::operator [] ( std::string name )
126 {
127  return get_child( name );
128 }
129 
130 Taxon const& Taxonomy::at ( size_t index ) const
131 {
132  if( index >= children_.size() ) {
133  throw std::invalid_argument(
134  "Index out of bounds for accessing Taxonomy children: " + std::to_string( index ) +
135  " >= " + std::to_string( children_.size() )
136  );
137  }
138  auto it = std::next( children_.begin(), index );
139  return *it;
140 }
141 
142 Taxon& Taxonomy::at ( size_t index )
143 {
144  if( index >= children_.size() ) {
145  throw std::invalid_argument(
146  "Index out of bounds for accessing Taxonomy children: " + std::to_string( index ) +
147  " >= " + std::to_string( children_.size() )
148  );
149  }
150  auto it = std::next( children_.begin(), index );
151  return *it;
152 }
153 
154 Taxon const& Taxonomy::operator [] ( size_t index ) const
155 {
156  return at( index );
157 }
158 
160 {
161  return at( index );
162 }
163 
164 size_t Taxonomy::index_of( std::string const& name ) const
165 {
166  auto it = children_.begin();
167  size_t i = 0;
168  while( it != children_.end() ) {
169  if( it->name() == name ) {
170  return i;
171  }
172  ++it;
173  ++i;
174  }
175  throw std::runtime_error( "Taxon has no child named '" + name + "'." );
176 }
177 
178 // =================================================================================================
179 // Modifiers
180 // =================================================================================================
181 
183 {
184  return add_child_( child, merge_duplicates );
185 }
186 
187 Taxon& Taxonomy::add_child( std::string const& name, bool merge_duplicates )
188 {
189  return add_child_( Taxon( name ), merge_duplicates );
190 }
191 
192 void Taxonomy::remove_child( std::string const& name )
193 {
194  auto it = std::find_if(
195  children_.begin(),
196  children_.end(),
197  [ &name ] ( Taxon const& r ) {
198  return r.name() == name;
199  }
200  );
201  if( it == children_.end() ) {
202  throw std::runtime_error( "Taxon has no child named '" + name + "'." );
203  }
204  children_.erase( it );
205 
206  // We probably don't need to call reset_parent_pointers_() here. The removal causes all
207  // following elements in the container to move, so that their particular move constructors
208  // (or assignment operators) are called, causing all their children to be updated. The
209  // elemetns themselves do not need an update, as their parent didn't move!
210  // (Hopefully, that's true... The tests don't fail, so that's a good sign!)
211 }
212 
213 void Taxonomy::remove_at( size_t index )
214 {
215  if( index >= children_.size() ) {
216  throw std::runtime_error( "Invalid Taxon index." );
217  }
218 
219  auto it = children_.begin();
220  std::advance( it, index );
221  children_.erase( it );
222 }
223 
225 {
226  children_.clear();
227 }
228 
229 // =================================================================================================
230 // Iterators
231 // =================================================================================================
232 
234 {
235  return children_.begin();
236 }
237 
239 {
240  return children_.end();
241 }
242 
244 {
245  return children_.cbegin();
246 }
247 
249 {
250  return children_.cend();
251 }
252 
254 {
255  return children_.cbegin();
256 }
257 
259 {
260  return children_.cend();
261 }
262 
263 // =================================================================================================
264 // Internal Implementation Details
265 // =================================================================================================
266 
268 {
269  // Check if a child taxon with the given name already exists.
270  if( merge_duplicates ) {
271  for( auto& c : children_ ) {
272  if( c.name() == child.name() ) {
273 
274  // If so, add the children of the new child to it (recursively), and return it.
275  for( auto& child_children : child ) {
276  c.add_child_( child_children, merge_duplicates );
277  }
278  return c;
279  }
280  }
281  }
282 
283  // If not, add it as a a new child.
284  children_.push_back( child );
285  // children_.back().parent_ = nullptr;
286 
287  // We added to the container. This might have cause relocation of the contant.
288  // Need to update parent pointers!
289  reset_parent_pointers_( nullptr );
290  return children_.back();
291 }
292 
294 {
295  for( auto& taxon : children_ ) {
296  taxon.parent_ = parent;
297  // Probably don't need recursion here, as this function will be called for the sub-objects
298  // anyway if needed.
299  // The following line is left here in case it turns out we need it after all...
300  // taxon.reset_parent_pointers_( &taxon );
301  }
302 }
303 
304 } // namespace taxonomy
305 } // namespace genesis
bool has_child(std::string name) const
Return whether an immediate child Taxon with the given name exists.
Definition: taxonomy.cpp:89
void remove_at(size_t index)
Remove a child Taxon at a certain index.
Definition: taxonomy.cpp:213
Taxonomy & operator=(Taxonomy const &)
Copy assigment operator.
Definition: taxonomy.cpp:57
virtual Taxon & add_child_(Taxon const &child, bool merge_duplicates)
Virtual implementation function for adding a child Taxon.
Definition: taxonomy.cpp:267
iterator begin()
Return an iterator to the beginning of the child taxa.
Definition: taxonomy.cpp:233
size_t size() const
Return the number of immediate child Taxa.
Definition: taxonomy.cpp:84
Taxon const & at(size_t index) const
Return the child Taxon at the given index.
Definition: taxonomy.cpp:130
STL namespace.
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
Taxon & add_child_(Taxon const &child, bool merge_duplicates) override
Virtual implementation function for adding a child taxon.
Definition: taxon.cpp:212
void reset_parent_pointers_(Taxon *parent)
Internal helper function that resets the parent pointer of all stored Taxa.
Definition: taxonomy.cpp:293
Store a Taxonomy, i.e., a nested hierarchy of Taxa.
std::list< Taxon >::const_iterator const_iterator
Taxon const & get_child(std::string name) const
Return the child Taxon with a given name if it exists, or throw otherwise.
Definition: taxonomy.cpp:100
Taxon & add_child(Taxon const &child, bool merge_duplicates=true)
Add a child Taxon as a copy of a given Taxon and return it.
Definition: taxonomy.cpp:182
std::string const & name() const
Return the name of this taxon.
Definition: taxon.cpp:131
size_t index_of(std::string const &name) const
Definition: taxonomy.cpp:164
const_iterator cend() const
Return a const iterator to the end of the child taxa.
Definition: taxonomy.cpp:258
Store a Taxon, i.e., an element in a Taxonomy, with its name, rank, ID and sub-taxa.
Definition: taxon.hpp:76
const_iterator cbegin() const
Return a const iterator to the beginning of the child taxa.
Definition: taxonomy.cpp:253
void remove_child(std::string const &name)
Remove a child Taxon with a certain name.
Definition: taxonomy.cpp:192
Taxon const & operator[](std::string name) const
Return the child Taxon with a given name if it exists, or throw otherwise.
Definition: taxonomy.cpp:120
iterator end()
Return an iterator to the end of the child taxa.
Definition: taxonomy.cpp:238
void swap(Taxonomy &lhs, Taxonomy &rhs)
Swapperator for Taxonomy.
Definition: taxonomy.cpp:74
std::list< Taxon >::iterator iterator
friend void swap(Taxonomy &lhs, Taxonomy &rhs)
Swapperator for Taxonomy.
Definition: taxonomy.cpp:74
void clear_children()
Remove all children.
Definition: taxonomy.cpp:224
void merge_duplicates(Sample &smp)
Look for Pqueries with the same name and merge them.