Problem Set 3
Problem Set 3
Siti Hawa
Marker's comments:
1 138
Total 138
Extension certification:
Signature of Convener:
1
COS30008 Semester August 2024 Ms. Siti Hawa
class ifstream12
{
private:
std::ifstream fIStream;
public:
// using C++11's nullptr
ifstream12( const char* aFileName = nullptr, size_t aBufferSize = 128 ); // [18 marks]
~ifstream12(); // [4 marks]
The class ifstream12 defines an object adapter for std::ifstream. Clearly, the
corresponding file input stream has to be binary and the data would constitute strings of 0s
and 1s. What makes this task somewhat difficult is the requirement that we need to use a
physical 8-bit stream to read 12-bit values. We cannot do this directly. Instead, we have to
employ a buffering mechanism to first “collect” the bits from the underlying 8-bit input
stream and then construct 12-bit values from the bits in the buffer.
Class ifstream12 requires a constructor and a destructor. The constructor has to initialize
the object, acquire the necessary buffer memory, and open the input file. The destructor
has to close the underlying file and free the buffer memory.
The methods open, close, isOpen, good, and eof correspond to their respective
std::ifstream methods. You should study the features of std::ifstream carefully.
The member function eof returns true, if there are no bytes left in the input stream (i.e.,
fByteCount == 0). Please note that fByteCount should be 0, if you have never read
anything from fIStream. There is a subtle handshake between std::ifstream,
ifstream12, and clients of ifstream12 when it comes to the detection of end-of-file.
The object adapter ifstream12 has to return true for EOF, if and only if there are no
further bits available. A boundary scenario allows the underlying std::ifstream object to
be in state EOF while the object adapter ifstream12 is not.
2
COS30008 Semester August 2024 Ms. Siti Hawa
The function readBit implements the mapping process. It returns an optional value 0 or 1.
The return type std::optional<size_t> signifies that readBit can reach EOF while
reading the next bit.
The base type of fBuffer is std::byte. Unfortunately, type std::byte offers only a
limit set of operations that focus on bit manipulations and make it somewhat difficult to
interpret std::byte values as plain integers. For the conversion of bit patterns to a single
value, we can use the following declaration:
std::byte lByte = fBuffer[fByteIndex] & (std::byte{1} << fBitIndex);
The value of lByte is a bit-mask for the bit at index fBitIndex. It is either 1 or 0. The
value lByte is still of type std::byte. You need to apply a type conversion to size_t to
interpret the value as integer using the following expression:
std::to_integer<size_t>(lByte).
If the resulting value is greater than zero, then it denotes the bit 1. Otherwise, it means the
bit 0.
The function readBit also triggers fetch_data, if necessary. More precisely, at the start,
you must check if fByteCount is 0. In this case, fetch_data must be called (the buffer
does not contain any data). You may reach EOF here. In this case, readBit has no value
to return.
When fetching the next bit (using the expressions shown above), store the result
temporarily, and then advance the indices fByteIndex and fBitIndex to the next
position (some additional logic is required that you must devise to make it work). If
fBitIndex (which runs from highest to lowest) becomes negative, then you need to switch
to the next byte in the buffer. This also means that you have processed a byte. Hence, you
need to decrement fByteCount. Once all indices have been properly adjusted, you return
the result.
The operator>> implements the read12Bits algorithm as shown in the tutorial. You need
to adjust it to incorporate std::optional values. That is, readBit may return no value
(when EOF has been reached). In this case, you need to break from the for-loop. In
addition. You may need to use a static cast to size_t to set the corresponding bit in the
12-bit value.
The file Main.cpp contains a test function to check your implementation. Your program
should produce the following output:
Writing data.
Write 4096 codes
Reading data.
Read 4096 codes
Done