Blame utils.h

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