СоНоты

Исправленная быстрая strncpy

В еще более быстрой версии функции strncpy был существенный недостаток, - она не полностью соответствовала спецификации, а именно, не дополняла нулями, если строка-источник оказывалась короче указанной длины. Вариант ниже исправляет этот недостаток, но по-прежнему быстрее стандартной функции будучи скомпилированным с включенной оптимизацией кода для современных процессоров:


typedef long long word;  /* up to 32 bytes long */
#define wsize sizeof(word)
#define wmask (wsize - 1)

inline void dps_minibzero(char *dst, size_t t) {
	if (t) { dst[0] = '\0'; 
	if (t > 1) { dst[1] = '\0'; 
	if (t > 2) { dst[2] = '\0'; 
	if (t > 3) { dst[3] = '\0'; 
	if (t > 4) { dst[4] = '\0'; 
	if (t > 5) { dst[5] = '\0'; 
	if (t > 6) { dst[6] = '\0'; 
	if (t > 7) { dst[7] = '\0'; 
	if (t > 8 ) { dst[8] = '\0'; 
	if (t > 9) { dst[9] = '\0'; 
	if (t > 10) { dst[10] = '\0'; 
	if (t > 11) { dst[11] = '\0'; 
	if (t > 12) { dst[12] = '\0'; 
	if (t > 13) { dst[13] = '\0'; 
	if (t > 14) { dst[14] = '\0'; 
	if (t > 15) { dst[15] = '\0'; 
	if (t > 16) { dst[16] = '\0'; 
	if (t > 17) { dst[17] = '\0'; 
	if (t > 18) { dst[18] = '\0'; 
	if (t > 19) { dst[19] = '\0'; 
	if (t > 20) { dst[20] = '\0'; 
	if (t > 21) { dst[21] = '\0'; 
	if (t > 22) { dst[22] = '\0'; 
	if (t > 23) { dst[23] = '\0'; 
	if (t > 24) { dst[24] = '\0'; 
	if (t > 25) { dst[25] = '\0'; 
	if (t > 26) { dst[26] = '\0'; 
	if (t > 27) { dst[27] = '\0'; 
	if (t > 28) { dst[28] = '\0'; 
	if (t > 29) { dst[29] = '\0'; 
	if (t > 30) { dst[30] = '\0'; 
	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}


void * dps_strncpy(char *dst0, char *src0, size_t length) {
  if (length) {
    register size_t n = length / 8;
    register size_t r = (length % 8);
    register char *dst = dst0, *src = src0;
    if (r == 0) r = 8; else n++;
    if (!(dst[0] = src[0])) { dst++; src++; goto dps_strncpy_second_pas; }
    if (r > 1) { if (!(dst[1] = src[1])) { dst += 2; src += 2; goto dps_strncpy_second_pas; }
    if (r > 2) { if (!(dst[2] = src[2])) { dst += 3; src += 3; goto dps_strncpy_second_pas; }
    if (r > 3) { if (!(dst[3] = src[3])) { dst += 4; src += 4; goto dps_strncpy_second_pas; }
    if (r > 4) { if (!(dst[4] = src[4])) { dst += 5; src += 5; goto dps_strncpy_second_pas; }
    if (r > 5) { if (!(dst[5] = src[5])) { dst += 6; src += 6; goto dps_strncpy_second_pas; }
    if (r > 6) { if (!(dst[6] = src[6])) { dst += 7; src += 7; goto dps_strncpy_second_pas; }
    if (r > 7) { if (!(dst[7] = src[7])) { dst += 8; src += 8; goto dps_strncpy_second_pas; }
    }}}}}}}
    src += r; dst += r;
    while (--n > 0) {
      if (!(dst[0] = src[0])) { dst++; src++; goto dps_strncpy_second_pas; }
      if (!(dst[1] = src[1])) { dst += 2; src += 2; goto dps_strncpy_second_pas; }
      if (!(dst[2] = src[2])) { dst += 3; src += 3; goto dps_strncpy_second_pas; }
      if (!(dst[3] = src[3])) { dst += 4; src += 4; goto dps_strncpy_second_pas; }
      if (!(dst[4] = src[4])) { dst += 5; src += 5; goto dps_strncpy_second_pas; }
      if (!(dst[5] = src[5])) { dst += 6; src += 6; goto dps_strncpy_second_pas; }
      if (!(dst[6] = src[6])) { dst += 7; src += 7; goto dps_strncpy_second_pas; }
      if (!(dst[7] = src[7])) { dst += 8; src += 8; goto dps_strncpy_second_pas; }
      src += 8; dst += 8;
    }
dps_strncpy_second_pas:
    if (dst < dst0 + length) {
      size_t t, restlen = length - (dst - dst0);
      t = (unsigned int)dst & wmask;
      if (t) {
    	if (restlen < wsize) {
		t = restlen;
    	} else {
		t = wsize - t;
    	}
	bzero(dst, t);
	dps_minibzero(dst, t);
	restlen -= t;
	dst += t;
      }
      t = restlen / wsize;
      if (t) {
	n = t / 8;
    	r = (t % 8 );
	register word *wdst = (word*)dst;
    	if (r == 0) r = 8; else n++;
    	wdst[0] = (word)0;
    	if (r > 1) { wdst[1] = (word)0;
    	if (r > 2) { wdst[2] = (word)0;
    	if (r > 3) { wdst[3] = (word)0;
    	if (r > 4) { wdst[4] = (word)0;
    	if (r > 5) { wdst[5] = (word)0;
    	if (r > 6) { wdst[6] = (word)0;
    	if (r > 7) { wdst[7] = (word)0;
	}}}}}}}
    	wdst += r;
    	while (--n > 0) {
    		wdst[0] = (word)0;
    		wdst[1] = (word)0;
    		wdst[2] = (word)0;
    		wdst[3] = (word)0;
    		wdst[4] = (word)0;
    		wdst[5] = (word)0;
    		wdst[6] = (word)0;
    		wdst[7] = (word)0;
    		wdst += 8;
    	}
 	dst = (char*)wdst;
      }
      if ( (t = (restlen & wmask)) ) dps_minibzero(dst, t);
    }
  }
  return dst0;
}