正在计算 Swift 中部分文件的 64 位校验和

Calculating 64bit checksum of a part of file in Swift

我正在尝试移植用于计算 OpenSubtitles 哈希的代码,我使用 Objective-C 示例作为参考 (http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes#Objective-C)。哈希的公式是文件大小+文件前64k的64位校验和+文件最后64k的64位校验和。

我在计算校验和的代码上遇到了问题。这是 Objective-C:

中代码的重要部分
const NSUInteger CHUNK_SIZE=65536;
NSData *fileDataBegin, *fileDataEnd;
uint64_t hash=0;

fileDataBegin = [handle readDataOfLength:(NSUInteger)CHUNK_SIZE];
[handle seekToEndOfFile];
unsigned long long fileSize = [handle offsetInFile];

uint64_t * data_bytes= (uint64_t*)[fileDataBegin bytes]; 
for( int i=0; i< CHUNK_SIZE/sizeof(uint64_t); i++ )
    hash+=data_bytes[i];

我尝试通过以类似的方式重写来转换大部分代码 ti Swift。我在想出这一点的替换代码时遇到了麻烦:

uint64_t * data_bytes= (uint64_t*)[fileDataBegin bytes]; 
for( int i=0; i< CHUNK_SIZE/sizeof(uint64_t); i++ )
    hash+=data_bytes[i];

任何帮助都会很棒。

uint64_t * data_bytes= (uint64_t*)[fileDataBegin bytes]; 

可以翻译为

let data_bytes = UnsafeBufferPointer<UInt64>(
                    start: UnsafePointer(fileDataBegin.bytes),
                    count: fileDataBegin.length/sizeof(UInt64)
                )

还有一个额外的好处就是 data_bytes 不仅仅是 一个指针,还存储了元素的个数。一个 UnsafeBufferPointer 几乎可以像 Swift Array.

一样对待

因此

for( int i=0; i< CHUNK_SIZE/sizeof(uint64_t); i++ )
    hash+=data_bytes[i];

可以简单写成

var hash : UInt64 = 0
// ...
hash = reduce(data_bytes, hash) { [=13=] &+  }

使用

/// Return the result of repeatedly calling `combine` with an
/// accumulated value initialized to `initial` and each element of
/// `sequence`, in turn.
func reduce<S : SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> U) -> U

"overflow operator" &+:

Unlike arithmetic operators in C, arithmetic operators in Swift do not overflow by default. Overflow behavior is trapped and reported as an error. To opt in to overflow behavior, use Swift’s second set of arithmetic operators that overflow by default, such as the overflow addition operator (&+). All of these overflow operators begin with an ampersand (&).