Disaster Area

NSString Cons

One of the fundamental operators in functional languages is ‘cons’. It concatenates lists of things together, and since strings are usually treated as lists of characters, cons gets a lot of use in string processing as well. One of the cool tricks I saw done with Objective-C a while ago was implementing cons on NSString, using : like Haskell and ML do. I have been unable to find the original site, so I decided to reimplement it myself recently.

A quick caveat to the following: this uses Objective-C trickery that may not be very safe in a production environment. Also, the upcoming Automatic Reference Counting in Clang/LLVM 3.0 will not compile this code. With that out of the way, lets look at how we’re going to do this. In Objective-C, methods are backed by a concrete implementation in the form of a standard C function. The runtime uses the IMP type for this, which is defined as

id (*IMP)(id self, SEL selector, ...)

The ... in this case stands for additional arguments for the method. For example, [@"foo" stringByAppendingString:@"bar"] will eventually be executed by a function matching the prototype below.

id functionName(id self, SEL sel, NSString *otherString)

Additional arguments are just tacked onto the end. This can be combined with standard C varargs. The only caveat is we need to signal the end of the varargs somehow. I used nil.

id stringCons(id self, SEL selector, ...){
    va_list strings;
    NSMutableString *fullString = [[NSMutableString alloc] initWithString:self];
    va_start(strings, selector);
    id currentString = nil;
    // End on nil
    while((currentString = va_arg(strings, id))){
        [fullString appendString:currentString];
    }
    va_end(strings);
    return fullString;
}

There are two approaches to adding a method to a class at runtime in Objective-C. The normal way is to use class_addMethod. This is enough in most cases, but because we have a variable length selector, we can’t use this method. Another way methods can be added is with the dynamic method resolution available through NSObject (Mike Ash touches on this method in a post on message forwarding).

+(BOOL)resolveInstanceMethod:(SEL)sel{
    // Check that the selector is just ':' characters
    const char *checkName = sel_getName(sel);
    BOOL isCons = YES;
    int i = 0;
    char c = checkName[i];
    while(c != '\0'){
        if(c != ':'){
            isCons = NO;
            break;
        }
        c = checkName[++i];
    }
    // Add the method, or pass this message up the chain
    if(isCons){
        // Make the type string
        size_t typesSize = 4 + i;
        char *types = malloc(sizeof(char) * typesSize);
        types[0] = '@';
        types[1] = '@';
        types[2] = ':';
        for(int j = 3; j < typesSize - 1; ++j){
            types[j] = '@';
        }
        types[typesSize - 1] = '\0';
        // Add the method
        class_addMethod([self class], sel, stringCons, types);
        return YES;
    }else{
        return [super resolveInstanceMethod:sel];
    }
}

Here all were doing is checking to see if the selector is completely made up of ‘:’ characters. If it is, we add the stringCons IMP from above for that selector. Note the else block at the end. The call to [super resolveInstanceMethod:sel] is very important, as other parts of a class may depend on this dynamic method resolution.

The final hurdle is how to add +resolveInstanceMethod: to NSString. The safest way would be to subclass NSString, but since NSString is a class cluster this is not possible. I ended up using a category, but a safer choice might be to use method swizzling to insert our method in addition to any NSString may have defined.

That’s it to adding a cons-like operator to NSString in Objective-C. To use it, just insert it between instances of NSString ending with nil, like below.

NSString *one = @"1";
NSString *two = @"2";
NSString *three = @"3";
NSString *all = [one:two:three:nil];

cWavelet

Weekend project I made: cWavelet.

It’s a simple wavelet library written in pure C. I’ve been trying to wrap my head around wavelets off and on for about three months, and I finally got them enough to write a library. It is still being developed, but it does simple forward transforms (as far as I can tell correctly) right now. In the future, I hope to implement portions of it in OpenCL and/or MPI so I can try it out on the clusters at school.


Ubuntu 10.04 on a Dell Mini 9

The Mac OS X install on my Mini 9 was recently borked (friend was borrowing it, and an unclean shutdown corrupted the file system), and I didn’t have the install discs on me. I’d also been messing with the Lucid Lynx beta in a VM on my machine, and was very impressed with the level of polish, so I decided to install Ubuntu on the Mini again and see how it went. This was a couple days before the release date, so I downloaded the release candidate and ran from there. I’ve used both the normal desktop and netbook remix in previous versions of Ubuntu, and for my workflow I prefer using the normal desktop. As there isn’t a desktop .img available, I downloaded the desktop ISO and used the USB IMage Writer in my VM to copy the ISO to a flash drive. Installation had a minor hitch in that the first install didn’t seem to take, in that after the installer was finished and the system rebooted, nothing showed up. I booted to the USB stick again, reinstalled, and everything worked after that.

Hardware support is very much improved in this version (I’ve previously used 8.04 and 9.04). I didn’t have to make any configuration changes to use sound hardware, Bluetooth worked right away, 3D acceleration was a given as I have an Intel GPU, and after I installed the Broadcom STA driver through the restricted driver installer, Wifi worked as well. Sleep works as well as it did under 9.10, as having an SD card mounted when you try sleeping causes the suspend process to hang. The fix is detailed in this MyDellMini forum post. Reproduced here, the fix is to add a hook to the sleep process that unmounts all memory cards. Put the following script in the /etc/pm/sleep.d/ directory.

#!/bin/bash

case $1 in
hibernate|suspend)
umount /dev/mmcblk*
    ;;
#    thaw|resume)
#        ;;
*)  echo $1
    ;;
esac
exit 0

Then make it executable.

Addendum: Turned out it wasn’t a bout of file system madness, it was the SSD dying. I sent it into Dell and got it back a week and a half later.