1
Files
lecture-operating-system-de…/c_os/lib/OutStream.h
2022-07-15 01:28:18 +02:00

258 lines
8.5 KiB
C++
Executable File

/*****************************************************************************
* *
* O U T S T R E A M *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Die Klasse OutStream enthaelt die Definition des *
* << Operators fuer die wichtigsten der vordefinierten *
* Datentypen und realisiert somit die bekannte Ausgabe- *
* funktion der C++ iO_Stream Bibliothek. Zur Zeit wird *
* die Darstellung von Zeichen, Zeichenketten und ganzen *
* Zahlen unterstuetzt. Ein weiterer << Operator erlaubt *
* die Verwendung von Manipulatoren. *
* *
* Neben der Klasse OutStream sind hier auch die *
* Manipulatoren hex, dec, oct und bin fuer die Wahl der *
* Basis bei der Zahlendarstellung, sowie endl fuer den *
* Zeilenumbruch definiert. *
* *
* Autor: Olaf Spinczyk, TU Dortmund *
* Aenderungen von Michael Schoettner, HHU, 06.04.20 *
*****************************************************************************/
#ifndef __OutStream_include__
#define __OutStream_include__
#include "lib/StringBuffer.h"
// #include <concepts> // NOTE: Only available in c++20
// NOTE: I added this
class fillw {
public:
constexpr fillw(const unsigned char w) : w(w) {}
const unsigned char w;
};
class fillc {
public:
constexpr fillc(const char c) : c(c) {}
const char c;
};
class OutStream : public StringBuffer {
private:
OutStream(const OutStream& copy) = delete; // Verhindere Kopieren
// Some stream formatting
unsigned char fill_used; // indicates how many characters are already used by the text internally
void fill_use_char(); // recognizes that one char from the print width has been used up
void fill_finalize(); // does the filling after text has been written to buffer
public:
int base; // Basis des Zahlensystems: z.B. 2, 8, 10 oder 16
// // Some stream formatting
unsigned char fill_width;
char fill_char; // fill character for fixed width
OutStream() : fill_used(0), base(10), fill_width(0), fill_char(' ') {}
// Methode zur Ausgabe des Pufferinhalts der Basisklasse StringBuffer.
void flush() override;
void put(char c) override;
// OPERATOR << : Umwandlung des angegebenen Datentypes in eine
// Zeichenkette.
// NOTE: I changed the stream manipulators to templates to be usable with different streams.
// If a Stream derived from OutStream gets passed to a operator<< the type won't be "lowered".
// This allows chaining of operator<< of different streams.
// Needed because I added operator<< overloads to the CGA_Stream class to change color with manipulators.
// NOTE: The templace concepts are only available in c++20.
// Leaving them out makes this unsafe, but it doesn't matter as much in this case since we only
// use a CGA_Stream in Globals.h anyway.
// Darstellung eines Zeichens (trivial)
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, char c) {
os.put(c);
if (c != '\n') {
// endl() doesn't has access to StringBuffer::put(), so ignore \n here
os.fill_finalize(); // NOTE: I added this
}
return os;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, unsigned char c) {
return os << (char)c;
}
// Darstellung einer nullterminierten Zeichenkette
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, char* string) {
char* pos = string;
while (*pos) {
os.put(*pos);
pos++;
}
os.fill_finalize(); // NOTE: I added this
return os;
}
// Darstellung ganzer Zahlen im Zahlensystem zur Basis base
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, short ival) {
return os << (long)ival;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, unsigned short ival) {
return os << (unsigned long)ival;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, int ival) {
return os << (long)ival;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, unsigned int ival) {
return os << (unsigned long)ival;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, long ival) {
// Bei negativen Werten wird ein Minuszeichen ausgegeben.
if (ival < 0) {
os.put('-');
ival = -ival;
}
// Dann wird der Absolutwert als vorzeichenlose Zahl ausgegeben.
return os << (unsigned long)ival;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, unsigned long ival) {
unsigned long div;
char digit;
if (os.base == 8) {
os.put('0'); // oktale Zahlen erhalten eine fuehrende Null
} else if (os.base == 16) {
os.put('0'); // hexadezimale Zahlen ein "0x"
os.put('x');
}
// Bestimmung der groessten Potenz der gewaehlten Zahlenbasis, die
// noch kleiner als die darzustellende Zahl ist.
for (div = 1; ival / div >= (unsigned long)os.base; div *= os.base) {}
// ziffernweise Ausgabe der Zahl
for (; div > 0; div /= (unsigned long)os.base) {
digit = ival / div;
if (digit < 10) {
os.put('0' + digit);
} else {
os.put('a' + digit - 10);
}
ival %= div;
}
os.fill_finalize(); // NOTE: I added this
return os;
}
// Darstellung eines Zeigers als hexadezimale ganze Zahl
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, void* ptr) {
int oldbase = os.base;
os.base = 16;
os << (unsigned long)ptr;
os.base = oldbase;
return os;
}
// Aufruf einer Manipulatorfunktion
// NOTE: Changed the function pointer type including the manipulator functions
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, T& (*f)(T&)) {
return f(os);
}
// For stream formatting
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, const fillw& w) {
os.flush(); // Flush the buffer to not modify previous output
os.fill_width = w.w;
return os;
}
template<typename T>
// requires std::derived_from<T, OutStream>
friend T& operator<<(T& os, const fillc& c) {
os.flush();
os.fill_char = c.c;
return os;
}
};
//
// Manipulatorfunktionen
//
// Die folgenden Funktionen erhalten und liefern jeweils eine Referenz auf
// ein OutStream Objekt. Da die Klasse OutStream einen Operator << fuer
// derartige Funktionen definiert, koennen sie mit Hilfe dieses Operators
// aufgerufen und sogar in weitere Eingaben eingebettet werden.
// Aufgabe der Manipulatoren ist, die Darstellung der nachfolgenden Ausgaben
// zu beeinflussen, z.B durch die Wahl des Zahlensystems.
// Zeilenumbruch in Ausgabe einfuegen.
template<typename T>
T& endl(T& os) {
os << '\n';
os.flush();
return os;
}
// Waehle binaeres Zahlensystem aus.
template<typename T>
T& bin(T& os) {
os.base = 2;
return os;
}
// Waehle oktales Zahlensystem aus.
template<typename T>
T& oct(T& os) {
os.base = 8;
return os;
}
// Waehle dezimales Zahlensystem aus.
template<typename T>
T& dec(T& os) {
os.base = 10;
return os;
}
// Waehle hexadezimales Zahlensystem aus.
template<typename T>
T& hex(T& os) {
os.base = 16;
return os;
}
#endif