CS253 HW7: Looping!                
Changes                
Comparing iterators with different rejection strings is
undefined behavior.
                
Description                
For this final assignment, you will improve on your HW5 class,
adding iteration. That is, this must work:
                
Words w("Belize Costa\\ Rica Panama");
for (auto p : w)
cout << p.first << (p.second ? " was escaped\n" : " was not escaped\n");
This implies the existence of the type Words::iterator
, and the
methods Words::begin()
and Words::end()
.
                
Methods and operations                
The following methods & operators must work, where wit is of type
Words::iterator
.
                
-
Words::
begin()
-
Returns a value of type
Words::iterator
that corresponds to the
first word/escaped pair in the Words
that is allowed by
.reject()
.
-
Words::
end()
-
Returns a value of type
Words::iterator
that corresponds to one
past the last word/escaped pair allowed by .reject()
in the
Words
. Past, I say! It does not correspond to the last
item, since begin()
& end()
form a half-open interval.
-
Words::
reject(string)
-
Set the rejection string. If not called, then no words are rejected.
-
++
wit -
- wit
++
-
-
--
wit -
- wit
--
-
Increments or decrements the iterator, going to the next/previous
word, skipping those rejected by
.reject()
.
Preincrement/predecrement return the new iterator value, and
postincrement/postdecrement return the previous value, in the same
manner as ++
and --
work on integers.
-
*
wit -
Yields, by value, the same sort of word/escaped pair that
Words::operator[]
returns. If .reject()
is in effect for this
iterator, then words containing any characters from the given string
are skipped.
- wit
==
wit -
- wit
!=
wit -
Compares two iterators for equality or inequality.
- copy, assignment
-
Iterators are copy-constructable, and assignable. Copying/assigning
preserves all state of the iterator, including current position and
what it rejects.
The types and names in the descriptions, above, do not determine the
C++ declarations of those methods. They only serve to informally
describe what sort of arguments a method might take.
                
Const-correctness, for methods, arguments, and operators, is your job.
For example, it must be possible call .begin()
on a const Words
objects.
                
You may define other methods or data, public or private, as you see fit.
You may define other classes, as you see fit. However, to use the
Words
class, the user need only #include "Words.h"
, not any
other header files.
                
Rejection                
Rejection of certain word/escaped pairs is controlled by .reject()
.
When an iterator is created via .begin()
or .end()
,
the most recent argument from .reject()
is passed along
to the iterator. That iterator will ignore string/bool pairs
that contain any character from the .reject()
argument.
                
Changing the rejection string for a Words
object does not
change the rejection strings for any iterators that already exist.
                
This is a fine opportunity for you to learn about the various string
methods, as opposed to doing the string-searching work yourself.
                
Iterator Invalidation                
A Words::iterator
can be invalidated by:
- The corresponding
Words
object being destroyed.
- Assigning to the corresponding
Words
object.
- Using
+=
or --
on the corresponding Words
object.
- Calling
.analyze()
on the corresponding Words
object.
Debugging                
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Sample Run                
This focuses on the features added in this assignment. This does
not imply that the previous features are abandoned.
                
% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(hw7)
# Are we in the wrong directory?
if(CMAKE_SOURCE_DIR MATCHES "[Hh][Ww]([0-9])$")
if(PROJECT_NAME MATCHES "[^${CMAKE_MATCH_1}]$")
message(FATAL_ERROR "Building ${PROJECT_NAME} in ${CMAKE_SOURCE_DIR}")
endif()
endif()
# Using -Wall is required:
add_compile_options(-Wall)
# These compile flags are highly recommended, but not required:
add_compile_options(-Wextra -Wpedantic)
# Optional super-strict mode:
add_compile_options(-fmessage-length=80 -fno-diagnostics-show-option
-fstack-protector-all -g -O3 -std=c++17 -Walloc-zero -Walloca
-Wctor-dtor-privacy -Wduplicated-cond -Wduplicated-branches
-Werror -Wextra-semi -Wfatal-errors -Winit-self -Wlogical-op
-Wold-style-cast -Wshadow -Wunused-const-variable=1
-Wzero-as-null-pointer-constant)
# add_compile_options must be BEFORE add_executable.
# Create the executable from the source file main.cc:
add_library(${PROJECT_NAME} Words.cc)
add_executable(test test.cc)
target_link_libraries(test ${PROJECT_NAME})
# Create a tar file every time:
add_custom_target(${PROJECT_NAME}.tar ALL COMMAND
tar -cf ${PROJECT_NAME}.tar *.cc *.h CMakeLists.txt)
% cmake . && make
… cmake output appears here …
… make output appears here …
Scanning dependencies of target test
[ 75%] Building CXX object CMakeFiles/test.dir/test.cc.o
[100%] Linking CXX executable test
[100%] Built target test
% cat test.cc
#include "Words.h"
#include "Words.h" // I meant to do that.
#include <iostream>
#include <cassert>
using namespace std;
int main() {
const Words a(R"(Raiders Temple\ of\ Doom Last\ Crusade)");
cout << "Normal:\n";
for (auto [word, esc] : a)
cout << '\t' << word << (esc ? " (escaped)\n" : "\n");
cout << "Reverse:\n";
const Words::iterator beg = a.begin();
for (Words::iterator it = a.end(); beg != it; ) {
it--;
auto p = *it;
cout << '\t' << p.first << '\n';
}
Words b(a);
b.reject("D");
cout << "Without D:\n";
for (auto [word, esc] : b)
cout << '\t' << word << '\n';
cout << "Without ca%b\n";
b.reject("ca%b");
for (auto [word, esc] : b)
cout << '\t' << word << '\n';
cout << "Without 123:\n";
b.reject("123");
for (auto [word, esc] : b)
cout << '\t' << word << '\n';
cout << "All:\n";
b.reject("");
auto begin_it = b.begin(), end_it = b.end(); // We like everything!
// This .reject() will NOT affect the iterators begin_it & end_it:
b.reject("aeiouy");
for (auto it=begin_it; it!=end_it; ++it)
cout << '\t' << (*it).first << '\n'; // Should really use ->
return 0;
}
% ./test
Normal:
Raiders
Temple of Doom (escaped)
Last Crusade (escaped)
Reverse:
Last Crusade
Temple of Doom
Raiders
Without D:
Raiders
Last Crusade
Without ca%b
Temple of Doom
Without 123:
Raiders
Temple of Doom
Last Crusade
All:
Raiders
Temple of Doom
Last Crusade
Libraries                
libhw7.a
is a library file. It contains a number of
*.o
(object) files. It must contain Words.o
, but it may also
contain whatever other *.o
files you need. The CMakeLists.txt
shown creates libhw7.a
. It does not contain main().
                
Testing                
You will have to write a main() function to test your code. Put it in a
separate file, and do not make it part of libhw7.a
.
Particularly, do not put main() in Words.h
or Words.cc
.
You will also have to create Words.h
, and put it into
hw7.tar
. We will test your program by doing something like
this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw7.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall test-program.cc libhw7.a
./a.out
We will supply a main program to do the testing that we want. You
should do something similar. It’s your choice whether to include your
test program in your hw7.tar
file.
However, cmake . && make
must work. If it fails because you
didn’t package test.cc
, but your CMakeLists.txt
requires
test.cc
, then your build failed, and you get no points.
Test your tar file, not just your code.
                
Requirements                
The HW5 requirements all apply, plus:
- The following produce undefined behavior:
- indirection on an end iterator
- incrementing an end iterator
- decrementing a begin iterator
- comparing iterators that don’t correspond to the same
Words
object
- comparing iterators with different rejection strings
Tar file                
- The tar file for this assignment must be called:
hw7.tar
- It must contain:
- source files (
*.cc
), including Words.cc
- header files (
*.h
), including Words.h
CMakeLists.txt
, which will create the library file
libhw7.a
.
- These commands must produce the library lib
hw7.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:                
In Canvas, check in the
file
hw7.tar
to the assignment “HW7”.
It’s due 10:00:00ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.