#pragma once

#if defined(__cforall)
extern "C" {
#endif
	#include <stdlib.h>
	#include <stdint.h>				// uint64_t
	#include <unistd.h>				// sysconf
#if ! defined(__cforall)
	#include <time.h>
	#include <sys/time.h>
#else
}
#include <time.hfa>
#endif

#define L1 l1
#define L2 L1, l2
#define L3 L2, l3
#define L4 L3, l4
#define L5 L4, l5
#define L6 L5, l6
#define L7 L6, l7
#define L8 L7, l8

static inline uint64_t bench_time() {
	struct timespec ts;
	clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
	return 1000000000LL * ts.tv_sec + ts.tv_nsec;
} // bench_time


#if defined(__cforall)
struct test_spinlock {
	volatile bool lock;
};

static inline void lock( test_spinlock & this ) {
	for ( ;; ) {
		if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
	}
}

static inline void unlock( test_spinlock & this ) {
	__atomic_clear( &this.lock, __ATOMIC_RELEASE );
}
#endif

size_t threads = 1, num_locks = -1;

#define BENCH_START()				\
	if ( argc > 3 ) exit( EXIT_FAILURE );	\
	if ( argc == 2 ) {			\
		threads = atoi( argv[1] );	\
	} else if ( argc == 3 ) {			\
		threads = atoi( argv[1] );	\
        num_locks = atoi( argv[2] );	\
	}

#define BENCH(statement, output, done_flag)		\
	uint64_t count = 0;		\
    while (true) {          \
	statement;				\
    count++;                \
    if (done_flag) break; \
    }                       \
    __atomic_add_fetch(&output, count, __ATOMIC_SEQ_CST);
	// EndTime = bench_time();			\
	// double output = (double)( EndTime - StartTime ) / times;


#if defined(__cforall)
Duration default_preemption() {
	return 0;
}
#endif
#if defined(__U_CPLUSPLUS__)
unsigned int uDefaultPreemption() {
	return 0;
}
#endif

// splitmix64 rand num generator
// https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
uint64_t state;                                  /* The state can be seeded with any (upto) 64 bit integer value. */

uint64_t next_int() {
    state += 0x9e3779b97f4a7c15;               /* increment the state variable */
    uint64_t z = state;                          /* copy the state to a working variable */
    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;  /* xor the variable with the variable right bit shifted 30 then multiply by a constant */
    z = (z ^ (z >> 27)) * 0x94d049bb133111eb;  /* xor the variable with the variable right bit shifted 27 then multiply by a constant */
    return z ^ (z >> 31);                      /* return the variable xored with itself right bit shifted 31 */
}

