CRC32Stream.st
changeset 4871 32729bea327d
parent 4869 d90f0348f3ef
child 4873 86aab8ca867c
equal deleted inserted replaced
4870:d4870b9aa0e5 4871:32729bea327d
    20 	classVariableNames:''
    20 	classVariableNames:''
    21 	poolDictionaries:''
    21 	poolDictionaries:''
    22 	category:'System-Crypt-Hashing'
    22 	category:'System-Crypt-Hashing'
    23 !
    23 !
    24 
    24 
       
    25 CRC32Stream subclass:#CRC32Stream_Castagnoli
       
    26 	instanceVariableNames:''
       
    27 	classVariableNames:''
       
    28 	poolDictionaries:''
       
    29 	privateIn:CRC32Stream
       
    30 !
       
    31 
       
    32 !CRC32Stream primitiveDefinitions!
       
    33 %{
       
    34 
       
    35 /*
       
    36  * includes, defines, structure definitions
       
    37  * and typedefs come here.
       
    38  */
       
    39 #ifdef __LP64__
       
    40 inline uint64_t _mm_crc32_u64(uint64_t crc, uint64_t value) {
       
    41   asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
       
    42   return crc;
       
    43 }
       
    44 #endif
       
    45 
       
    46 inline uint32_t _mm_crc32_u32(uint32_t crc, uint32_t value) {
       
    47   asm("crc32l %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
       
    48   return crc;
       
    49 }
       
    50 
       
    51 inline uint32_t _mm_crc32_u16(uint32_t crc, uint16_t value) {
       
    52   asm("crc32w %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
       
    53   return crc;
       
    54 }
       
    55 
       
    56 inline uint32_t _mm_crc32_u8(uint32_t crc, uint8_t value) {
       
    57   asm("crc32b %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value));
       
    58   return crc;
       
    59 }
       
    60 %}
       
    61 ! !
       
    62 
    25 !CRC32Stream class methodsFor:'documentation'!
    63 !CRC32Stream class methodsFor:'documentation'!
    26 
    64 
    27 copyright
    65 copyright
    28 "
    66 "
    29  COPYRIGHT (c) 2003 by eXept Software AG
    67  COPYRIGHT (c) 2003 by eXept Software AG
    44     The default CRC polynomial employed is
    82     The default CRC polynomial employed is
    45 
    83 
    46         x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
    84         x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
    47         (or 16r04C11DB7)
    85         (or 16r04C11DB7)
    48 
    86 
    49     You can also create an instace performing the Castagnioli CRC-32C 
    87     You can also create an instace performing the Castagnoli CRC-32C 
    50     (used in iSCSI & SCTP [RFC3720], G.hn payload, SSE4.2):
    88     (used in iSCSI & SCTP [RFC3720], G.hn payload, SSE4.2):
    51 
    89 
    52         self newCrc32c
    90         self newCrc32c
    53 
    91 
    54         poly: 16r1edc6f41
    92         poly: 16r1edc6f41
    60     Notice that this CRC is also used with PNG images; 
    98     Notice that this CRC is also used with PNG images; 
    61     therefore, its performance directly affects png image processing (png write speed).
    99     therefore, its performance directly affects png image processing (png write speed).
    62 
   100 
    63     throughput:
   101     throughput:
    64         235 Mb/s on MacBook Pro (2.6Ghz I7)
   102         235 Mb/s on MacBook Pro (2.6Ghz I7)
    65         157000 Kb/s on a 2.5Ghz 64X2 Athlon 4800+ (64bit)
   103         157 Mb/s on a 2.5Ghz 64X2 Athlon 4800+ (64bit)
    66         150000 Kb/s on 2Ghz Duo
   104         150 Mb/s on 2Ghz Duo
       
   105      new:
       
   106         500 Mb/s for castagnoli on MacBook Pro (2.6Ghz I7)
    67 
   107 
    68     [author:]
   108     [author:]
    69         Stefan Vogel (stefan@zwerg)
   109         Stefan Vogel (stefan@zwerg)
    70 
   110 
    71     [instance variables:]
   111     [instance variables:]
   111              16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF
   151              16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF
   112              16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF]) hexPrintString)
   152              16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF 16rFF]) hexPrintString)
   113                                                                 [exEnd]
   153                                                                 [exEnd]
   114 
   154 
   115   timing throughput:
   155   timing throughput:
       
   156   230Mb/s (on MacBook Pro 2012 / 2.6Ghz I7) 
   116                                                                 [exBegin]
   157                                                                 [exBegin]
   117     |hashStream n t|
   158     |hashStream n t|
   118 
   159 
   119     hashStream := CRC32Stream new.
   160     hashStream := CRC32Stream new.
   120     n := 2000000.
   161     n := 2000000.
   127     Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString.
   168     Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString.
   128     Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'.
   169     Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'.
   129     Transcript show:(n*50/1024 / t); showCR:' Kb/s'
   170     Transcript show:(n*50/1024 / t); showCR:' Kb/s'
   130                                                                 [exEnd]
   171                                                                 [exEnd]
   131 
   172 
       
   173   500Mb/s (on MacBook Pro 2012 / 2.6Ghz I7) 
       
   174                                                                 [exBegin]
       
   175     |hashStream n t|
       
   176 
       
   177     hashStream := CRC32Stream newCastagnoli.
       
   178     n := 2000000.
       
   179     t := Time millisecondsToRun:[
       
   180             n timesRepeat:[
       
   181                 hashStream nextPutAll:'12345678901234567890123456789012345678901234567890'.
       
   182             ].
       
   183          ].
       
   184     t := (t / 1000) asFloat.
       
   185     Transcript show:'crc32:'; showCR: hashStream hashValue hexPrintString.
       
   186     Transcript show:t; show:' seconds for '; show:(50*n/1024) asFloat; showCR:' Kb'.
       
   187     Transcript show:(n*50/1024 / t); showCR:' Kb/s'
       
   188                                                                 [exEnd]
       
   189 
   132   test vectors from https://tools.ietf.org/html/rfc3720#page-217:
   190   test vectors from https://tools.ietf.org/html/rfc3720#page-217:
   133   
   191   
   134   expect 0
   192   expect 0
   135                                                                 [exBegin]
   193                                                                 [exBegin]
   136     self information:(CRC32Stream newCrc32c hashValueOf:'') hexPrintString
   194     self information:(CRC32Stream newCrc32c hashValueOf:'') hexPrintString
   158 
   216 
   159 "
   217 "
   160 ! !
   218 ! !
   161 
   219 
   162 !CRC32Stream class methodsFor:'instance creation'!
   220 !CRC32Stream class methodsFor:'instance creation'!
       
   221 
       
   222 castagnoli_nextPutBytes:count from:anObject startingAt:start
       
   223     "add the hash of anObject to the computed hash so far.
       
   224      This uses an x86 crc instruction,
       
   225      and works only with the castagnoli polynom"
       
   226 
       
   227 %{
       
   228 #if defined(__x86__) || defined(__x86_64__)
       
   229 # if defined(__clang__) || defined(__GNUC__)
       
   230 #  pragma GCC push_options
       
   231 #  pragma GCC target ("arch=core-avx2")
       
   232 
       
   233     if (__bothSmallInteger(count, start)) {
       
   234         int len, offs;
       
   235         int objSize;
       
   236         unsigned char *extPtr;
       
   237 
       
   238         len = __intVal(count);
       
   239         offs = __intVal(start) - 1;
       
   240 
       
   241         if (__isExternalBytesLike(anObject)) {
       
   242             OBJ sz = __externalBytesSize(anObject);
       
   243 
       
   244             extPtr = (unsigned char *)__externalBytesAddress(anObject);
       
   245             if (__isSmallInteger(sz)) {
       
   246                 objSize = __intVal(sz);
       
   247             } else {
       
   248                 objSize = 0; /* unknown */
       
   249             }
       
   250         } else {
       
   251             int nInstVars, nInstBytes;
       
   252             OBJ oClass = __Class(anObject);
       
   253 
       
   254             switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
       
   255                 case BYTEARRAY:
       
   256                 case WORDARRAY:
       
   257                 case LONGARRAY:
       
   258                 case SWORDARRAY:
       
   259                 case SLONGARRAY:
       
   260                 case FLOATARRAY:
       
   261                 case DOUBLEARRAY:
       
   262                     break;
       
   263                 default:
       
   264                     goto bad;
       
   265             }
       
   266             nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
       
   267             nInstBytes = __OBJS2BYTES__(nInstVars);
       
   268             // nInstBytes is the number of bytes occupied by pointer instance variables
       
   269             // subtract from size and add to byte-pointer
       
   270             objSize = __qSize(anObject) - OHDR_SIZE - nInstBytes;
       
   271             extPtr = (unsigned char *)__byteArrayVal(anObject)+nInstBytes;
       
   272         }
       
   273 
       
   274         if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) {
       
   275             unsigned int _crc;
       
   276             unsigned int *_crcTable = __integerArrayVal( __INST(crcTable) );
       
   277             unsigned char *cp = extPtr+offs;
       
   278             unsigned int n = len;
       
   279 
       
   280             if (__isSmallInteger(__INST(crc))) {
       
   281                 _crc = (unsigned int) (__intVal( __INST(crc) ));
       
   282             } else {
       
   283                 _crc = __unsignedLongIntVal( __INST(crc) );
       
   284             }
       
   285 
       
   286 #if 0
       
   287 # if __POINTER_SIZE__ == 8
       
   288             if (((unsigned INT)cp & 7) == 0) {
       
   289                 // longword aligned
       
   290                 for ( ; n >= 8 ; n -= 8, cp += 8) {
       
   291                     unsigned INT lWord;
       
   292                     unsigned char _idx;
       
   293 
       
   294                     lWord = ((unsigned INT *)cp)[0];
       
   295                     _idx = (_crc ^ lWord) & 0xFF;
       
   296                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   297                     _idx = (_crc ^ (lWord>>8)) & 0xFF;
       
   298                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   299                     _idx = (_crc ^ (lWord>>16)) & 0xFF;
       
   300                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   301                     _idx = (_crc ^ (lWord>>24)) & 0xFF;
       
   302                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   303 
       
   304                     _idx = (_crc ^ (lWord>>32)) & 0xFF;
       
   305                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   306                     _idx = (_crc ^ (lWord>>40)) & 0xFF;
       
   307                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   308                     _idx = (_crc ^ (lWord>>48)) & 0xFF;
       
   309                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   310                     _idx = (_crc ^ (lWord>>56)) & 0xFF;
       
   311                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   312                 }
       
   313             }
       
   314 # endif // __POINTER_SIZE__ == 8          
       
   315             if (((unsigned INT)cp & 3) == 0) {
       
   316                 // word aligned
       
   317                 for ( ; n >= 4 ; n -= 4, cp += 4) {
       
   318                     unsigned int word;
       
   319                     unsigned char _idx;
       
   320 
       
   321                     word = ((unsigned int *)cp)[0];
       
   322                     _idx = (_crc ^ word) & 0xFF;
       
   323                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   324                     _idx = (_crc ^ (word>>8)) & 0xFF;
       
   325                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   326                     _idx = (_crc ^ (word>>16)) & 0xFF;
       
   327                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   328                     _idx = (_crc ^ (word>>24)) & 0xFF;
       
   329                     _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   330                 }
       
   331             }
       
   332 #endif // 0
       
   333             for ( ; n >= 4 ; n -= 4, cp += 4) {
       
   334                 unsigned char _idx;
       
   335 
       
   336                 _idx = (_crc ^ cp[0]) & 0xFF;
       
   337                 _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   338                 _idx = (_crc ^ cp[1]) & 0xFF;
       
   339                 _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   340                 _idx = (_crc ^ cp[2]) & 0xFF;
       
   341                 _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   342                 _idx = (_crc ^ cp[3]) & 0xFF;
       
   343                 _crc = _crcTable[_idx] ^ (_crc >> 8);
       
   344             }
       
   345             while (n-- > 0) {
       
   346                 unsigned char ch = *cp++;
       
   347                 
       
   348                 _crc = __builtin_ia32_crc32qi(_crc, ch);
       
   349             }
       
   350 
       
   351             if ((__POINTER_SIZE__==8) || (_crc <= _MAX_INT)) {
       
   352                 __INST(crc) = __MKSMALLINT(_crc);
       
   353             } else {
       
   354                 // this code fails with gcc 4.7.2:
       
   355                 // __INST(crc) = __MKUINT(_crc); __STORESELF(crc);
       
   356                 OBJ temp = __MKUINT(_crc); 
       
   357                 __INST(crc) = temp; __STORESELF(crc);
       
   358             }
       
   359 
       
   360             RETURN (count);
       
   361         }
       
   362     }
       
   363 bad: ;
       
   364 # endif
       
   365 #endif
       
   366 %}.
       
   367     self primitiveFailed
       
   368 
       
   369     "Created: / 17-03-2019 / 15:36:45 / Claus Gittinger"
       
   370 !
   163 
   371 
   164 generatorPolynomMSB:anInteger
   372 generatorPolynomMSB:anInteger
   165     "notice, in literature, the generator polynom is usually specified as an MSB number"
   373     "notice, in literature, the generator polynom is usually specified as an MSB number"
   166     
   374     
   167     ^ self generatorPolynom:(anInteger bitReversed32)
   375     ^ self generatorPolynom:(anInteger bitReversed32)
   216 newCastagnoli
   424 newCastagnoli
   217     "return an instance of the Castagnoli CRC-32
   425     "return an instance of the Castagnoli CRC-32
   218         x32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 1
   426         x32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 1
   219      (used in iSCSI & SCTP, G.hn payload, SSE4.2)"
   427      (used in iSCSI & SCTP, G.hn payload, SSE4.2)"
   220 
   428 
       
   429     |impl|
       
   430     
       
   431     impl := (self canUseFastCRC) ifTrue:[CRC32Stream_Castagnoli] ifFalse:[self].
       
   432     
   221     "/ 16r1edc6f41 bitReversed32 -> 16r82F63B78
   433     "/ 16r1edc6f41 bitReversed32 -> 16r82F63B78
   222     ^ self generatorPolynomMSB:16r1edc6f41 
   434     ^ impl generatorPolynomMSB:16r1edc6f41 
   223            initValue:16rFFFFFFFF xorOut:16rFFFFFFFF
   435            initValue:16rFFFFFFFF xorOut:16rFFFFFFFF
   224 
   436 
   225     "
   437     "
   226      Castagnoli crc:
   438      Castagnoli crc:
   227        self assert:((self newCrc32c)
   439        self assert:((self newCrc32c)
   233                                 nextPut:'123456789';
   445                                 nextPut:'123456789';
   234                                 hashValue) = 3421780262. '16rCBF43926'
   446                                 hashValue) = 3421780262. '16rCBF43926'
   235     "
   447     "
   236 
   448 
   237     "Created: / 17-03-2019 / 14:33:54 / Claus Gittinger"
   449     "Created: / 17-03-2019 / 14:33:54 / Claus Gittinger"
       
   450     "Modified: / 17-03-2019 / 17:08:32 / Claus Gittinger"
   238 !
   451 !
   239 
   452 
   240 newCrc32c
   453 newCrc32c
   241     "return an instance of the Castagnoli CRC-32"
   454     "return an instance of the Castagnoli CRC-32"
   242 
   455 
   256 
   469 
   257     "Modified (comment): / 17-05-2012 / 12:48:53 / cg"
   470     "Modified (comment): / 17-05-2012 / 12:48:53 / cg"
   258     "Modified: / 17-03-2019 / 14:34:26 / Claus Gittinger"
   471     "Modified: / 17-03-2019 / 14:34:26 / Claus Gittinger"
   259 ! !
   472 ! !
   260 
   473 
       
   474 !CRC32Stream class methodsFor:'private'!
       
   475 
       
   476 canUseFastCRC
       
   477 %{ /* NOCONTEXT */
       
   478 #if defined(__x86__) || defined(__x86_64__)
       
   479 # if defined(__clang__) || defined(__GNUC__)
       
   480     extern unsigned char __cpu_hasSSE4_2;
       
   481     
       
   482     RETURN (__cpu_hasSSE4_2 ? true : false);
       
   483 # endif
       
   484 #endif
       
   485 %}.
       
   486     ^ false
       
   487 
       
   488     "
       
   489      self canUseFastCRC
       
   490     "
       
   491 
       
   492     "Created: / 17-03-2019 / 16:45:42 / Claus Gittinger"
       
   493 ! !
       
   494 
   261 !CRC32Stream methodsFor:'initialization'!
   495 !CRC32Stream methodsFor:'initialization'!
   262 
   496 
   263 generatorPolynom:anLSBInteger
   497 generatorPolynom:anLSBInteger
   264     "set the generator polynom for this instance.
   498     "set the generator polynom for this instance.
   265      set start and xorOut to 16rFFFFFFFF.
   499      set start and xorOut to 16rFFFFFFFF.
   282 
   516 
   283     "Created: / 16-03-2019 / 21:06:16 / Claus Gittinger"
   517     "Created: / 16-03-2019 / 21:06:16 / Claus Gittinger"
   284     "Modified (format): / 17-03-2019 / 14:02:31 / Claus Gittinger"
   518     "Modified (format): / 17-03-2019 / 14:02:31 / Claus Gittinger"
   285 ! !
   519 ! !
   286 
   520 
       
   521 !CRC32Stream::CRC32Stream_Castagnoli class methodsFor:'documentation'!
       
   522 
       
   523 documentation
       
   524 "
       
   525     redefined to use the CPU's CRC instruction
       
   526 
       
   527     [author:]
       
   528         Claus Gittinger
       
   529 "
       
   530 ! !
       
   531 
       
   532 !CRC32Stream::CRC32Stream_Castagnoli methodsFor:'writing'!
       
   533 
       
   534 nextPutBytes:count from:anObject startingAt:start
       
   535     "add the hash of anObject to the computed hash so far.
       
   536      This uses the x86/x86_64 crc instruction,
       
   537      and works only for the castagnoli polynom"
       
   538 
       
   539 %{  /* NOCONTEXT */
       
   540 #if defined(__x86__) || defined(__x86_64__)
       
   541 # if defined(__clang__) || defined(__GNUC__)
       
   542 
       
   543     if (__bothSmallInteger(count, start)) {
       
   544         int len, offs;
       
   545         int objSize;
       
   546         unsigned char *extPtr;
       
   547 
       
   548         len = __intVal(count);
       
   549         offs = __intVal(start) - 1;
       
   550 
       
   551         if (__isExternalBytesLike(anObject)) {
       
   552             OBJ sz = __externalBytesSize(anObject);
       
   553 
       
   554             extPtr = (unsigned char *)__externalBytesAddress(anObject);
       
   555             if (__isSmallInteger(sz)) {
       
   556                 objSize = __intVal(sz);
       
   557             } else {
       
   558                 objSize = 0; /* unknown */
       
   559             }
       
   560         } else {
       
   561             int nInstVars, nInstBytes;
       
   562             OBJ oClass = __Class(anObject);
       
   563 
       
   564             switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
       
   565                 case BYTEARRAY:
       
   566                 case WORDARRAY:
       
   567                 case LONGARRAY:
       
   568                 case SWORDARRAY:
       
   569                 case SLONGARRAY:
       
   570                 case FLOATARRAY:
       
   571                 case DOUBLEARRAY:
       
   572                     break;
       
   573                 default:
       
   574                     goto bad;
       
   575             }
       
   576             nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
       
   577             nInstBytes = __OBJS2BYTES__(nInstVars);
       
   578             // nInstBytes is the number of bytes occupied by pointer instance variables
       
   579             // subtract from size and add to byte-pointer
       
   580             objSize = __qSize(anObject) - OHDR_SIZE - nInstBytes;
       
   581             extPtr = (unsigned char *)__byteArrayVal(anObject)+nInstBytes;
       
   582         }
       
   583 
       
   584         if ((offs >= 0) && (len >= 0) && (objSize >= (len + offs))) {
       
   585             unsigned int _crc;
       
   586             unsigned int *_crcTable = __integerArrayVal( __INST(crcTable) );
       
   587             unsigned char *cp = extPtr+offs;
       
   588             unsigned int n = len;
       
   589 
       
   590             if (__isSmallInteger(__INST(crc))) {
       
   591                 _crc = (unsigned int) (__intVal( __INST(crc) ));
       
   592             } else {
       
   593                 _crc = __unsignedLongIntVal( __INST(crc) );
       
   594             }
       
   595 
       
   596 # if __POINTER_SIZE__ == 8
       
   597             if (((unsigned INT)cp & 7) == 0) {
       
   598                 // longword aligned
       
   599                 for ( ; n >= 32 ; n -= 32, cp += 32) {
       
   600                     unsigned INT w0 = ((unsigned INT *)cp)[0];
       
   601                     unsigned INT w1, w2, w3;
       
   602                     
       
   603                     _crc = _mm_crc32_u64(_crc, w0);
       
   604                     w1 = ((unsigned INT *)cp)[1];
       
   605                     _crc = _mm_crc32_u64(_crc, w1);
       
   606                     w2 = ((unsigned INT *)cp)[2];
       
   607                     _crc = _mm_crc32_u64(_crc, w2);
       
   608                     w3 = ((unsigned INT *)cp)[3];
       
   609                     _crc = _mm_crc32_u64(_crc, w3);
       
   610                 }
       
   611                 for ( ; n >= 8 ; n -= 8, cp += 8) {
       
   612                     _crc = _mm_crc32_u64(_crc, ((unsigned INT *)cp)[0]);
       
   613                 }
       
   614             }
       
   615 # endif // __POINTER_SIZE__ == 8          
       
   616             if (((unsigned INT)cp & 3) == 0) {
       
   617                 // word aligned
       
   618                 for ( ; n >= 4 ; n -= 4, cp += 4) {
       
   619                     _crc = _mm_crc32_u32(_crc, ((unsigned int *)cp)[0]);
       
   620                 }
       
   621             }
       
   622             for ( ; n >= 4 ; n -= 4, cp += 4) {
       
   623                 _crc = _mm_crc32_u8(_crc, cp[0]);
       
   624                 _crc = _mm_crc32_u8(_crc, cp[1]);
       
   625                 _crc = _mm_crc32_u8(_crc, cp[2]);
       
   626                 _crc = _mm_crc32_u8(_crc, cp[3]);
       
   627             }
       
   628             while (n-- > 0) {
       
   629                 unsigned char ch = *cp++;
       
   630 
       
   631                 _crc = _mm_crc32_u8(_crc, ch);
       
   632             }
       
   633 
       
   634             if ((__POINTER_SIZE__==8) || (_crc <= _MAX_INT)) {
       
   635                 __INST(crc) = __MKSMALLINT(_crc);
       
   636             } else {
       
   637                 // this code fails with gcc 4.7.2:
       
   638                 // __INST(crc) = __MKUINT(_crc); __STORESELF(crc);
       
   639                 OBJ temp = __MKUINT(_crc); 
       
   640                 __INST(crc) = temp; __STORESELF(crc);
       
   641             }
       
   642 
       
   643             RETURN (count);
       
   644         }
       
   645     }
       
   646 bad: ;
       
   647 # endif
       
   648 #endif
       
   649 %}.
       
   650     self primitiveFailed
       
   651 
       
   652     "Created: / 17-03-2019 / 16:44:27 / Claus Gittinger"
       
   653 ! !
       
   654 
   287 !CRC32Stream class methodsFor:'documentation'!
   655 !CRC32Stream class methodsFor:'documentation'!
   288 
   656 
   289 version
   657 version
   290     ^ '$Header$'
   658     ^ '$Header$'
   291 !
   659 !