mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 21:35:45 +02:00
We are using ByteVectors from multiple threads in some cases. Mostly these are the status and progress threads which read the ByteVector object references embedded in BEESNOTE macros. Since it's not clear what the data race implications are, protect the shared_ptr in ByteVector with a mutex for now. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
77 lines
2.1 KiB
C++
77 lines
2.1 KiB
C++
#ifndef _CRUCIBLE_BYTEVECTOR_H_
|
|
#define _CRUCIBLE_BYTEVECTOR_H_
|
|
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <ostream>
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
|
|
namespace crucible {
|
|
using namespace std;
|
|
// new[] is a little slower than malloc
|
|
// shared_ptr is about 2x slower than unique_ptr
|
|
// vector<uint8_t> is ~160x slower
|
|
// so we won't bother with unique_ptr because we can't do shared copies with it
|
|
|
|
class ByteVector {
|
|
public:
|
|
using Pointer = shared_ptr<uint8_t>;
|
|
using value_type = Pointer::element_type;
|
|
using iterator = value_type*;
|
|
|
|
ByteVector() = default;
|
|
ByteVector(const ByteVector &that);
|
|
ByteVector& operator=(const ByteVector &that);
|
|
ByteVector(size_t size);
|
|
ByteVector(const ByteVector &that, size_t start, size_t length);
|
|
ByteVector(iterator begin, iterator end, size_t min_size = 0);
|
|
|
|
ByteVector at(size_t start, size_t length) const;
|
|
|
|
value_type& at(size_t) const;
|
|
iterator begin() const;
|
|
void clear();
|
|
value_type* data() const;
|
|
bool empty() const;
|
|
iterator end() const;
|
|
value_type& operator[](size_t) const;
|
|
size_t size() const;
|
|
bool operator==(const ByteVector &that) const;
|
|
|
|
// this version of erase only works at the beginning or end of the buffer, else throws exception
|
|
void erase(iterator first);
|
|
void erase(iterator first, iterator last);
|
|
|
|
// An important use case is ioctls that have a fixed-size header struct
|
|
// followed by a buffer for further arguments. These templates avoid
|
|
// doing reinterpret_casts every time.
|
|
template <class T> ByteVector(const T& object, size_t min_size);
|
|
template <class T> T* get() const;
|
|
private:
|
|
Pointer m_ptr;
|
|
size_t m_size = 0;
|
|
mutable mutex m_mutex;
|
|
friend ostream & operator<<(ostream &os, const ByteVector &bv);
|
|
};
|
|
|
|
template <class T>
|
|
ByteVector::ByteVector(const T& object, size_t min_size)
|
|
{
|
|
const auto size = max(min_size, sizeof(T));
|
|
m_ptr = Pointer(static_cast<value_type*>(malloc(size)), free);
|
|
memcpy(m_ptr.get(), &object, sizeof(T));
|
|
m_size = size;
|
|
}
|
|
|
|
template <class T>
|
|
T*
|
|
ByteVector::get() const
|
|
{
|
|
return reinterpret_cast<T*>(data());
|
|
}
|
|
}
|
|
|
|
#endif // _CRUCIBLE_BYTEVECTOR_H_
|