我需要将一个6字节的整数值复制到一个内存区域,从它的开始和尽可能快的方式开始.如果硬件支持这样的操作,我想使用它(我现在在x64处理器上,编译器是GCC 4.6.3).
这memset不适合作业,因为它只能复制字节.这std::fill也不好,因为我甚至无法定义迭代器,在内存区域中的6个字节宽度位置之间跳转.
所以,我想要一个功能:
void myMemset(void* ptr, uint64_t value, uint8_t width, size_t num)
Run Code Online (Sandbox Code Playgroud)
这看起来像memset,但有一个额外的参数width来定义如何多字节从value复制.如果这样的东西可以用C++表达,那就更好了.
我已经知道了明显的myMemset实现,它将调用memcpy带有最后一个参数(要复制的字节)的in循环等于width.我也知道,我可以用大小6 * 8 = 48字节定义一个临时内存区域,用6字节整数填充它然后memcpy到目标区域.
我们可以做得更好吗?
沿东西@马克赎金的评论:
复制6个字节,然后复制6,12,24,48,96等.
void memcpy6(void *dest, const void *src, size_t n /* number of 6 byte blocks */) {
if (n-- == 0) {
return;
}
memcpy(dest, src, 6);
size_t width = 1;
while (n >= width) {
memcpy(&((char *) dest)[width * 6], dest, width * 6);
n -= width;
width <<= 1; // double w
}
if (n > 0) {
memcpy(&((char *) dest)[width * 6], dest, n * 6);
}
}
Run Code Online (Sandbox Code Playgroud)
优化:规模n和width6.
[编辑]
更正目的地@SchighSchagh已
添加演员表(char *)
一次写入 8 个字节。
在 64 位机器上,生成的代码当然可以很好地进行 8 字节写入操作。处理完一些设置问题后,在紧密循环中,每次写入大约 8 字节num。假设适用 - 请参阅代码。
// assume little endian
void myMemset(void* ptr, uint64_t value, uint8_t width, size_t num) {
assert(width > 0 && width <= 8);
uint64_t *ptr64 = (uint64_t *) ptr;
// # to stop early to prevent writing past array end
static const unsigned stop_early[8 + 1] = { 0, 8, 3, 2, 1, 1, 1, 1, 0 };
size_t se = stop_early[width];
if (num > se) {
num -= se;
// assume no bus-fault with 64-bit write @ `ptr64, ptr64+1, ... ptr64+7`
while (num > 0) { // tight loop
num--;
*ptr64 = value;
ptr64 = (uint64_t *) ((char *) ptr64 + width);
}
ptr = ptr64;
num = se;
}
// Cope with last few writes
while (num-- > 0) {
memcpy(ptr, &value, width);
ptr = (char *) ptr + width;
}
}
Run Code Online (Sandbox Code Playgroud)
进一步的优化包括一次写入 2 个块width == 3 or 4、一次写入 4 个块width == 2以及一次写入 8 个块width == 1。