contracts/whatami.cpp
This is an example of how Programming with Contracts can help clarify the specification of an interface.
#include <list>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <toast/contracts.hpp>
class am_i_a_stack_or_queue
{
virtual void doadd(char) = 0;
virtual void doremove() = 0;
virtual char dopeek() const = 0;
virtual int dosize() const = 0;
virtual bool doempty() const = 0;
virtual bool dofull() const = 0;
TOAST_INVARIANTS_BEGIN();
TOAST_DEFINE_INVARIANT(size() >= 0);
TOAST_DEFINE_INVARIANT(empty() == (size() == 0));
TOAST_INVARIANTS_END();
public:
virtual ~am_i_a_stack_or_queue() {}
void add(char c)
{
TOAST_IN(!full());
int oldsize = size();
doadd(c);
TOAST_OUT(c == peek());
TOAST_OUT(size() == oldsize + 1);
TOAST_OUT(!empty());
}
void remove()
{
TOAST_IN(!empty());
int oldsize = size();
doremove();
TOAST_OUT(size() == oldsize - 1);
TOAST_OUT(!full());
}
char peek() const
{
TOAST_IN(!empty());
return dopeek();
}
int size() const { return dosize(); }
bool empty() const { return doempty(); }
bool full() const { return dofull(); }
};
class queue : public am_i_a_stack_or_queue
{
std::list<char> l;
void doadd(char c) { l.push_back(c); }
void doremove() { l.pop_front(); }
char dopeek() const { return l.front(); }
int dosize() const { return l.size(); }
bool doempty() const { return l.empty(); }
bool dofull() const { return false; }
};
class stack : public am_i_a_stack_or_queue
{
std::list<char> l;
void doadd(char c) { l.push_back(c); }
void doremove() { l.pop_back(); }
char dopeek() const { return l.back(); }
int dosize() const { return l.size(); }
bool doempty() const { return l.empty(); }
bool dofull() const { return false; }
};
void printall(am_i_a_stack_or_queue const &cont)
{
std::cout << "full? " << cont.full() << "\nempty? " << cont.empty();
if(!cont.empty())
std::cout << "\n Peek: " << cont.peek();
std::cout << "\nsize: " << cont.size() << std::endl;
}
void testit(am_i_a_stack_or_queue &cont)
{
printall(cont);
std::cout << "Add 'n'" << std::endl;
cont.add('n');
printall(cont);
std::cout << "on second thought, remove it." << std::endl;
cont.remove();
printall(cont);
std::string s("toast");
for(std::string::iterator i = s.begin(); i != s.end(); ++i)
{
std::cout << "Add '" << *i << "'" << std::endl;
cont.add(*i);
printall(cont);
}
}
void usage()
{
std::cout << "usage: whatami stack|queue" << std::endl;
std::exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
if(argc != 2) usage();
if(std::strcmp("stack", argv[1]) == 0)
{
stack s;
testit(s);
}
else if(std::strcmp("queue", argv[1]) == 0)
{
queue q;
testit(q);
}
else usage();
return EXIT_SUCCESS;
}