|
|
71057f |
#ifndef UTILS_H
|
|
|
71057f |
#define UTILS_H
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
#include <cassert></cassert>
|
|
|
51b3f0 |
#include <cstdio></cstdio>
|
|
|
71057f |
|
|
|
71057f |
#include <atomic></atomic>
|
|
|
71057f |
#include <thread></thread>
|
|
|
51b3f0 |
#include <chrono></chrono>
|
|
|
51b3f0 |
|
|
|
51b3f0 |
|
|
|
51b3f0 |
#define ShowDebugMSG(...) do { \
|
|
|
51b3f0 |
printf("DEBUG %10ld %s:%s:%d:", \
|
|
|
51b3f0 |
std::chrono::duration_cast<std::chrono::milliseconds>( \</std::chrono::milliseconds>
|
|
|
51b3f0 |
std::chrono::steady_clock::now().time_since_epoch() ).count(), \
|
|
|
51b3f0 |
__FILE__, __func__, __LINE__); \
|
|
|
51b3f0 |
printf(" " __VA_ARGS__); \
|
|
|
51b3f0 |
printf("\n"); \
|
|
|
51b3f0 |
fflush(stdout); \
|
|
|
51b3f0 |
} while(0)
|
|
|
51b3f0 |
|
|
|
51b3f0 |
#define HideDebugMSG(...) do {} while(0)
|
|
|
51b3f0 |
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
class ReadProtector {
|
|
|
71057f |
private:
|
|
|
71057f |
std::atomic<int> enters;</int>
|
|
|
71057f |
std::atomic<int> exits;</int>
|
|
|
71057f |
|
|
|
71057f |
public:
|
|
|
71057f |
inline ReadProtector(): enters(0), exits(0) { }
|
|
|
71057f |
inline ~ReadProtector() { assert(!(enters - exits)); }
|
|
|
71057f |
inline void lock() { enters++; }
|
|
|
71057f |
inline void unlock() { exits++; }
|
|
|
71057f |
inline void wait() const {
|
|
|
71057f |
int en = enters;
|
|
|
71057f |
while(en - exits > 0) std::this_thread::yield();
|
|
|
71057f |
}
|
|
|
71057f |
};
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
class ReadLock {
|
|
|
71057f |
private:
|
|
|
71057f |
ReadProtector &protector;
|
|
|
71057f |
ReadLock(const ReadLock&) = delete;
|
|
|
71057f |
public:
|
|
|
71057f |
inline explicit ReadLock(ReadProtector &protector): protector(protector) { protector.lock(); }
|
|
|
71057f |
inline ~ReadLock() { protector.unlock(); }
|
|
|
71057f |
};
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
template<typename t*="" t,="" t::*nextfield=""></typename>
|
|
|
71057f |
class ChainFuncs {
|
|
|
71057f |
private:
|
|
|
71057f |
ChainFuncs() { }
|
|
|
71057f |
|
|
|
71057f |
public:
|
|
|
71057f |
typedef T Type;
|
|
|
71057f |
static constexpr Type* Type::*Next = NextField;
|
|
|
71057f |
|
|
|
71057f |
static inline void push(Type* &first, Type &item)
|
|
|
71057f |
{ assert(!(item.*Next)); item.*Next = first; first = &item; }
|
|
|
71057f |
static inline void push(std::atomic<type*> &first, Type &item)</type*>
|
|
|
71057f |
{ assert(!(item.*Next)); item.*Next = first; while(!first.compare_exchange_weak(item.*Next, &item)); }
|
|
|
71057f |
|
|
|
71057f |
static inline Type* pop(Type* &first) {
|
|
|
71057f |
Type *item = first;
|
|
|
71057f |
if (!item) return nullptr;
|
|
|
71057f |
first = item->next;
|
|
|
71057f |
item->next = nullptr;
|
|
|
71057f |
return item;
|
|
|
71057f |
}
|
|
|
71057f |
static inline Type* pop(std::atomic<type*> &first) {</type*>
|
|
|
71057f |
Type *item = first;
|
|
|
71057f |
do {
|
|
|
71057f |
if (!item) return nullptr;
|
|
|
71057f |
} while(!first.compare_exchange_weak(item, item->*Next));
|
|
|
71057f |
item->next = nullptr;
|
|
|
71057f |
return item;
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
static inline void invert(Type* &first) {
|
|
|
71057f |
if (Type *curr = first) {
|
|
|
71057f |
Type *prev = nullptr;
|
|
|
71057f |
while(Type *next = curr->*Next)
|
|
|
71057f |
{ curr->*Next = prev; prev = curr; curr = next; }
|
|
|
71057f |
first = curr;
|
|
|
71057f |
}
|
|
|
71057f |
}
|
|
|
71057f |
static inline Type* inverted(Type *first)
|
|
|
71057f |
{ invert(first); return first; }
|
|
|
71057f |
};
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
// multhreaded input, single threaded output
|
|
|
71057f |
// simultaneus read and write are allowed
|
|
|
71057f |
template<typename t*="" t,="" t::*nextfield=""></typename>
|
|
|
71057f |
class QueueMISO {
|
|
|
71057f |
public:
|
|
|
71057f |
typedef T Type;
|
|
|
71057f |
typedef ChainFuncs<type, nextfield=""> Funcs;</type,>
|
|
|
71057f |
static constexpr Type* Type::*Next = NextField;
|
|
|
71057f |
|
|
|
71057f |
private:
|
|
|
71057f |
std::atomic<type*> pushed;</type*>
|
|
|
71057f |
Type *first;
|
|
|
71057f |
|
|
|
71057f |
public:
|
|
|
71057f |
inline QueueMISO():
|
|
|
71057f |
pushed(nullptr), first() { }
|
|
|
71057f |
inline ~QueueMISO()
|
|
|
71057f |
{ assert(!pushed && !first); }
|
|
|
71057f |
inline void push(Type &item)
|
|
|
71057f |
{ Funcs::push(pushed, item); }
|
|
|
71057f |
inline Type& pop()
|
|
|
71057f |
{ assert(first); return *Funcs::pop(first); }
|
|
|
71057f |
inline void unpop(Type &item)
|
|
|
71057f |
{ return Funcs::push(first, item); }
|
|
|
71057f |
inline Type *peek()
|
|
|
71057f |
{ return first ? first : (first = Funcs::inverted(pushed.exchange(nullptr))); }
|
|
|
71057f |
};
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
template<typename t*="" t,="" t::*nextfield=""></typename>
|
|
|
71057f |
class CounteredQueueMISO: public QueueMISO<t, nextfield=""> {</t,>
|
|
|
71057f |
public:
|
|
|
71057f |
typedef T Type;
|
|
|
71057f |
typedef QueueMISO<type, nextfield=""> Queue;</type,>
|
|
|
71057f |
|
|
|
71057f |
private:
|
|
|
71057f |
std::atomic<int> counter;</int>
|
|
|
71057f |
|
|
|
71057f |
public:
|
|
|
71057f |
inline CounteredQueueMISO():
|
|
|
71057f |
counter(0) { }
|
|
|
71057f |
inline ~CounteredQueueMISO()
|
|
|
71057f |
{ assert(!counter); }
|
|
|
71057f |
inline void push(Type &item)
|
|
|
71057f |
{ Queue::push(item); counter++; }
|
|
|
71057f |
inline Type& pop()
|
|
|
6ebd3b |
{ Type &item = Queue::pop(); counter--; return item; }
|
|
|
6ebd3b |
inline void unpop(Type &item)
|
|
|
6ebd3b |
{ return Queue::unpop(item); counter++; }
|
|
|
71057f |
inline int count() const
|
|
|
71057f |
{ return counter; }
|
|
|
71057f |
};
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
#endif
|