Skip to content

Commit 29d46d4

Browse files
committed
[misc] various things I would rather have in SeqAn
1 parent a6b66ae commit 29d46d4

File tree

16 files changed

+247
-77
lines changed

16 files changed

+247
-77
lines changed

include/bio/detail/range.hpp

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
#pragma once
1515

16+
#include <ranges>
17+
#include <span>
18+
1619
#include <seqan3/alphabet/concept.hpp>
17-
#include <seqan3/utility/concept/container.hpp>
1820

1921
#include <bio/platform.hpp>
2022

@@ -25,6 +27,57 @@ namespace bio::detail
2527
* \{
2628
*/
2729

30+
// ----------------------------------------------------------------------------
31+
// concepts
32+
// ----------------------------------------------------------------------------
33+
34+
/*!\interface bio::detail::back_insertable_with <>
35+
* \extends std::ranges::output_range
36+
* \tparam rng_t The container type.
37+
* \tparam val_t The type to append to the container.
38+
* \brief Describes range types that can grow in amortised constant time by appending an element of type val_t.
39+
*/
40+
//!\cond
41+
template <typename rng_t, typename val_t>
42+
concept back_insertable_with = std::ranges::output_range<rng_t, val_t> && requires(rng_t & v)
43+
{
44+
v.push_back(std::declval<val_t>());
45+
};
46+
//!\endcond
47+
48+
/*!\interface bio::detail::back_insertable <>
49+
* \extends std::ranges::output_range
50+
* \extends std::ranges::input_range
51+
* \tparam rng_t The container type.
52+
* \brief Describes range types that can grow in amortised constant time by appending an element.
53+
*/
54+
//!\cond
55+
template <typename rng_t>
56+
concept back_insertable =
57+
std::ranges::input_range<rng_t> && back_insertable_with<rng_t, std::ranges::range_reference_t<rng_t>>;
58+
//!\endcond
59+
60+
//!\brief A seqan3::alphabet that is **not** a character or number (any std::integral).
61+
template <typename t>
62+
concept deliberate_alphabet = seqan3::alphabet<t> && !std::integral<std::remove_cvref_t<t>>;
63+
64+
//!\brief A range whose value type is `char`.
65+
template <typename t>
66+
concept char_range = std::ranges::range<t> && std::same_as<char, std::remove_cvref_t<std::ranges::range_value_t<t>>>;
67+
68+
//!\brief A range whose value type is an integral type other than `char`.
69+
template <typename t>
70+
concept int_range = std::ranges::range<t> && std::integral<std::remove_cvref_t<std::ranges::range_value_t<t>>> &&
71+
!std::same_as<char, std::remove_cvref_t<std::ranges::range_value_t<t>>>;
72+
73+
//!\brief A type that is not std::span<std::byte const>.
74+
template <typename t>
75+
concept not_a_byte_span = !std::same_as<t, std::span<std::byte const>>;
76+
77+
// ----------------------------------------------------------------------------
78+
// copy functions
79+
// ----------------------------------------------------------------------------
80+
2881
/*!\brief Copy elements from the first range into the second range.
2982
* \param[in] in The range to copy from.
3083
* \param[out] out The range to copy to.
@@ -36,8 +89,8 @@ namespace bio::detail
3689
* If the input range is sized and the target range offers a `.resize()` member, this function uses
3790
* resize and assignment instead of back-insertion.
3891
*/
39-
void sized_range_copy(std::ranges::input_range auto && in,
40-
seqan3::back_insertable_with<std::ranges::range_reference_t<decltype(in)>> auto && out)
92+
void sized_range_copy(std::ranges::input_range auto && in,
93+
back_insertable_with<std::ranges::range_reference_t<decltype(in)>> auto && out)
4194
{
4295
using in_t = decltype(in);
4396
using out_t = decltype(out);
@@ -64,23 +117,6 @@ void string_copy(std::string_view const in, auto & out)
64117
sized_range_copy(in, out);
65118
}
66119

67-
//!\brief A seqan3::alphabet that is **not** a character or number (any std::integral).
68-
template <typename t>
69-
concept deliberate_alphabet = seqan3::alphabet<t> && !std::integral<std::remove_cvref_t<t>>;
70-
71-
//!\brief A range whose value type is `char`.
72-
template <typename t>
73-
concept char_range = std::ranges::range<t> && std::same_as<char, std::remove_cvref_t<std::ranges::range_value_t<t>>>;
74-
75-
//!\brief A range whose value type is an integral type other than `char`.
76-
template <typename t>
77-
concept int_range = std::ranges::range<t> && std::integral<std::remove_cvref_t<std::ranges::range_value_t<t>>> &&
78-
!std::same_as<char, std::remove_cvref_t<std::ranges::range_value_t<t>>>;
79-
80-
//!\brief A type that is not std::span<std::byte const>.
81-
template <typename t>
82-
concept not_a_byte_span = !std::same_as<t, std::span<std::byte const>>;
83-
84120
//!\}
85121

86122
} // namespace bio::detail

include/bio/format/fasta_input_handler.hpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class format_input_handler<fasta> : public format_input_handler_base<format_inpu
100100
* \{
101101
*/
102102
//!\brief The fields that this format supports [the base class accesses this type].
103-
using format_fields = seqan3::vtag_t<field::id, field::seq>;
103+
using format_fields = vtag_t<field::id, field::seq>;
104104
//!\brief Type of the raw record.
105105
using raw_record_type = record<format_fields, std::string_view, std::string_view>;
106106
//!\brief Type of the low-level iterator.
@@ -180,13 +180,10 @@ class format_input_handler<fasta> : public format_input_handler_base<format_inpu
180180
* \{
181181
*/
182182
//!\brief We can prevent another copy if the user wants a string.
183-
void parse_field(seqan3::vtag_t<field::id> const & /**/, std::string & parsed_field)
184-
{
185-
std::swap(id_buffer, parsed_field);
186-
}
183+
void parse_field(vtag_t<field::id> const & /**/, std::string & parsed_field) { std::swap(id_buffer, parsed_field); }
187184

188185
//!\brief We can prevent another copy if the user wants a string.
189-
void parse_field(seqan3::vtag_t<field::seq> const & /**/, std::string & parsed_field)
186+
void parse_field(vtag_t<field::seq> const & /**/, std::string & parsed_field)
190187
{
191188
std::swap(seq_buffer, parsed_field);
192189
}

include/bio/format/format_input_handler.hpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include <vector>
1919

2020
#include <seqan3/alphabet/views/char_to.hpp> // TODO replace with char_strictly_to
21-
#include <seqan3/utility/concept/container.hpp>
2221

2322
#include <bio/detail/charconv.hpp>
2423
#include <bio/detail/range.hpp>
@@ -105,15 +104,15 @@ class format_input_handler_base
105104
}
106105

107106
//!\brief Parse into string-like types.
108-
template <seqan3::back_insertable parsed_field_t>
107+
template <detail::back_insertable parsed_field_t>
109108
requires detail::char_range<parsed_field_t>
110109
static void parse_field_aux(std::string_view const in, parsed_field_t & parsed_field)
111110
{
112111
detail::sized_range_copy(in, parsed_field);
113112
}
114113

115114
//!\brief Parse into containers of alphabets.
116-
template <seqan3::back_insertable parsed_field_t>
115+
template <detail::back_insertable parsed_field_t>
117116
requires detail::deliberate_alphabet<std::ranges::range_reference_t<parsed_field_t>>
118117
static void parse_field_aux(std::string_view const in, parsed_field_t & parsed_field)
119118
{
@@ -146,7 +145,7 @@ class format_input_handler_base
146145

147146
//!\brief Various target types have sane default implementations.
148147
template <field field_id, typename parsed_field_t>
149-
void parse_field(seqan3::vtag_t<field_id> const & /**/, parsed_field_t & parsed_field) requires(requires {
148+
void parse_field(vtag_t<field_id> const & /**/, parsed_field_t & parsed_field) requires(requires {
150149
derived_t::parse_field_aux(get<field_id>(to_derived()->raw_record), parsed_field);
151150
})
152151
{
@@ -160,21 +159,21 @@ class format_input_handler_base
160159
*/
161160
//!\brief Only act on those fields that are present in the record and also provided by the format.
162161
template <field field_id, typename parsed_record_t>
163-
void parse_record_impl(seqan3::vtag_t<field_id> const & /**/, parsed_record_t & parsed_record)
162+
void parse_record_impl(vtag_t<field_id> const & /**/, parsed_record_t & parsed_record)
164163
{
165164
if constexpr (parsed_record_t::field_ids::contains(field_id))
166165
{
167166
auto & parsed_field = get<field_id>(parsed_record);
168-
to_derived()->parse_field(seqan3::vtag<field_id>, parsed_field);
167+
to_derived()->parse_field(vtag<field_id>, parsed_field);
169168
}
170169
// fields that are not in format or not in target record are simply ignored
171170
}
172171

173172
//!\brief Splits the record into individual fields.
174173
template <field... field_ids, typename parsed_record_t>
175-
void parse_record(seqan3::vtag_t<field_ids...> const & /**/, parsed_record_t & parsed_record)
174+
void parse_record(vtag_t<field_ids...> const & /**/, parsed_record_t & parsed_record)
176175
{
177-
(to_derived()->parse_record_impl(seqan3::vtag<field_ids>, parsed_record), ...);
176+
(to_derived()->parse_record_impl(vtag<field_ids>, parsed_record), ...);
178177
}
179178
//!\}
180179

include/bio/misc.hpp

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
#pragma once
1010

11+
#include <concepts>
12+
#include <tuple>
13+
14+
#include <seqan3/utility/type_list/type_list.hpp>
15+
1116
#include <bio/platform.hpp>
1217

1318
/*!\file
@@ -18,17 +23,121 @@
1823
namespace bio
1924
{
2025

26+
//-----------------------------------------------------------------------------
27+
// ownership
28+
//-----------------------------------------------------------------------------
29+
2130
/*!\brief An enum used as an argument for templates that switch between owning and non-owning behaviour.
31+
* \ingroup bio
2232
* \details
2333
*
2434
* Typically used to configure a class template to have members that are vectors/strings VS members that are views.
2535
* The "shallow" version of such a class is typically cheap to copy (no dynamic memory) while the "deep" version
26-
* is exppensive to copy (holds dynamic memory).
36+
* is expensive to copy (holds dynamic memory).
2737
*/
2838
enum class ownership
2939
{
30-
shallow, //< Cheap to copy.
31-
deep //< Expensive to copy.
40+
shallow, //!< Cheap to copy.
41+
deep //!< Expensive to copy.
42+
};
43+
44+
//-----------------------------------------------------------------------------
45+
// vtag
46+
//-----------------------------------------------------------------------------
47+
48+
/*!\brief The type of bio::vtag. [Default "specialisation" for 0 arguments.]
49+
* \tparam more_vs Any number of values [only 0 arguments pick this specialisation].
50+
* \ingroup bio
51+
* \see bio::vtag
52+
*/
53+
template <auto... more_vs>
54+
struct vtag_t
55+
{
56+
//!\brief The number of values stored in the tag.
57+
static constexpr size_t size = 0;
58+
59+
//!\brief The tag converted to a tuple.
60+
static constexpr auto as_tuple = std::tuple{};
61+
62+
//!\brief A function that checks if a value is contained in the tag.
63+
static constexpr bool contains(auto &&) { return false; }
64+
65+
//!\brief A function that returns the index of a value or ((size_t)-1) if the value is not found.
66+
static constexpr size_t index_of(auto &&) { return static_cast<size_t>(-1ULL); }
67+
};
68+
69+
/*!\brief The type of bio::vtag. [Specialisation for 1 or more arguments]
70+
* \tparam v First value.
71+
* \tparam more_vs More values.
72+
* \ingroup bio
73+
* \see bio::vtag
74+
*/
75+
template <auto v, auto... more_vs>
76+
struct vtag_t<v, more_vs...>
77+
{
78+
//!\brief The first value in the tag.
79+
static constexpr auto first_value = v;
80+
81+
//!\copybrief bio::vtag_t::size
82+
static constexpr size_t size = sizeof...(more_vs) + 1;
83+
84+
//!\copybrief bio::vtag_t::as_tuple
85+
static constexpr auto as_tuple = std::tuple{v, more_vs...};
86+
87+
//!\brief Whether all values in the tag are unique.
88+
static constexpr bool unique_values = ((v != more_vs) && ...);
89+
90+
//!\copybrief bio::vtag_t::contains
91+
static constexpr bool contains(auto && s) requires std::equality_comparable_with<decltype(s), decltype(v)> &&
92+
(std::equality_comparable_with<decltype(s), decltype(more_vs)> &&...)
93+
{
94+
return s == v || ((s == more_vs) || ...);
95+
}
96+
97+
//!\copybrief bio::vtag_t::index_of
98+
static constexpr size_t index_of(auto && s) requires std::equality_comparable_with<decltype(s), decltype(v)> &&
99+
(std::equality_comparable_with<decltype(s), decltype(more_vs)> &&...)
100+
{
101+
size_t c = 0;
102+
((v != s && ++c) && ((more_vs != s && ++c) && ...));
103+
return c >= size ? static_cast<size_t>(-1ULL) : c;
104+
}
32105
};
33106

107+
/*!\brief A value-tag template.
108+
* \tparam vs The values to store in the tag.
109+
* \ingroup bio
110+
* \details
111+
*
112+
* Using this template, you can easily turn a value, e.g. a literal value, into a compile-time constant with a unique
113+
* type.
114+
*
115+
* ### Example
116+
*
117+
* \snippet test/snippet/snippet_tag.cpp vtag
118+
*/
119+
template <auto... vs>
120+
inline constexpr vtag_t<vs...> vtag{};
121+
122+
//-----------------------------------------------------------------------------
123+
// ttag
124+
//-----------------------------------------------------------------------------
125+
126+
/*!\brief A type-tag template.
127+
* \tparam type The first type to store.
128+
* \tparam more_types More types to store (optional).
129+
* \ingroup bio
130+
* \see seqan3::type_list
131+
*
132+
* \details
133+
*
134+
* Using this template, you can easily turn a type into a compile-time constant (value).
135+
*
136+
* ### Example
137+
*
138+
* \snippet test/snippet/snippet_tag.cpp ttag
139+
*/
140+
template <typename type, typename... more_types>
141+
inline constexpr seqan3::type_list<type, more_types...> ttag{};
142+
34143
} // namespace bio

include/bio/record.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
#include <bio/platform.hpp>
1919

2020
#include <seqan3/core/detail/template_inspection.hpp>
21-
#include <seqan3/utility/tag.hpp>
2221
#include <seqan3/utility/type_list/type_list.hpp>
2322

23+
#include <bio/misc.hpp>
24+
2425
namespace bio
2526
{
2627

@@ -89,7 +90,7 @@ enum class field : uint64_t
8990
* \implements seqan3::tuple_like
9091
* \ingroup bio
9192
* \tparam field_types The types of the fields in this record as a seqan3::type_list.
92-
* \tparam field_ids A seqan3::vtag_t type with bio::field IDs corresponding to field_types.
93+
* \tparam field_ids A vtag_t type with bio::field IDs corresponding to field_types.
9394
* \details
9495
*
9596
* This class template behaves just like an std::tuple, with the exception that it provides an additional
@@ -346,8 +347,8 @@ auto const && get(record<field_ids, field_types...> const && r)
346347
* TODO
347348
*/
348349
template <auto... field_ids, typename... field_type_ts>
349-
constexpr auto make_record(seqan3::vtag_t<field_ids...>, field_type_ts &... fields)
350-
-> record<seqan3::vtag_t<field_ids...>, field_type_ts...>
350+
constexpr auto make_record(vtag_t<field_ids...>, field_type_ts &... fields)
351+
-> record<vtag_t<field_ids...>, field_type_ts...>
351352
{
352353
return {fields...};
353354
}
@@ -364,8 +365,8 @@ constexpr auto make_record(seqan3::vtag_t<field_ids...>, field_type_ts &... fiel
364365
* TODO
365366
*/
366367
template <auto... field_ids, typename... field_type_ts>
367-
constexpr auto tie_record(seqan3::vtag_t<field_ids...>, field_type_ts &... fields)
368-
-> record<seqan3::vtag_t<field_ids...>, field_type_ts &...>
368+
constexpr auto tie_record(vtag_t<field_ids...>, field_type_ts &... fields)
369+
-> record<vtag_t<field_ids...>, field_type_ts &...>
369370
{
370371
return {fields...};
371372
}

include/bio/seq_io/misc.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
#pragma once
1515

16-
#include <seqan3/utility/tag.hpp>
16+
#include <bio/misc.hpp>
1717

1818
#include <bio/record.hpp>
1919

@@ -22,6 +22,6 @@ namespace bio::seq_io
2222

2323
//!\brief Default fields for seqan3::seq_io::reader_options.
2424
//!\ingroup seq_io
25-
inline constexpr auto default_field_ids = seqan3::vtag<field::id, field::seq, field::qual>;
25+
inline constexpr auto default_field_ids = vtag<field::id, field::seq, field::qual>;
2626

2727
} // namespace bio::seq_io

0 commit comments

Comments
 (0)