Friday, 25 December 2015

Updating our Christmas lights

Transitioning our Christmas lights to a central controller

Those who know us know that we have a reasonably decent Christmas lights display. Our home is blessed with a very large front gable: the entire width of the house!

And because we've got a corner block with the house at an angle to the streets, we've actually got 2.5 sides of the house able to support lights (the 0.5 being the western end where, part-way along the carport, the neighbour's carport butts onto our roofline).

So, we've currently got 8 sets of deep blue icicle lights stretched all the way around almost to the back of the house. We've got a few more sets (e.g. some stars and shooting stars) on the house proper and in the garden. We've recently added some lights to the tree in our front yard: warm white around the trunk and partway up the two main branches, and some pink in the foliage (the pink matching the colour of the blossoms in mid December).

The Problem

These lights all run off separate controllers. There are 8 identical but unique controllers for the icicles, for example, and while these controllers state that they are supposed to remember their pattern (I endeavoured to have them all on the same pattern), they simply don't. This leaves wierd strobing effects at the set boundaries in places and makes me hope none of the neighbours suffer from epilepsy!

And then there's the fact that none of the other sets work in tandem.

It all looks a jumbled mess to be honest - and I'd like something different

My Plan

I've had a look at some computer-controlled systems, and they all seem to rely on music input. I'd rather not do that, since we have a community hall on the street and we (along with the neighbours) are pretty sick of loud music most of the night in some occasions (even if it is nice).

I've discovered a nice newish microcontroller, the PIC16F18344. It has 2 dedicated PWM (pulse width modulation) outputs along with 4 additional possible PWM outputs in a set of multi-function modules. And there are two additional timer modules which can be configured together for another couple of additional software PWM outputs. 8 PWM outputs; yum!

Why all those outputs?

2 of the outputs will be used to drive the two halves of the icicle lights. All of the strands can be linked together and run off them, so they'll all be properly synchronised: all the way around the house! Our waterfall-style Christmas tree on the front of the house has 2 channels, too, as do the pink lights in our tree... so I can run these off the same channels for really nice synch of the major display pieces.

4 of the outputs will be for the RGBO style lights (red-green-blue-orange), of which we've got a few sets (including my very favourite mini shooting stars, bought from Coles of all places all the way back in 2008 and still mostly going strong).

The last 2 channels will be for any monochromatic pieces that we might like to link in (there are some that we'll leave permanently on, for example the long warm white strand around the tree... it's simply stunning as-is and making it flash, etc., I think will detract from the spectacle). Actually, I'm not sure we've got any of these at the moment, but that might change... and I'd be silly to not include it in the chip when I program it since it's not terribly hard!

Why PWM?

PWM allows the signal to quickly switch on-off the light strings (works really well with LEDs in particular). This on-off occurs much faster than the human eye can detect, but the amount on and off modulates the apparent LED brightness... so if the lights are on only 10% of the time, they'll appear to have 10% of the brightness compared to constantly on. Or something like that.

Where to from here?

Well, I need to start working on the program for the chip. In fact, it's not terribly hard, since the dedicated PWM modules require only a few instructions to configure and set going... ditto the CCP modules (an additional instruction required to put them in PWM mode compared to the dedicated PWM modules). The 2 software PWM modules utilise the same base timer as the PWM/CCP modules but require pre-loading the timer modules with particular values, and handling the interrupts with dedicated code to toggle some general purpose I/O pins (the PWM and CCP modules toggle their outputs automatically... once set up, they can pretty much run forever without monitoring).

The only issue is working out the timer control values to pump into the various PWM modules to make them flash, dim, etc. And then having some way of stringing the values together to make a set of patterns... which could be a problem since the chip has only 256 bytes of EEPROM. At 8 channels needing 2 bytes per channel per value, 256 bytes leaves only 16 combinations of value! I'd need probably 10 times that... Looks like some kind of external EEPROM interface, though the chip does have UART, SPI and IIC inter-chip communications modules to help...

Hopefully, more on this later!

Monday, 30 March 2015

Gluten-free, sugar-free Part #1

My gluten-free, sugar-free journey.

Part 1

For many years I've known that my body has an issue with gluten and sugar. But there's a big problem if you try to find pre-made foods: you can (sometimes) find gluten-free products, or (more rarely) sugar-free products, but both? Not a hope.

So I've decided enough is enough and I'm embarking on a journey to find GF+SF recipes, or invent my own. The main reason is that now I have a little girl and I'd like to be around longer for her if I can... so looking after myself better is more a priority. Besides, I'm hoping that as she grows she'll pick up the desire to cook/bake like I do (though it is the case that I've struggled to be organised enough to actually follow through on it), and that she'll be healthier for it in the long run, too.

Given that I'm suffering from a severely sore throat and lost voice at the time of writing (not to mention that it's become hot-ish again), I thought I'd start with ice cream. Just plain vanilla to start with.

I own an ice cream maker with a freezable base. I bought it before I got married (I gave my lovely missus one as well at the time, so technically I own two... though one base has gone missing in the interim...), and have used it precisely once. The ice cream was a flop and I didn't ever try again.

So, here's the ingredients I used:
  • 250ml A2 cream
  • 300ml A2 skim milk
  • 1/2 cup Natvia
  • 1/2 tsp vanilla essence
Some notes about this.
  1. The recipe came from the instructions for the ice cream maker, but I'm tailoring it to my needs. It's the "simple plain vanilla".
  2. I'm using A2 dairy (since I'm alpha-1-beta-casein intolerant as well); regular dairy will work fine.
  3. Natvia is a stevia-based sweetener, that's normally a 1-for-1 replacement with sugar. I say normally because my experiences previously are that it doesn't always square away that easily
  4. I omitted the salt; I saw no reason for it.
Having stored the base in the freezer for some years, it was definitely ready to use (it's got a plastic bag over it to stop ice crystals forming in it).

Simply mix the ingredients together and pour into ice cream maker and leave to churn for 20-40 minutes. In theory.

The first problem was one I should have predicted. Natvia is crystals of stevia with a bulking agent since stevia is about 1000x sweeter than sugar. However, it does not dissolve the way sugar does; I know this because I sometimes have stevia-based strawberry and chocolate milk mixes (think Quik but without the sugar) and the sweetener doesn't dissolve unless you heat the drink a bit.

To solve this, I dragged out the electric beaters and used that on a low setting for a while. It worked to some extent but left a wierd slurry in the bottom of the bowl.

The second problem is, I think, a reflection of the first. Having made the ice cream yesterday, I went to eat some today and it was rock hard. The slurry mixed through the cream mixture seems to have set quite firmly indeed. After allowing it to thaw, though, scooping out of the container became easier (it still seemed like cutting it worked better, and it was rather brittle).

The third problem was the stevia crystals themselves. Again a reflection of the first, the crystals were detectable in the ice cream so it didn't have a smooth texture. But I did use regular Natvia...

Finally, it is waaaay too sweet.

Apart from those issues, it was still very creamy but not overly so, and with some tweaks could be very morish (though because it's got only fat and no sugar other than the lactose from the dairy, it satisfies faster than regular ice cream).

So, over the coming long weekend, I intend to try it again but insteasd use 1/4 cup of the icing mixture version of Natvia (this is powdered, not crystalline, so shouldn't have the problems with the crystals or mixing).

I'll let you know how it goes!

The next job after thatis GF+SF donuts. I miss donuts. Lots.

And no, I'm not Homer Simpson ;-)

Friday, 20 March 2015

C++ integer event handling

Background

I've recently been looking into event handling in C++; the particular case is SDL (a C library for cross-platform GUI, etc., implementations). The event is identified as some kind of integer, and the handling of each different integer is done via a specialised virtual function (allowing sub-classes to override the default behaviour).

Most cases I've seen have event integers as non-contiguous, and SDL is no exception. In straight C the best approach is to use a switch statement since there's little chance (short of creating your own struct) of making a sparse matrix handler to limit the amount of memory contained (SDL has a maximum event ID of 65536, though only a limited number of numbers below 4096 are actually assigned as event IDs).

In C++, there's a few different options for sparse matrix handling, but the two best out-of-the-box ones are std::map and boost:unordered_map.

I wanted to evaluate the execution speeds (read: overhead) of the different mechanisms (i.e. std::map, boost::unordered_map and switch). For completeness, I'll throw in a pure array and an if-else method.

Note: I used BOOST 1.47.0, which is not the latest (at the time of writing, that's 1.53.0), so there may be speed improvements between library versions.

The mechanism

The idea was to push 1,000,000 randomly-generated numbers between 0-99 inclusive (i.e. there are 100 different event IDs), using a normal distribution to mimic the fact that some events occur more frequently than others. To achieve this, I used the BOOST random library.

Each event ID is routed via the particular mechanism to a single virtual function of the class as the callback, which takes the event ID as a parameter (in lieu of more complex possible callbacks which typically require some kind of argument list). The callback is implemented to do nothing, minimising any overhead of the callback operation in skewing the timing data.

The array implementation was a simple array of member function pointers. The boost::unordered_map implementation was a map of the event id as the key with a member function pointer as the item. Likewise the std::map implementation. These 3 arrays were initialised with the callback pointer assigned in the constructor of the class; the overhead of doing so was not included in the timing calculations.

With a set of numbers fixed per run, each number set is pumped through the different algorithms and the elapsed execution time captured. Since each algorithm is executed sequentially but in the one program, the possibility of statistical anomalies caused by random external processes are reduced. Running the program multiple times and aggregating the results should hopefully further reduce the possibility of statistical anomalies.

The code was compiled under MS VC 2010 Express, in release mode, and run 10 times on my AMD A6 quad-core laptop with 4GB RAM running Win7 x64 home premium. The only other app open other than Visual Studio was Firefox.

The results


All numbers in the below table are in milliseconds.

AlgorithmRun 1Run 2Run 3Run 4Run 5Run 6Run 7Run 8Run 9Run 10Mean
Array65666667655.9
boost::unordered_map3631333534333233383133.6
if8887889088888985888687.7
std::map7775777677777675787476.2
switch2221212122212121222121.3

Analysis

At first, some of the results seem a little bizarre. Naturally, the slowness of the if mechanism was unsurprising, as was the absolute raw speed of the straight array implementation.

What was surprising was that the switch method was only 2/3 of the execution time of the boost::unordered_map. Likewise, the MSVC implementation of std::map meant it executed more than twice as slowly as the boost::unordered_map. It's probable that different compiler/library implementations of std::map will render different results to that here; I've used MSVC since as a non-open-source compiler/library I'm assuming that it will have the least efficient implementation.

It all needs to be kept in context, however, and that these times in milliseconds are for 1,000,000 events. For each event, then, these times for the callback are in nanoseconds; on the face of it, if you're talking frame rates in the 50-100 fps category, then a processing time of even 88ns per event is not significant. However, this timing doesn't take into account the follow-up processing done by the event handling and the corresponding memory updates required, e.g., for rending the frame using different textures that perhaps aren't cached. It's still therefore good to minimise the time spent doing the actual event isolation detection as fast as possible...

Conclusions

If your program can take the memory hit of a pure array, then clearly this is the single fastest method of handling the events. However, should the IDs of the events change, then there is a significant potential of problematic maintenance with changing the array element assignments (particularly if a sparse assignment is used with some kind of default "not-handled" handler for the rest). There is a significant drawback with this approach, which is the significant memory overhead required (e.g. for SDL, on a 32-bit system, allocating an array for the entire 65536 event ID space requires 256k); the sparse-matrix approach using boost::unordered_map or std::map can reduce this (especially if only a limited subset of events are intended to be handled), however on memory-limited platforms (e.g. mobiles) this approach should probably be avoided (even the sparse-matrix approach).

Of the more algorithmic handling (compared to the brute-force of the pure array), either the switch or the boost::unordered_map would be the options. The switch method is still faster, but it does lead to rather ugly code which could have significant maintenance issues unless the event IDs are rendered as constants somewhere. The boost::unordered_map throws up some different potential maintenance issues, in that the linkage between event IDs and the callbacks is not programatic, so changes would not necessarily be in the place a maintainer might expect.

Regardless, the choice of if and std::map should be avoided.

Code

Here's the code used in this experiment:
#include <map>
#include <boost/unordered_map.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <ctime>
#include <iostream>

class member_fns
{
public:
member_fns(void);
~member_fns(void);

void HandleIntViaArray(void);
void HandleIntViaHash(void);
void HandleIntViaIf(void);
void HandleIntViaMap(void);
void HandleIntViaSwitch(void);

protected:

static const unsigned int NUM_NUMBERS;

typedef void (member_fns::*mem_func)(int);

virtual void Handler(int n);

std::map<int, mem_func> _map;
boost::unordered_map<int, mem_func> _hashmap;
mem_func _array[100];

int * _nums;
};

const unsigned int member_fns::NUM_NUMBERS = 1000000;

member_fns::member_fns(void)
{
int i = 0;
for ( ; i < 100 ; ++i) {
_map[i] = &member_fns::Handler;
_hashmap[i] = &member_fns::Handler;
_array[i] = &member_fns::Handler;
}

boost::random::mt19937 gen;
boost::random::uniform_int_distribution<> dist(1, 100);
_nums = new int[member_fns::NUM_NUMBERS];
for (i = 0 ; i < member_fns::NUM_NUMBERS ; ++i) {
_nums[i] = dist(gen) - 1;
}
}

member_fns::~member_fns(void)
{
delete [] _nums;
}

void member_fns::HandleIntViaArray(void)
{
int i = 0;

clock_t end = 0;
clock_t start = clock();

for ( ; i < member_fns::NUM_NUMBERS ; ++i) {
(this->*_array[_nums[i]])(_nums[i]);
}

end = clock();
std::cout << "Array " << (end - start)/double(CLOCKS_PER_SEC)*1000 << " ms" << std::endl;
}

void member_fns::HandleIntViaIf(void)
{
int i = 0;

clock_t end = 0;
clock_t start = clock();

for ( ; i < member_fns::NUM_NUMBERS ; ++i) {
if (_nums[i] == 0) {
Handler(_nums[i]);
}
else if (_nums[i] == 1) {
Handler(_nums[i]);
}
else if (_nums[i] == 2) {
Handler(_nums[i]);
}
else if (_nums[i] == 3) {
Handler(_nums[i]);
}
else if (_nums[i] == 4) {
Handler(_nums[i]);
}
else if (_nums[i] == 5) {
Handler(_nums[i]);
}
else if (_nums[i] == 6) {
Handler(_nums[i]);
}
else if (_nums[i] == 7) {
Handler(_nums[i]);
}
else if (_nums[i] == 8) {
Handler(_nums[i]);
}
else if (_nums[i] == 9) {
Handler(_nums[i]);
}
else if (_nums[i] == 10) {
Handler(_nums[i]);
}
else if (_nums[i] == 11) {
Handler(_nums[i]);
}
else if (_nums[i] == 12) {
Handler(_nums[i]);
}
else if (_nums[i] == 13) {
Handler(_nums[i]);
}
else if (_nums[i] == 14) {
Handler(_nums[i]);
}
else if (_nums[i] == 15) {
Handler(_nums[i]);
}
else if (_nums[i] == 16) {
Handler(_nums[i]);
}
else if (_nums[i] == 17) {
Handler(_nums[i]);
}
else if (_nums[i] == 18) {
Handler(_nums[i]);
}
else if (_nums[i] == 19) {
Handler(_nums[i]);
}
else if (_nums[i] == 20) {
Handler(_nums[i]);
}
else if (_nums[i] == 21) {
Handler(_nums[i]);
}
else if (_nums[i] == 22) {
Handler(_nums[i]);
}
else if (_nums[i] == 23) {
Handler(_nums[i]);
}
else if (_nums[i] == 24) {
Handler(_nums[i]);
}
else if (_nums[i] == 25) {
Handler(_nums[i]);
}
else if (_nums[i] == 26) {
Handler(_nums[i]);
}
else if (_nums[i] == 27) {
Handler(_nums[i]);
}
else if (_nums[i] == 28) {
Handler(_nums[i]);
}
else if (_nums[i] == 29) {
Handler(_nums[i]);
}
else if (_nums[i] == 30) {
Handler(_nums[i]);
}
else if (_nums[i] == 31) {
Handler(_nums[i]);
}
else if (_nums[i] == 32) {
Handler(_nums[i]);
}
else if (_nums[i] == 33) {
Handler(_nums[i]);
}
else if (_nums[i] == 34) {
Handler(_nums[i]);
}
else if (_nums[i] == 35) {
Handler(_nums[i]);
}
else if (_nums[i] == 36) {
Handler(_nums[i]);
}
else if (_nums[i] == 37) {
Handler(_nums[i]);
}
else if (_nums[i] == 38) {
Handler(_nums[i]);
}
else if (_nums[i] == 39) {
Handler(_nums[i]);
}
else if (_nums[i] == 40) {
Handler(_nums[i]);
}
else if (_nums[i] == 41) {
Handler(_nums[i]);
}
else if (_nums[i] == 42) {
Handler(_nums[i]);
}
else if (_nums[i] == 43) {
Handler(_nums[i]);
}
else if (_nums[i] == 44) {
Handler(_nums[i]);
}
else if (_nums[i] == 45) {
Handler(_nums[i]);
}
else if (_nums[i] == 46) {
Handler(_nums[i]);
}
else if (_nums[i] == 47) {
Handler(_nums[i]);
}
else if (_nums[i] == 48) {
Handler(_nums[i]);
}
else if (_nums[i] == 49) {
Handler(_nums[i]);
}
else if (_nums[i] == 50) {
Handler(_nums[i]);
}
else if (_nums[i] == 51) {
Handler(_nums[i]);
}
else if (_nums[i] == 52) {
Handler(_nums[i]);
}
else if (_nums[i] == 53) {
Handler(_nums[i]);
}
else if (_nums[i] == 54) {
Handler(_nums[i]);
}
else if (_nums[i] == 55) {
Handler(_nums[i]);
}
else if (_nums[i] == 56) {
Handler(_nums[i]);
}
else if (_nums[i] == 57) {
Handler(_nums[i]);
}
else if (_nums[i] == 58) {
Handler(_nums[i]);
}
else if (_nums[i] == 59) {
Handler(_nums[i]);
}
else if (_nums[i] == 60) {
Handler(_nums[i]);
}
else if (_nums[i] == 61) {
Handler(_nums[i]);
}
else if (_nums[i] == 62) {
Handler(_nums[i]);
}
else if (_nums[i] == 63) {
Handler(_nums[i]);
}
else if (_nums[i] == 64) {
Handler(_nums[i]);
}
else if (_nums[i] == 65) {
Handler(_nums[i]);
}
else if (_nums[i] == 66) {
Handler(_nums[i]);
}
else if (_nums[i] == 67) {
Handler(_nums[i]);
}
else if (_nums[i] == 68) {
Handler(_nums[i]);
}
else if (_nums[i] == 69) {
Handler(_nums[i]);
}
else if (_nums[i] == 70) {
Handler(_nums[i]);
}
else if (_nums[i] == 71) {
Handler(_nums[i]);
}
else if (_nums[i] == 72) {
Handler(_nums[i]);
}
else if (_nums[i] == 73) {
Handler(_nums[i]);
}
else if (_nums[i] == 74) {
Handler(_nums[i]);
}
else if (_nums[i] == 75) {
Handler(_nums[i]);
}
else if (_nums[i] == 76) {
Handler(_nums[i]);
}
else if (_nums[i] == 77) {
Handler(_nums[i]);
}
else if (_nums[i] == 78) {
Handler(_nums[i]);
}
else if (_nums[i] == 79) {
Handler(_nums[i]);
}
else if (_nums[i] == 80) {
Handler(_nums[i]);
}
else if (_nums[i] == 81) {
Handler(_nums[i]);
}
else if (_nums[i] == 82) {
Handler(_nums[i]);
}
else if (_nums[i] == 83) {
Handler(_nums[i]);
}
else if (_nums[i] == 84) {
Handler(_nums[i]);
}
else if (_nums[i] == 85) {
Handler(_nums[i]);
}
else if (_nums[i] == 86) {
Handler(_nums[i]);
}
else if (_nums[i] == 87) {
Handler(_nums[i]);
}
else if (_nums[i] == 88) {
Handler(_nums[i]);
}
else if (_nums[i] == 89) {
Handler(_nums[i]);
}
else if (_nums[i] == 90) {
Handler(_nums[i]);
}
else if (_nums[i] == 91) {
Handler(_nums[i]);
}
else if (_nums[i] == 92) {
Handler(_nums[i]);
}
else if (_nums[i] == 93) {
Handler(_nums[i]);
}
else if (_nums[i] == 94) {
Handler(_nums[i]);
}
else if (_nums[i] == 95) {
Handler(_nums[i]);
}
else if (_nums[i] == 96) {
Handler(_nums[i]);
}
else if (_nums[i] == 97) {
Handler(_nums[i]);
}
else if (_nums[i] == 98) {
Handler(_nums[i]);
}
else if (_nums[i] == 99) {
Handler(_nums[i]);
}
else {
std::cout << "If: Unhandled number " << _nums[i] << std::endl;
}
}

end = clock();
std::cout << "If " << (end - start)/double(CLOCKS_PER_SEC)*1000 << " ms" << std::endl;
}

void member_fns::HandleIntViaHash(void)
{
int i = 0;

clock_t end = 0;
clock_t start = clock();

for ( ; i < member_fns::NUM_NUMBERS ; ++i) {
(this->*_hashmap[_nums[i]])(_nums[i]);
}

end = clock();
std::cout << "Hash " << (end - start)/double(CLOCKS_PER_SEC)*1000 << " ms" << std::endl;
}

void member_fns::HandleIntViaMap(void)
{
int i = 0;

clock_t end = 0;
clock_t start = clock();

for ( ; i < member_fns::NUM_NUMBERS ; ++i) {
(this->*_map[_nums[i]])(_nums[i]);
}

end = clock();
std::cout << "Map " << (end - start)/double(CLOCKS_PER_SEC)*1000 << " ms" << std::endl;
}

void member_fns::HandleIntViaSwitch(void)
{
int i = 0;

clock_t end = 0;
clock_t start = clock();

for ( ; i < member_fns::NUM_NUMBERS ; ++i) {
switch(_nums[i]) {
case 0:
Handler(_nums[i]);
break;
case 1:
Handler(_nums[i]);
break;
case 2:
Handler(_nums[i]);
break;
case 3:
Handler(_nums[i]);
break;
case 4:
Handler(_nums[i]);
break;
case 5:
Handler(_nums[i]);
break;
case 6:
Handler(_nums[i]);
break;
case 7:
Handler(_nums[i]);
break;
case 8:
Handler(_nums[i]);
break;
case 9:
Handler(_nums[i]);
break;
case 10:
Handler(_nums[i]);
break;
case 11:
Handler(_nums[i]);
break;
case 12:
Handler(_nums[i]);
break;
case 13:
Handler(_nums[i]);
break;
case 14:
Handler(_nums[i]);
break;
case 15:
Handler(_nums[i]);
break;
case 16:
Handler(_nums[i]);
break;
case 17:
Handler(_nums[i]);
break;
case 18:
Handler(_nums[i]);
break;
case 19:
Handler(_nums[i]);
break;
case 20:
Handler(_nums[i]);
break;
case 21:
Handler(_nums[i]);
break;
case 22:
Handler(_nums[i]);
break;
case 23:
Handler(_nums[i]);
break;
case 24:
Handler(_nums[i]);
break;
case 25:
Handler(_nums[i]);
break;
case 26:
Handler(_nums[i]);
break;
case 27:
Handler(_nums[i]);
break;
case 28:
Handler(_nums[i]);
break;
case 29:
Handler(_nums[i]);
break;
case 30:
Handler(_nums[i]);
break;
case 31:
Handler(_nums[i]);
break;
case 32:
Handler(_nums[i]);
break;
case 33:
Handler(_nums[i]);
break;
case 34:
Handler(_nums[i]);
break;
case 35:
Handler(_nums[i]);
break;
case 36:
Handler(_nums[i]);
break;
case 37:
Handler(_nums[i]);
break;
case 38:
Handler(_nums[i]);
break;
case 39:
Handler(_nums[i]);
break;
case 40:
Handler(_nums[i]);
break;
case 41:
Handler(_nums[i]);
break;
case 42:
Handler(_nums[i]);
break;
case 43:
Handler(_nums[i]);
break;
case 44:
Handler(_nums[i]);
break;
case 45:
Handler(_nums[i]);
break;
case 46:
Handler(_nums[i]);
break;
case 47:
Handler(_nums[i]);
break;
case 48:
Handler(_nums[i]);
break;
case 49:
Handler(_nums[i]);
break;
case 50:
Handler(_nums[i]);
break;
case 51:
Handler(_nums[i]);
break;
case 52:
Handler(_nums[i]);
break;
case 53:
Handler(_nums[i]);
break;
case 54:
Handler(_nums[i]);
break;
case 55:
Handler(_nums[i]);
break;
case 56:
Handler(_nums[i]);
break;
case 57:
Handler(_nums[i]);
break;
case 58:
Handler(_nums[i]);
break;
case 59:
Handler(_nums[i]);
break;
case 60:
Handler(_nums[i]);
break;
case 61:
Handler(_nums[i]);
break;
case 62:
Handler(_nums[i]);
break;
case 63:
Handler(_nums[i]);
break;
case 64:
Handler(_nums[i]);
break;
case 65:
Handler(_nums[i]);
break;
case 66:
Handler(_nums[i]);
break;
case 67:
Handler(_nums[i]);
break;
case 68:
Handler(_nums[i]);
break;
case 69:
Handler(_nums[i]);
break;
case 70:
Handler(_nums[i]);
break;
case 71:
Handler(_nums[i]);
break;
case 72:
Handler(_nums[i]);
break;
case 73:
Handler(_nums[i]);
break;
case 74:
Handler(_nums[i]);
break;
case 75:
Handler(_nums[i]);
break;
case 76:
Handler(_nums[i]);
break;
case 77:
Handler(_nums[i]);
break;
case 78:
Handler(_nums[i]);
break;
case 79:
Handler(_nums[i]);
break;
case 80:
Handler(_nums[i]);
break;
case 81:
Handler(_nums[i]);
break;
case 82:
Handler(_nums[i]);
break;
case 83:
Handler(_nums[i]);
break;
case 84:
Handler(_nums[i]);
break;
case 85:
Handler(_nums[i]);
break;
case 86:
Handler(_nums[i]);
break;
case 87:
Handler(_nums[i]);
break;
case 88:
Handler(_nums[i]);
break;
case 89:
Handler(_nums[i]);
break;
case 90:
Handler(_nums[i]);
break;
case 91:
Handler(_nums[i]);
break;
case 92:
Handler(_nums[i]);
break;
case 93:
Handler(_nums[i]);
break;
case 94:
Handler(_nums[i]);
break;
case 95:
Handler(_nums[i]);
break;
case 96:
Handler(_nums[i]);
break;
case 97:
Handler(_nums[i]);
break;
case 98:
Handler(_nums[i]);
break;
case 99:
Handler(_nums[i]);
break;
default:
std::cout << "Switch: Unhandled number " << _nums[i] << std::endl;
}
}

end = clock();
std::cout << "Switch " << (end - start)/double(CLOCKS_PER_SEC)*1000 << " ms" << std::endl;
}

void member_fns::Handler(int n)
{
}

int _tmain(int argc, _TCHAR* argv[])
{
member_fns analyser;
analyser.HandleIntViaArray();
analyser.HandleIntViaHash();
analyser.HandleIntViaIf();
analyser.HandleIntViaMap();
analyser.HandleIntViaSwitch();
return 0;
}