A library for working with phylogenetic and population genetic data.
v0.27.0
taxopath.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 
37 
38 #include <stdexcept>
39 
40 namespace genesis {
41 namespace taxonomy {
42 
43 // =================================================================================================
44 // Taxopath
45 // =================================================================================================
46 
77  Taxonomy& taxonomy,
78  Taxopath const& taxopath,
79  bool expect_parents
80 ) {
81  // The return value of this function is the added Taxon. If we don't add anything, we
82  // cannot return anything. So better throw. This might need to change in the future...
83  if( taxopath.empty() ) {
84  throw std::runtime_error(
85  "Cannot add empty Taxopath to Taxonomy."
86  );
87  }
88 
89  // Prepare: we need a Taxonomy to add children to. This pointer is updated in the loop so that
90  // we go deeper and deeper into the taxonomy.
91  Taxonomy* cur_taxon = &taxonomy;
92 
93  // Add the names to the Taxonomy.
94  for( size_t i = 0; i < taxopath.size(); ++i ) {
95 
96  // If we expect parents to exists, we need to check if the child exists
97  // (but only when we are still considering parents, and not the last taxon itself,
98  // that is, if we are not at the last element of the taxopath).
99  if( ( expect_parents ) &&
100  ( i < taxopath.size() - 1 ) &&
101  ( ! cur_taxon->has_child( taxopath[i] ))
102  ) {
103  throw std::runtime_error(
104  "Not all super-taxa of the Taxon in the Taxopath are present in the given Taxonomy."
105  );
106  }
107 
108  cur_taxon = &cur_taxon->add_child( taxopath[i] );
109  }
110 
111  // Convert to Taxon. This is always legal because we have ensured that we are adding at least
112  // one sub-taxon to the taxonomy, and in the loop set cur_taxon to this taxon, so that it is
113  // actually of dynamic type Taxon.
114  return dynamic_cast< Taxon& >( *cur_taxon );
115 }
116 
120 Taxon const* find_taxon_by_taxopath( Taxonomy const& tax, Taxopath const& taxopath )
121 {
122  // Border condition: nothing to search for.
123  if( taxopath.empty() ) {
124  return nullptr;
125  }
126 
127  // Use a pointer that is updated in the loop while we go deeper and deeper into the taxonomy.
128  Taxonomy const* cur_taxon = &tax;
129 
130  // Find the elements of the Taxopath in the Taxonomy.
131  for( auto const& name : taxopath ) {
132  if( ! cur_taxon->has_child( name )) {
133  return nullptr;
134  }
135  cur_taxon = &cur_taxon->get_child( name );
136  }
137 
138  // Convert to Taxon. This is always legal because we have ensured that we execute the loop at
139  // least once. If we thus reach this point, we have set cur_taxon to a child of the Taxonomy,
140  // which is a Taxon.
141  return dynamic_cast< Taxon const* >( cur_taxon );
142 }
143 
148 {
149  // Avoid code duplication according to Scott Meyers.
150  auto const& ctax = static_cast< Taxonomy const& >( tax );
151  return const_cast< Taxon* >( find_taxon_by_taxopath( ctax, taxopath ));
152 }
153 
154 } // namespace taxonomy
155 } // namespace genesis
genesis::taxonomy::Taxopath::size
size_t size() const
Return the number of elements of this Taxopath.
Definition: taxopath.hpp:154
taxopath.hpp
genesis::taxonomy::Taxopath::empty
bool empty() const
Return whether the Taxopath is empty, i.e., does not contain any elements.
Definition: taxopath.hpp:146
genesis::taxonomy::Taxon
Store a Taxon, i.e., an element in a Taxonomy, with its name, rank, ID and sub-taxa.
Definition: taxon.hpp:76
genesis::taxonomy::Taxonomy::has_child
bool has_child(std::string name) const
Return whether an immediate child Taxon with the given name exists.
Definition: taxonomy.cpp:89
genesis::taxonomy::Taxonomy::add_child
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
taxonomy.hpp
genesis::taxonomy::Taxopath
Helper class to store a taxonomic path.
Definition: taxopath.hpp:83
string.hpp
Provides some commonly used string utility functions.
taxopath.hpp
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::taxonomy::add_from_taxopath
Taxon & add_from_taxopath(Taxonomy &taxonomy, Taxopath const &taxopath, bool expect_parents)
Add a Taxon to a Taxonomy, using the taxonomic elements of a Taxopath.
Definition: taxopath.cpp:76
genesis::taxonomy::Taxonomy
Store a Taxonomy, i.e., a nested hierarchy of Taxa.
Definition: taxonomy/taxonomy.hpp:96
taxon.hpp
genesis::taxonomy::Taxonomy::get_child
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
genesis::taxonomy::find_taxon_by_taxopath
Taxon const * find_taxon_by_taxopath(Taxonomy const &tax, Taxopath const &taxopath)
Find a Taxon in a Taxonomy, given its Taxopath.
Definition: taxopath.cpp:120