Is there a memset-like function which can set inte

2019-09-06 00:04发布

问题:

1, It is a pity that memset(void* dst, int value, size_t size) fools a lot of people when they first use this function! 2nd parameter "int value" should be "uchar value" to describe the real operation inside. Don't misunderstand me, I am asking a memset-like function!

2, I know there are some c++ candy function like std::fill_n(my_array, array_length, constant_value); even a pure c function in OS X: memset_pattern4(grid, &pattern, sizeof grid); mentioned in a perfect thread Why is memset() incorrectly initializing int?.

So, is there a similar c function in runtime library of visual studio like memset_pattern4()?

3, for somebody asked why i wouldn't use a for-loop to set integer by integer. here is my answer: memset turns to a better performance when setting big trunk(10K?) of memory at least in x86.

http://www.gamedev.net/topic/472631-performance-of-memset/page-2 gives more discussion, although without a conclusion(I doubt there will be).

4, said function can be used to simplify counting sort by avoiding useless Fibonacci accumulation. Original:

for (int i = 0; i < SRC_ARRY_SIZE; i++)
    counter_arry[src_arry[i]]++; 

for (int i = SRC_LOW_BOUND; i < SRC_HI_BOUND; i++)//forward fabnacci??
    counter_arry[i+1] += counter_arry[i];

for (int i = 0; i < SRC_ARRY_SIZE; i++) 
{   
    value = src_arry[i];
    map = --counter_arry[value];//then counter down!
    temp[map] = value;
}

Expected:

for (int i = 0; i < SRC_ARRY_SIZE; i++)
    counter_arry[src_arry[i]]++; 

for (int i = SRC_LOW_BOUND; i < SRC_HI_BOUND+1; i++)//forward fabnacci??
{           
    memset_4(cur_ptr,i, counter_arry[i]);
    cur_ptr += counter_arry[i];
}

Thanks for your kindly review and reply!

回答1:

Here's an implementation of memset_pattern4() that you might find useful. It's nothing like Darwin's SSE assembly language version, except that it has the same interface.

#include <string.h>
#include <stdint.h>

/*

A portable implementation of the Darwin memset_patternX() family of functions:

These are analogous to memset(), except that they fill memory with a replicated
pattern either 4, 8, or 16 bytes long.  b points to a buffer of size len bytes
which is to be filled.  The second parameter points to the pattern.  If the
buffer length is not an even multiple of the pattern length, the last instance
of the pattern will be truncated.  Neither the buffer nor the pattern pointer
need be aligned.

*/

/*
alignment utility macros stolen from Linux
see https://lkml.org/lkml/2006/11/25/2 for a discussion of why typeof() is used
*/

#if !_MSC_VER

       #define __ALIGN_KERNEL(x, a)            __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
       #define __ALIGN_KERNEL_MASK(x, mask)    (((x) + (mask)) & ~(mask))

       #define ALIGN(x, a)             __ALIGN_KERNEL((x), (a))
       #define __ALIGN_MASK(x, mask)   __ALIGN_KERNEL_MASK((x), (mask))
       #define PTR_ALIGN(p, a)         ((typeof(p))ALIGN((uintptr_t)(p), (a)))
       #define IS_ALIGNED(x, a)        (((x) & ((typeof(x))(a) - 1)) == 0)

       #define IS_PTR_ALIGNED(p, a)      (IS_ALIGNED((uintptr_t)(p), (a)))
#else
       /* MS friendly versions */

       /* taken from the DDK's fltKernel.h header */
       #define IS_ALIGNED(_pointer, _alignment)                        \
                     ((((uintptr_t) (_pointer)) & ((_alignment) - 1)) == 0)

       #define ROUND_TO_SIZE(_length, _alignment)                      \
                           ((((uintptr_t)(_length)) + ((_alignment)-1)) & ~(uintptr_t) ((_alignment) - 1))

       #define __ALIGN_KERNEL(x, a)    ROUND_TO_SIZE( (x), (a))
       #define ALIGN(x, a)             __ALIGN_KERNEL((x), (a))
       #define PTR_ALIGN(p, a)         ALIGN((p), (a))

       #define IS_PTR_ALIGNED(p, a)      (IS_ALIGNED((uintptr_t)(p), (a)))
#endif



void nx_memset_pattern4(void *b, const void *pattern4, size_t len)
{
       enum { pattern_len = 4 };

       unsigned char* dst = (unsigned char*) b;
       unsigned const char* src = (unsigned const char*) pattern4;

       if (IS_PTR_ALIGNED( dst, pattern_len) && IS_PTR_ALIGNED( src, pattern_len)) {
              /* handle aligned moves */
              uint32_t val = *((uint32_t*)src);
              uint32_t* word_dst = (uint32_t*) dst;

              size_t word_count = len / pattern_len;
              dst += word_count * pattern_len;
              len -= word_count * pattern_len;

              for (; word_count != 0; --word_count) {
                     *word_dst++ = val;
              }
       }
       else {
              while (pattern_len <= len) {
                     memcpy(dst, src, pattern_len);
                     dst += pattern_len;
                     len -= pattern_len;
              }
       }

       memcpy( dst, src, len);
}