CS253 HW6: Doc with Iterators                
Changes                
I have changed:
d2.append(values, values+2); // excluded gamma
to:
d2.append(values+0, values+2); // excluded gamma
Technically, values
and values+2
have slightly different types,
and so a valid implementation might reject them, but using
values+0
ensures that it’s the same type as values+2
.
                
Erasing or replacing no lines is a valid operation, given a valid
starting line, and has no effect. It is undefined behavior to erase
zero lines with an invalid starting line. That is, for a five-line
Doc
, .erase(2,0)
and .erase(5,0)
have no effect, and
.erase(99,0)
is undefined behavior. .erase(5,1)
must throw.
                
Description                
For this assignment, you will improve upon your class Doc
from
HW4. All requirements from HW4 apply.
                
Methods                
The notation [
…]
means that the stuff between the
brackets is optional. a([b])
means that both a()
and a(b)
are valid.
                
Doc
must have the following additional public methods.
                
-
.erase(size_t start[, size_t count])
-
Remove
count
lines from the Doc
, starting at line start
.
-
.append(Doc)
-
Append all lines (indentation & data) from the argument to the end of
the current object. The argument must not be modified.
-
.insert(Doc, size_t start)
-
Insert all lines (indentation & data) from the argument
Doc
into
the current object. The first line inserted will be line start
,
the second line start+1
, etc. The Doc
argument must not be
modified.
-
.replace(Doc, size_t start[, size_t count])
-
Replace the
count
lines starting at line start
with the
contents of the Doc
argument. The first line inserted will be
line start
, the second line start+1
, etc. The Doc
argument must not be modified
-
.append(iter, iter)
-
The arguments must be two iterators of the same type that form a
half-open interval to a collection of strings. Append those strings
to the current object as if
+=
were called on each one. Leading
spaces must be converted into an indentation amount, but no other
processing of the line (tab check, stripping trailing spaces or
\r
) should occur.
-
.insert(iter, iter, size_t start)
-
The initial arguments must be two iterators of the same type that form
a half-open interval to a collection of strings. Insert those strings
into the current object starting at line
start
. Leading spaces
must be converted into an indentation amount, but no other processing
of the line (tab check, stripping trailing spaces or \r
) should
occur.
-
.replace(iter, iter, size_t start[, size_t count])
-
Replace the
count
lines starting at line start
with the
contents of the half-open range of iterators, which must refer to a
collection of strings. Leading spaces must be converted into an
indentation amount, but no other processing of the line (tab check,
stripping trailing spaces or \r
) should occur.
The argument start
is a line number; the first line of a Doc
is
line 0, as it is for the []
operator.
                
If count
is missing, assume the rest of the lines. That is, for a
ten-line Doc
, .erase(6)
will erase lines 6,7,8,9 (there is no
line 10), so it’s the same as .erase(6,4)
.
                
For methods with start
, if the values are out of range (line 17 of a
five-line Doc
, or .erase(10,6)
for a twelve-line Doc
) throw
a out_of_range error containing the offending arguments, and the
actual number of lines in the Doc
.
                
It’s a shame that the iterator arguments are a half-open interval,
but the start
/count
arguments aren’t. Life is like that.
                
The types and names in the method & operator descriptions, above, do
not determine the C++ declarations of those functions. They only
serve to informally describe what sort of arguments a method might take.
You might pass certain arguments by reference, use const, declare
return types, etc.
                
Const-correctness, for arguments, methods, and operators, is your job.
For example, it must be possible to .append()
a const Doc
onto a non-const Doc
.
                
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
Doc
class, the user need only #include "Doc.h"
, not any other
header files.
                
Hints                
- If you find yourself writing ten non-trivial methods, then your code
is WET. Reduce the duplication!
- It might help to refresh yourself on the syntax of
function arguments.
Debugging                
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Libraries                
libhw6.a
is a library file. It contains a number of
*.o
(object) files. It must contain Doc.o
, but it may also
contain whatever other *.o
files you need. The CMakeLists.txt
shown creates libhw6.a
. It does not contain main().
                
To be explicit, the provided CMakeLists.txt
does:
- creates
Doc.o
by compiling Doc.cc
- creates a library
libhw6.a
from Doc.o
- creates
test.o
by compiling test.cc
- creates an executable called
test
by linking test.o
with libhw6.a
.
The tar file must contain at least all the files required to do this.
                
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 libhw6.a
.
Particularly, do not put main() in Doc.h
or Doc.cc
. You
will also have to create Doc.h
, and put it into hw6.tar
.
We will test your program by doing something like this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw6.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall -std=c++17 test-program.cc libhw6.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 hw6.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.
                
This is the Colorado State University CS253 web page
https://cs.colostate.edu/~cs253/Fall22/HW6
fetched by unknown <unknown> with Linux UID 65535
at 2024-08-30T16:20:10 from IP address 3.148.145.130.
Registered CSU students are permitted to copy this web page for personal
use, but it is forbidden to repost the information from this web page to the
internet. Doing so is a violation of the rules in the CS253 syllabus,
will be considered cheating, and will get you an F in CS253.
Sample Run                
Here is a sample run, where %
is my shell prompt:
                
% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(hw6)
# Are we in the wrong directory?
if (CMAKE_SOURCE_DIR MATCHES "[Hh][Ww]([0-9])$")
if (NOT 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
-Wconversion -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} Doc.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 …
% cat test.cc
#include "Doc.h"
#include <cassert>
#include <fstream>
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;
int main() {
ofstream("data") << " \n one\n two\n three\n \n \r \n";
Doc d1;
assert(d1.empty() && !d1);
ifstream in("data");
in >> d1;
assert(d1 && !d1.empty());
assert(d1.size()==3);
assert(d1[0].indent == 1); assert(d1[0].data == "one");
assert(d1[1].indent == 2); assert(d1[1].data == "two");
assert(d1[2].indent == 3); assert(d1[2].data == "three");
cout << "*** d:\n" << d1;
Doc d2;
const string values[] = {"alpha", " beta", "gamma"};
d2.append(values+0, values+2); // excluded gamma
cout << "*** d2:\n" << d2;
Doc d3(d1); d3.replace(d2, 1, 1);
cout << "*** d3:\n" << d3;
vector<const char *> v = {"truth", " beauty "};
Doc d4(d3); d4.insert(v.begin(), v.end(), 3);
cout << "*** d4:\n" << d4;
const set<string> s = {" yes", " no "}; // set is sorted
Doc d5(d4); d5.replace(s.begin(), s.end(), 4);
cout << "*** d5:\n" << d5;
assert(d5.size()==6);
assert(d5[0].indent == 1); assert(d5[0].data == "one");
assert(d5[1].indent == 0); assert(d5[1].data == "alpha");
assert(d5[2].indent == 2); assert(d5[2].data == "beta");
assert(d5[3].indent == 0); assert(d5[3].data == "truth");
assert(d5[4].indent == 1); assert(d5[4].data == "no ");
assert(d5[5].indent == 1); assert(d5[5].data == "yes");
return 0;
}
% ./test
*** d:
one
two
three
*** d2:
alpha
beta
*** d3:
one
alpha
beta
three
*** d4:
one
alpha
beta
truth
beauty
three
*** d5:
one
alpha
beta
truth
no
yes
Tar file                
- The tar file for this assignment must be called:
hw6.tar
- It must contain:
- source files (
*.cc
), including Doc.cc
- header files (
*.h
), including Doc.h
CMakeLists.txt
, which will create the library file
libhw6.a
.
- These commands must produce the library lib
hw6.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:                
In Canvas, check in the
file
hw6.tar
to the assignment “HW6”.
It’s due 11:59ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.