CS253 HW4: Document Class                
Changes                
Updates to the assignment will be noted here. None yet!
                
Description                
For this assignment, you will write a class called Doc
that
represents a simple document. This document is a collection of lines of
text, indented by varying amounts. Documents can be read from or written
to I/O streams, and manipulated programatically.
                
Methods                
Doc
must have the following public methods:                
- default constructor
-
The default ctor creates an empty
Doc
.
- Copy constructor
-
- Assignment operator
-
Copy all information from another object of the same class.
- Destructor
-
Destroy.
-
.size()
-
Return a size_t indicating the number of lines in the object.
-
.empty()
-
Return true iff the document contains no lines.
The following operators must work:                
-
istream >> Doc
-
Read all remaining data in the istream as a document, replacing any
existing data. For each line, strip trailing spaces and
trailing carriage return (
'\r'
) characters. The newline does not
become part of the Doc
object. Any remaining leading spaces
become the indentation amount for this line. The input line
" x "
must be stored as the number 3
and the string
"x"
. If a tab character ('\t'
) is read, throw a
runtime_error.
Leading & trailing (at the start or the end of the document) empty
(after stripping trailing space/return) lines are ignored, and do not
participate in any other methods.
-
ostream << Doc
-
Write the document to the ostream. The indentation for each line is
written as the appropriate number of spaces. Every line is terminated
by a newline.
-
Doc + Doc
-
Build & return another
Doc
that contains all the data from the
left-hand Doc
, followed by all the data from the right-hand
Doc
.
This operator does not modify either argument.
-
Doc + string
-
Build & return another
Doc
that contains all the data from the
left-hand Doc
, plus the right-hand string. It is assumed that
the string doesn’t contain a newline. Treat leading spaces in the
string as the indentation, which are not stored as part of the
string. The trailing space/return stripping of operator<<
,
ignoring leading/trailing empty lines, and tab detection, do not
apply. This operator does not modify either argument.
-
string + Doc
-
Build & return another
Doc
that contains the left-hand string,
plus all the data from the right-hand Doc
. It is assumed that the
string doesn’t contain a newline. Treat leading spaces in the
string as the indentation, which are not stored as part of the
string. The trailing space/return stripping of operator<<
,
ignoring leading/trailing empty lines, and tab detection, do not
apply. This operator does not modify either argument.
-
Doc += Doc
-
Adds all the data from the right-hand
Doc
to the end of the
left-hand Doc
. Return a reference to the left-hand object.
The right-hand argument is not modified.
-
Doc += string
-
Add a line to the end of the
Doc
. It is assumed that the line
doesn’t contain a newline. Treat leading spaces as the indentation,
which are not stored as part of the string. The trailing space/return
stripping of operator<<
, ignoring leading/trailing empty lines,
and tab detection, do not apply.
The right-hand argument is not modified.
-
Doc[size_t]
-
Return a struct object that represents a given line of the
Doc
.
The first line is line zero. The struct object contains two fields:
a size_t indent
which contains the indentation of the line, and
a std::string data
which contains the data for the line, without
the indentation. If the number given is too large to indicate a line,
throw an out_of_range error mentioning the bad line number and how
many lines the object has.
-
Doc
in a boolean context -
Evaluating a
Doc
in a boolean context returns false
iff the Doc
contains no lines.
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 call .size()
on a const
object, or to copy a const object to a non-const object.
                
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                
Dynamic memory (new, new[], delete, delete[]) is not allowed.
Really.
                
Debugging                
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Libraries                
libhw4.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 libhw4.a
. It does not contain main().
                
To be explicit, the provided CMakeLists.txt
does:
- creates
Doc.o
by compiling Doc.cc
- creates a library
libhw4.a
from Doc.o
- creates
test.o
by compiling test.cc
- creates an executable called
test
by linking test.o
with libhw4.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 libhw4.a
.
Particularly, do not put main() in Doc.h
or Doc.cc
. You
will also have to create Doc.h
, and put it into hw4.tar
.
We will test your program by doing something like this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw4.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall test-program.cc libhw4.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 hw4.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/HW4
fetched by unknown <unknown> with Linux UID 65535
at 2024-08-30T16:17:31 from IP address 18.221.156.173.
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(hw4)
# 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 <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ofstream("data") << "\r \r \n\n Peter \n Ray\r \nEgon \n \n\r\n\n";
Doc d;
assert(d.empty() && !d);
ifstream in("data");
in >> d;
assert(d && !d.empty());
assert(d.size()==3);
assert(d[0].indent == 1);
assert(d[1].indent == 3);
assert(d[2].indent == 0);
assert(d[0].data == "Peter");
assert(d[1].data == "Ray");
assert(d[2].data == "Egon");
d += " Winston ";
assert(d.size() == 4);
assert(d[3].indent == 6);
assert(d[3].data == "Winston ");
for (size_t n=0; n<d.size(); n++) {
const auto stuff = d[n];
cout << n << ": " << stuff.indent << ' ' << stuff.data << '\n';
}
cout << "---\n" << d << "---\n";
d += "";
assert(d.size() == 5);
assert(d[4].indent == 0);
assert(d[4].data == "");
const Doc vacant;
assert(vacant.empty() && !vacant && vacant.size()==0);
d = vacant;
assert(d.empty() && !d && d.size()==0);
cout << d << "---\nDone.\n";
return 0;
}
% ./test
0: 1 Peter
1: 3 Ray
2: 0 Egon
3: 6 Winston
---
Peter
Ray
Egon
Winston
---
---
Done.
Requirements                
- Requirements are not inherited from HW2.
- Your class must not use cin, cout or cerr, or call exit().
- An empty line, or a completely empty document, is not an error.
- It must be an compile-time error or warning to ignore the return value
of
.size()
, .empty()
, or operator[]
.
- You may not have any
using namespace
declarations in your
header files.
- All copies (copy ctor, assignment operator) are “deep”.
Do not share data between copies—that’s not making a copy.
- You may not use any external programs. You may not use system(),
fork(), popen(), execl(), execvp(), etc.
- You may not use C-style I/O, such as printf(), scanf(), fopen(),
and getchar().
- You may not use endl. Use flush if needed.
- You may not use dynamic memory via new, delete, malloc(),
calloc(), realloc(), free(), strdup(), etc.
- It’s ok to implicitly use dynamic memory via containers such as
string or vector.
- You may not use the .eof() method.
- No global variables.
- For readability, don’t use ASCII int constants (
65
) instead of
char constants ('A'
) for printable characters.
- We will compile your code like this:
cmake . && make
- If that generates warnings, you will lose a point.
- If that generates errors, you will lose all points.
- There is no automated testing/pre-grading/re-grading.
- Test your code yourself. It’s your job.
- Even if you only change it a little bit.
- Even if all you do is add a comment.
- Test with the CSU compilers, not just your laptop’s compiler.
If you have any questions about the requirements, ask.
In the real world, your programming tasks will almost always be
vague and incompletely specified. Same here.
                
Tar file                
- The tar file for this assignment must be called:
hw4.tar
- It must contain:
- source files (
*.cc
), including Doc.cc
- header files (
*.h
), including Doc.h
CMakeLists.txt
, which will create the library file
libhw4.a
.
- These commands must produce the library lib
hw4.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:                
In Canvas, check in the
file
hw4.tar
to the assignment “HW4”.
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.