An Interface for an Int Queue
It may seem obvious that the most fundamental operations of a queue are ENQUEUE and DEQUEUE, but there are many choices to make in the design of an interface, including:
- Naming — What exactly should we call these operations?
- Error handling — What guarantees do we want to provide if the user misuses the data structure?
- Range of Operations — What other operations should we provide?
- Complexity — How efficient do we want these operations to be?
Naming
In this assignment, we'll adopt the same member-function naming conventions that the C++ Standard Library uses for list-like data structures. In particular, this choice means we'll have to forgo the usual camelCase naming convention that we use for member functions, and instead use snake_case naming.
I approve of this choice. Understandably, I like
snake_casegenerally, but it seems super appropriate for a data structure we'll use in a Snake game.
We'll stick to our usual naming conventions for the class name itself (IntList), and for its data members.
Error Handling
In the previous assignment, we required that your code throw an exception if the user used the data structure incorrectly (e.g., trying to access an invalid index of a list or popping when the list was empty). In this assignment, we will adopt an approach more typical in C++ standard library data structures, namely that misuse is forbidden. From an interface perspective, it is not specified what happens if the user misuses the data structure.
…Undefined behavior makes me anxious.
And rightly so. But when we actually implement the data structure, we'll still include checks where we can, but from the perspective of promises we make to users of the data structure, we won't promise anything if they misuse it.
Meh. Promise nothing. I like it.
Operations & Complexity
We'll provide the following fundamental operations for our data structure so that it can be used as a queue:
q.push_back(value)- Add
valueto the end of the list (the back of the queue). q.pop_front()- Remove value at the front of the list (the front of the queue). Does not return it, just removes it. (Popping from an empty list is misuse.)
q.front()- Return (but do not remove) the value at the front of the list. (Asking for the front item of an empty list is misuse.)
q.empty()- Return whether the list is empty.
While the abstract ENQUEUE operation maps to push_back, performing a DEQUEUE operation maps to front followed by pop_front.
In addition to these fundamental operations, we'll also provide:
- (default constructor)
- Create an empty list.
q.push_front(value)- Add
valueto the front of the list. (This is not a queue operation, in fact it allows our data structure to be used as a stack, but it's a useful operation to have.) q.size()- Return the number of elements in the list.
q.clear()- Remove all elements from the list.
q.swap(other)- Exchange the contents of this list with another list.
With the exception of q.clear(), all the operations we've listed must run in constant time. Clearing the list requires time proportional to the number of elements in the list, since each element must be destroyed.
Building Test Cases
When it comes time for you to write your IntList class, it would be nice to have some test cases to check that it works correctly. In the previous assignment, we provided you with prewritten test cases for the CoordVector class, but in this assignment, we want you to write your own test cases for the IntList class.
This feels like a bit of a chicken-and-egg problem. How can we write test cases for a class that doesn't exist yet?
Good question! The idea is that you can write test cases based on the interface we've specified here, without worrying about how the class is implemented.
But even better, although you haven't yet written the
IntListclass, we do already have anIntVectorclass that satisfies the same interface (and more). So you can write test cases that useIntVector, and then later, once you start writingIntList, you can just change the type of the variable in your test cases fromIntVectortoIntList.
Meh. Can't we just use the test cases we wrote for
CoordVector?
Alas, because
CoordVectorstoresCoordvalues rather thanints and providesoperator[], the test cases we wrote forCoordVectorwon't work forIntList. But you can use them as inspiration for writing your own test cases and as a reminder of how to write test cases in general.
Also, whereas last week we specified how things should behave when misused, this week we don't specify that behavior, so you don't need to (and must not) write test cases for misuse.
Meh. It's almost like you did that deliberately.
Variety is the spice of life.
Your Task, Part 1
In intlist-test.cpp, write test cases to check the behavior of the IntList class, based on the interface specified here. For now, use IntVector in place of IntList, so that you can run your test cases and check that they work.
Test the following aspects of the interface:
- The fundamental operations (
push_back,pop_front,front, andempty). - The additional operations (default constructor,
push_front,size,clear, andswap).
You do not need to test the complexity of the operations (that would be hard to do in a test case!), nor should you test misuse (since we don't specify what happens in that case). If you do misuse the IntVector class, strange things may happen.
Just how comprehensive do you want these test cases to be?
You need to take a balanced approach. Your goal is to catch implementation errors, because you don't want an obvious implementation error to slip through. On the other hand, you shouldn't overthink things and try to consider every possible edge case.
There's plenty more to do in the assignment, so don't spend too much time on this part.
Music to my ears.
Your Task, Part 2
In intlist.hpp, you'll find declarations of many of the functions we've talked about here, but they're lacking docstring comments. Add docstring comments to each function declaration, describing what the function does, its parameters, return value, rules for usage, and complexity.
There are also a few key functions that are missing entirely. Add declarations for the missing functions, along with docstring comments. (You don't need to implement any of the functions yet, just declare them.)
Helpful Hints
If You See Strange Red Text…
When I run my test cases, it crashed out with some bright red text that said something kinda creepy? I think it was a movie quote.
Remember what we said about undefined behavior? If you misuse the IntVector class, strange things may happen, including weird messages. So if you see something like that, check your code to make sure you're not misusing the class.
(When logged in, completion status appears here.)