#include "stdafx.h"
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
#include <memory.h>
#include <intrin.h>
#ifdef _WIN64
typedef unsigned long long step_t;
#else
typedef unsigned int step_t;
#endif
#if 1
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define WORD_SIZE sizeof(step_t)
#define WORD_MASK (WORD_SIZE - 1)
#define BYTE_COPY_FORWARD *d = *s; s++; d++; c--;
#define WORD_COPY_FORWARD *(int *)d = *(int *)s; s += WORD_SIZE; d += WORD_SIZE; c -= WORD_SIZE;
#define BYTE_COPY_BACKWARD s--; d--; c--; *d = *s;
#define WORD_COPY_BACKWARD s -= WORD_SIZE; d -= WORD_SIZE; c -= WORD_SIZE;*(int *)d = *(int *)s;
void memmove_tsutsu(void *destination, const void *source, size_t count)
{
if (count <= 0 || destination == source) return;
register char *d = (char *)destination;
register const char *s = (char *)source;
register size_t c = count;
if (source > destination) {
while ((step_t)s & WORD_MASK && c > 0) { BYTE_COPY_FORWARD; }
while (c >= WORD_SIZE) { WORD_COPY_FORWARD; }
while (c > 0) { BYTE_COPY_FORWARD; }
}
else {
s += c;
d += c;
while ((step_t)s & WORD_MASK && c > 0) { BYTE_COPY_BACKWARD; }
while (c >= WORD_SIZE) { WORD_COPY_BACKWARD; }
while (c > 0) { BYTE_COPY_BACKWARD; }
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#endif
typedef unsigned char i8u;
typedef unsigned long long i64u;
typedef unsigned int i32u;
#define BIG_STEP (step_t)(sizeof(step_t) * 4)
#define STEP_MASK (step_t)(sizeof(step_t) - 1)
#define wb(n) db[n] = sb[n]
#define cb(n) case n: wb(n - 1)
#define ww(n) dw[n] = (upper << (8 * (step_t)(sizeof(step_t) - p))) | \
(sw[n] >> (8 * p)), upper = sw[n]
#define cw(n) case n: ww(n - 1)
inline void remnant_move(const i8u*& const _sb, i8u*& const _db, const step_t remnant)
{
const i8u* sb = _sb;
i8u* db = _db;
switch (remnant)
{
#ifdef _WIN64
cb(7); cb(6); cb(5); cb(4);
#endif
cb(3); cb(2); cb(1);
}
}
template<step_t p>
inline void aligned_move(const i8u*& sb, i8u*& db, const step_t*& _sw, step_t*& _dw, size_t& _size)
{
const step_t* sw = _sw;
step_t* dw = _dw;
size_t size = _size;
step_t upper, step_size;
upper = sw[BIG_STEP];
while (size >= sizeof(step_t) * BIG_STEP)
{
size -= sizeof(step_t) * BIG_STEP;
#ifdef _WIN64
ww(0x1F); ww(0x1E); ww(0x1D); ww(0x1C); ww(0x1B); ww(0x1A); ww(0x19); ww(0x18);
ww(0x17); ww(0x16); ww(0x15); ww(0x14); ww(0x13); ww(0x12); ww(0x11); ww(0x10);
#endif
ww(0x0F); ww(0x0E); ww(0x0D); ww(0x0C); ww(0x0B); ww(0x0A); ww(0x09); ww(0x08);
ww(0x07); ww(0x06); ww(0x05); ww(0x04); ww(0x03); ww(0x02); ww(0x01); ww(0x00);
dw -= BIG_STEP;
sw -= BIG_STEP;
}
step_size = size / sizeof(step_t);
dw -= step_size - BIG_STEP;
sw -= step_size - BIG_STEP;
upper = sw[step_size];
switch (step_size)
{
#ifdef _WIN64
cw(0x1F); cw(0x1E); cw(0x1D); cw(0x1C); cw(0x1B); cw(0x1A); cw(0x19); cw(0x18);
cw(0x17); cw(0x16); cw(0x15); cw(0x14); cw(0x13); cw(0x12); cw(0x11); cw(0x10);
#endif
cw(0x0F); cw(0x0E); cw(0x0D); cw(0x0C); cw(0x0B); cw(0x0A); cw(0x09); cw(0x08);
cw(0x07); cw(0x06); cw(0x05); cw(0x04); cw(0x03); cw(0x02); cw(0x01);
}
size -= step_size * sizeof(step_t);
db = (i8u*)dw - size;
sb = (i8u*)sw - size + p;
_sw = sw;
_dw = dw;
_size = size;
}
void* memmove_codesafer(void* dst, const void* src, size_t size)
{
if (!size || src == dst) return dst;
const i8u* sb = (const i8u*)src;
i8u* db = (i8u*)dst;
const step_t* sw;
step_t* dw;
if (db < sb || db >= sb + size)
return memcpy(dst, src, size);
if (size >= sizeof(step_t))
{
step_t step_size = (step_t)dst + size & STEP_MASK;
size -= step_size;
db = (i8u*)((step_t)dst + size & ~STEP_MASK);
sb = (i8u*)((step_t)src + size);
dw = (step_t*)db - BIG_STEP;
sw = (step_t*)((step_t)sb & ~STEP_MASK) - BIG_STEP;
remnant_move(sb, db, step_size);
switch ((step_t)sb & STEP_MASK)
{
case 0: aligned_move< 0 >(sb, db, sw, dw, size); break;
case 1: aligned_move< 1 >(sb, db, sw, dw, size); break;
case 2: aligned_move< 2 >(sb, db, sw, dw, size); break;
case 3: aligned_move< 3 >(sb, db, sw, dw, size); break;
#ifdef _WIN64
case 4: aligned_move< 4 >(sb, db, sw, dw, size); break;
case 5: aligned_move< 5 >(sb, db, sw, dw, size); break;
case 6: aligned_move< 6 >(sb, db, sw, dw, size); break;
case 7: aligned_move< 7 >(sb, db, sw, dw, size); break;
#endif
}
}
remnant_move(sb, db, size);
return dst;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MEM_SIZE 0x10000
#define SRC_OFFSET 2
#define TGT_OFFSET 3
#define LOOP_COUNT 1000
int main()
{
i8u src0_[MEM_SIZE * 2];
i8u src1_[MEM_SIZE * 2];
i8u src2_[MEM_SIZE * 2];
int* src0 = (int*)(src0_ + SRC_OFFSET);
int* src1 = (int*)(src1_ + SRC_OFFSET);
int* src2 = (int*)(src2_ + SRC_OFFSET);
int* tgt0 = (int*)(src0_ + TGT_OFFSET);
int* tgt1 = (int*)(src1_ + TGT_OFFSET);
int* tgt2 = (int*)(src2_ + TGT_OFFSET);
i64u set_, end_, min_;
i64u set0, end0, min0;
i64u set1, end1, min1;
i64u set2, end2, min2;
min_ = min0 = min1 = min2 = (i64u)-1LL;
for (int i = 0; i < LOOP_COUNT; ++i)
{
set_ = __rdtsc();
end_ = __rdtsc();
if (end_ - set_ < min_) min_ = end_ - set_;
}
int try_count = LOOP_COUNT;
while (try_count--)
{
for (int i = 0; i < MEM_SIZE * 2; ++i) src0_[i] = i;
set0 = __rdtsc();
memmove(tgt0, src0, MEM_SIZE);
end0 = __rdtsc();
if (end0 - set0 < min0) min0 = end0 - set0;
for (int i = 0; i < MEM_SIZE * 2; ++i) src1_[i] = i;
set1 = __rdtsc();
memmove_tsutsu(tgt1, src1, MEM_SIZE);
end1 = __rdtsc();
if (end1 - set1 < min1) min1 = end1 - set1;
for (int i = 0; i < MEM_SIZE * 2; ++i) src2_[i] = i;
set2 = __rdtsc();
memmove_codesafer(tgt2, src2, MEM_SIZE);
end2 = __rdtsc();
if (end2 - set2 < min2) min2 = end2 - set2;
for (int i = 0; i < MEM_SIZE * 2; ++i)
if (src0_[i] != src2_[i])
printf("%06d %u %u\n", i, (unsigned int)src0_[i], (unsigned int)src2_[i]);
}
min0 -= min_;
min1 -= min_;
min2 -= min_;
printf("\n");
printf("memmove %10u\n", (i32u)min0);
printf("memmove_tsutsu %10u\n", (i32u)min1);
printf("memmove_codesafer %10u\n", (i32u)min2);
getchar();
return 0;
}