Skip to content

Instantly share code, notes, and snippets.

@markd2
Created March 20, 2012 13:45

Revisions

  1. markd2 created this gist Mar 20, 2012.
    13 changes: 13 additions & 0 deletions BNRDiggyDict.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    #import <Foundation/Foundation.h>

    @interface BNRDiggyDict : NSObject

    // React to object indexing. Would be nice to have a @protocol for this
    - (id) objectForKeyedSubscript: (id) key;
    - (void) setObject: (id) thing forKeyedSubscript: (id<NSCopying>) key;

    // And for fun, it also can react to scalar indexing.
    // Returns the N'th key of the top-level collection.
    - (id) objectAtIndexedSubscript: (NSInteger) index;

    @end // BWDiggyDict
    89 changes: 89 additions & 0 deletions BNRDiggyDict.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    #import "BNRDiggyDict.h"

    @interface BNRDiggyDict () {
    NSMutableDictionary *_rootDictionary;
    }

    @end // BWDiggyDict


    @implementation BNRDiggyDict

    - (id) init {
    if ((self = [super init])) {
    _rootDictionary = [NSMutableDictionary dictionary];
    }

    return self;

    } // init


    - (NSString *) description {
    return [_rootDictionary description];
    } // description



    - (NSMutableDictionary *) innerDictionaryForSplitKey: (NSArray *) splitKey {

    NSMutableDictionary *interim = _rootDictionary;

    for (int i = 0; i < splitKey.count - 1; i++) {
    id key = [splitKey objectAtIndex: i];
    NSMutableDictionary *next = interim[key];
    if (next == nil) {
    next = [NSMutableDictionary dictionary];
    interim[key] = next;
    }
    interim = next;
    }

    return interim;

    } // innerDictionaryForSplitKey


    - (id) objectForKeyedSubscript: (id) key {
    if (![key respondsToSelector: @selector(componentsSeparatedByString:)]) {
    return nil;
    }

    // Use slashes rather than periods since we're not really doing KVC
    NSArray *splitKey = [key componentsSeparatedByString: @"/"];

    NSMutableDictionary *dict = [self innerDictionaryForSplitKey: splitKey];
    id leafKey = [splitKey lastObject];
    id result = dict[leafKey];

    return result;

    } // objectForKeyedSubscript


    - (void) setObject: (id) thing forKeyedSubscript: (id<NSCopying>) key {
    id idKey = (id) key; // Strip off <NSCopying> so we can send it other messages.
    if (![idKey respondsToSelector: @selector(componentsSeparatedByString:)]) {
    return;
    }

    // Use slashes rather than periods since we're not really doing KVC
    NSArray *splitKey = [idKey componentsSeparatedByString: @"/"];

    NSMutableDictionary *dict = [self innerDictionaryForSplitKey: splitKey];
    id leafKey = [splitKey lastObject];

    [dict setObject: thing forKey: leafKey];

    } // setObject forKeyedSubscript


    // And just for fun
    - (id) objectAtIndexedSubscript: (NSInteger) index {
    NSArray *keys = [_rootDictionary.allKeys
    sortedArrayUsingSelector: @selector(compare:)];
    return [keys objectAtIndex: index];
    } // objectAtIndexedSubscript


    @end // BWDiggyDict
    9 changes: 9 additions & 0 deletions BNRNegativeArray.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    #import <Foundation/Foundation.h>

    @interface BNRNegativeArray : NSObject

    // Necessary to declare these. Would be nice to have a protocol to adopt.
    - (id) objectAtIndexedSubscript: (NSInteger) index;
    - (void) setObject: (id) thing atIndexedSubscript: (NSInteger) index;

    @end // BWNegativeArray
    55 changes: 55 additions & 0 deletions BNRNegativeArray.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    #import "BNRNegativeArray.h"


    @interface BNRNegativeArray () {
    NSMutableArray *_backingstore;
    }

    @end // extension


    @implementation BNRNegativeArray

    - (id) init {
    if ((self = [super init])) {
    _backingstore = [NSMutableArray array];
    }
    return self;
    } // init


    - (NSString *) description {
    return [_backingstore description];
    } // descriptioin


    - (id) objectAtIndexedSubscript: (NSInteger) index {
    if (index < 0) index = _backingstore.count + index;

    return [_backingstore objectAtIndex: index];

    } // objectAtIndexedSubscript


    - (void) setObject: (id) thing atIndexedSubscript: (NSInteger) index {
    if (index < 0) index = _backingstore.count + index;

    // Mutable array only allows setting the first-empty-index, like
    // -insertObject:atIndex:. Any past that throws a range exception.
    // So let's be different and fill in intervening spaces with [NSNull null]
    // If you want to see @NULL, dupe rdar://10892975

    NSInteger toAdd = index - _backingstore.count;;
    for (int i = 0; i < toAdd; i++) {
    [_backingstore addObject: [NSNull null]];
    }

    if (index >= _backingstore.count) {
    [_backingstore addObject: thing];
    } else {
    [_backingstore replaceObjectAtIndex: index withObject: thing];
    }

    } // setObject atIndexedSubscript

    @end // BWNegativeArray
    39 changes: 39 additions & 0 deletions main.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    #import <Foundation/Foundation.h>

    #import "BNRNegativeArray.h"
    #import "BNRDiggyDict.h"

    int main (int argc, const char * argv[]) {
    @autoreleasepool {
    BNRNegativeArray *negatory = [[BNRNegativeArray alloc] init];
    negatory[0] = @"hi";
    negatory[1] = @"ohai";
    negatory[0] = @"obai";
    negatory[10] = @"end!";
    NSLog (@"negatory: %@", negatory);

    NSLog (@"0 - %@", negatory[0]);
    NSLog (@"5 - %@", negatory[5]);
    NSLog (@"10 - %@", negatory[10]);
    NSLog (@"-1 - %@", negatory[-1]);
    NSLog (@"-10 - %@", negatory[-10]);
    NSLog (@"-11 - %@", negatory[-11]);


    BNRDiggyDict *dauchs = [[BNRDiggyDict alloc] init];
    dauchs[@"i can has"] = @"cheezburger";
    NSLog (@"badger: %@", dauchs);

    dauchs[@"for/great/justice"] = @"every 'ZIG'";
    NSLog (@"badger: %@", dauchs);

    NSLog (@"TAKE OFF %@", dauchs[@"for/great/justice"]);

    // Exercise a scalar accessor on the diggydict
    dauchs[@"Alphabet"] = @"A";
    dauchs[@"Badger"] = @"B";
    dauchs[@"Carnivorous Tofu"] = @"Nom!";
    NSLog (@"second key: %@", dauchs[2]);
    }
    return 0;
    } // main