#ifndef STRINGLIST_H #define STRINGLIST_H #include #include #define BEGIN_STRINGLIST_NAMESPACE namespace STRINGLIST { using namespace std; #define END_STRINGLIST_NAMESPACE } BEGIN_STRINGLIST_NAMESPACE #define BUF_SIZE 4096 /** * Self-referential structure * Represents one element in our list */ typedef struct node { char original[BUF_SIZE]; struct node *next; } Node; /** * In this class, we will manually create a list * of C-style strings to demonstrate defensive programming * techniques on a simple example * */ class StringList { public: StringList() : _head(NULL) {} ~StringList(); /** * Insert a string into the list * * Precondition: * original is not NULL * original is a NULL terminated string at most BUF_SIZE-1 in length * * Postcondition: * Modifies (this) * Makes a copy of the string and inserts it into the list * @param original the string to insert */ void insert (const char *original); /** * Removes a string from the list * * Precondition: * original is not NULL * original is a NULL terminated string at most BUF_SIZE-1 in length * list is not empty (we do not really need this as a precondition, * I'm just putting it here to have an extra example) * * Postcondition: * Modifies (this) * If the string is in the list, removes the string from the list * If the string is not in the list, prints an error message to stderr * and does not modify the list * @param original the string to insert */ void remove (const char *original); /** * Prints the content of the list to stdout * The elements of the list are printed in alphabetical order * */ void print () const; /** * Tests if list is empty or not * @return true if the list is empty and false otherwise */ bool is_empty() const; /** * Looks up a string in the list * * Here, we are demonstrating a sneaky way in which internal * representation can be leaked by returning a pointer instead of a copy * The function returns the Node element containing the given string * Even though we use a constant pointer, we are revealing our * internal representation. Instead, we should make * a copy of the Node element that we return. * * As a second problem, it is even questionable why we show the entire * Node element to the caller. In this example, there is nothing * interesting to lookup. In general, if the original string was * associated with other information, then we would only return that * other information to the caller, not the entire Node element. * * Precondition: * original is not NULL * original is a NULL terminated string at most BUF_SIZE-1 in length * * Postcondition: * @param original the string to insert * @return if the string is in the list, returns a constant pointer * a Node element containing the string. Returns NULL otherwise. */ const Node* lookup(const char* original) const; private: Node *_head; // Function to check the representation invariant // stating that the list is always in sorted order // Not really need to write the specs for this function // because it is private bool check_list () const; }; END_STRINGLIST_NAMESPACE #endif