How does Duff's device work?

前端 未结 11 2003
日久生厌
日久生厌 2020-11-22 04:56

I\'ve read the article on Wikipedia on the Duff\'s device, and I don\'t get it. I am really interested, but I\'ve read the explanation there a couple of times and I still do

11条回答
  •  忘掉有多难
    2020-11-22 05:40

    Here is a working example for 64-bit memcpy with Duff's Device:

    #include 
    #include 
    
    inline void __memcpy(void* to, const void* from, size_t count)
    {
        size_t numIter = (count  + 56) / 64;  // gives the number of iterations;  bit shift actually, not division
        size_t rest = count & 63; // % 64
        size_t rest7 = rest&7;
        rest -= rest7;
    
        // Duff's device with zero case handled:
        switch (rest) 
        {
            case 0:  if (count < 8)
                         break;
                     do { *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 56:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 48:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 40:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 32:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 24:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 16:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
            case 8:      *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
                    } while (--numIter > 0);
        }
    
        switch (rest7)
        {
            case 7: *(((unsigned char*)to)+6) = *(((unsigned char*)from)+6);
            case 6: *(((unsigned short*)to)+2) = *(((unsigned short*)from)+2); goto case4;
            case 5: *(((unsigned char*)to)+4) = *(((unsigned char*)from)+4);
            case 4: case4: *((unsigned long*)to) = *((unsigned long*)from); break; 
            case 3: *(((unsigned char*)to)+2) = *(((unsigned char*)from)+2);
            case 2: *((unsigned short*)to) = *((unsigned short*)from); break;
            case 1: *((unsigned char*)to) = *((unsigned char*)from);
        }
    }
    
    void main()
    {
        static const size_t NUM = 1024;
    
        std::unique_ptr str1(new char[NUM+1]);  
        std::unique_ptr str2(new char[NUM+1]);
    
        for (size_t i = 0 ; i < NUM ; ++ i)
        {
            size_t idx = (i % 62);
            if (idx < 26)
                str1[i] = 'a' + idx;
            else
                if (idx < 52)
                    str1[i] = 'A' + idx - 26;
                else
                    str1[i] = '0' + idx - 52;
        }
    
        for (size_t i = 0 ; i < NUM ; ++ i)
        {
            memset(str2.get(), ' ', NUM); 
            __memcpy(str2.get(), str1.get(), i);
            if (memcmp(str1.get(), str2.get(), i) || str2[i] != ' ')
            {
                std::cout << "Test failed for i=" << i;
            }
    
        }
    
        return;
    }
    
    
    

    It handles zero-length case (in original Duff's Device there is assumption num>0). Function main() contains simple test cases for __memcpy.

提交回复
热议问题