1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
//
// HFSharedMemoryByteSlice.m
// HexFiend_2
//
// Copyright 2008 ridiculous_fish. All rights reserved.
//
#import <HexFiend/HFByteSlice_Private.h>
#import <HexFiend/HFSharedMemoryByteSlice.h>
#define MAX_FAST_PATH_SIZE (1 << 13)
#define MAX_TAIL_LENGTH (sizeof ((HFSharedMemoryByteSlice *)NULL)->inlineTail / sizeof *((HFSharedMemoryByteSlice *)NULL)->inlineTail)
@implementation HFSharedMemoryByteSlice
- (instancetype)initWithUnsharedData:(NSData *)unsharedData {
self = [super init];
REQUIRE_NOT_NULL(unsharedData);
NSUInteger dataLength = [unsharedData length];
NSUInteger inlineAmount = MIN(dataLength, MAX_TAIL_LENGTH);
NSUInteger sharedAmount = dataLength - inlineAmount;
HFASSERT(inlineAmount <= UCHAR_MAX);
inlineTailLength = (unsigned char)inlineAmount;
length = sharedAmount;
if (inlineAmount > 0) {
[unsharedData getBytes:inlineTail range:NSMakeRange(dataLength - inlineAmount, inlineAmount)];
}
if (sharedAmount > 0) {
data = [[NSMutableData alloc] initWithBytes:[unsharedData bytes] length:sharedAmount];
}
return self;
}
// retains, does not copy
- (instancetype)initWithData:(NSMutableData *)dat {
REQUIRE_NOT_NULL(dat);
return [self initWithData:dat offset:0 length:[dat length]];
}
- (instancetype)initWithData:(NSMutableData *)dat offset:(NSUInteger)off length:(NSUInteger)len {
self = [super init];
REQUIRE_NOT_NULL(dat);
HFASSERT(off + len >= off); //check for overflow
HFASSERT(off + len <= [dat length]);
offset = off;
length = len;
data = [dat retain];
return self;
}
- (instancetype)initWithSharedData:(NSMutableData *)dat offset:(NSUInteger)off length:(NSUInteger)len tail:(const void *)tail tailLength:(NSUInteger)tailLen {
self = [super init];
if (off || len) REQUIRE_NOT_NULL(dat);
if (tailLen) REQUIRE_NOT_NULL(tail);
HFASSERT(tailLen <= MAX_TAIL_LENGTH);
HFASSERT(off + len >= off);
HFASSERT(off + len <= [dat length]);
offset = off;
length = len;
data = [dat retain];
HFASSERT(tailLen <= UCHAR_MAX);
inlineTailLength = (unsigned char)tailLen;
memcpy(inlineTail, tail, tailLen);
HFASSERT([self length] == tailLen + len);
return self;
}
- (void)dealloc {
[data release];
[super dealloc];
}
- (unsigned long long)length {
return length + inlineTailLength;
}
- (void)copyBytes:(unsigned char *)dst range:(HFRange)lrange {
HFASSERT(HFSum(length, inlineTailLength) >= HFMaxRange(lrange));
NSRange requestedRange = NSMakeRange(ll2l(lrange.location), ll2l(lrange.length));
NSRange dataRange = NSMakeRange(0, length);
NSRange tailRange = NSMakeRange(length, inlineTailLength);
NSRange dataRangeToCopy = NSIntersectionRange(requestedRange, dataRange);
NSRange tailRangeToCopy = NSIntersectionRange(requestedRange, tailRange);
HFASSERT(HFSum(dataRangeToCopy.length, tailRangeToCopy.length) == lrange.length);
if (dataRangeToCopy.length > 0) {
HFASSERT(HFSum(NSMaxRange(dataRangeToCopy), offset) <= [data length]);
const void *bytes = [data bytes];
memcpy(dst, bytes + dataRangeToCopy.location + offset, dataRangeToCopy.length);
}
if (tailRangeToCopy.length > 0) {
HFASSERT(tailRangeToCopy.location >= length);
HFASSERT(NSMaxRange(tailRangeToCopy) - length <= inlineTailLength);
memcpy(dst + dataRangeToCopy.length, inlineTail + tailRangeToCopy.location - length, tailRangeToCopy.length);
}
}
- (HFByteSlice *)subsliceWithRange:(HFRange)lrange {
if (HFRangeEqualsRange(lrange, HFRangeMake(0, HFSum(length, inlineTailLength)))) return [[self retain] autorelease];
HFByteSlice *result;
HFASSERT(lrange.length > 0);
HFASSERT(HFSum(length, inlineTailLength) >= HFMaxRange(lrange));
NSRange requestedRange = NSMakeRange(ll2l(lrange.location), ll2l(lrange.length));
NSRange dataRange = NSMakeRange(0, length);
NSRange tailRange = NSMakeRange(length, inlineTailLength);
NSRange dataRangeToCopy = NSIntersectionRange(requestedRange, dataRange);
NSRange tailRangeToCopy = NSIntersectionRange(requestedRange, tailRange);
HFASSERT(HFSum(dataRangeToCopy.length, tailRangeToCopy.length) == lrange.length);
NSMutableData *resultData = NULL;
NSUInteger resultOffset = 0;
NSUInteger resultLength = 0;
const unsigned char *tail = NULL;
NSUInteger tailLength = 0;
if (dataRangeToCopy.length > 0) {
resultData = data;
HFASSERT(resultData != NULL);
resultOffset = offset + dataRangeToCopy.location;
resultLength = dataRangeToCopy.length;
HFASSERT(HFSum(resultOffset, resultLength) <= [data length]);
}
if (tailRangeToCopy.length > 0) {
tail = inlineTail + tailRangeToCopy.location - length;
tailLength = tailRangeToCopy.length;
HFASSERT(tail >= inlineTail && tail + tailLength <= inlineTail + inlineTailLength);
}
HFASSERT(resultLength + tailLength == lrange.length);
result = [[[[self class] alloc] initWithSharedData:resultData offset:resultOffset length:resultLength tail:tail tailLength:tailLength] autorelease];
HFASSERT([result length] == lrange.length);
return result;
}
- (HFByteSlice *)byteSliceByAppendingSlice:(HFByteSlice *)slice {
REQUIRE_NOT_NULL(slice);
const unsigned long long sliceLength = [slice length];
if (sliceLength == 0) return self;
const unsigned long long thisLength = [self length];
HFASSERT(inlineTailLength <= MAX_TAIL_LENGTH);
NSUInteger spaceRemainingInTail = MAX_TAIL_LENGTH - inlineTailLength;
if (sliceLength <= spaceRemainingInTail) {
/* We can do our work entirely within the tail */
NSUInteger newTailLength = (NSUInteger)sliceLength + inlineTailLength;
unsigned char newTail[MAX_TAIL_LENGTH];
memcpy(newTail, inlineTail, inlineTailLength);
[slice copyBytes:newTail + inlineTailLength range:HFRangeMake(0, sliceLength)];
HFByteSlice *result = [[[[self class] alloc] initWithSharedData:data offset:offset length:length tail:newTail tailLength:newTailLength] autorelease];
HFASSERT([result length] == HFSum(sliceLength, thisLength));
return result;
}
else {
/* We can't do our work entirely in the tail; see if we can append some shared data. */
HFASSERT(offset + length >= offset);
if (offset + length == [data length]) {
/* We can append some shared data. But impose some reasonable limit on how big our slice can get; this is 16 MB */
if (HFSum(thisLength, sliceLength) < (1ULL << 24)) {
NSUInteger newDataOffset = offset;
NSUInteger newDataLength = length;
unsigned char newDataTail[MAX_TAIL_LENGTH];
unsigned char newDataTailLength = MAX_TAIL_LENGTH;
NSMutableData *newData = (data ? data : [[[NSMutableData alloc] init] autorelease]);
NSUInteger sliceLengthInt = ll2l(sliceLength);
NSUInteger newTotalTailLength = sliceLengthInt + inlineTailLength;
HFASSERT(newTotalTailLength >= MAX_TAIL_LENGTH);
NSUInteger amountToShiftIntoSharedData = newTotalTailLength - MAX_TAIL_LENGTH;
NSUInteger amountToShiftIntoSharedDataFromTail = MIN(amountToShiftIntoSharedData, inlineTailLength);
NSUInteger amountToShiftIntoSharedDataFromNewSlice = amountToShiftIntoSharedData - amountToShiftIntoSharedDataFromTail;
if (amountToShiftIntoSharedDataFromTail > 0) {
HFASSERT(amountToShiftIntoSharedDataFromTail <= inlineTailLength);
[newData appendBytes:inlineTail length:amountToShiftIntoSharedDataFromTail];
newDataLength += amountToShiftIntoSharedDataFromTail;
}
if (amountToShiftIntoSharedDataFromNewSlice > 0) {
HFASSERT(amountToShiftIntoSharedDataFromNewSlice <= [slice length]);
NSUInteger dataLength = offset + length + amountToShiftIntoSharedDataFromTail;
HFASSERT([newData length] == dataLength);
[newData setLength:dataLength + amountToShiftIntoSharedDataFromNewSlice];
[slice copyBytes:[newData mutableBytes] + dataLength range:HFRangeMake(0, amountToShiftIntoSharedDataFromNewSlice)];
newDataLength += amountToShiftIntoSharedDataFromNewSlice;
}
/* We've updated our data; now figure out the tail */
NSUInteger amountOfTailFromNewSlice = sliceLengthInt - amountToShiftIntoSharedDataFromNewSlice;
HFASSERT(amountOfTailFromNewSlice <= MAX_TAIL_LENGTH);
[slice copyBytes:newDataTail + MAX_TAIL_LENGTH - amountOfTailFromNewSlice range:HFRangeMake(sliceLengthInt - amountOfTailFromNewSlice, amountOfTailFromNewSlice)];
/* Copy the rest, if any, from the end of self */
NSUInteger amountOfTailFromSelf = MAX_TAIL_LENGTH - amountOfTailFromNewSlice;
HFASSERT(amountOfTailFromSelf <= inlineTailLength);
if (amountOfTailFromSelf > 0) {
memcpy(newDataTail, inlineTail + inlineTailLength - amountOfTailFromSelf, amountOfTailFromSelf);
}
HFByteSlice *result = [[[[self class] alloc] initWithSharedData:newData offset:newDataOffset length:newDataLength tail:newDataTail tailLength:newDataTailLength] autorelease];
HFASSERT([result length] == HFSum([slice length], [self length]));
return result;
}
}
}
return nil;
}
@end
|