views:

78

answers:

3

I have a underlying API that passes a const char* and a length:

foo(const char* data, const uint32_t len);

I'd like to wrap this data/length in a light weight container that can be iterated and has the ability to be randomly accessed but not make a copy (e.g. like a vector). What is the best way to achieve this? The const char* data is not necessarily a 'string'; it may contain NULL's throughout.

I am using STL and Boost. I've seen boost::as_array<> and as_literal<> -- is one of these appropriate here?

A: 

I don't think as_array and/or as_literal will do what you want. While not terribly difficult to write, I don't know of an existing class intended to do what you you want (or at least what I think you want).

Edit: I probably shouldn't say I don't know of any such classes -- I just don't know of any that's particularly well known, widely used, or thoroughly tested. If you search the archives of comp.lang.c++ and/or comp.lang.c++.moderated from, say, 12 to 15 years ago or so, you can probably find at least a dozen (at least provided Google's newsgroup searching is working at the moment). Unless memory fails me particularly badly, I posted one myself somewhere along the line (though I can't seem to find it right now...) As you might guess from their age, however, you probably wouldn't want to use most (any?) of them as-is -- their use of C++ is often quite primitive.

Jerry Coffin
+2  A: 

I have used iterator_facade http://www.boost.org/doc/libs/1_43_0/libs/iterator/doc/iterator_facade.html together with iterator_range

you can easily use iterator_range to construct your wrapper, http://www.boost.org/doc/libs/1_42_0/libs/range/doc/utility_class.html#iter_range

boost::iterator_range<char*> range(begin, begin + N);

special cases can be handled with iterator_facade

aaa
How does iterator_range<> compare with the template posted by Evan above? His solution appears to be basically what I'm looking for, but as I'm already using Boost, if there is a "Boost preferred way", I'd like to stick to that.
NuSkooler
@Nus it looks pretty similar, try boost first, if it does not work, use custom template
aaa
+4  A: 

It would be easy to make such a class. Something like this:

template <class T>
class array_ref {
public:
    // makes it work with iterator traits..
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;

    typedef T*        pointer;
    typedef T*        iterator;
    typedef T&        reference;

    typedef const T*  const_pointer;
    typedef const T*  const_iterator;
    typedef const T&  const_reference;

public:
    array_ref(T *p, size_t n) : data_(p), len_(n) {}

    // iteration
    iterator begin()             { return data_; }
    iterator end()               { return data_ + len_; }
    const_iterator begin() const { return data_; }
    const_iterator end() const   { return data_ + len_; }

    // access
    reference operator[](size_t n)             { return data_[n]; }
    reference at(size_t n)                     { return data_[n]; }
    const_reference operator[](size_t n) const { return data_[n]; }
    const_reference at(size_t n) const         { return data_[n]; }

    // capacity
    size_t size() const { return len_; }
    bool empty() const  { return size() == 0; }

    // raw access
    T* data() const { return data_; }

    // etc...
private:
    T* data_;
    size_t len_;
};

This looks like a bunch of code, most of it isn't strictly necessary. However, since it is a template the compiler will only generate code for the methods used. And the actual class itself only uses space for the pointer and the length members.

But in the end, this really isn't much of a gain. Since pointers themselves are nice pointers, I'd probably just use raw pointers here.

Evan Teran
NuSkooler