LLVM Compiler Overview(By Apple)

LLVM is the next generation of compiler created by Apple, intended to replace the whole GCC-family tools. It’s really, really awesome!

Here is an overview guide provided by Apple, but it hasn’t been updated for over 1 year. And during 2011, Apple released LLVM 3.1

NOTE: This page is the official release page, and will always show the most recent release. So if you visit this page and see LLVM 4.x, don’t be surprised.

Any way, it’s a good source for understanding the low level tool chains used by Apple and how apple is changing the C family compiler.

The documentations

Go to DevCenter, this page is free, no login is necessary. And all the videos has transcripts!

Other videos

Actually, the Clang community has some regular events held in San Francisco or San Jose. You can check it out from LLVM’s official site, for example, LLVM Developers’ Meeting@Nov 2011


And, as always, don’t forget to follow me @TonnyXu

ARC Learning Notes(1)

ARC(Automatic Reference Counting) was introduced by Apple on WWDC 2011, along with iCloud and OS X Lion. It’s a wonderful feature we need, but, how much it has been adopted to real projects?

How many projects adopted ARC?

Currently, 0 project is using ARC in my company.

This does not mean we hadn’t started new project since ARC was released, but because we have some constraints. We are using some common libraries across our projects, and we need to maintain the libraries consistent. We also need to add many features to the apps we released, and also, using ARC means all of our team members need to learn how to use ARC and know the common practices and have a better understanding of memory usage. That’s the time we could not afford in the past 8 months.

But we know we will move to ARC inevitably. So the problem is when?

Status of My projects

Currently we started to use ARC in some test projects. Here the Test Project means we use such kind of project to test some features quickly and without infecting the real projects.

What about yours?

How about yours? Are you starting to use ARC in your project now? Tell me about your projects’ status in the comment please.

It’s the time!

After 8 months, by watching a lot of Open Source project adopting ARC, I think it is our time to start using ARC from now on.

ARC only needs the new compiler, and it has a good backward compatibility to iOS 4. So let’s just try it.

Start from where?

Where should we start from? I think we can start from 2 things.

Apple’s document

Apple’s DevCenter for iOS has a good document for using ARC. Here is a simple list as far as I know.

  1. What’s New in iOS 5
  2. Transitioning to ARC Release Notes
  3. Advanced Memory Management Programming Guide
  4. Memory Management Programming Guide for Core Foundation

WWDC 2011′s HD Video

Also, WWDC 2011′s videos are great, don’t miss this one.

  1. Session 323 – Introducing Automatic Reference Counting

Next time, I will post what I learned about ARC.


And as always, don’t forget to follow me @TonnyXu

Have you seen MIN and MAX macro in Objective-C

How will you write a MIN(a, b) or MAX(a, b) macro?

In the real world, it is easy to tell which is the minimum and which is the maximum of 2 numbers. But to write a correct function in computer, it’s not an easy job as we can see.

Usually, MIN and MAX functions are written in macro, so how will you write it?

#define MYMIN1(a, b) {a < b ? a : b;}

This is definitely wrong, at least you need to add the parenthesis to the parameters. OK, it’s easy, let’s add this:

#define MYMIN2(a, b) ({(a) < (b) ? (a) : (b);})

But, this is still wrong. Let’s take a look at what Objective-C and other languages defines these 2 macros.

How does Objective-C define MIN and MAX?

Because there is no MIN or MAX defined by C standard library, Objective-C defined this in NSObjCRuntime.h

Let’s see the code:

#if !defined(MIN)
#define MIN(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
#endif

#if !defined(MAX)
#define MAX(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
#endif

Wow! that’s extremely long. Let’s see why it is necessary. Say your user write a piece of code like this:

int i=1, j=2;
int r = MIN(i++, j++);

What’s the supposed result of r? Obviously, it should be 2, but if you use MYMIN2, you got 3.

That’s why MIN and MAX are defined so complicated in Objective-C and other languages.

Make sure MIN/MAX does not change the value passed in

That’s the key point of write MIN and MAX in macro.

__typeof__(A) __a = (A);

is the key point to the correct result.


Don’t forget to follow me @TonnyXu

CoreData with NSOrderedSet does not work well on insertion

Usually, we generate an entity class with Editor->Create NSManagedOBject Subclass... For example we created a subclass of NSManagedObject

Xcode generates the .h file like this:

@interface MyEntity : NSManagedObject

@property (nonatomic, retain) NSOrderedSet manySubs;

//... some methods generated by Xcode
- (void)addManySubsObject:(MySubEntity*)value;
//... some other methods generated by Xcode

@end

and the .m file like this:

@implement MyEntity

@dynamic manySubs;

@end

If you use MyEntity just like this, you will get an error when you try to insert a new MySubEntity class by calling [myEntityObj addManySubsObject:aSubEntityObj];.

The error reads:

*** -[NSSet intersectsSet:]: set argument is not an NSSet

This is a bug Apple hasn’t resolved yet, but you can work around this bug by adding the following method to .m file.

- (void)addManySubsObject:(MySubEntity*)value{
    [self willChangeValueForKey:@"manySubs"];
    NSMutableOrderedSet *tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.manySubs];
    [tempSet addObject: value];
    self.manySubs = tempSet;
    [self didChangeValueForKey:@"manySubs"];
}

Be careful

[Updated]Billboard problem Resolved – Facebook Hacker Cup 2012

[Update@2012-01-24] I made a little mistake in a if...else... statement.

Facebook started Facebook Hacker Cup 2012 from January 20 at 4:00pm PST, and until January 23 at 4:00pm PST, the event is closed to receive submission.

There are three questions, when I learned the event, the event is already started and left me only near 16 hours to take some challenge.

I picked “Billboard problem”.

The original question

Billboards

We are starting preparations for Hacker Cup 2013 really early. Our first step is to prepare billboards to advertise the contest. We have text for hundreds of billboards, but we need your help to design them.

The billboards are of different sizes, but are all rectangular. The billboard widths and heights are all integers. We will supply you with the size in inches and the text we want printed. We want you to tell us how large we can print the text, such that it fits on the billboard without splitting any words across lines. Since this is to attract hackers like yourself, we will use a monospace font, meaning that all characters are of the same width (e.g.. ‘l’ and ‘m’ take up the same horizontal space, as do space characters). The characters in our font are of equal width and height, and there will be no additional spacing between adjacent characters or adjacent rows. If you print a word on one line and print the next word on the next line, you do not need to print a space between them.

Let’s say we want to print the text “Facebook Hacker Cup 2013″ on a 350×100″ billboard. If we use a font size of 33″ per character, then we can print “Facebook” on the first line, “Hacker Cup” on the second and “2013″ on the third. The widest of the three lines is “Hacker Cup”, which is 330″ wide. There are three lines, so the total height is 99″. We cannot go any larger.

Input

The first line of the input file contains a single integer T: the number of test cases. T lines follow, each representing a single test case in the form “W H S”. W and H are the width and height in inches of the available space. S is the text to be written.

Output

Output T lines, one for each test case. For each case, output “Case #t: s”, where t is the test case number (starting from 1) and s is the maximum font size, in inches per character, we can use. The size must be an integral number of inches. If the text does not fit when printed at a size of 1″, then output 0.

Constraints

  • 1 ≤ T ≤ 20
  • 1 ≤ W, H ≤ 1000

The text will contain only lower-case letters a-z, upper-case letters A-Z, digits 0-9 and the space character. The text will not start or end with the space character, and will never contain two adjacent space characters. The text in each case contains at most 1000 characters

Example input

5
20 6 hacker cup
100 20 hacker cup 2013
10 20 MUST BE ABLE TO HACK
55 25 Can you hack
100 20 Hack your way to the cup

Example output

Case #1: 3
Case #2: 10
Case #3: 2
Case #4: 8
Case #5: 7

My Solution

I used Objective-C to resolve this problem. I created a Mac app project. Later I think it’s completely unnecessary. I will try to use maybe pure C or Cocoa Console later.

Here is the my solution on github

The key idea behind my solution is divide and conquer.

1. Find the possible max font size

  1. Assume the billboard only show one line or one column, the MIN(width, height) will give the first guess of the max font size.
  2. Assume all the characters without space will be layout on the billboard one by one, the biggest font to whole all characters will be our possible max font size. Because if we add any space or non-hyphenation constraints to layout, we must shrink the font to hold these extra constraints.

Here I used the D&C to find the possible max font size:

- (NSInteger)maxFontSizeForText:(NSString *)text 
                withTextInArray:(NSArray *)textInArray 
               constraintToArea:(NSInteger)rectArea 
                     withBounds:(NSDictionary *)bounds
{
  NSParameterAssert(text);
  NSParameterAssert(textInArray);
  NSParameterAssert(bounds);

  NSInteger upperSize = [[bounds objectForKey:UPPER_BOUND_KEY] integerValue];
  NSInteger lowerSize = [[bounds objectForKey:LOWER_BOUND_KEY] integerValue];
//  NSLog(@"*** finding max size between %4ld...%ld", lowerSize, upperSize);

  NSInteger upperArea = upperSize * upperSize * ([text length] - ([textInArray count] - 1));
  NSInteger lowerArea = lowerSize * ([text length] - ([textInArray count] - 1));

  // No need to go further, there will be one size suitable for rectArea
  if (1 >= (upperSize - lowerSize)) { // there could be a case of 0
    if (upperArea <= rectArea) {
      return upperSize;
    }else if (lowerArea <= rectArea){
      return lowerSize;
    }else {
      return 0;
    }
  }

  // Otherwise, we need to go recursive routine to find the max size in lower...upper
  NSInteger middleSize = lowerSize + ((upperSize - lowerSize) >> 1);
  NSInteger middleArea = middleSize * middleSize * ([text length] - ([textInArray count] - 1));
  if (middleArea > rectArea) {
    NSDictionary *boundsDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                [bounds objectForKey:LOWER_BOUND_KEY], LOWER_BOUND_KEY,
                                [NSNumber numberWithInteger:middleSize], UPPER_BOUND_KEY,
                                nil];
    return [self maxFontSizeForText:text withTextInArray:textInArray constraintToArea:rectArea withBounds:boundsDict];
  }else {
    NSDictionary *boundsDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithInteger:middleSize], LOWER_BOUND_KEY,
                                [bounds objectForKey:UPPER_BOUND_KEY], UPPER_BOUND_KEY,
                                nil];
    return [self maxFontSizeForText:text withTextInArray:textInArray constraintToArea:rectArea withBounds:boundsDict];
  }
}

2. Find the correct max font size

Try to fit the text start with possible max font, then shrink the font size to meet the constraints.

This is simple but have some complex if...else... statements.

[Update 2012-01-24] Thanks to Chong, the following algorithm failed to find the correct font size for Case #7, it should be 9 instead of 8, to fix this, I need to modify 2 places, change realFontSize = width/[aWord length]; to realFontSize--; and change realFontSize = height/(currentLineIndex + 1); to realFontSize--;

// Another core algorithm that will try and shrink the font size to fit the billboard
- (NSInteger)correctMaxFontSizeForNoHyphenationFor:(NSArray *)textInArray 
                                      constraintTo:(NSInteger)possibleMaxFontSize 
                                        boardWidth:(NSInteger)width 
                                       boardHeight:(NSInteger)height
{
  NSParameterAssert(textInArray);

  if (possibleMaxFontSize == 0) {
    return 0;
  }

  NSInteger realFontSize = possibleMaxFontSize;
  BOOL finished = NO;
  do {
    NSInteger currentLineWidth = 0;
    NSInteger currentLineIndex = 0;

    for (int idx= 0; idx < [textInArray count]; idx++) {
      NSString *aWord = [textInArray objectAtIndex:idx];
      NSInteger wordLengthAppliedFontSize = [aWord length]*realFontSize;
      // width is not enough for a single word
      if (wordLengthAppliedFontSize > width) {
        realFontSize = width/[aWord length];
        currentLineIndex = 0;
        currentLineWidth = 0;
        break;
      }

      // current word is safe for at least one line, see if it is safe to add to current line.
      if (currentLineWidth + wordLengthAppliedFontSize > width) {
        // need a new line
        currentLineIndex++;
        currentLineWidth = wordLengthAppliedFontSize;

      }else{
        currentLineWidth += wordLengthAppliedFontSize;
      }

      if (currentLineWidth + realFontSize < width) {
        // current line is safe for one more space.
        currentLineWidth += realFontSize;
      //}else{   //<- Here cause the case #1 failed
      }else if (idx != ([textInArray count] -1)){
        // need a new line
        currentLineIndex++;
        currentLineWidth = 0;
      }

      // height is not enough for the whole text
      if ((currentLineIndex + 1) * realFontSize > height){
        realFontSize = height/(currentLineIndex + 1);
        currentLineIndex = 0;
        currentLineWidth = 0;
        break;
      }
      // done.
      if (idx == [textInArray count] -1) {
        // last line
        finished = YES;
      }

    }

  } while (realFontSize > 0 && !finished);

  return realFontSize;
}

3. Verify it

I created some test cases to test on it. It includes some extra test cases that need to be omitted when read in the file.

Download my test cases

Meanwhile, Facebook has an input file, you can also download it.

Output

Here is my output, what’s yours? Whose one is correct?

Case #1: 30 //<- Wrong, should be 60
Case #2: 5
Case #3: 31
Case #4: 6
Case #5: 30
Case #6: 83
Case #7: 8      //<- Wrong, should be 9
Case #8: 80
Case #9: 21
Case #10: 4
Case #11: 31
Case #12: 21
Case #13: 30
Case #14: 21
Case #15: 30
Case #16: 21
Case #17: 4
Case #18: 21
Case #19: 4
Case #20: 4

After modified step2, I think the following result is correct:

Case #1: 60 
Case #2: 5 
Case #3: 31 
Case #4: 6 
Case #5: 30 
Case #6: 83 
Case #7: 9 
Case #8: 80 
Case #9: 21 
Case #10: 4 
Case #11: 31 
Case #12: 21 
Case #13: 30 
Case #14: 21 
Case #15: 30 
Case #16: 21 
Case #17: 4 
Case #18: 21 
Case #19: 4 
Case #20: 4 

It’s fun, I’m no longer qualified for next round now, good luck, my friends. (hope I can enter the qualification round. And so do you.)