#include "StringList.h" BEGIN_STRINGLIST_NAMESPACE StringList::~StringList() { while (_head) { Node *next = _head->next; delete _head; _head = next; } } void StringList::insert (const char *original) { // CHECK: Checking all inputs, all preconditions assert( original ); assert( strlen(original) < BUF_SIZE ); // CHECK invariant assert(check_list()); // Trying to modify the constant data is a compile time error //original[0] = 'a'; Node *node = new Node(); // CHECK: Handle possible error condition if ( !node ) { cerr << "Out of memmory\n"; return; } // CHECK Do not trust that strings are shorter than the // size of our buffers. Instead make sure no more characters // are copied than the size of the buffers // This is not strictly necessary because we have the assert // above, but what if someone comments out the asserts or // compiles the code with NDEBUG defined. It is // better to be extra careful. strncpy(node->original,original,BUF_SIZE); node->next = NULL; Node *previous = NULL; Node *current = _head; // Find the appropriate location in the list where to add the new element // CHECK: Compare only as many characters as the size of the buffer while ( (current != NULL) && (strncmp(current->original,original,BUF_SIZE) <= 0) ) { previous = current; current = current->next; } // Inserting at the beginning of the list if ( previous == NULL ) { node->next = _head; _head = node; } else { previous->next = node; node->next = current; } // CHECK invariant before exciting the function assert(check_list()); } void StringList::remove (const char *original) { // CHECK preconditions assert(original); assert(strlen(original) < BUF_SIZE); // CHECK invariant assert(check_list()); // CHECK precondition that list is not empty if ( !is_empty() ) { Node *previous = NULL; Node *current = _head; if ( strncmp( _head->original, original, BUF_SIZE) == 0) { current = _head; _head = _head->next; delete current; return; } while ( (current != NULL) && (strncmp(current->original,original,BUF_SIZE) != 0) ) { previous = current; current = current->next; } if ( !current ) { cerr << "Element not found\n"; } else { previous->next = current->next; delete current; } } // CHECK invariant assert(check_list()); } bool StringList::is_empty () const { return (_head == NULL); } void StringList::print () const { Node *current = _head; cout << "\nList content is:\n"; while (current) { cout << current->original << endl; current = current->next; } } /* * The function below demonstrates the use of the * const type qualifier for arguments and return values. * Note that there is still a problem with this function * If a caller does a lookup followed by a remove, then * the pointer returned by the lookup will become dangling. * In this case, it would be better to return a copy of * the element instead of a const pointer! */ const Node* StringList::lookup (const char *original) const { // CHECK preconditions assert(original); assert(strlen(original) < BUF_SIZE); Node *current = _head; while ( (current != NULL) && (strncmp(current->original,original,BUF_SIZE) != 0) ) { current = current->next; } // Even though we are returning a const pointer, we have // a representation exposure. We should make a copy instead return current; } bool StringList::check_list () const { if ( !_head ) { return true; } Node *previous= _head; Node *current = _head->next; while ( current ) { if ( strncmp(previous->original,current->original,BUF_SIZE) > 0 ) { return false; } previous = current; current = current->next; } return true; } END_STRINGLIST_NAMESPACE