SeqAn3
alignment_matrix_formatter.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
40 #pragma once
41 
42 #include <iomanip>
43 #include <iostream>
44 #include <optional>
45 #include <sstream>
46 
50 
51 namespace seqan3::detail
52 {
53 
72 struct alignment_matrix_format
73 {
75  char const * epsilon{};
77  char const * col_sep{};
79  char const * row_sep{};
81  char const * row_col_sep{};
82 
101  char const * trace_dir[8]{};
102 
113  static const alignment_matrix_format csv;
114 
125  static const alignment_matrix_format ascii;
126 
137  static const alignment_matrix_format unicode_block;
138 
149  static const alignment_matrix_format unicode_braille;
150 
161  static const alignment_matrix_format unicode_arrows;
162 };
163 
164 constexpr alignment_matrix_format alignment_matrix_format::csv
165 {
166  " ", ";", "", "",
167  {"N","D","U","DU","L","DL","UL","DUL"}
168 };
169 
170 constexpr alignment_matrix_format alignment_matrix_format::ascii
171 {
172  " ", "|", "-", "/",
173  {" ","D","U","DU","L","DL","UL","DUL"}
174 };
175 
176 constexpr alignment_matrix_format alignment_matrix_format::unicode_block
177 {
178  u8"ε", u8"║", u8"═", u8"╬",
179  {u8"█",u8"▘",u8"▝",u8"▀",u8"▖",u8"▌",u8"▞",u8"▛"}
180 };
181 
182 constexpr alignment_matrix_format alignment_matrix_format::unicode_braille
183 {
184  u8"ε", u8"║", u8"═", u8"╬",
185  {u8"⠀",u8"⠁",u8"⠈",u8"⠉",u8"⠄",u8"⠅",u8"⠌",u8"⠍"}
186 };
187 
188 constexpr alignment_matrix_format alignment_matrix_format::unicode_arrows
189 {
190  u8"ε", u8"║", u8"═", u8"╬",
191  {u8"↺",u8"↖",u8"↑",u8"↖↑",u8"←",u8"↖←",u8"↑←",u8"↖↑←"}
192 };
193 
208 template <matrix_concept alignment_matrix_t>
209 class alignment_matrix_formatter
210 {
211 public:
213  using alignment_matrix_type = alignment_matrix_t;
214 
215 private:
217  alignment_matrix_type const & matrix;
218 
219 public:
221  alignment_matrix_format symbols;
222 
228  alignment_matrix_formatter() = delete;
229  alignment_matrix_formatter(alignment_matrix_formatter const &) = default;
230  alignment_matrix_formatter(alignment_matrix_formatter &&) = default;
231  alignment_matrix_formatter & operator=(alignment_matrix_formatter const &) = default;
232  alignment_matrix_formatter & operator=(alignment_matrix_formatter &&) = default;
238  alignment_matrix_formatter(alignment_matrix_type const & _matrix, alignment_matrix_format _symbols = alignment_matrix_format::unicode_arrows)
239  : matrix{_matrix}, symbols{_symbols}
240  {}
242 
244  using entry_type = typename alignment_matrix_type::entry_type;
245 
247  static constexpr bool is_traceback_matrix = std::is_same_v<entry_type, trace_directions>;
248 
251  size_t auto_width() const noexcept
252  {
253  size_t col_width = 1;
254  for (size_t row = 0; row < matrix.rows(); ++row)
255  for (size_t col = 0; col < matrix.cols(); ++col)
256  col_width = std::max(col_width, unicode_str_length(entry_at(row, col)));
257  return col_width;
258  }
259 
264  template <typename database_t, typename query_t>
265  void format(database_t && database, query_t && query, std::optional<size_t> column_width = std::nullopt) const noexcept
266  {
267  format(std::forward<database_t>(database), std::forward<query_t>(query), std::cout, column_width);
268  }
269 
278  template <typename database_t, typename query_t, typename char_t, typename traits_t>
279  void format(database_t && database, query_t && query, std::basic_ostream<char_t, traits_t> & cout, std::optional<size_t> const column_width) const noexcept
280  {
281  size_t const _column_width = column_width.has_value() ? column_width.value() : auto_width();
282 
283  auto print_cell = [&](std::string const & symbol)
284  {
285  // deal with unicode chars that mess up std::setw
286  size_t const length_bytes = unicode_str_length_bytes(symbol);
287  size_t const length = unicode_str_length(symbol);
288  size_t const offset = length_bytes - length;
289 
290  cout << std::left
291  << std::setw(_column_width + offset)
292  << symbol
293  << symbols.col_sep;
294  };
295 
296  auto print_first_cell = [&](std::string const & symbol)
297  {
298  cout << symbol << symbols.col_sep;
299  };
300 
301  // |_|d|a|t|a|b|a|s|e|
302  auto print_first_row = [&]
303  {
304  print_first_cell(" ");
305  print_cell(symbols.epsilon);
306 
307  for (size_t col = 0; col < matrix.cols() - 1; ++col)
308  print_cell(as_string(database[col]));
309  cout << "\n";
310  };
311 
312  // |-|-|-|-|-|-|-|-|-|
313  auto print_divider = [&]
314  {
315  cout << " " << symbols.row_col_sep;
316  for (size_t col = 0; col < matrix.cols(); ++col)
317  {
318  for (size_t i = 0; i < _column_width; ++i)
319  cout << symbols.row_sep;
320  cout << symbols.row_col_sep;
321  }
322  cout << "\n";
323  };
324 
325  print_first_row();
326  for (size_t row = 0; row < matrix.rows(); ++row)
327  {
328  if (symbols.row_sep[0] != '\0')
329  print_divider();
330 
331  // one query letter + one row of scores / traces
332  if (row == 0)
333  print_first_cell(symbols.epsilon);
334  else
335  print_first_cell(as_string(query[row - 1]));
336  for (size_t col = 0; col < matrix.cols(); ++col)
337  print_cell(entry_at(row, col));
338  cout << "\n";
339  }
340  }
341 
342 private:
346  std::string entry_at(size_t const row, size_t const col) const noexcept
347  {
348  if constexpr(is_traceback_matrix)
349  {
350  trace_directions direction = matrix.at(row, col);
351  return symbols.trace_dir[(size_t)(direction) % 8u];
352  }
353  else
354  {
355  entry_type entry = matrix.at(row, col);
356  return as_string(entry);
357  }
358  }
359 
361  template <typename entry_type>
362  static std::string as_string(entry_type && entry) noexcept
363  {
364  std::stringstream strstream;
365  debug_stream_type stream{strstream};
366  stream << entry;
367  return strstream.str();
368  }
369 
372  static size_t unicode_str_length(std::string const & str) noexcept
373  {
374  size_t length = 0u;
375  for (auto it = str.cbegin(), it_end = str.cend(); it < it_end; ++it, ++length)
376  {
377  uint8_t v = *it;
378  if ((v & 0b11100000) == 0b11000000)
379  ++it;
380  else if ((v & 0b11110000) == 0b11100000)
381  it += 2;
382  else if ((v & 0b11111000) == 0b11110000)
383  it += 3;
384  }
385  return length;
386  }
387 
389  static size_t unicode_str_length_bytes(std::string const & str) noexcept
390  {
391  return str.length();
392  }
393 
395  friend struct matrix_formatter_test;
396 };
397 
402 template<typename alignment_matrix_t>
403 alignment_matrix_formatter(alignment_matrix_t const &) -> alignment_matrix_formatter<alignment_matrix_t>;
404 
405 template<typename alignment_matrix_t>
406 alignment_matrix_formatter(alignment_matrix_t const &, alignment_matrix_format) -> alignment_matrix_formatter<alignment_matrix_t>;
408 } // namespace seqan3
Contains the declaration of seqan3::detail::alignment_trace_matrix.
Definition: aligned_sequence_concept.hpp:288
Contains seqan3::detail::matrix_concept.
Provides seqan3::debug_stream and related types.