Created
March 14, 2011 15:28
-
-
Save drbobbeaty/869313 to your computer and use it in GitHub Desktop.
C++ version of the Erlang Ring from Chapter 8 of Armstrong
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ring.cpp - this is the C++ equivalent of the Armstrong Chapter 8 | |
* exercise where you are supposed to make a ring of 'n' | |
* objects and have one fire another for a total of 'm' laps. | |
*/ | |
// System Headers | |
#include <stdint.h> | |
#include <iostream> | |
#include <sys/time.h> | |
// Third-Party Headers | |
// Other Headers | |
// Forward Declarations | |
// Public Constants | |
// Public Datatypes | |
// Public Data Constants | |
/** | |
* These are the different messages that we're going to pass around from | |
* Node to Node. They will be simple uint8_t values as they don't need | |
* to be anything special. | |
*/ | |
#define PING 0 | |
#define PONG 1 | |
/** | |
* This is the node that will make up the ring. It's got a nice pointer | |
* to the next Node in the ring and a few simple methods to make the ring | |
* a little easier to build and use. | |
*/ | |
class Node { | |
public: | |
// Constructors and Destructors | |
Node() : mNext(NULL), mStopOnPing(false) { } | |
~Node() { } | |
// Accessor Methods | |
void setNext( Node *aNode ) { mNext = aNode; } | |
void setStopOnPing( bool aFlag ) { mStopOnPing = aFlag; } | |
bool stopOnPing() { return mStopOnPing; } | |
// this method sends the message to the target where it can respond | |
bool send( Node *aTarget, uint8_t aMessage ) { | |
bool error = false; | |
if (aTarget == NULL) { | |
error = true; | |
} else { | |
error = !aTarget->onMessage(this, aMessage); | |
} | |
return !error; | |
} | |
// this method is what is called when a message is sent to this guy | |
bool onMessage( Node *aSource, uint8_t aMessage ) { | |
bool error = false; | |
switch (aMessage) { | |
case PING: | |
if (((error = !send(aSource, PONG)) == false) && | |
!mStopOnPing) { | |
error = !send(mNext, PING); | |
} | |
break; | |
case PONG: | |
break; | |
default: | |
error = true; | |
break; | |
} | |
return !error; | |
} | |
// this is a simple way to send a ping around the ring | |
bool ping() { | |
return send(mNext, PING); | |
} | |
private: | |
// this is the next node in the ring - wrapping back around | |
Node *mNext; | |
// this flag lets me know if I need to stop on a PING (loop done) | |
bool mStopOnPing; | |
}; | |
/** | |
* This method just gives me a nice microseconds since epoch that I can | |
* use for timing the operations. | |
*/ | |
uint32_t snap() { | |
struct timeval tp; | |
gettimeofday(&tp, NULL); | |
return (tp.tv_sec * 1000000) + tp.tv_usec; | |
} | |
/** | |
* This is the main entry point that will build up the ring and then fire | |
* it off 'm' times and then we'll see how fast it runs. | |
*/ | |
int main(int argc, char *argv[]) { | |
bool error = false; | |
// start off with the defaults for the program | |
uint16_t n = 1000; | |
uint16_t m = 500; | |
// start the timer | |
uint32_t click = snap(); | |
// now, let's make the ring of the right size, holding onto the head | |
Node *head = NULL; | |
if (!error) { | |
std::cout << "Building the " << n << " element ring..." << std::endl; | |
if ((head = new Node()) == NULL) { | |
error = true; | |
} else { | |
head->setStopOnPing(true); | |
} | |
} | |
Node *tail = head; | |
for (uint16_t i = 0; !error && (i < (n - 1)); ++i) { | |
Node *newbie = new Node(); | |
if (newbie == NULL) { | |
error = true; | |
break; | |
} else { | |
tail->setNext(newbie); | |
tail = newbie; | |
tail->setNext(head); | |
} | |
} | |
// now let's run it the right number of times | |
if (!error) { | |
std::cout << "Running the " << n << " element ring " << m | |
<< " times..." << std::endl; | |
for (uint16_t i = 0; i < m; ++i) { | |
head->ping(); | |
} | |
} | |
// stop the timer | |
if (!error) { | |
click = snap() - click; | |
std::cout << "Took " << click << " usec or " << click*1000.0/(n*m) | |
<< " nsec/op" << std::endl; | |
} | |
return (error ? 1 : 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment