more vector compatibility
This commit is contained in:
parent
04964cd2a0
commit
0587129fc6
@ -8,6 +8,9 @@
|
|||||||
#ifndef TL_NOINLINE
|
#ifndef TL_NOINLINE
|
||||||
#define TL_NOINLINE __attribute__((noinline))
|
#define TL_NOINLINE __attribute__((noinline))
|
||||||
#endif /* TL_NOINLINE */
|
#endif /* TL_NOINLINE */
|
||||||
|
#ifndef TL_INLINE
|
||||||
|
#define TL_INLINE __attribute__((always_inline))
|
||||||
|
#endif /* TL_INLINE */
|
||||||
|
|
||||||
#ifndef TL_LIKELY
|
#ifndef TL_LIKELY
|
||||||
#define TL_LIKELY(x) __builtin_expect(!!(x), 1)
|
#define TL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
@ -16,6 +19,10 @@
|
|||||||
#define TL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
#define TL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
#endif /* TL_UNLIKELY */
|
#endif /* TL_UNLIKELY */
|
||||||
|
|
||||||
|
#ifndef TL_GROWTH_RATE
|
||||||
|
#define TL_GROWTH_RATE 2
|
||||||
|
#endif /* TL_GROWTH_RATE */
|
||||||
|
|
||||||
typedef void*(MallocLike)(size_t);
|
typedef void*(MallocLike)(size_t);
|
||||||
typedef void(FreeLike)(void*);
|
typedef void(FreeLike)(void*);
|
||||||
|
|
||||||
@ -29,20 +36,32 @@ class TurboList {
|
|||||||
|
|
||||||
uint32_t capacity;
|
uint32_t capacity;
|
||||||
|
|
||||||
TL_NOINLINE T& grow_and_insert(T elem) noexcept {
|
TL_NOINLINE void grow_and_insert(T elem) noexcept {
|
||||||
// assert(mid == 0);
|
// assert(mid == 0);
|
||||||
if(old) FREE(old);
|
if(old) FREE(old);
|
||||||
old = nex;
|
old = nex;
|
||||||
mid = end;
|
mid = end;
|
||||||
capacity *= 2;
|
capacity *= TL_GROWTH_RATE;
|
||||||
nex = (T *) MALLOC(this->capacity * sizeof(T));
|
nex = (T *) MALLOC(this->capacity * sizeof(T));
|
||||||
|
|
||||||
// Will go into the INSERT code path here
|
// Will go into the INSERT code path here
|
||||||
return insert(elem);
|
insert(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
TL_NOINLINE T& grow_and_emplace(Args&&... args) noexcept {
|
||||||
|
// assert(mid == 0);
|
||||||
|
if(old) FREE(old);
|
||||||
|
old = nex;
|
||||||
|
mid = end;
|
||||||
|
capacity *= TL_GROWTH_RATE;
|
||||||
|
nex = (T *) MALLOC(this->capacity * sizeof(T));
|
||||||
|
|
||||||
|
// Will go into the INSERT code path here
|
||||||
|
return emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
inline TurboList(uint32_t initial_size = 0, uint32_t initial_cap = 16) noexcept :
|
TL_INLINE TurboList(uint32_t initial_size = 0, uint32_t initial_cap = 16) noexcept :
|
||||||
old(nullptr),
|
old(nullptr),
|
||||||
mid(0),
|
mid(0),
|
||||||
end(initial_size),
|
end(initial_size),
|
||||||
@ -51,20 +70,29 @@ public:
|
|||||||
nex = (T *) MALLOC(this->capacity * sizeof(T));
|
nex = (T *) MALLOC(this->capacity * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ~TurboList() noexcept {
|
TL_INLINE ~TurboList() noexcept {
|
||||||
if(nex) FREE(nex);
|
if(nex) FREE(nex);
|
||||||
if(old) FREE(old);
|
if(old) FREE(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T& operator[](uint32_t i) noexcept {
|
TL_INLINE T& operator[](uint32_t i) const noexcept {
|
||||||
// This seem to be more often compiled to cmov
|
// This seem to be more often compiled to cmov
|
||||||
// branchless conditional codes this way..
|
// branchless conditional codes this way..
|
||||||
|
//
|
||||||
T *base = (i < mid) ? old : nex;
|
T *base = (i < mid) ? old : nex;
|
||||||
return base[i];
|
return base[i];
|
||||||
|
//
|
||||||
|
// if(i < mid) return old[i];
|
||||||
|
// else return nex[i];
|
||||||
|
//
|
||||||
|
// T* loc = (T*) ((i < mid) * (size_t)old +
|
||||||
|
// (i>=mid) * (size_t)nex +
|
||||||
|
// i* sizeof(T));
|
||||||
|
// return *loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is much faster than operator[] if you do small amounts of work per access */
|
/** This is much faster than operator[] if you do small amounts of work per access */
|
||||||
inline void iterate(void(callback)(T&)) noexcept {
|
TL_INLINE void iterate(void(callback)(T&)) noexcept {
|
||||||
// old
|
// old
|
||||||
for(uint32_t i = 0; i < mid; ++i) {
|
for(uint32_t i = 0; i < mid; ++i) {
|
||||||
callback(old[i]);
|
callback(old[i]);
|
||||||
@ -75,35 +103,54 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T& insert(T elem) noexcept {
|
/** Vector compatibility: Use insert() if you want the inserted thing as reference too */
|
||||||
|
TL_INLINE void push_back(T elem) noexcept {
|
||||||
|
this->insert(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vector compatibility: Use pop() if you want the popped thing out as copy too */
|
||||||
|
TL_INLINE void pop_back() noexcept {
|
||||||
|
if(end > 0) {
|
||||||
|
--end;
|
||||||
|
if(end < mid) { // end > 0 here!
|
||||||
|
end = mid;
|
||||||
|
mid = 0;
|
||||||
|
FREE(nex);
|
||||||
|
nex = old;
|
||||||
|
old = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TL_INLINE void insert(T elem) noexcept {
|
||||||
if(TL_LIKELY(end < capacity)) {
|
if(TL_LIKELY(end < capacity)) {
|
||||||
|
|
||||||
// INSERT
|
// INSERT
|
||||||
|
|
||||||
/* Same as this:
|
/* Same as this - but in this case it measures as faster:
|
||||||
if(mid > 0) {
|
if(mid > 0) {
|
||||||
nex[mid - 1] = old[mid - 1];
|
|
||||||
--mid;
|
--mid;
|
||||||
|
nex[mid] = old[mid];
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
bool hasmid = (mid > 0);
|
bool hasmid = (mid > 0);
|
||||||
mid -= hasmid;
|
mid -= hasmid;
|
||||||
nex[mid] = hasmid ? old[mid] : nex[mid];
|
nex[mid] = hasmid ? old[mid] : nex[mid];
|
||||||
|
|
||||||
return (nex[end++] = elem);
|
nex[end++] = elem;
|
||||||
} else {
|
} else {
|
||||||
// GROW
|
// GROW
|
||||||
return grow_and_insert(elem);
|
grow_and_insert(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline T& emplace(Args&&... args) {
|
TL_INLINE T& emplace_back(Args&&... args) {
|
||||||
if(TL_LIKELY(end < capacity)) {
|
if(TL_LIKELY(end < capacity)) {
|
||||||
|
|
||||||
// INSERT
|
// INSERT
|
||||||
|
|
||||||
/* Same as this:
|
/* Same as this - but in this case it measures as faster:
|
||||||
if(mid > 0) {
|
if(mid > 0) {
|
||||||
nex[mid - 1] = old[mid - 1];
|
nex[mid - 1] = old[mid - 1];
|
||||||
--mid;
|
--mid;
|
||||||
@ -117,21 +164,13 @@ public:
|
|||||||
return *new (nex + end++) T(std::forward<Args>(args)...);
|
return *new (nex + end++) T(std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
// GROW
|
// GROW
|
||||||
//
|
return grow_and_emplace(std::forward<Args>(args)...);
|
||||||
// Rem.: I just chose this to be less optimized than
|
|
||||||
// it is possible by making a copy and reusing
|
|
||||||
// the existing grow and insert code instead of
|
|
||||||
// writing a new "grow_and_emplace" again.
|
|
||||||
//
|
|
||||||
// This happens rarely so its probably fine and
|
|
||||||
// makes less template instantiations, smaller binary.
|
|
||||||
return grow_and_insert(T(std::forward<Args>(args)...));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: finalize() call which memcpy remaining elements of old into nex and then frees old and sets nullptr + mid = 0;
|
// TODO: finalize() call which memcpy remaining elements of old into nex and then frees old and sets nullptr + mid = 0;
|
||||||
|
|
||||||
inline uint32_t size() noexcept {
|
TL_INLINE uint32_t size() noexcept {
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user