# What mapped_view.h (#301) must get right, and the test in test/unit/mapped_view.cpp that notices.
#
#     scripts/mutate/mutate.py --file include/ankerl/mapped_view.h \
#         --bugs scripts/mutate/bugs/mapped-view.txt --test-filter 'mapped_view*'

# the layout check multiplies: a count whose byte count wraps to a small number gets through
<<<
            return offset <= size && count <= (size - offset) / element_size;
===
            return offset <= size && count * element_size <= size - offset;
>>>

# the layout check forgets the offset: an offset past the end wraps around
<<<
            return offset <= size && count <= (size - offset) / element_size;
===
            return count <= (size - offset) / element_size;
>>>

# only the values are checked against the file's end
<<<
        if (!fits(layout.values_offset, layout.num_values, sizeof(value_type)) ||
            !fits(layout.index_offset, layout.num_blocks, sizeof(index_block))) {
===
        if (!fits(layout.values_offset, layout.num_values, sizeof(value_type))) {
>>>

# huge_copy maps memory and never reads the file into it
<<<
        m_region = map_anonymous(m_region_size);
        read_into(d.fd);
===
        m_region = map_anonymous(m_region_size);
>>>

# the move leaves the source owning the mapping: two munmaps of one region
<<<
    mapped_file(mapped_file&& other) noexcept {
        swap(other);
    }
===
    mapped_file(mapped_file&& other) noexcept
        : m_region(other.m_region)
        , m_region_size(other.m_region_size)
        , m_size(other.m_size) {}
>>>

# the view is built over the wrong array
<<<
        auto const* blocks = layout.num_blocks == 0 ? nullptr : file.data() + layout.index_offset;
===
        auto const* blocks = layout.num_blocks == 0 ? nullptr : file.data() + layout.values_offset;
>>>

# an empty file is mapped anyway (mmap of length 0 fails)
<<<
        if (m_size == 0) {
            return;
        }
===
>>>

# the trust argument is dropped: every view is unchecked
<<<
        , m_view(make_view(m_file, layout, t, hash, equal)) {}
===
        , m_view(make_view(m_file, layout, t == trust::checked ? trust::unchecked : t, hash, equal)) {}
>>>

# The first of the two below needs a hugetlbfs mount: run with UDM_HUGETLBFS_DIR set
# (mapped_view_hugetlbfs says how), else that test skips and the mutant survives.

# huge_copy never asks for MAP_HUGETLB: reserved huge pages stay unused, THP is all it gets
<<<
        auto* hugetlb = ::mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
===
        auto* hugetlb = ::mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        ::munmap(hugetlb, len);
        hugetlb = MAP_FAILED;
>>>

# the file mapping's munmap length is a page short: the last page of an ordinary file's mapping
# leaks, and on hugetlbfs, where munmap takes only whole huge pages, nothing is unmapped at all.
# (One byte short is equivalent: munmap rounds the length up to a page.)
<<<
            m_region_size = m_size;
===
            m_region_size = m_size - 4096;
>>>
