Silicomancer Silicomancer - 17 days ago 10
C++ Question

Standard replacement for QByteArray

I want to port a Qt C++11 function to standard C++11. The function has a

QByteArray
parameter that accepts any kind of data (text, binary data, etc.) using a
QByteArray
parameter and calculates a hash from the data.

QByteArray
seems well suited because it can carry any kind of data and has a lot of functions that allow filling it from streams, devices, strings, etc. It even can wrap data without doing a deep copy using
fromRawData()
.


Is there a standard C++11 solution that provides similar flexibility? Currently I tend to use good old
void*
plus size.

Answer

Is there a standard C++11 solution that provides similar flexibility? Currently I tend to use good old void* plus size.

There's no standard C++11 solution that provides a container that can either manage its own memory or wrap memory managed by someone else.

You could simply copy the QByteArray (it's a few files) and bundle it with your project, if licensing terms allow.

Otherwise, if you only intend to work on containers with contiguous storage for all elements, the const void* and size_t arguments make perfect sense, and will be most portable and adaptable. You can provide convenience overloads as needed. E.g.

HashType calculateHash(const void*, size_t);

template <typename T> HashType calculateHash(const T& container) {
  static_assert(sizeof(typename T::value_type) == 1, "value_type must be byte-sized");
  assert(&container[container.size()-1] == &container[0]+container.size());
  return calculateHash(&container[0], container.size());
}

To support any container, even those with non-contiguous storage, the base calculateHash can take a range and offer an overload for hashing an entire container.

template <typename I>
HashType calculateHash(I start, I const end) {
  HashType hash;
  for (; start != end; ++start)
    hash.update(*start);
  return hash;
}

template <typename C>
HashType calculateHash(const C& container) {
  using std::begin;
  using std::end;
  return calculateHash(begin(container), end(container));
}