SeqAn3  3.0.0
The Modern C++ library for sequence analysis.
misc_input.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2019, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2019, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <iostream>
16 #include <string>
17 #include <tuple>
18 
20 #ifdef SEQAN3_HAS_BZIP2
21  #include <seqan3/contrib/stream/bz2_istream.hpp>
22 #endif
23 #ifdef SEQAN3_HAS_ZLIB
24  #include <seqan3/contrib/stream/bgzf_istream.hpp>
26  #include <seqan3/contrib/stream/gz_istream.hpp>
27 #endif
29 #include <seqan3/std/concepts>
30 #include <seqan3/std/filesystem>
31 #include <seqan3/std/ranges>
32 
33 namespace seqan3::detail
34 {
35 
40 template <std::ranges::ForwardRange ref_t, std::ranges::ForwardRange query_t>
41 inline bool starts_with(ref_t && reference, query_t && query)
43  requires std::EqualityComparableWith<reference_t<ref_t>, reference_t<query_t>>
45 {
46  auto rit = std::ranges::begin(reference);
47  auto rend = std::ranges::end(reference);
48 
49  auto qit = std::ranges::begin(query);
50  auto qend = std::ranges::end(query);
51 
52  while (true)
53  {
54  if (qit == qend)
55  return true;
56 
57  if (rit == rend)
58  return false;
59 
60  if (*qit != *rit)
61  return false;
62 
63  ++qit;
64  ++rit;
65  }
66 }
67 
74 template <Char char_t>
75 inline auto make_secondary_istream(std::basic_istream<char_t> & primary_stream, std::filesystem::path & filename)
77 {
78  assert(primary_stream.good());
79 
80  // don't assume ownership
81  constexpr auto stream_deleter_noop = [] (std::basic_istream<char_t> *) {};
82  // assume ownership
83  [[maybe_unused]] constexpr auto stream_deleter_default = [] (std::basic_istream<char_t> * ptr) { delete ptr; };
84 
85  // extract "magic header"
86  std::istreambuf_iterator<char_t> it{primary_stream};
87  std::array<char, magic_header<bgzf_compression>.size()> magic_number{}; // Largest magic header from bgzf
88  size_t read_chars = 0;
89  for (; read_chars < magic_number.size(); ++read_chars)
90  {
92  break;
93 
94  magic_number[read_chars] = *it;
95  ++it;
96  }
97 
98  // unget all read chars.
99  for (size_t i = 0 ; i < read_chars; ++i)
100  primary_stream.unget();
101 
102  std::string const extension = filename.extension().string();
103 
104  // set return value appropriately
105  if (read_chars == magic_number.size() && contrib::_bgzfCheckHeader(magic_number.data())) // BGZF
106  {
107  #ifdef SEQAN3_HAS_ZLIB
108  if ((extension == ".bgzf"))
109  filename.replace_extension();
110 
111  return {new contrib::basic_bgzf_istream<char_t>{primary_stream},
112  stream_deleter_default};
113  #else
114  throw file_open_error{"Trying to read from a bgzf file, but no ZLIB available."};
115  #endif
116  }
117  else if (starts_with(magic_number, magic_header<gz_compression>)) // GZIP
118  {
119  #ifdef SEQAN3_HAS_ZLIB
120  if ((extension == ".gz") || (extension == ".bgzf"))
121  filename.replace_extension();
122 
123  return {new contrib::basic_gz_istream<char_t>{primary_stream}, stream_deleter_default};
124  #else
125  throw file_open_error{"Trying to read from a gzipped file, but no ZLIB available."};
126  #endif
127  }
128  else if (starts_with(magic_number, magic_header<bz2_compression>)) // BZip2
129  {
130  #ifdef SEQAN3_HAS_BZIP2
131  if (extension == ".bz2")
132  filename.replace_extension();
133 
134  return {new contrib::basic_bz2_istream<char_t>{primary_stream}, stream_deleter_default};
135  #else
136  throw file_open_error{"Trying to read from a bzipped file, but no libbz2 available."};
137  #endif
138  }
139  else if (starts_with(magic_number, magic_header<zstd_compression>)) // ZStd
140  {
141  throw file_open_error{"Trying to read from a zst'ed file, but SeqAn does not yet support this."};
142  }
143 
144  return {&primary_stream, stream_deleter_noop};
145 }
146 
148 template <Char char_t>
149 inline auto make_secondary_istream(std::basic_istream<char_t> & primary_stream)
150 {
152  return make_secondary_istream(primary_stream, p);
153 }
154 
155 } // namespace seqan3::detail
Provides concepts for core language types and relations that don&#39;t have concepts in C++20 (yet)...
Provides stream compression utilities.
T rend(T... args)
The Concepts library.
Adaptations of concepts from the Ranges TS.
::ranges::begin begin
Alias for ranges::begin. Returns an iterator to the beginning of a range.
Definition: ranges:174
Definition: aligned_sequence_concept.hpp:35
T size(T... args)
Requires std::detail::WeaklyEqualityComparableWitht<t1,t2>, but also that t1 and t2, as well as their common_reference_t satisfy std::EqualityComparable.
Provides seqan3::detail::magic_header.
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:179
This header includes C++17 filesystem support and imports it into namespace seqan3::filesystem (indep...