
#ifndef PLS_SYSTEM_DETAILS_H
#define PLS_SYSTEM_DETAILS_H

#if MSVC
#ifdef _M_X86
#define ARCH_X86
#endif
#endif

#if GCC
#ifdef __i386__
#define ARCH_X86
#endif
#endif

#include <cstdint>

namespace pls {
namespace internal {
namespace base {

/**
 * Collection of system details, e.g. hardware cache line size.
 *
 * PORTABILITY:
 * Currently sane default values for x86.
 */
namespace system_details {

/**
 * Pointer Types needed for ABA protection mixed into addresses.
 * pointer_t should be an integer type capable of holding ANY pointer value.
 */
using pointer_t = std::uintptr_t;

/**
 * Biggest type that supports atomic CAS operations.
 * Usually it is sane to assume a pointer can be swapped in a single CAS operation.
 */
using cas_integer = std::uintptr_t;
constexpr unsigned long CAS_SIZE = sizeof(cas_integer);

/**
 * Most processors have 64 byte cache lines (last 6 bit of the address are zero at line beginnings).
 */
constexpr pointer_t CACHE_LINE_SIZE = 64;

/**
 * Choose one of the following ways to store thread specific data.
 * Try to choose the fastest available on this processor/system.
 */
//#define PLS_THREAD_SPECIFIC_PTHREAD
#define PLS_THREAD_SPECIFIC_COMPILER

/**
 * When spinning one wants to 'relax' the CPU from some task,
 * e.g. disabling speculative execution/branch prediction
 * or reducing its clock speed.
 * This is both good for power draw, as well as for hyperthreading.
 *
 * Choose the implementation appropriate for your compiler-cpu combination.
 */
inline void relax_cpu() {
#ifdef ARCH_X86
  asm volatile("pause":: : "memory");
#endif
}

}
}
}
}

#endif //PLS_SYSTEM_DETAILS_H
