1

templates for << chaining + new manipulators

This commit is contained in:
churl
2022-05-06 16:51:41 +02:00
parent ab7a9c2ecb
commit 12513926d8
6 changed files with 187 additions and 184 deletions

View File

@ -25,16 +25,21 @@
*****************************************************************************/
void CGA_Stream::flush() {
print(buffer, pos, attribute(this->color_bg, this->color_fg, this->blink));
// Flushing resets attributes
this->blink = false;
this->color_bg = CGA::BLACK;
this->color_fg = CGA::LIGHT_GREY;
pos = 0;
}
// NOTE: I added this
// TODO
// CGA_Stream& CGA_Stream::operator<<(const fgc& fg) {
// this->color_fg = fg.fg;
// return *this;
// }
// CGA_Stream& CGA_Stream::operator<<(const bgc& bg) {
// this->color_bg = bg.bg;
// return *this;
// Alternative way to write the templates which keeps definition separated
// Usable for our case but somehow defeats the purpose of templates
// template<typename T>
// T& operator<<(T& os, const fgc& fg) {
// os.color_fg = fg.fg;
// return os;
// }
// template CGA_Stream& operator<<<CGA_Stream>(CGA_Stream&, const fgc&);

View File

@ -53,9 +53,19 @@ public:
void flush() override;
// NOTE: I added this
// TODO: Problem: Implementing this here breaks the << chaining
// CGA_Stream& operator<<(const fgc&);
// CGA_Stream& operator<<(const bgc&);
template<typename T>
friend T& operator<<(T& os, const fgc& fg) {
os.flush();
os.color_fg = fg.fg;
return os;
}
template<typename T>
friend T& operator<<(T& os, const bgc& bg) {
os.flush();
os.color_fg = bg.bg;
return os;
}
};
#endif

View File

@ -22,16 +22,6 @@
#include "lib/OutStream.h"
// NOTE: I added this, stream manipulators with arg
OutStream& OutStream::operator<<(const fillw& w) {
this->fill_width = w.w;
return *this;
}
OutStream& OutStream::operator<<(const fillc& c) {
this->fill_char = c.c;
return *this;
}
// NOTE: I added this, fixed width printing
void OutStream::put(char c) {
if (this->fill_width == 0) {
@ -66,109 +56,18 @@ void OutStream::fill_use_char() {
}
this->fill_used++;
}
void OutStream::flush() {
// Flushing resets fixed width
this->base = 10;
this->fill_char = ' ';
this->fill_width = 0;
this->fill_used = 0;
}
//
// Zeichen und Zeichenketten in Stream ausgeben
//
OutStream& OutStream::operator<<(char c) {
put(c);
if (c != '\n') {
// endl() doesn't has access to StringBuffer::put(), so ignore \n here
this->fill_finalize(); // NOTE: I added this
}
return *this;
}
// TODO: shouldn't this be printed as number?
OutStream& OutStream::operator<<(unsigned char c) {
return *this << (char)c;
}
OutStream& OutStream::operator<<(char* string) {
char* pos = string;
while (*pos) {
put(*pos);
pos++;
}
this->fill_finalize(); // NOTE: I added this
return *this;
}
//
// Ganzer Zahlen im Zahlensystem zur Basis base in Stream ausgeveb
// Alle vorzeichenbehafteten Datentypen werden als long dargestellt,
// Alle vorzeichenlosen als unsigned long.
OutStream& OutStream::operator<<(short ival) {
return *this << (long)ival;
}
OutStream& OutStream::operator<<(unsigned short ival) {
return *this << (unsigned long)ival;
}
OutStream& OutStream::operator<<(int ival) {
return *this << (long)ival;
}
OutStream& OutStream::operator<<(unsigned int ival) {
return *this << (unsigned long)ival;
}
// Darstellung eine vorzeichenbehafteten ganzen Zahl.
OutStream& OutStream::operator<<(long ival) {
// Bei negativen Werten wird ein Minuszeichen ausgegeben.
if (ival < 0) {
put('-');
ival = -ival;
}
// Dann wird der Absolutwert als vorzeichenlose Zahl ausgegeben.
return *this << (unsigned long)ival;
}
// Darstellung einer vorzeichenlosen ganzen Zahl.
OutStream& OutStream::operator<<(unsigned long ival) {
unsigned long div;
char digit;
if (base == 8) {
put('0'); // oktale Zahlen erhalten eine fuehrende Null
} else if (base == 16) {
put('0'); // hexadezimale Zahlen ein "0x"
put('x');
}
// Bestimmung der groessten Potenz der gewaehlten Zahlenbasis, die
// noch kleiner als die darzustellende Zahl ist.
for (div = 1; ival / div >= (unsigned long)base; div *= base)
;
// ziffernweise Ausgabe der Zahl
for (; div > 0; div /= (unsigned long)base) {
digit = ival / div;
if (digit < 10) {
put('0' + digit);
} else {
put('a' + digit - 10);
}
ival %= div;
}
this->fill_finalize(); // NOTE: I added this
return *this;
}
// Darstellung eines Zeigers als hexadezimale ganze Zahl
OutStream& OutStream::operator<<(void* ptr) {
int oldbase = base;
base = 16;
*this << (unsigned long)ptr;
base = oldbase;
return *this;
}
// Aufruf einer Manipulatorfunktion
OutStream& OutStream::operator<<(OutStream& (*f)(OutStream&)) {
return f(*this);
}
// NOTE: The implementations now resides in the OutStream.h as I switched them to templated functions
//
// Manipulatorfunktionen
@ -180,33 +79,4 @@ OutStream& OutStream::operator<<(OutStream& (*f)(OutStream&)) {
// Aufgabe der Manipulatoren ist, die Darstellung der nachfolgenden Ausgaben
// zu beeinflussen, z.B durch die Wahl des Zahlensystems.
// Fuege einen Zeilenumbruch in die Ausgabe ein.
OutStream& endl(OutStream& os) {
os << '\n';
os.flush();
return os;
}
// Waehlt das binaere Zahlensystem aus.
OutStream& bin(OutStream& os) {
os.base = 2;
return os;
}
// Waehlt das oktale Zahlensystem aus.
OutStream& oct(OutStream& os) {
os.base = 8;
return os;
}
// Waehlt das dezimale Zahlensystem aus.
OutStream& dec(OutStream& os) {
os.base = 10;
return os;
}
// Waehlt das hexadezimale Zahlensystem aus.
OutStream& hex(OutStream& os) {
os.base = 16;
return os;
}
// NOTE: The implementations now resides in the OutStream.h as I switched them to templated functions

View File

@ -25,8 +25,6 @@
#include "lib/StringBuffer.h"
// NOTE: I added this
// TODO: I should probably put this inside some FormatStream or sth...
// TODO: Should this only work for the next << ?
class fillw {
public:
fillw() : w(0) {};
@ -41,7 +39,6 @@ public:
};
class OutStream : public StringBuffer {
private:
OutStream(const OutStream& copy); // Verhindere Kopieren
@ -65,7 +62,8 @@ public:
fill_used = 0;
}
void flush() override = 0; // weiterhin undefiniert aber public
// Methode zur Ausgabe des Pufferinhalts der Basisklasse StringBuffer.
void flush() override;
// NOTE: I added this, override put for fixed width
void put(char c) override;
@ -73,30 +71,131 @@ public:
// OPERATOR << : Umwandlung des angegebenen Datentypes in eine
// Zeichenkette.
// NOTE: I changed the stream manipulators to templates to be usable with different streams
// Needed because I added manipulators to the CGA_Stream class
// Darstellung eines Zeichens (trivial)
OutStream& operator<<(char c);
OutStream& operator<<(unsigned char c);
template<typename T>
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>
friend T& operator<<(T& os, unsigned char c) {
return os << (char)c;
}
// Darstellung einer nullterminierten Zeichenkette
OutStream& operator<<(char* string);
template<typename T>
friend T& operator<<(T& os, char* string) {
// Darstellung ganzer Zahlen im Zahlensystem zur Basis base
OutStream& operator<<(short ival);
OutStream& operator<<(unsigned short ival);
OutStream& operator<<(int ival);
OutStream& operator<<(unsigned int ival);
OutStream& operator<<(long ival);
OutStream& operator<<(unsigned long ival);
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>
friend T& operator<<(T& os, short ival) {
return os << (long)ival;
}
template<typename T>
friend T& operator<<(T& os, unsigned short ival) {
return os << (unsigned long)ival;
}
template<typename T>
friend T& operator<<(T& os, int ival) {
return os << (long)ival;
}
template<typename T>
friend T& operator<<(T& os, unsigned int ival) {
return os << (unsigned long)ival;
}
template<typename T>
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>
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
OutStream& operator<<(void* ptr);
// NOTE: I added this
OutStream& operator<<(const fillw&);
OutStream& operator<<(const fillc&);
template<typename T>
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
OutStream& operator<<(OutStream& (*f)(OutStream&));
// NOTE: Changed the function pointer type including the manipulator functions
template<typename T>
friend T& operator<<(T& os, T& (*f)(T&)) {
return f(os);
}
// NOTE: I added this
template<typename T>
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>
friend T& operator<<(T& os, const fillc& c) {
os.flush();
os.fill_char = c.c;
return os;
}
};
//
@ -110,18 +209,39 @@ public:
// zu beeinflussen, z.B durch die Wahl des Zahlensystems.
// Zeilenumbruch in Ausgabe einfuegen.
OutStream& endl(OutStream& os);
template<typename T>
T& endl(T& os) {
os << '\n';
os.flush();
return os;
}
// Waehle binaeres Zahlensystem aus.
OutStream& bin(OutStream& os);
template<typename T>
T& bin(T& os) {
os.base = 2;
return os;
}
// Waehle oktales Zahlensystem aus.
OutStream& oct(OutStream& os);
template<typename T>
T& oct(T& os) {
os.base = 8;
return os;
}
// Waehle dezimales Zahlensystem aus.
OutStream& dec(OutStream& os);
template<typename T>
T& dec(T& os) {
os.base = 10;
return os;
}
// Waehle hexadezimales Zahlensystem aus.
OutStream& hex(OutStream& os);
template<typename T>
T& hex(T& os) {
os.base = 16;
return os;
}
#endif

View File

@ -21,12 +21,10 @@ int main() {
// Bildschirm loeschen.
kout.clear();
// TODO: Startmeldung ausgeben
// text_demo();
text_demo();
// sound_demo();
keyboard_demo();
while (1);
while (1) {};
return 0;
}

View File

@ -13,10 +13,10 @@
void text_demo() {
/* Hier muess Code eingefuegt werden */
kout << "Attribut (GREEN on WHITE, blinking): "
<< (unsigned short)kout.attribute(CGA::WHITE, CGA::GREEN, true) << endl
<< "Attribut (WHITE on BLACK, no blink): "
<< (unsigned short)kout.attribute(CGA::BLACK, CGA::WHITE, false) << endl
kout << "Attribut (GREEN on WHITE): "
<< bgc(CGA::WHITE) << fgc(CGA::GREEN) << "GREEN on WHITE" << endl
<< "Attribut (WHITE on BLACK): "
<< bgc(CGA::BLACK) << fgc(CGA::WHITE) << "WHITE on BLACK" << endl
<< endl;
kout << "Test der Zahlenausgabefunktion:" << endl