Skip to content

Instantly share code, notes, and snippets.

@drbobbeaty
Created March 14, 2011 15:28
Show Gist options
  • Save drbobbeaty/869313 to your computer and use it in GitHub Desktop.
Save drbobbeaty/869313 to your computer and use it in GitHub Desktop.
C++ version of the Erlang Ring from Chapter 8 of Armstrong
/**
* 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