Pass type as param to VectorRef instead of bool

This commit is contained in:
mpilman 2019-07-15 14:46:00 -07:00
parent 707b29cbcc
commit 54416f46fd
3 changed files with 105 additions and 81 deletions

View File

@ -159,7 +159,7 @@ struct WatchValueRequest {
struct GetKeyValuesReply : public LoadBalancedReply {
constexpr static FileIdentifier file_identifier = 1783066;
Arena arena;
VectorRef<KeyValueRef, true> data;
VectorRef<KeyValueRef, VecSerStrategy::String> data;
Version version; // useful when latestVersion was requested
bool more;

View File

@ -1028,7 +1028,7 @@ ACTOR Future<Void> getShardStateQ( StorageServer* data, GetShardStateRequest req
return Void();
}
void merge( Arena& arena, VectorRef<KeyValueRef, true>& output, VectorRef<KeyValueRef> const& base,
void merge( Arena& arena, VectorRef<KeyValueRef, VecSerStrategy::String>& output, VectorRef<KeyValueRef> const& base,
StorageServer::VersionedData::iterator& start, StorageServer::VersionedData::iterator const& end,
int versionedDataCount, int limit, bool stopAtEndOfBase, int limitBytes = 1<<30 )
// Combines data from base (at an older version) with sets from newer versions in [start, end) and appends the first (up to) |limit| rows to output

View File

@ -825,13 +825,17 @@ struct string_serialized_traits : std::false_type {
}
};
template <class T, bool>
enum class VecSerStrategy {
FlatBuffers, String
};
template <class T, VecSerStrategy>
struct VectorRefPreserializer {
VectorRefPreserializer() {}
VectorRefPreserializer(const VectorRefPreserializer<T, true>&) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, true>&) { return *this; }
VectorRefPreserializer(const VectorRefPreserializer<T, false>&) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, false>&) { return *this; }
VectorRefPreserializer(const VectorRefPreserializer<T, VecSerStrategy::FlatBuffers>&) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, VecSerStrategy::FlatBuffers>&) { return *this; }
VectorRefPreserializer(const VectorRefPreserializer<T, VecSerStrategy::String>&) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, VecSerStrategy::String>&) { return *this; }
void invalidate() {}
void add(const T& item) {}
@ -839,18 +843,22 @@ struct VectorRefPreserializer {
};
template <class T>
struct VectorRefPreserializer<T, true> {
struct VectorRefPreserializer<T, VecSerStrategy::String> {
mutable int32_t _cached_size; // -1 means unknown
string_serialized_traits<T> _string_traits;
VectorRefPreserializer() : _cached_size(0) {}
VectorRefPreserializer(const VectorRefPreserializer<T, true>& other) : _cached_size(other._cached_size) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, true>& other) {
VectorRefPreserializer(const VectorRefPreserializer<T, VecSerStrategy::String>& other)
: _cached_size(other._cached_size) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, VecSerStrategy::String>& other) {
_cached_size = other._cached_size;
return *this;
}
VectorRefPreserializer(const VectorRefPreserializer<T, false>&) : _cached_size(-1) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, false>&) { _cached_size = -1; return *this; }
VectorRefPreserializer(const VectorRefPreserializer<T, VecSerStrategy::FlatBuffers>&) : _cached_size(-1) {}
VectorRefPreserializer& operator=(const VectorRefPreserializer<T, VecSerStrategy::FlatBuffers>&) {
_cached_size = -1;
return *this;
}
void invalidate() { _cached_size = -1; }
void add(const T& item) {
@ -865,21 +873,24 @@ struct VectorRefPreserializer<T, true> {
}
};
template <class T, bool StringSerialized = false>
class VectorRef : public ComposedIdentifier<T, 0x8>, public VectorRefPreserializer<T, StringSerialized> {
using VPS = VectorRefPreserializer<T, StringSerialized>;
friend class VectorRef<T, !StringSerialized>;
template <class T, VecSerStrategy SerStrategy = VecSerStrategy::FlatBuffers>
class VectorRef : public ComposedIdentifier<T, 0x8>, public VectorRefPreserializer<T, SerStrategy> {
using VPS = VectorRefPreserializer<T, SerStrategy>;
friend class VectorRef<T, SerStrategy == VecSerStrategy::FlatBuffers ? VecSerStrategy::String
: VecSerStrategy::FlatBuffers>;
public:
using value_type = T;
static_assert(!StringSerialized || string_serialized_traits<T>::value);
static_assert(SerStrategy == VecSerStrategy::FlatBuffers || string_serialized_traits<T>::value);
// T must be trivially destructible (and copyable)!
VectorRef() : data(0), m_size(0), m_capacity(0) {}
template<bool b2>
VectorRef(const VectorRef<T, b2>& other) : VPS(other), data(other.data), m_size(other.m_size), m_capacity(other.m_capacity) {}
template <bool b2>
VectorRef& operator=(const VectorRef<T, b2>& other) {
template <VecSerStrategy S>
VectorRef(const VectorRef<T, S>& other)
: VPS(other), data(other.data), m_size(other.m_size), m_capacity(other.m_capacity) {}
template <VecSerStrategy S>
VectorRef& operator=(const VectorRef<T, S>& other) {
*static_cast<VPS*>(this) = other;
data = other.data;
m_size = other.m_size;
@ -888,7 +899,7 @@ public:
}
// Arena constructor for non-Ref types, identified by memcpy_able
template <class T2 = T, bool S>
template <class T2 = T, VecSerStrategy S>
VectorRef(Arena& p, const VectorRef<T, S>& toCopy, typename std::enable_if<memcpy_able<T2>::value, int>::type = 0)
: VPS(toCopy), data((T*)new (p) uint8_t[sizeof(T) * toCopy.size()]), m_size(toCopy.size()),
m_capacity(toCopy.size()) {
@ -896,7 +907,7 @@ public:
}
// Arena constructor for Ref types, which must have an Arena constructor
template <class T2 = T, bool S>
template <class T2 = T, VecSerStrategy S>
VectorRef(Arena& p, const VectorRef<T, S>& toCopy, typename std::enable_if<!memcpy_able<T2>::value, int>::type = 0)
: VPS(), data((T*)new (p) uint8_t[sizeof(T) * toCopy.size()]), m_size(toCopy.size()), m_capacity(toCopy.size()) {
for (int i = 0; i < m_size; i++) {
@ -905,13 +916,13 @@ public:
}
}
VectorRef( T* data, int size ) : data(data), m_size(size), m_capacity(size) {}
VectorRef( T* data, int size, int capacity ) : data(data), m_size(size), m_capacity(capacity) {}
//VectorRef( const VectorRef<T>& toCopy ) : data( toCopy.data ), m_size( toCopy.m_size ), m_capacity( toCopy.m_capacity ) {}
//VectorRef<T>& operator=( const VectorRef<T>& );
VectorRef(T* data, int size) : data(data), m_size(size), m_capacity(size) {}
VectorRef(T* data, int size, int capacity) : data(data), m_size(size), m_capacity(capacity) {}
// VectorRef( const VectorRef<T>& toCopy ) : data( toCopy.data ), m_size( toCopy.m_size ), m_capacity(
// toCopy.m_capacity ) {} VectorRef<T>& operator=( const VectorRef<T>& );
template<bool S = StringSerialized>
typename std::enable_if<S, uint32_t>::type serializedSize() const {
template <VecSerStrategy S = SerStrategy>
typename std::enable_if<S == VecSerStrategy::String, uint32_t>::type serializedSize() const {
uint32_t result = sizeof(uint32_t);
string_serialized_traits<T> t;
if (VPS::_cached_size >= 0) {
@ -932,59 +943,78 @@ public:
bool empty() const { return m_size == 0; }
const T& operator[](int i) const { return data[i]; }
std::reverse_iterator<const T*> rbegin() const { return std::reverse_iterator<const T*>( end() ); }
std::reverse_iterator<const T*> rend() const { return std::reverse_iterator<const T*>( begin() ); }
std::reverse_iterator<const T*> rbegin() const { return std::reverse_iterator<const T*>(end()); }
std::reverse_iterator<const T*> rend() const { return std::reverse_iterator<const T*>(begin()); }
template<bool S = StringSerialized>
typename std::enable_if<!S, VectorRef>::type slice(int begin, int end) const { return VectorRef(data+begin, end-begin); }
template <VecSerStrategy S = SerStrategy>
typename std::enable_if<S == VecSerStrategy::FlatBuffers, VectorRef>::type slice(int begin, int end) const {
return VectorRef(data + begin, end - begin);
}
template<bool S>
bool operator == ( VectorRef<T, S> const& rhs ) const {
template <VecSerStrategy S>
bool operator==(VectorRef<T, S> const& rhs) const {
if (size() != rhs.size()) return false;
for(int i=0; i<m_size; i++)
if ( (*this)[i] != rhs[i] )
return false;
for (int i = 0; i < m_size; i++)
if ((*this)[i] != rhs[i]) return false;
return true;
}
// Warning: Do not mutate a VectorRef that has previously been copy constructed or assigned,
// since copies will share data
T* begin() { VPS::invalidate(); return data; }
T* end() { VPS::invalidate(); return data + m_size; }
T& front() { VPS::invalidate(); return *begin(); }
T& back() { VPS::invalidate(); return end()[-1]; }
T& operator[](int i) { VPS::invalidate(); return data[i]; }
void push_back( Arena& p, const T& value ) {
if (m_size + 1 > m_capacity) reallocate(p, m_size+1);
T* begin() {
VPS::invalidate();
return data;
}
T* end() {
VPS::invalidate();
return data + m_size;
}
T& front() {
VPS::invalidate();
return *begin();
}
T& back() {
VPS::invalidate();
return end()[-1];
}
T& operator[](int i) {
VPS::invalidate();
return data[i];
}
void push_back(Arena& p, const T& value) {
if (m_size + 1 > m_capacity) reallocate(p, m_size + 1);
auto ptr = new (&data[m_size]) T(value);
VPS::add(*ptr);
m_size++;
}
// invokes the "Deep copy constructor" T(Arena&, const T&) moving T entirely into arena
void push_back_deep( Arena& p, const T& value ) {
if (m_size + 1 > m_capacity) reallocate(p, m_size+1);
void push_back_deep(Arena& p, const T& value) {
if (m_size + 1 > m_capacity) reallocate(p, m_size + 1);
auto ptr = new (&data[m_size]) T(p, value);
VPS::add(*ptr);
m_size++;
}
void append( Arena& p, const T* begin, int count ) {
void append(Arena& p, const T* begin, int count) {
if (m_size + count > m_capacity) reallocate(p, m_size + count);
VPS::invalidate();
memcpy( data+m_size, begin, sizeof(T)*count );
memcpy(data + m_size, begin, sizeof(T) * count);
m_size += count;
}
template <class It>
void append_deep( Arena& p, It begin, int count ) {
void append_deep(Arena& p, It begin, int count) {
if (m_size + count > m_capacity) reallocate(p, m_size + count);
for(int i=0; i<count; i++) {
auto ptr = new (&data[m_size+i]) T( p, *begin++ );
for (int i = 0; i < count; i++) {
auto ptr = new (&data[m_size + i]) T(p, *begin++);
VPS::add(*ptr);
}
m_size += count;
}
void pop_back() { VPS::remove(back()); m_size--; }
void pop_back() {
VPS::remove(back());
m_size--;
}
void pop_front( int count ) {
void pop_front(int count) {
VPS::invalidate();
count = std::min(m_size, count);
@ -993,52 +1023,46 @@ public:
m_capacity -= count;
}
void resize( Arena& p, int size ) {
void resize(Arena& p, int size) {
if (size > m_capacity) reallocate(p, size);
for(int i=m_size; i<size; i++) {
for (int i = m_size; i < size; i++) {
auto ptr = new (&data[i]) T();
VPS::add(*ptr);
}
m_size = size;
}
void reserve( Arena& p, int size ) {
void reserve(Arena& p, int size) {
if (size > m_capacity) reallocate(p, size);
}
// expectedSize() for non-Ref types, identified by memcpy_able
template<class T2 = T>
template <class T2 = T>
typename std::enable_if<memcpy_able<T2>::value, size_t>::type expectedSize() const {
return sizeof(T)*m_size;
return sizeof(T) * m_size;
}
// expectedSize() for Ref types, which must in turn have expectedSize() implemented.
template<class T2 = T>
typename std::enable_if<!memcpy_able<T2>::value, size_t>::type expectedSize() const
{
size_t t = sizeof(T)*m_size;
for(int i=0; i<m_size; i++)
t += data[i].expectedSize();
template <class T2 = T>
typename std::enable_if<!memcpy_able<T2>::value, size_t>::type expectedSize() const {
size_t t = sizeof(T) * m_size;
for (int i = 0; i < m_size; i++) t += data[i].expectedSize();
return t;
}
int capacity() const {
return m_capacity;
}
int capacity() const { return m_capacity; }
void extendUnsafeNoReallocNoInit(int amount) {
m_size += amount;
}
void extendUnsafeNoReallocNoInit(int amount) { m_size += amount; }
private:
T* data;
int m_size, m_capacity;
void reallocate(Arena& p, int requiredCapacity) {
requiredCapacity = std::max( m_capacity*2, requiredCapacity );
requiredCapacity = std::max(m_capacity * 2, requiredCapacity);
// SOMEDAY: Maybe we are right at the end of the arena and can expand cheaply
T* newData = (T*)new (p) uint8_t[ requiredCapacity * sizeof(T) ];
memcpy(newData, data, m_size*sizeof(T));
T* newData = (T*)new (p) uint8_t[requiredCapacity * sizeof(T)];
memcpy(newData, data, m_size * sizeof(T));
data = newData;
m_capacity = requiredCapacity;
}
@ -1063,8 +1087,8 @@ struct Traceable<VectorRef<T>> {
}
};
template <class Archive, class T, bool b>
inline void load( Archive& ar, VectorRef<T, b>& value ) {
template <class Archive, class T, VecSerStrategy S>
inline void load( Archive& ar, VectorRef<T, S>& value ) {
// FIXME: range checking for length, here and in other serialize code
uint32_t length;
ar >> length;
@ -1074,8 +1098,8 @@ inline void load( Archive& ar, VectorRef<T, b>& value ) {
for(uint32_t i=0; i<length; i++)
ar >> value[i];
}
template <class Archive, class T, bool b>
inline void save( Archive& ar, const VectorRef<T, b>& value ) {
template <class Archive, class T, VecSerStrategy S>
inline void save( Archive& ar, const VectorRef<T, S>& value ) {
uint32_t length = value.size();
ar << length;
for(uint32_t i=0; i<length; i++)
@ -1083,7 +1107,7 @@ inline void save( Archive& ar, const VectorRef<T, b>& value ) {
}
template <class T>
struct vector_like_traits<VectorRef<T, false>> : std::true_type {
struct vector_like_traits<VectorRef<T, VecSerStrategy::FlatBuffers>> : std::true_type {
using Vec = VectorRef<T>;
using value_type = typename Vec::value_type;
using iterator = const T*;
@ -1105,8 +1129,8 @@ struct vector_like_traits<VectorRef<T, false>> : std::true_type {
};
template <class V>
struct dynamic_size_traits<VectorRef<V, true>> : std::true_type {
using T = VectorRef<V, true>;
struct dynamic_size_traits<VectorRef<V, VecSerStrategy::String>> : std::true_type {
using T = VectorRef<V, VecSerStrategy::String>;
// May be called multiple times during one serialization
template <class Context>
static size_t size(const T& t, Context&) {