eupp
eupp

Reputation: 545

Determine that elements in range placed in contiguous memory

Suppose I write template function that processes a range of elements.

template <typename Iter>
void func(Iter first, Iter last);

In this function I want to call some low-level c-function that expects to get contiguous buffer and it's size. Generic way to do this stuff is to copy my range to contiguous container and then call c-function.

template <typename Iter>
void func(Iter first, Iter last)
{
    typedef typename iterator_traits<Iter>::value_type value_type;
    vector<value_type> buf(first, last);
    c_func((void*) buf.data(), buf.size() * sizeof(value_type));
}

But if iterators are already point to some contiguous memory space extra copying will be performed.

So the question is, is there a way to determine are iterators point to contiguous memory space and if it is how can I specialize my function for this case.

Upvotes: 3

Views: 232

Answers (1)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153840

At the moment there is no direct way to determine if an iterator is used for contiguous memory. There is a proposal to add an iterator refinement (see e.g. n3884) but without something like that and a way to detect the property being added for the different iterators you'll have a hard time determining this trait.

The key problem requiring implementer support is that the name if iterator types is not specified. As a result, you can't create a traits applicable to all known to be contiguous iterator types. Since the iterator types for std::vector<T> and std::array<T> can be identical and T* I don't think you can even create a portable specialization.

What you could do, however, is to test in a trait whether an iterator type matches one of the known iterator types for its value type. For example:

template <typename T, typename It>
struct test_iterator
    : std::integral_constant<bool,
        std::is_same<T*, It>::value
        || std::is_same<typename std::vector<T>::iterator, It>::value
        || std::is_same<std::string::iterator, It>::value
        || std::is_same<std::wstring::iterator, It>::value
        > {
};
template <typename It>
struct is_contiguous
    : std::integral_constant<bool,
           test_iterator<typename std::iterator_traits<It>::value_type,
                         It>::value> {
};

[I haven't tried to compile the code, i.e., it is probably littered with small typos; the general approach should work, though]

To add, e.g., std::array<T, N> you'd need some way to figure out the dimension in a static way. I guess, that won't be viable. It may also be necessary to test the various const_iterators.

Upvotes: 3

Related Questions