[ 
https://issues.apache.org/jira/browse/THRIFT-2640?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14499971#comment-14499971
 ] 

ASF GitHub Bot commented on THRIFT-2640:
----------------------------------------

Github user jeremy-w commented on a diff in the pull request:

    https://github.com/apache/thrift/pull/442#discussion_r28601691
  
    --- Diff: lib/cocoa/src/protocol/TCompactProtocol.m ---
    @@ -0,0 +1,706 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements. See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership. The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License. You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied. See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +
    +#import "TCompactProtocol.h"
    +#import "TObjective-C.h"
    +#import "TProtocolException.h"
    +
    +static const uint8_t COMPACT_PROTOCOL_ID = 0x82;
    +static const uint8_t COMPACT_VERSION = 1;
    +static const uint8_t COMPACT_VERSION_MASK = 0x1F; // 0001 1111
    +static const uint8_t COMPACT_TYPE_MASK = 0xE0; // 1110 0000
    +static const uint8_t COMPACT_TYPE_BITS = 0x07; // 0000 0111
    +static const int COMPACT_TYPE_SHIFT_AMOUNT = 5;
    +
    +static uint8_t ttypeToCompactType[16] = {0};
    +
    +enum
    +{
    +    TCType_STOP = 0x00,
    +    TCType_BOOLEAN_TRUE = 0x01,
    +    TCType_BOOLEAN_FALSE = 0x02,
    +    TCType_BYTE = 0x03,
    +    TCType_I16 = 0x04,
    +    TCType_I32 = 0x05,
    +    TCType_I64 = 0x06,
    +    TCType_DOUBLE = 0x07,
    +    TCType_BINARY = 0x08,
    +    TCType_LIST = 0x09,
    +    TCType_SET = 0x0A,
    +    TCType_MAP = 0x0B,
    +    TCType_STRUCT = 0x0C,
    +};
    +
    +@implementation TCompactProtocolFactory
    +
    ++(TCompactProtocolFactory*)sharedFactory
    +{
    +    static TCompactProtocolFactory* gSharedFactory = nil;
    +    if (gSharedFactory == nil)
    +    {
    +        gSharedFactory = [[TCompactProtocolFactory alloc] init];
    +    }
    +    
    +    return gSharedFactory;
    +}
    +
    +-(TCompactProtocol*)newProtocolOnTransport:(id <TTransport>)transport
    +{
    +    return [[TCompactProtocol alloc] initWithTransport:transport];
    +}
    +
    +@end
    +
    +@implementation TCompactProtocol
    +{
    +    NSMutableArray* lastField;
    +    short lastFieldId;
    +    id <TTransport> mTransport;
    +    
    +    NSString* boolFieldName;
    +    NSNumber* boolFieldType;
    +    NSNumber* boolFieldId;
    +    NSNumber* booleanValue;
    +}
    +
    +-(id)init
    +{
    +    self = [super init];
    +    
    +    if (self != nil)
    +    {
    +        lastField = [[NSMutableArray alloc] init];
    +    }
    +    
    +    return self;
    +}
    +
    +-(id)initWithTransport:(id <TTransport>)transport
    +{
    +    self = [self init];
    +    
    +    if (self != nil)
    +    {
    +        mTransport = [transport retain_stub];
    +        
    +        ttypeToCompactType[TType_STOP] = TCType_STOP;
    +        ttypeToCompactType[TType_BOOL] = TCType_BOOLEAN_FALSE;
    +        ttypeToCompactType[TType_BYTE] = TCType_BYTE;
    +        ttypeToCompactType[TType_DOUBLE] = TCType_DOUBLE;
    +        ttypeToCompactType[TType_I16] = TCType_I16;
    +        ttypeToCompactType[TType_I32] = TCType_I32;
    +        ttypeToCompactType[TType_I64] = TCType_I64;
    +        ttypeToCompactType[TType_STRING] = TCType_BINARY;
    +        ttypeToCompactType[TType_STRUCT] = TCType_STRUCT;
    +        ttypeToCompactType[TType_MAP] = TCType_MAP;
    +        ttypeToCompactType[TType_SET] = TCType_SET;
    +        ttypeToCompactType[TType_LIST] = TCType_LIST;
    +    }
    +    
    +    return self;
    +}
    +
    +-(void)dealloc
    +{
    +    [lastField release_stub];
    +    [mTransport release_stub];
    +    [boolFieldName release_stub];
    +    [boolFieldType release_stub];
    +    [boolFieldId release_stub];
    +    [booleanValue release_stub];
    +    [super dealloc_stub];
    +}
    +
    +-(id<TTransport>)transport
    +{
    +    return mTransport;
    +}
    +
    +-(void)writeByteDirect:(int8_t)n
    +{
    +    [mTransport write:(uint8_t*)&n offset:0 length:1];
    +}
    +
    +-(void)writeVarint32:(uint32_t)n
    +{
    +    uint8_t i32buf[5] = {0};
    +    uint32_t idx = 0;
    +    while (true)
    +    {
    +        if ((n & ~0x7F) == 0)
    +        {
    +            i32buf[idx++] = (uint8_t)n;
    +            break;
    +        }
    +        else
    +        {
    +            i32buf[idx++] = (uint8_t)((n & 0x7F) | 0x80);
    +            n >>= 7;
    +        }
    +    }
    +    [mTransport write:i32buf offset:0 length:idx];
    +}
    +
    +-(void)writeMessageBeginWithName:(NSString *)name type:(int)messageType 
sequenceID:(int)sequenceID
    +{
    +    [self writeByteDirect:COMPACT_PROTOCOL_ID];
    +    [self writeByteDirect:(uint8_t)((COMPACT_VERSION & 
COMPACT_VERSION_MASK) | ((((uint32_t)messageType) << COMPACT_TYPE_SHIFT_AMOUNT) 
& COMPACT_TYPE_MASK))];
    +    [self writeVarint32:(uint32_t)sequenceID];
    +    [self writeString:name];
    +}
    +
    +-(void)writeStructBeginWithName:(NSString*)name
    +{
    +    [lastField addObject:[NSNumber numberWithShort:lastFieldId]];
    +    lastFieldId = 0;
    +}
    +
    +-(void)writeStructEnd
    +{
    +    lastFieldId = [[lastField lastObject] shortValue];
    +    [lastField removeLastObject];
    +}
    +
    +-(void)writeFieldBeginWithName:(NSString*)name type:(int)fieldType 
fieldID:(int)fieldID
    +{
    +    if (fieldType == TType_BOOL)
    +    {
    +        boolFieldName = [name copy];
    +        boolFieldType = [[NSNumber numberWithInt:fieldType] retain_stub];
    +        boolFieldId = [[NSNumber numberWithInt:fieldID] retain_stub];
    +    }
    +    else
    +    {
    +        [self writeFieldBeginInternalWithName:name type:fieldType 
fieldID:fieldID typeOverride:0xFF];
    +    }
    +}
    +
    +-(void)writeFieldBeginInternalWithName:(NSString *)name 
type:(int)fieldType fieldID:(int)fieldID typeOverride:(uint8_t)typeOverride
    +{
    +    uint8_t typeToWrite = typeOverride == 0xFF ? [self 
getCompactTypeForTType:fieldType] : typeOverride;
    +    
    +    // check if we can use delta encoding for the field id
    +    if (fieldID > lastFieldId && fieldID - lastFieldId <= 15)
    +    {
    +        // Write them together
    +        [self writeByteDirect:(fieldID - lastFieldId) << 4 | typeToWrite];
    +    }
    +    else
    +    {
    +        // Write them separate
    +        [self writeByteDirect:typeToWrite];
    +        [self writeI16:fieldID];
    +    }
    +    
    +    lastFieldId = fieldID;
    +}
    +
    +-(void)writeFieldStop
    +{
    +    [self writeByteDirect:TCType_STOP];
    +}
    +
    +-(void)writeMapBeginWithKeyType:(int)keyType valueType:(int)valueType 
size:(int)size
    +{
    +    if (size == 0)
    +    {
    +        [self writeByteDirect:0];
    +    }
    +    else
    +    {
    +        [self writeVarint32:(uint32_t)size];
    +        [self writeByteDirect:[self getCompactTypeForTType:keyType] << 4 | 
[self getCompactTypeForTType:valueType]];
    +    }
    +}
    +
    +-(void)writeListBeginWithElementType:(int)elementType size:(int)size
    +{
    +    [self writeCollectionBeginWithElementType:elementType size:size];
    +}
    +
    +-(void)writeSetBeginWithElementType:(int)elementType size:(int)size
    +{
    +    [self writeCollectionBeginWithElementType:elementType size:size];
    +}
    +
    +-(void)writeBool:(BOOL)b
    +{
    +    if (boolFieldId != nil && boolFieldName != nil && boolFieldType != nil)
    +    {
    +        // we haven't written the field header yet
    +        [self writeFieldBeginInternalWithName:boolFieldName 
type:[boolFieldType intValue] fieldID:[boolFieldId intValue] typeOverride:b ? 
TCType_BOOLEAN_TRUE : TCType_BOOLEAN_FALSE];
    +        
    +        [boolFieldId release_stub];
    +        [boolFieldName release_stub];
    +        [boolFieldType release_stub];
    +        
    +        boolFieldId = nil;
    +        boolFieldName = nil;
    +        boolFieldType = nil;
    +    }
    +    else
    +    {
    +        // we're not part of a field, so just Write the value.
    +        [self writeByteDirect:b ? TCType_BOOLEAN_TRUE : 
TCType_BOOLEAN_FALSE];
    +    }
    +}
    +
    +-(void)writeByte:(uint8_t)value
    +{
    +    [self writeByteDirect:value];
    +}
    +
    +-(void)writeI16:(short)value
    +{
    +    [self writeVarint32:[self i32ToZigZag:value]];
    +}
    +
    +-(void)writeI32:(int32_t)value
    +{
    +    [self writeVarint32:[self i32ToZigZag:value]];
    +}
    +
    +-(void)writeI64:(int64_t)value
    +{
    +    [self writeVarint64:[self i64ToZigZag:value]];
    +}
    +
    +-(void)writeDouble:(double)value
    +{
    +    //Safe bit-casting double->uint64
    +    uint8_t data[8];
    +    uint64_t bits = 0;
    +    memcpy(data, &value, 8);
    +    memcpy(&bits, data, 8);
    +    
    +    bits = OSSwapHostToLittleInt64(bits);
    +    [mTransport write:(uint8_t*)&bits offset:0 length:8];
    +}
    +
    +-(void)writeString:(NSString*)value
    +{
    +    [self writeBinary:[value dataUsingEncoding:NSUTF8StringEncoding]];
    +}
    +
    +-(void)writeBinary:(NSData*)data
    +{
    +    [self writeVarint32:(uint32_t)data.length];
    +    [mTransport write:data.bytes offset:0 length:data.length];
    +}
    +
    +-(void)writeMessageEnd {}
    +-(void)writeMapEnd {}
    +-(void)writeListEnd {}
    +-(void)writeSetEnd {}
    +-(void)writeFieldEnd {}
    +
    +-(void)writeCollectionBeginWithElementType:(int)elementType size:(int)size
    +{
    +    if (size <= 14)
    +    {
    +        [self writeByteDirect:size << 4 | [self 
getCompactTypeForTType:elementType]];
    +    }
    +    else
    +    {
    +        [self writeByteDirect:0xf0 | [self 
getCompactTypeForTType:elementType]];
    +        [self writeVarint32:(uint32_t)size];
    +    }
    +}
    +
    +-(void)writeVarint64:(UInt64)n
    +{
    +    uint8_t varint64out[10] = {0};
    +    
    +    int idx = 0;
    +    while (true)
    +    {
    +        if ((n & ~0x7FL) == 0)
    +        {
    +            varint64out[idx++] = (uint8_t)n;
    +            break;
    +        }
    +        else
    +        {
    +            varint64out[idx++] = (uint8_t)((n & 0x7F) | 0x80);
    +            n >>= 7;
    +        }
    +    }
    +    [mTransport write:varint64out offset:0 length:idx];
    +}
    +
    +-(uint32_t)i32ToZigZag:(int32_t)n
    +{
    +    return (uint32_t)(n << 1) ^ (uint32_t)(n >> 31);
    +}
    +
    +-(uint64_t)i64ToZigZag:(int64_t)n
    +{
    +    return (uint64_t)(n << 1) ^ (uint64_t)(n >> 63);
    +}
    +
    +-(void)readMessageBeginReturningName:(NSString**)pname type:(int*)ptype 
sequenceID:(int*)psequenceID
    +{
    +    uint8_t protocolId = [self readByte];
    +    if (protocolId != COMPACT_PROTOCOL_ID)
    +    {
    +        @throw [TProtocolException exceptionWithName:@"TProtocolException" 
reason:[NSString stringWithFormat:@"Expected protocol id %X but got %X", 
COMPACT_PROTOCOL_ID, protocolId]];
    +    }
    +    
    +    uint8_t versionAndType = [self readByte];
    +    uint8_t version = versionAndType & COMPACT_VERSION_MASK;
    +    if (version != COMPACT_VERSION)
    +    {
    +        @throw [TProtocolException exceptionWithName:@"TProtocolException" 
reason:[NSString stringWithFormat:@"Expected version %d but got %d", 
COMPACT_VERSION, version]];
    +    }
    +    
    +    int type = (versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & 
COMPACT_TYPE_BITS;
    +    int sequenceID = (int)[self readVarint32];
    +    NSString* name = [self readString];
    +    
    +    if (ptype != NULL)
    +    {
    +        *ptype = type;
    +    }
    +    if (psequenceID != NULL)
    +    {
    +        *psequenceID = sequenceID;
    +    }
    +    if (pname != NULL)
    +    {
    +        *pname = name;
    +    }
    +}
    +
    +-(void)readStructBeginReturningName:(NSString**)pname
    +{
    +    [lastField addObject:[NSNumber numberWithShort:lastFieldId]];
    +    lastFieldId = 0;
    +    
    +    if (pname != NULL)
    +    {
    +        *pname = @"";
    +    }
    +}
    +
    +-(void)readStructEnd
    +{
    +    lastFieldId = [[lastField lastObject] shortValue];
    +    [lastField removeLastObject];
    +}
    +
    +-(void)readFieldBeginReturningName:(NSString**)pname type:(int*)pfieldType 
fieldID:(int*)pfieldID
    +{
    +    uint8_t byte = [self readByte];
    +    uint8_t type = byte & 0x0f;
    +    
    +    // if it's a stop, then we can return immediately, as the struct is 
over.
    +    if (type == TCType_STOP)
    +    {
    +        if (pname != NULL)
    +        {
    +            *pname = @"";
    +        }
    +        if (pfieldType != NULL)
    +        {
    +            *pfieldType = TType_STOP;
    +        }
    +        if (pfieldID != NULL)
    +        {
    +            *pfieldID = 0;
    +        }
    +        return;
    +    }
    +    
    +    short fieldId = 0;
    +    
    +    // mask off the 4 MSB of the type header. it could contain a field id 
delta.
    +    short modifier = (byte & 0xf0) >> 4;
    +    if (modifier == 0)
    +    {
    +        // not a delta. look ahead for the zigzag varint field id.
    +        fieldId = [self readI16];
    +    }
    +    else
    +    {
    +        // has a delta. add the delta to the last Read field id.
    +        fieldId = lastFieldId + modifier;
    +    }
    +    
    +    int fieldType = [self getTTypeForCompactType:type];
    +    
    +    if (pname != NULL)
    +    {
    +        *pname = @"";
    +    }
    +    if (pfieldType != NULL)
    +    {
    +        *pfieldType = fieldType;
    +    }
    +    if (pfieldID != NULL)
    +    {
    +        *pfieldID = fieldId;
    +    }
    +    
    +    // if this happens to be a boolean field, the value is encoded in the 
type
    +    if (type == TCType_BOOLEAN_TRUE || type == TCType_BOOLEAN_FALSE)
    +    {
    +        // save the boolean value in a special instance variable.
    +        booleanValue = [[NSNumber numberWithBool:type == 
TCType_BOOLEAN_TRUE ? YES : NO] retain_stub];
    +    }
    +    
    +    // push the new field onto the field stack so we can keep the deltas 
going.
    +    lastFieldId = fieldId;
    +}
    +
    +-(void)readMapBeginReturningKeyType:(int*)pkeyType 
valueType:(int*)pvalueType size:(int*)psize
    +{
    +    uint8_t keyAndValueType = 0;
    +    int size = (int)[self readVarint32];
    +    if (size != 0)
    +    {
    +        keyAndValueType = [self readByte];
    +    }
    +    
    +    int keyType = [self getTTypeForCompactType:keyAndValueType >> 4];
    +    int valueType = [self getTTypeForCompactType:keyAndValueType & 0xf];
    +    
    +    if (pkeyType != NULL)
    +    {
    +        *pkeyType = keyType;
    +    }
    +    if (pvalueType != NULL)
    +    {
    +        *pvalueType = valueType;
    +    }
    +    if (psize != NULL)
    +    {
    +        *psize = size;
    +    }
    +}
    +
    +-(void)readListBeginReturningElementType:(int*)pelementType 
size:(int*)psize
    +{
    +    uint8_t size_and_type = [self readByte];
    +    int size = (size_and_type >> 4) & 0x0f;
    +    if (size == 15)
    +    {
    +        size = (int)[self readVarint32];
    +    }
    +    
    +    int elementType = [self getTTypeForCompactType:size_and_type & 0x0f];
    +    
    +    if (pelementType != NULL)
    +    {
    +        *pelementType = elementType;
    +    }
    +    if (psize != NULL)
    +    {
    +        *psize = size;
    +    }
    +}
    +
    +-(void)readSetBeginReturningElementType:(int*)pelementType size:(int*)psize
    +{
    +    [self readListBeginReturningElementType:pelementType size:psize];
    +}
    +
    +-(BOOL)readBool
    +{
    +    if (booleanValue != nil)
    +    {
    +        BOOL result = [booleanValue boolValue];
    +        [booleanValue release_stub];
    +        booleanValue = nil;
    +        return result;
    +    }
    +    else
    +    {
    +        return [self readByte] == TCType_BOOLEAN_TRUE;
    +    }
    +}
    +
    +-(uint8_t)readByte
    +{
    +    uint8_t buf = 0;
    +    [mTransport readAll:&buf offset:0 length:1];
    +    return buf;
    +}
    +
    +-(short)readI16
    --- End diff --
    
    This should be `int16_t` since it deals in a specific integer size, rather 
than relying on the fact that for a specific target `short` happens to be 
16-bit.


> Compact Protocol in Cocoa
> -------------------------
>
>                 Key: THRIFT-2640
>                 URL: https://issues.apache.org/jira/browse/THRIFT-2640
>             Project: Thrift
>          Issue Type: Sub-task
>          Components: Cocoa - Library
>    Affects Versions: 0.9.1
>            Reporter: Mark Hornsby
>            Assignee: Jens Geyer
>            Priority: Minor
>




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to