Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add range adapter for streams that allows using range-based for loops #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions include/stxxl/bits/stream/range.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/***************************************************************************
* include/stxxl/bits/stream/range.h
*
* Part of the STXXL. See http://stxxl.org
*
* Copyright (C) 2018 Michael Hamann <michael.hamann@kit.edu>
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
**************************************************************************/

#ifndef STXXL_STREAM_RANGE_HEADER
#define STXXL_STREAM_RANGE_HEADER

#include <tlx/define/likely.hpp>

#include <functional>

namespace stxxl {

//! Stream package subnamespace.
namespace stream {

//! \addtogroup streampack
//! \{

//! An output range adapter for a stream, to be used in range-based for loops.
template <typename InputStream>
class stream2range
{
private:
InputStream& m_input;

public:
//! Type of the elements of the stream and range
using value_type = typename InputStream::value_type;

class range {
private:
InputStream* m_stream;

public:
//! Construct a range for the given stream.
range(InputStream* stream) : m_stream(stream)
{ }

//! Copy constructor: delete as the semantics are broken,
//! copies would not be independent.
range(const range&) = delete;

//! Copy assignment: delete as the semantics are broken,
//! copies would not be independent.
range& operator=(const range&) = delete;

//! Move constructor
range(range&&) = default;

//! Move assignment
range& operator=(range&&) = default;

//! Increment underlying stream.
range& operator ++ ()
{
++(*m_stream);

if (TLX_UNLIKELY(m_stream->empty())) {
m_stream = nullptr;
}

return *this;
}

//! Check equality with another range
//!
//! All ranges pointing to the same stream are equal.
//! Ranges pointing past the end are all equal.
bool operator == (const range& other)
{
return m_stream == other.m_stream;
}

//! Check inequality with another range
//!
//! All ranges pointing to the same stream are equal.
//! Ranges pointing past the end are all equal.
bool operator != (const range& other)
{
return m_stream != other.m_stream;
}

//! Dereference the underlying stream.
//!
//! Dereferencing a range that is past the end is a null
//! pointer dereference.
const value_type& operator * ()
{
return *(*m_stream);
}

const value_type* operator -> () const
{
return &(*(*m_stream));
}
};

//! Initialize the stream2range container
//!
//! Stores a reference to the given input.
stream2range(InputStream& input)
: m_input(input)
{ }

//! Return a range pointing to the current position of the underlying stream.
range begin() const
{
return range(&this->m_input);
}

//! Return a range pointing past the end of any stream.
range end() const
{
return range(nullptr);
}
};

//! Utility function to construct a stream2range container from the given stream.
template <typename InputStream>
stream2range<InputStream> range(InputStream& input)
{
return stream2range<InputStream>(input);
}


//! \}

} // namespace stream
} // namespace stxxl

#endif // !STXXL_STREAM_RANGE_HEADER
1 change: 1 addition & 0 deletions include/stxxl/bits/stream/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,7 @@ class make_tuple<Input1, Input2, Input3, Input4, Input5, Stopper>
#include <stxxl/bits/stream/choose.h>
#include <stxxl/bits/stream/materialize.h>
#include <stxxl/bits/stream/unique.h>
#include <stxxl/bits/stream/range.h>

#endif // !STXXL_STREAM_STREAM_HEADER
// vim: et:ts=4:sw=4
2 changes: 2 additions & 0 deletions tests/stream/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ stxxl_build_test(test_push_sort)
stxxl_build_test(test_sorted_runs)
stxxl_build_test(test_stream)
stxxl_build_test(test_stream1)
stxxl_build_test(test_range)

add_define(test_stream1 "STXXL_VERBOSE_LEVEL=1")
add_define(test_push_sort "STXXL_VERBOSE_LEVEL=0")
Expand All @@ -32,3 +33,4 @@ stxxl_test(test_push_sort)
stxxl_test(test_sorted_runs)
stxxl_test(test_stream)
stxxl_test(test_stream1)
stxxl_test(test_range)
45 changes: 45 additions & 0 deletions tests/stream/test_range.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***************************************************************************
* tests/stream/test_range.cpp
*
* Part of the STXXL. See http://stxxl.org
*
* Copyright (C) 2018 Michael Hamann <michael.hamann@kit.edu>
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
**************************************************************************/

#include <algorithm>
#include <cstdint>
#include <random>

#include <tlx/die.hpp>

#include <stxxl/stream>

int main()
{
constexpr size_t num_values = 1024;
using value_type = uint64_t;

std::vector<value_type> values;
values.reserve(num_values);

for (size_t i = 0; i < num_values; ++i) {
values.push_back(i);
}

auto stream = stxxl::stream::streamify(values.begin(), values.end());

size_t i = 0;
for (size_t v : stxxl::stream::range(stream))
{
die_unequal(i, v);
++i;
}

die_unequal(i, num_values);

return 0;
}