+
+ template<typename T>
+ struct GrowableArray : public MutableArray<T> {
+ using MutableArray<T>::ptr;
+ using MutableArray<T>::count;
+ size_t bufsize;
+
+ GrowableArray()
+ {
+ bufsize = 0;
+ }
+
+ GrowableArray(NullArray na) : MutableArray<T>(na)
+ {
+ bufsize = 0;
+ }
+
+ GrowableArray(T *PTR, size_t COUNT) : MutableArray<T>(PTR, COUNT)
+ {
+ bufsize = COUNT;
+ }
+
+ GrowableArray(T *PTR, size_t COUNT, size_t BUFSIZE) :
+ MutableArray<T>(PTR, COUNT)
+ {
+ bufsize = BUFSIZE;
+ }
+
+ GrowableArray(MutableArray<T> &ma) : MutableArray<T>(ma)
+ {
+ bufsize = count;
+ }
+
+ void grow(size_t newsize)
+ {
+ if (newsize <= bufsize)
+ return;
+
+ T *oldptr = ptr;
+ T *newptr = new(orbmm) T[newsize];
+ memcpy(newptr, ptr, count * sizeof(T));
+ ptr = newptr;
+ ll_smp_membar_store_after_store();
+ bufsize = newsize;
+ // FIXME: Should release imply membar?
+ ll_smp_membar_any_after_store();
+ orbmm->release(oldptr);
+ }
+
+ // Caller must sync against all writers.
+ void append(T *newptr, size_t len, size_t max = ULONG_MAX)
+ {
+ if (count + len < count)
+ throw ArrayException();
+
+ if (count + len > max)
+ throw ArrayException();
+
+ if (count + len > bufsize)
+ grow(ll_get_order_round_up(count + len));
+
+ memcpy(ptr + count, newptr, len * sizeof(T));
+ count += len;
+ }
+ };