#if _MSC_VER
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
#include <algorithm>
#include <random>
#include <cmath>
#include <typeinfo>
#ifndef SYS_BITS
#define CHAR_BITS 8
#define SYS_BYTES sizeof(std::size_t)
#define SYS_BITS (SYS_BYTES * CHAR_BITS)
#endif
#define min_(a,b) ( (a) < (b) ? (a) : (b))
#define FUN(function_name) #function_name, function_name
#define as_array( ptr, size ) ( *(std::array< std::remove_reference< decltype( *ptr ) >::type, size >*)ptr )
using SOURCE = short;
using RESULT = SOURCE;
using DISTRIBUTION_SOURCE = double;
using ON_RUN = void(&)(void*);
using ON_PREPARE = void(&)(void*);
using ON_COMPARE = bool(&)(void*, void*, std::size_t);
SOURCE src[1 << 11];
constexpr std::size_t SIZE = sizeof src / sizeof *src;
RESULT dst0[SIZE], dst1[SIZE], dst2[SIZE], dst3[SIZE], dst4[SIZE];
void Prepare(void* _result)
{
memcpy(_result, src, sizeof src);
}
bool Compare(void* _result, void* _answer, std::size_t _bytes)
{
return memcmp(_result, _answer, _bytes) == 0;
}
class RUNNER
{
friend class BENCH;
private:
const char* name;
unsigned long long elapsed;
const ON_RUN onRun;
void* result;
RUNNER(const char* _name, ON_RUN& _onRun, void* _result)
: name(_name)
, onRun(_onRun)
, elapsed(-1)
, result(_result)
{
}
void Run()
{
auto begin = __rdtsc();
onRun(result);
elapsed = min_(elapsed, __rdtsc() - begin);
}
};
class BENCH
{
private:
const char* title;
const unsigned int trial;
ON_PREPARE onPrepare;
ON_COMPARE onCompare;
std::vector< RUNNER*> runners;
std::size_t answerSize;
void* answer;
public:
BENCH(const char* _title, const int _trial, ON_PREPARE&& _onPrepare, ON_COMPARE& _onCompare)
: title(_title)
, trial(_trial)
, onPrepare(_onPrepare)
, onCompare(_onCompare)
{
}
~BENCH()
{
for (auto runner : runners)
{
delete[] runner;
}
runners.clear();
}
auto Record(unsigned int index) const
{
return runners[index]->elapsed;
}
auto RunnerCount() const
{
return runners.size();
}
void Solution(ON_RUN&& _correctFunction, void* _result, const std::size_t _bytes)
{
answer = _result;
answerSize = _bytes;
onPrepare(_result);
_correctFunction(_result);
}
template<typename T>
void PenzerDebug(T& _result)
{
printf("\nPenzer's debug log - DataType: %s\n", typeid(_result).name());
}
template<typename T>
void Solution(ON_RUN& _correctFunction, T& _result, const std::size_t _bytes)
{
PenzerDebug(_result);
Solution(_correctFunction, &_result, _bytes);
}
void Add(const char* _name, ON_RUN& _onRun, void* _result)
{
runners.emplace_back(new RUNNER(_name, _onRun, _result));
}
template<typename T>
void Add(const char* _name, ON_RUN& _onRun, T& _result)
{
Add(_name, _onRun, &_result);
}
void run() const
{
if (runners.empty())
{
return;
}
printf("\n < %d bits %d trial > %s\n", (int)SYS_BITS, trial, title);
puts(" ----------------+---------------------------------+-----------------------");
puts(" | CHECKER | function name | minimum clocks |");
puts(" ----------------+---------------------------------+-----------------------");
unsigned long long minClocks = -1;
unsigned long long maxClocks = 0;
unsigned long long penzerClocks = 0;
unsigned long long bossClocks = 0;
RUNNER* minRunner = runners[0];
RUNNER* maxRunner = runners[0];
for (const auto runner : runners)
{
int passCount = 0;
for (unsigned int i = 0; i < trial; i++)
{
onPrepare(runner->result);
runner->Run();
passCount += onCompare(runner->result, answer, answerSize);
}
if (runner->name == "BOSS::run")
{
bossClocks = runner->elapsed;
}
if (runner->name == "PENZER::run")
{
penzerClocks = runner->elapsed;
}
if (minClocks > runner->elapsed)
{
minRunner = runner;
minClocks = runner->elapsed;
}
if (maxClocks < runner->elapsed)
{
maxRunner = runner;
maxClocks = runner->elapsed;
}
char temp[14];
if (trial == passCount)
{
sprintf(temp, " PASSED");
}
else
{
sprintf(temp, "FAILED%7d", trial - passCount);
}
printf(" [ %s ] %32s %15llu clocks\n", temp, runner->name, runner->elapsed);
}
puts(" --------------------------------------------------------------------------");
if (penzerClocks < bossClocks)
{
printf(" PENZER is faster than BOSS ( %.2f times faster )\n\n", float(bossClocks) / penzerClocks);
}
else
{
printf(" BOSS is faster than PENZER ( %.2f times faster )\n\n", float(penzerClocks) / bossClocks);
}
}
};
namespace BOSS
{
void run(void* dst)
{
auto& arr = as_array((SOURCE*)dst, SIZE);
std::sort(arr.begin(), arr.end());
}
};
//------------------------------+---------------------------------------------------------------
namespace PENZER
{
#include <cstdlib>
#define SAFE_DELETE_ARRAY(p) if(p != nullptr) delete[] p; p = nullptr;
enum RADIX_TYPE
{
RT_8BIT = 0,
RT_16BIT,
RT_MAX
};
constexpr int g_insertKeyValue = 1 << 6;
const int Log2(const int N)
{
return (N > 1) ? (1 + Log2(N >> 1)) : 0;
}
const int Max(const int first, const int second)
{
return (first > second) ? first : second;
}
const int Min(const int first, const int second)
{
return (first < second) ? first : second;
}
template< typename T >
inline void Swap(T& first, T& second)
{
T swapTemp = first;
first = second;
second = swapTemp;
};
template<typename T>
const int CounterBigO(int N)
{
return N + (1 << ((sizeof(T) < sizeof(int)) ? (sizeof(T) * CHAR_BITS) : (sizeof(int) * CHAR_BITS - 1)));
}
template<typename T>
constexpr int QuickBigO(int N)
{
return N * Log2(N);
}
template<typename T>
constexpr int RadixBigO_8(int N)
{
return sizeof(T) * (2 * N + 2 * (1 << 8));
}
template<typename T>
constexpr int RadixBigO_16(int N)
{
return (sizeof(T) >> 1) * (2 * N + 2 * (1 << 16));
}
template<typename T>
constexpr int RadixBigO(int N)
{
if (sizeof(T) < sizeof(int))
{
return RadixBigO_8<T>(N);
}
return Min(RadixBigO_8<T>(N), RadixBigO_16<T>(N));
}
constexpr bool IsInsertSort(int N)
{
return N < g_insertKeyValue;
}
template<typename T>
constexpr bool IsCounterSort(int N)
{
if (std::numeric_limits<T>::is_integer && sizeof(T) <= sizeof(short))
{
return CounterBigO<T>(N) < 2* Min(QuickBigO<T>(N), RadixBigO<T>(N));
}
return false;
}
template<typename T>
constexpr bool IsQuickSort(int N)
{
return 3 * QuickBigO<T>(N) < RadixBigO<T>(N);
}
template<typename T>
class Sort
{
public:
void virtual operator()(T* const _first, T* const _last) = 0;
};
template<typename T>
class InsertSort : public Sort<T>
{
public:
void operator()(T* const _first, T* const _last)
{
T* iteratorPointer = _first;
while (++iteratorPointer < _last)
{
T temp = *iteratorPointer;
T* now = iteratorPointer;
while (now > _first)
{
if (temp > *(now - 1))
{
break;
}
*now = *(now - 1);
now--;
}
*now = temp;
}
return;
}
};
template<typename T>
class CounterSort : public Sort<T>
{
private:
const unsigned int m_cacheSize;
const long long m_moveValue;
unsigned long long* m_cache;
public:
CounterSort()
: m_cacheSize(1 << ((sizeof(T) < sizeof(int)) ? (sizeof(T) * CHAR_BITS) : (sizeof(short) * CHAR_BITS - 1)))
, m_moveValue(m_cacheSize >> 1)
{
m_cache = new unsigned long long[m_cacheSize];
}
~CounterSort()
{
SAFE_DELETE_ARRAY(m_cache);
}
void operator()(T* const _first, T* const _last)
{
memset(m_cache, 0, m_cacheSize * sizeof(unsigned long long));
T* iteratorPointer = _first;
while (iteratorPointer < _last)
{
m_cache[static_cast<long long>(*iteratorPointer) + m_moveValue]++;
iteratorPointer++;
}
iteratorPointer = _first;
for (long long i = 0; i < m_cacheSize; i++)
{
while (m_cache[i]--)
{
*iteratorPointer = static_cast<T>(i - m_moveValue);
iteratorPointer++;
}
}
iteratorPointer = nullptr;
return;
}
};
template<typename T>
class QuickSort_Real : public Sort<T>
{
private:
InsertSort<T> m_insertSort;
public:
QuickSort_Real(int _size = 0){ }
void operator()(T* const _first, T* const _last)
{
if (_last - _first < g_insertKeyValue)
{
m_insertSort(_first, _last);
return;
}
Swap(*_first, *(_first + (_last - _first) / 2));
T temp = *_first;
T* leftIteratorPointer = _first;
T* rightIteratorPointer = _last;
while (
[&]() -> bool
{
while (leftIteratorPointer < --rightIteratorPointer)
{
if (*rightIteratorPointer < temp)
{
return true;
}
}
return false;
}()
&&
[&]() -> bool
{
while (++leftIteratorPointer < rightIteratorPointer)
{
if (*leftIteratorPointer > temp)
{
Swap(*leftIteratorPointer, *rightIteratorPointer);
return true;
}
}
return false;
}()
);
*_first = *rightIteratorPointer;
*rightIteratorPointer = temp;
operator()(_first, rightIteratorPointer);
operator()(++leftIteratorPointer, _last);
return;
}
};
template<typename T>
class QuickSort_Integer : public Sort<T>
{
private:
InsertSort<T> m_insertSort;
T** m_memoryLeftTemp;
T** m_memoryRightTemp;
T** m_memoryStart;
T** m_memoryLast;
const int m_size;
public:
QuickSort_Integer(int _size)
: m_size(_size)
{
m_memoryStart = new T*[m_size];
m_memoryLast = &m_memoryStart[m_size - 1];
m_memoryLeftTemp = m_memoryStart;
m_memoryRightTemp = m_memoryLast;
}
~QuickSort_Integer()
{
SAFE_DELETE_ARRAY(m_memoryStart);
m_memoryLast = nullptr;
m_memoryLeftTemp = nullptr;
m_memoryRightTemp = nullptr;
}
void operator()(T* const _first, T* const _last)
{
if (_last - _first < g_insertKeyValue)
{
m_insertSort(_first, _last);
return;
}
Swap(*_first, *(_first + (_last - _first) / 2));
T temp = *_first;
T* leftIteratorPointer = _first;
T* rightIteratorPointer = _last;
m_memoryLeftTemp = m_memoryStart;
m_memoryRightTemp = m_memoryLast;
while (
[&]() -> bool
{
while (leftIteratorPointer < --rightIteratorPointer)
{
if (*rightIteratorPointer < temp)
{
return true;
}
else if (*rightIteratorPointer == temp)
{
*m_memoryRightTemp = rightIteratorPointer;
m_memoryRightTemp--;
}
}
return false;
}()
&&
[&]() -> bool
{
while (++leftIteratorPointer < rightIteratorPointer)
{
if (*leftIteratorPointer > temp)
{
Swap(*leftIteratorPointer, *rightIteratorPointer);
return true;
}
else if (*leftIteratorPointer == temp)
{
*m_memoryLeftTemp = leftIteratorPointer;
m_memoryLeftTemp++;
}
}
return false;
}()
);
*_first = *rightIteratorPointer;
*rightIteratorPointer = temp;
while (--m_memoryLeftTemp >= m_memoryStart)
{
rightIteratorPointer--;
**m_memoryLeftTemp = *rightIteratorPointer;
*rightIteratorPointer = temp;
}
while (++m_memoryRightTemp <= m_memoryLast)
{
leftIteratorPointer++;
**m_memoryRightTemp = *leftIteratorPointer;
*leftIteratorPointer = temp;
}
operator()(_first, rightIteratorPointer);
operator()(++leftIteratorPointer, _last);
return;
}
};
template<typename T, RADIX_TYPE TYPE>
class RadixSort : public Sort<T>
{
using SHIFT_TYPE = std::conditional_t
<
TYPE == RT_8BIT,
unsigned char,
unsigned short
> ;
union UNION_TYPE
{
T OriginType;
SHIFT_TYPE shiftArray[sizeof(T) / sizeof(SHIFT_TYPE)];
};
const int m_size;
const long long m_shiftNum;
const SHIFT_TYPE m_cacheMSB;
const SHIFT_TYPE m_cacheMSBInvert;
unsigned int m_cacheSize;
unsigned int m_cacheHalfSize;
long long* m_cachePlus;
long long* m_cachePlusHalfPoint;
long long* m_cacheMinus;
UNION_TYPE* m_memory;
void RadixNormal(UNION_TYPE* const _srcFirst, UNION_TYPE* const _dstFirst, const long long _index)
{
memset(m_cachePlus, 0, m_cacheSize * sizeof(long long));
UNION_TYPE* srcIterator = _srcFirst;
const UNION_TYPE* srcLast = _srcFirst + m_size;
while (srcIterator < srcLast)
{
m_cachePlus[srcIterator->shiftArray[_index]]++;
srcIterator++;
}
long long* cacheIterator = m_cachePlus + m_cacheSize - 1;
*cacheIterator = m_size - *cacheIterator;
while (m_cachePlus <= --cacheIterator)
{
*cacheIterator = *(cacheIterator + 1) - *cacheIterator;
}
srcIterator = _srcFirst;
while (srcIterator < srcLast)
{
(_dstFirst + m_cachePlus[srcIterator->shiftArray[_index]])->OriginType = srcIterator->OriginType;
m_cachePlus[srcIterator->shiftArray[_index]]++;
srcIterator++;
}
}
void RadixFinal_Real(UNION_TYPE* const _srcFirst, UNION_TYPE* const _dstFirst, const long long _index)
{
memset(m_cachePlus, 0, m_cacheHalfSize * sizeof(long long));
memset(m_cacheMinus, 0, m_cacheHalfSize * sizeof(long long));
UNION_TYPE* srcIterator = _srcFirst;
const UNION_TYPE* srcLast = _srcFirst + m_size;
while (srcIterator < srcLast)
{
SHIFT_TYPE tempMSB = srcIterator->shiftArray[_index] & m_cacheMSB;
SHIFT_TYPE tempRest;
if (tempMSB)
{
tempRest = (srcIterator->shiftArray[_index] + 1) & m_cacheMSBInvert;
m_cacheMinus[tempRest]++;
}
else
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
m_cachePlus[tempRest]++;
}
srcIterator++;
}
long long* cachePlusIterator = m_cachePlus + m_cacheHalfSize - 1;
long long* cacheMinusIterator = m_cacheMinus + m_cacheHalfSize - 1;
*cachePlusIterator = *cachePlusIterator - 1;
*cacheMinusIterator = *cacheMinusIterator - 1;
cachePlusIterator--;
cacheMinusIterator--;
while (cachePlusIterator >= m_cachePlus)
{
*cachePlusIterator = *(cachePlusIterator + 1) + *cachePlusIterator;
*cacheMinusIterator = *(cacheMinusIterator + 1) + *cacheMinusIterator;
cachePlusIterator--;
cacheMinusIterator--;
}
srcIterator = _srcFirst;
UNION_TYPE* const dstLast = _dstFirst + m_size - 1;
while (srcIterator < srcLast)
{
SHIFT_TYPE tempMSB = srcIterator->shiftArray[_index] & m_cacheMSB;
SHIFT_TYPE tempRest;
if (tempMSB)
{
tempRest = (srcIterator->shiftArray[_index] + 1) & m_cacheMSBInvert;
(_dstFirst + m_cacheMinus[tempRest])->OriginType = srcIterator->OriginType;
m_cacheMinus[tempRest]--;
}
else
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
(dstLast - m_cachePlus[tempRest])->OriginType = srcIterator->OriginType;
m_cachePlus[tempRest]--;
}
srcIterator++;
}
}
void RadixFinal_Integer(UNION_TYPE* const _srcFirst, UNION_TYPE* const _dstFirst, const long long _index)
{
memset(m_cachePlus, 0, m_cacheHalfSize * sizeof(long long));
memset(m_cacheMinus, 0, m_cacheHalfSize * sizeof(long long));
UNION_TYPE* srcIterator = _srcFirst ;
const UNION_TYPE* srcLast = _srcFirst + m_size;
while (srcIterator < srcLast)
{
SHIFT_TYPE tempMSB = srcIterator->shiftArray[_index] & m_cacheMSB;
SHIFT_TYPE tempRest;
if (tempMSB)
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
m_cacheMinus[tempRest]++;
}
else
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
m_cachePlus[tempRest]++;
}
srcIterator++;
}
long long* cachePlusIterator = m_cachePlus + m_cacheHalfSize - 1;
long long* cacheMinusIterator = m_cacheMinus;
long long cacheMinusTemp = *cacheMinusIterator;
long long cacheMinusSum = 0;
*cachePlusIterator = *cachePlusIterator - 1;
*cacheMinusIterator = 0;
cachePlusIterator--;
cacheMinusIterator++;
while (cachePlusIterator >= m_cachePlus)
{
cacheMinusSum += cacheMinusTemp;
cacheMinusTemp = *cacheMinusIterator;
*cachePlusIterator = *(cachePlusIterator + 1) + *cachePlusIterator;
*cacheMinusIterator = cacheMinusSum;
cachePlusIterator--;
cacheMinusIterator++;
}
srcIterator = _srcFirst;
UNION_TYPE* const dstLast = _dstFirst + m_size - 1;
while (srcIterator < srcLast)
{
SHIFT_TYPE tempMSB = srcIterator->shiftArray[_index] & m_cacheMSB;
SHIFT_TYPE tempRest;
if (tempMSB)
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
(_dstFirst + m_cacheMinus[tempRest])->OriginType = srcIterator->OriginType;
m_cacheMinus[tempRest]++;
}
else
{
tempRest = srcIterator->shiftArray[_index] & m_cacheMSBInvert;
(dstLast - m_cachePlus[tempRest])->OriginType = srcIterator->OriginType;
m_cachePlus[tempRest]--;
}
srcIterator++;
}
}
const unsigned int GetCacheSize()
{
if (sizeof(T) <= sizeof(short))
{
return (1 << sizeof(char) * CHAR_BITS);
}
return (RadixBigO_8<T>(m_size) < RadixBigO_16<T>(m_size)) ? (1 << sizeof(char) * CHAR_BITS) : (1 << sizeof(short) * CHAR_BITS);
}
public:
RadixSort(int _size)
: m_shiftNum(sizeof(T) / sizeof(SHIFT_TYPE) - 1)
, m_cacheMSB(1 << (sizeof(SHIFT_TYPE) * CHAR_BITS - 1))
, m_cacheMSBInvert(m_cacheMSB ^ (static_cast<SHIFT_TYPE>(0) - 1))
, m_size(_size)
{
m_cacheSize = GetCacheSize();
m_cacheHalfSize = m_cacheSize >> 1;
m_cachePlus = new long long[m_cacheSize];
m_cacheMinus = new long long[m_cacheHalfSize];
m_memory = new UNION_TYPE[m_size];
m_cachePlusHalfPoint = m_cachePlus + m_cacheHalfSize;
}
~RadixSort()
{
SAFE_DELETE_ARRAY(m_cachePlus);
SAFE_DELETE_ARRAY(m_cacheMinus);
SAFE_DELETE_ARRAY(m_memory);
m_cachePlusHalfPoint = nullptr;
}
void operator()(T* const _first, T* const _last)
{
UNION_TYPE* src = reinterpret_cast<UNION_TYPE*>(_first);
UNION_TYPE* dst = m_memory;
long long index = 0LL;
while (index < m_shiftNum)
{
RadixNormal(src, dst, index);
Swap(src, dst);
index++;
}
if (std::numeric_limits<T>::is_integer)
{
RadixFinal_Integer(src, dst, index);
}
else
{
RadixFinal_Real(src, dst, index);
}
return;
}
};
template<bool _flag, typename T>
struct QuickSort
{
typedef QuickSort_Real <T> type;
};
template<typename T>
struct QuickSort<true, T>
{
typedef QuickSort_Integer<T> type;
};
template<typename T>
using QuickSort_t = typename QuickSort<std::numeric_limits<T>::is_integer, T>::type;
template<typename T>
class SortController
{
private:
SortController()
{
std::atexit(Destroy);
};
~SortController() {};
static Sort<T>* m_instance;
public:
static void Destroy()
{
delete m_instance;
m_instance = nullptr;
}
static Sort<T>* GetInstance(const int _size)
{
if (m_instance == nullptr)
{
if (IsInsertSort(_size))
{
m_instance = new InsertSort<T>();
}
else if (IsCounterSort<T>(_size))
{
m_instance = new CounterSort<T>();
}
else if (IsQuickSort<T>(_size))
{
m_instance = new QuickSort_t<T>(_size);
}
else
{
if (RadixBigO_8<T>(_size) < RadixBigO_16<T>(_size) || sizeof(T) <= sizeof(short))
{
m_instance = new RadixSort <T, RT_8BIT>(_size);
}
else
{
m_instance = new RadixSort <T, RT_16BIT>(_size);
}
}
}
return m_instance;
}
};
template <typename T>
Sort<T>* SortController<T>::m_instance = nullptr;
template<typename T = SOURCE>
void run(void* dst)
{
T* arr = static_cast<T*>(dst);
Sort<T>& m_sort = *(SortController<T>::GetInstance(SIZE));
m_sort(arr, arr + SIZE);
return;
}
};
int main(int argc, char* argv[])
{
std::random_device randomDevice;
std::mt19937 rng(randomDevice());
// std::normal_distribution< DISTRIBUTION_SOURCE > get(5, 2);
std::uniform_int_distribution< int > get;
for (auto& value : src)
{
value = static_cast<SOURCE>(get(rng));
}
BENCH bench("sort", 100, Prepare, Compare);
bench.Solution(BOSS::run, dst0, sizeof dst0); // 정답 참고용 함수 등록.
bench.Add(FUN(BOSS::run), dst1);
bench.Add(FUN(PENZER::run), dst2);
bench.run();
unsigned short* temp = reinterpret_cast<unsigned short*>(dst2);
for (int i = 0; i < 10; i++)
{
printf("%4X ", *(temp + i));
}
getchar();
return 0;
}