Skip to content

Commit

Permalink
Merge pull request #3038 from eseiler/misc/trivial_alphabet
Browse files Browse the repository at this point in the history
[FEATURE] Make alphabets trivial
  • Loading branch information
eseiler authored Oct 20, 2022
2 parents 44643d9 + d0011c9 commit f71d4de
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ If possible, provide tooling that performs the changes, e.g. a shell-script.
* `seqan3::cigar` can now be assigned from `std::string_view` ([\#2966](https://github.com/seqan/seqan3/pull/2966)).
* Added `seqan3::views::char_strictly_to`. Behaves like `seqan3::views::char_to`, but throws on invalid
input ([\#2898](https://github.com/seqan/seqan3/pull/2898)).
* Improved performance of vector assignment for alphabets ([\#3038](https://github.com/seqan/seqan3/pull/3038)).

#### I/O
* Added `seqan3::sequence_file_option::fasta_ignore_blanks_before_id` to ignore blanks before IDs when reading FASTA
Expand Down
2 changes: 1 addition & 1 deletion include/seqan3/alphabet/alphabet_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ class alphabet_base

private:
//!\brief The value of the alphabet letter is stored as the rank.
rank_type rank{};
rank_type rank;
};

} // namespace seqan3
2 changes: 1 addition & 1 deletion include/seqan3/alphabet/aminoacid/aminoacid_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace seqan3
* \stableapi{Since version 3.1.}
*/
template <typename derived_type, auto size>
class aminoacid_base : public alphabet_base<derived_type, size, char>, public aminoacid_empty_base
class aminoacid_base : public aminoacid_empty_base, public alphabet_base<derived_type, size, char>
{
private:
//!\brief Type of the base class.
Expand Down
1 change: 1 addition & 0 deletions test/performance/range/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_subdirectories ()

seqan3_benchmark (container_assignment_benchmark.cpp)
seqan3_benchmark (container_push_back_benchmark.cpp)
seqan3_benchmark (container_seq_read_benchmark.cpp)
seqan3_benchmark (container_seq_write_benchmark.cpp)
Expand Down
152 changes: 152 additions & 0 deletions test/performance/range/container_assignment_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

#include <benchmark/benchmark.h>

#include <seqan3/alphabet/aminoacid/aa27.hpp>
#include <seqan3/alphabet/nucleotide/dna4.hpp>
#include <seqan3/alphabet/nucleotide/dna5.hpp>
#include <seqan3/test/literal/bytes.hpp>
#include <seqan3/test/performance/sequence_generator.hpp>

using namespace seqan3::test::literals;

#ifndef NDEBUG
static constexpr size_t vector_size{1_MiB};
#else
static constexpr size_t vector_size{16_MiB};
#endif // NDEBUG

enum tag
{
assignment_operator,
std_copy,
uninitialized_copy
};

template <tag id>
struct assignment_functor
{
template <typename container_t>
requires (id == tag::assignment_operator)
static constexpr void call(container_t & to, container_t const & from) noexcept(
noexcept(std::is_nothrow_assignable_v<container_t, container_t>))
{
benchmark::DoNotOptimize(to = from);
}

template <typename container_t>
requires (id == tag::std_copy)
static constexpr void call(container_t & to, container_t const & from) noexcept
{
benchmark::DoNotOptimize(std::copy(std::ranges::begin(from), std::ranges::end(from), std::ranges::begin(to)));
}

template <typename container_t>
requires (id == tag::uninitialized_copy)
static constexpr void call(container_t & to, container_t const & from) noexcept
{
benchmark::DoNotOptimize(
std::uninitialized_copy(std::ranges::begin(from), std::ranges::end(from), std::ranges::begin(to)));
}
};

template <typename container_t>
requires requires (container_t v) { v.clear(); }
static constexpr void clear(container_t & container) noexcept(noexcept(std::declval<container_t>().clear()))
{
container.clear();
}

template <typename container_t>
requires requires (container_t v) { v.resize(1u); }
static constexpr void resize(container_t & container,
size_t const size) noexcept(noexcept(std::declval<container_t>().resize(1u)))
{
container.resize(size);
}

#if SEQAN3_HAS_SEQAN2
template <typename container_t>
static constexpr void clear(container_t & container) noexcept(noexcept(seqan::clear(std::declval<container_t>())))
{
seqan::clear(container);
}

template <typename container_t>
static constexpr void resize(container_t & container,
size_t const size) noexcept(noexcept(seqan::resize(std::declval<container_t>(), 1u)))
{
seqan::resize(container, size);
}
#endif // SEQAN3_HAS_SEQAN2

template <tag id, template <typename> typename container_t, typename alphabet_t>
static void assign(benchmark::State & state)
{
auto random_sequence = []() constexpr
{
if constexpr (seqan3::alphabet<alphabet_t>)
return seqan3::test::generate_sequence<alphabet_t>(vector_size);
#if SEQAN3_HAS_SEQAN2
else
return seqan3::test::generate_sequence_seqan2<alphabet_t>(vector_size);
#endif // SEQAN3_HAS_SEQAN2
}();

container_t<alphabet_t> from{};
resize(from, vector_size);
std::copy(std::ranges::begin(random_sequence), std::ranges::end(random_sequence), std::ranges::begin(from));
container_t<alphabet_t> to{};
resize(to, vector_size);
assignment_functor<id> fn{};

for (auto _ : state)
{
fn.call(to, from);
benchmark::ClobberMemory();
clear(to);
benchmark::ClobberMemory();
}
}

BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan3::dna4);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan3::dna5);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan3::aa27);

BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan3::dna4);
BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan3::dna5);
BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan3::aa27);

BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan3::dna4);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan3::dna5);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan3::aa27);

#if SEQAN3_HAS_SEQAN2
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, std::vector, seqan::AminoAcid);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, seqan::String, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, seqan::String, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::assignment_operator, seqan::String, seqan::AminoAcid);

BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::std_copy, std::vector, seqan::AminoAcid);
BENCHMARK_TEMPLATE(assign, tag::std_copy, seqan::String, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::std_copy, seqan::String, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::std_copy, seqan::String, seqan::AminoAcid);

BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, std::vector, seqan::AminoAcid);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, seqan::String, seqan::Dna);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, seqan::String, seqan::Dna5);
BENCHMARK_TEMPLATE(assign, tag::uninitialized_copy, seqan::String, seqan::AminoAcid);
#endif // SEQAN3_HAS_SEQAN2

BENCHMARK_MAIN();
2 changes: 2 additions & 0 deletions test/unit/alphabet/aminoacid/aminoacid_test_template.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ TYPED_TEST_SUITE_P(aminoacid);

TYPED_TEST_P(aminoacid, concept_check)
{
EXPECT_TRUE(std::is_trivial_v<TypeParam>);

EXPECT_TRUE(seqan3::aminoacid_alphabet<TypeParam>);
EXPECT_TRUE(seqan3::aminoacid_alphabet<TypeParam &>);
EXPECT_TRUE(seqan3::aminoacid_alphabet<TypeParam const>);
Expand Down
2 changes: 2 additions & 0 deletions test/unit/alphabet/nucleotide/nucleotide_test_template.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ TYPED_TEST_SUITE_P(nucleotide);

TYPED_TEST_P(nucleotide, concept_check)
{
EXPECT_TRUE(std::is_trivial_v<TypeParam>);

EXPECT_TRUE(seqan3::nucleotide_alphabet<TypeParam>);
EXPECT_TRUE(seqan3::nucleotide_alphabet<TypeParam &>);
EXPECT_TRUE(seqan3::nucleotide_alphabet<TypeParam const>);
Expand Down
2 changes: 2 additions & 0 deletions test/unit/alphabet/quality/phred_test_template.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ TYPED_TEST_SUITE_P(phred);
// test provision of data type `phred_type` and phred converter.
TYPED_TEST_P(phred, concept_check)
{
EXPECT_TRUE(std::is_trivial_v<TypeParam>);

EXPECT_TRUE(seqan3::quality_alphabet<TypeParam>);
EXPECT_TRUE(seqan3::quality_alphabet<TypeParam &>);
EXPECT_TRUE(seqan3::quality_alphabet<TypeParam const>);
Expand Down

1 comment on commit f71d4de

@vercel
Copy link

@vercel vercel bot commented on f71d4de Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

seqan3 – ./

seqan3.vercel.app
seqan3-git-master-seqan.vercel.app
seqan3-seqan.vercel.app

Please sign in to comment.