#include "histogram.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <list>
using namespace std;
namespace HistogramNS
{
const unsigned long cMaxStars = 50;
class Slot
{
public:
Slot(long start, long end)
: mCount(0), mStart(start), mEnd(end)
{
}
Slot() : mCount(0), mStart(0), mEnd(0)
{
}
bool isEmpty()
{
return mCount == 0;
}
virtual void bump()
{
mCount++;
}
bool contains(long val)
{
return val >= mStart && val <= mEnd;
}
unsigned long getGreater(unsigned long max)
{
return max > mCount ? max : mCount;
}
void print(ostream& os, unsigned long maxcount)
{
if (isEmpty()) return;
printPrefix(os);
os << string(CalcNumStars(maxcount), '*') << endl;
}
int CalcNumStars(unsigned long maxcount)
{
return ((mCount * cMaxStars * 10) + 5) / (10 * maxcount);
}
virtual void printPrefix(ostream& os)
{
os << setw(4) << mStart
<< " - "
<< setw(4) << mEnd
<< setw(6) << mCount
<< " : ";
}
bool operator < (const Slot& other)
{
return mStart < other.mStart;
}
protected:
unsigned long mCount;
long mStart;
long mEnd;
} ;
class OutOfBoundsSlot : public Slot
{
public:
void printPrefix(ostream& os)
{
os << " outside "
<< setw(6) << mCount
<< " : ";
}
} ;
class Slots
{
public:
Slots(long increment, long start, long end)
: mInc(increment), mRangeStart(start), mRangeEnd(end), mMaxCount(0)
{
}
void bump(long val)
{
bump(inRange(val) ? &(*findSlot(val)) : &mOutOfBounds);
}
void print(std::ostream& os)
{
mSlots.sort();
for(SlotListIterator it = mSlots.begin(); it != mSlots.end(); ++it)
(*it).print(os, mMaxCount);
mOutOfBounds.print(os, mMaxCount);
}
private:
typedef list<Slot> SlotList;
typedef SlotList::iterator SlotListIterator;
void bump(Slot* s)
{
s->bump();
mMaxCount = s->getGreater(mMaxCount);
}
bool inRange(long val)
{
return val >= mRangeStart && val < mRangeEnd;
}
SlotListIterator findSlot(long val)
{
SlotList::iterator it;
for(it = mSlots.begin(); it != mSlots.end(); ++it)
{
if ((*it).contains(val)) break;
}
return it == mSlots.end() ? CreateNewSlot(val) : it;
}
SlotListIterator CreateNewSlot(long val)
{
long start = (val / mInc) * mInc;
Slot s(start, start + mInc - 1);
SlotListIterator it = mSlots.insert(mSlots.begin(), s);
return it;
}
unsigned long mMaxCount;
long mInc;
long mRangeStart;
long mRangeEnd;
OutOfBoundsSlot mOutOfBounds;
SlotList mSlots;
};
class Histogram::Private
{
public:
Private(long increment, long start, long end)
: slots(increment, start, end)
{
}
Slots slots;
} ;
Histogram::Histogram(long increment, long start, long end)
: impl(* new Private(increment, start, end))
{
}
Histogram::~Histogram(void)
{
delete &impl;
}
void Histogram::bump(long val)
{
impl.slots.bump(val);
}
void Histogram::print(std::ostream& os)
{
impl.slots.print(os);
}
}
|
#include <strstream>
#include "utx.h"
#include "histogram.h"
using namespace std;
using namespace HistogramNS;
TEST(histogram_empty)
{
Histogram h(10, 0, 100);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), "");
}
TEST(histogram_outofrange_low)
{
Histogram h(10, 0, 100);
h.bump(-1);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), " outside 1 : **************************************************\n");
}
TEST(histogram_outofrange_high)
{
Histogram h(10, 0, 100);
h.bump(100);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), " outside 1 : **************************************************\n");
}
TEST(histogram_oneslot_once)
{
Histogram h(10, 0, 100);
h.bump(0);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), " 0 - 9 1 : **************************************************\n");
}
TEST(histogram_oneslot_twice)
{
Histogram h(10, 0, 100);
h.bump(0);
h.bump(0);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), " 0 - 9 2 : **************************************************\n");
}
TEST(histogram_oneslot_entirerange)
{
Histogram h(10, 0, 100);
for(long i = 0; i < 10; ++i)
h.bump(i);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(), " 0 - 9 10 : **************************************************\n");
}
TEST(histogram_entirerange_plusone)
{
Histogram h(2, 0, 10);
for(long i = 0; i <= 10; ++i)
h.bump(i);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 1 2 : **************************************************\n"
" 2 - 3 2 : **************************************************\n"
" 4 - 5 2 : **************************************************\n"
" 6 - 7 2 : **************************************************\n"
" 8 - 9 2 : **************************************************\n"
" outside 1 : *************************\n"
);
}
TEST(histogram_entirerange_plusone_2)
{
Histogram h(1, 0, 5);
for(long i = 0; i <= 5; ++i)
h.bump(i);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 0 1 : **************************************************\n"
" 1 - 1 1 : **************************************************\n"
" 2 - 2 1 : **************************************************\n"
" 3 - 3 1 : **************************************************\n"
" 4 - 4 1 : **************************************************\n"
" outside 1 : **************************************************\n"
);
}
TEST(histogram_twoslots_onceeach)
{
Histogram h(10, 0, 100);
h.bump(0);
h.bump(10);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 9 1 : **************************************************\n"
" 10 - 19 1 : **************************************************\n"
);
}
TEST(histogram_threeslots_onceeach)
{
Histogram h(10, 0, 100);
h.bump(40); //reverse order to test the sort works...
h.bump(20);
h.bump(0);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 9 1 : **************************************************\n"
" 20 - 29 1 : **************************************************\n"
" 40 - 49 1 : **************************************************\n"
);
}
TEST(histogram_twoslots_1full_1half)
{
Histogram h(10, 0, 100);
h.bump(0);
h.bump(0);
h.bump(11);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 9 2 : **************************************************\n"
" 10 - 19 1 : *************************\n"
);
}
TEST(histogram_manyentry_half)
{
Histogram h(50, 0, 100);
for(int i=0; i < 50; ++i)
h.bump(i);
for(int i=50; i < 75; ++i)
h.bump(i);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 49 50 : **************************************************\n"
" 50 - 99 25 : *************************\n"
);
}
TEST(histogram_manyentry_oddsplits)
{
Histogram h(1, 0, 3);
for(int i=0; i < 33; ++i)
h.bump(0);
for(int i=0; i < 22; ++i)
h.bump(1);
for(int i=0; i < 11; ++i)
h.bump(2);
strstream s;
h.print(s);
s << ends;
utxassert(s.str(),
" 0 - 0 33 : **************************************************\n"
" 1 - 1 22 : *********************************\n"
" 2 - 2 11 : ****************\n"
);
}
|