Run-length encoding/Objective-C: Difference between revisions

From Rosetta Code
Content added Content deleted
(moved from Run-length encoding)
 
m (modernize)
 
Line 12: Line 12:
NSMutableArray *counters;
NSMutableArray *counters;
}
}
+ (instancetype)encoderWithData: (NSData *)data;
+ (id)alloc;
+ (id)encoderWithData: (NSData *)data;
- (instancetype)initWithData: (NSData *)data;
- (id)init;
- (id)initWithData: (NSData *)data;
- (void)dealloc;
- (void)addByte: (char)aByte;
- (void)addByte: (char)aByte;
- (void)addByte: (char)aByte repeated: (int)repetitionCount;
- (void)addByte: (char)aByte repeated: (int)repetitionCount;
Line 27: Line 24:


@implementation RCRunLengthEncoder
@implementation RCRunLengthEncoder
+ (id)encoderWithData: (NSData *)data
+ (instancetype)encoderWithData: (NSData *)data
{
{
return [[[self alloc] initWithData: data] autorelease];
return [[self alloc] initWithData: data];
}
}


- (id)initWithData: (NSData *)data
- (instancetype)initWithData: (NSData *)data
{
{
if ((self = [self init]) != nil) {
if ((self = [self init]) != nil) {
Line 40: Line 37:
}
}


- (id)init
- (instancetype)init
{
{
if ((self = [super init]) != nil) {
if ((self = [super init]) != nil) {
Line 47: Line 44:
}
}
return self;
return self;
}

- (void)dealloc
{
[counters release];
[contents release];
[super dealloc];
}
}


Line 64: Line 54:
{
{
if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) {
if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) {
[contents addObject: [NSNumber numberWithChar: aByte]];
[contents addObject: @(aByte)];
[counters addObject: [NSNumber numberWithInt: repetitionCount]];
[counters addObject: @(repetitionCount)];
} else {
} else {
NSNumber *a = [counters lastObject];
int a = [[counters lastObject] intValue];
[counters removeLastObject];
[counters removeLastObject];
[counters addObject: [NSNumber numberWithInt:
[counters addObject: @(a + repetitionCount)];
([a intValue] + repetitionCount) ]];
}
}
}
}
Line 98: Line 87:


for(i=0; i < [contents count]; i++) {
for(i=0; i < [contents count]; i++) {
char c = [[contents objectAtIndex: i] charValue];
char c = [contents[i] charValue];
int n = [[counters objectAtIndex: i] intValue];
int n = [counters[i] intValue];
memset(buf, c, 256);
memset(buf, c, 256);
while ( n > 0 ) {
while ( n > 0 ) {
Line 106: Line 95:
}
}
}
}
return [d autorelease];
return d;
}
}
@end</lang>
@end</lang>
Line 147: Line 136:


for(i=0; i < [counters count]; i++) {
for(i=0; i < [counters count]; i++) {
char c = [[contents objectAtIndex: i] charValue];
char c = [contents[i] charValue];
int howMany = [[counters objectAtIndex: i] intValue];
int howMany = [counters[i] intValue];
if ( literalCount == 128 ) {
if ( literalCount == 128 ) {
buf[0] = 0;
buf[0] = 0;
Line 175: Line 164:
}
}
}
}
return [r autorelease];
return r;
}
}
@end</lang>
@end</lang>
Line 185: Line 174:
int main()
int main()
{
{
@autoreleasepool {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


codecRLE *enc = [[codecRLE alloc]
codecRLE *enc = [[codecRLE alloc]
initWithData: [NSData dataWithBytes: s
initWithData: [NSData dataWithBytes: s
length: strlen(s)] ];
length: strlen(s)] ];


NSData *repr = [enc encode];
NSData *repr = [enc encode];
fwrite([repr bytes], 1, [repr length], stdout);
fwrite([repr bytes], 1, [repr length], stdout);
[enc release];


enc = [[codecRLE alloc] init];
enc = [[codecRLE alloc] init];
[enc decode: repr];
[enc decode: repr];
NSData *d = [enc data];
NSData *d = [enc data];
fwrite([d bytes], 1, [d length], stdout);
fwrite([d bytes], 1, [d length], stdout);
[enc release];


}
[pool release];
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}</lang>
}</lang>

Latest revision as of 07:20, 27 February 2014

Run-length encoding/Objective-C is part of Run-length encoding. You may find other members of Run-length encoding at Category:Run-length encoding.
Works with: GNUstep

The class RCRunLengthEncoder represents internally data with which it was feeded as pair character - repetition counter: it does not implement a binary representation of itself; it is left to another class, so that different input/output encodings are possible starting from the same class.

<lang objc>#import <Foundation/Foundation.h>

@interface RCRunLengthEncoder : NSObject {

 NSMutableArray *contents;
 NSMutableArray *counters;

} + (instancetype)encoderWithData: (NSData *)data; - (instancetype)initWithData: (NSData *)data; - (void)addByte: (char)aByte; - (void)addByte: (char)aByte repeated: (int)repetitionCount; - (void)addData: (NSData *)data; - (NSData *)data; - (NSArray *)counters; - (NSArray *)contents; @end


@implementation RCRunLengthEncoder + (instancetype)encoderWithData: (NSData *)data {

 return [[self alloc] initWithData: data];

}

- (instancetype)initWithData: (NSData *)data {

 if ((self = [self init]) != nil) {
   [self addData: data];
 }
 return self;

}

- (instancetype)init {

 if ((self = [super init]) != nil) {
   contents = [[NSMutableArray alloc] init];
   counters = [[NSMutableArray alloc] init];
 }
 return self;

}

- (void)addByte: (char)aByte {

 [self addByte: aByte repeated: 1];

}

- (void)addByte: (char)aByte repeated: (int)repetitionCount {

 if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) {
   [contents addObject: @(aByte)];
   [counters addObject: @(repetitionCount)];
 } else {
   int a = [[counters lastObject] intValue];
   [counters removeLastObject];
   [counters addObject: @(a + repetitionCount)];
 }

}

- (void)addData: (NSData *)data {

 const char *d = [data bytes];
 NSUInteger i;
 for(i=0; i < [data length]; i++) [self addByte: d[i]];

}

- (NSArray *)contents {

 return contents;

}

- (NSArray *)counters {

 return counters;

}

- (NSData *)data {

 NSMutableData *d = [[NSMutableData alloc] initWithCapacity: 256];
 char buf[256];
 int i;
 for(i=0; i < [contents count]; i++) {
   char c = [contents[i] charValue];
   int n = [counters[i] intValue];
   memset(buf, c, 256);
   while ( n > 0 ) {
     [d appendBytes: buf length: MIN(256, n)];
     n -= 256;
   }
 }
 return d;

} @end</lang>

The class codecRLE is derived from the previous, adding the methods that allow to binary encode the data internally held, and to create a internal representation from the encoded data. The specification here used are:

  • byte N >= 128, then the next byte must be repeated N-128 times (if N-128 is 0, the the byte must be repeated 128 times)
  • byte N < 128, then the next N bytes must be taken as they are (if N is 0, the next 128 bytes are literal)

<lang objc>@interface codecRLE : RCRunLengthEncoder - (NSData *)encode; - (void)decode: (NSData *)enc; @end

@implementation codecRLE - (void)decode: (NSData *)enc {

 const char *buf = [enc bytes];
 int i;
 for(i = 0; i < [enc length]; ) {
   if ( (buf[i] & 0x80) != 0) {
     [self addByte: buf[i+1] repeated: ( ((buf[i]&0x7f) == 0) ? 128 : (buf[i]&0x7f) ) ];
     i += 2;
   } else {
     int rc = (buf[i] == 0) ? 128 : buf[i];
     [self addData: [NSData dataWithBytes: &buf[i+1] length: rc]];
     i += rc + 1;
   }
 }

}

- (NSData *)encode {

 int literalCount=0;
 int i;
 char buf[129];
 NSMutableData *r = [[NSMutableData alloc] initWithCapacity: 256];
 for(i=0; i < [counters count]; i++) {
   char c = [contents[i] charValue];
   int howMany = [counters[i] intValue];
   if ( literalCount == 128 ) {
     buf[0] = 0;
     [r appendBytes: buf length: 129];
     literalCount = 0;
   }
   if ( howMany == 1 ) {
     buf[literalCount+1] = c;
     literalCount++;
   } else {
     if ( literalCount > 0 ) {

buf[0] = literalCount & 0x7f; [r appendBytes: buf length: (literalCount+1) ]; literalCount = 0;

     }
     buf[1] = c;
     while( howMany > 127 ) {

buf[0] = 0x80; [r appendBytes: buf length: 2]; howMany -= 128;

     }
     if (howMany > 0) {

buf[0] = howMany | 0x80; [r appendBytes: buf length: 2];

     }
   }
 }
 return r;

} @end</lang>

Usage example:

<lang objc>const char *s = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";

int main() {

 @autoreleasepool {
   codecRLE *enc = [[codecRLE alloc]

initWithData: [NSData dataWithBytes: s length: strlen(s)] ];

   NSData *repr = [enc encode];
   fwrite([repr bytes], 1, [repr length], stdout);
   enc = [[codecRLE alloc] init];
   [enc decode: repr];
   NSData *d = [enc data];
   fwrite([d bytes], 1, [d length], stdout);
 }
 return EXIT_SUCCESS;

}</lang>

Notes

  • The code is not deeply tested yet