Created
March 9, 2016 20:52
-
-
Save 421p/12cba2f84a26db868428 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Hello world! application | |
* | |
* \file hello.cpp | |
*/ | |
#include <iostream> | |
#include <vector> | |
#include <algorithm> | |
#include <functional> | |
#include <cassert> | |
/*! | |
* Dispay message. | |
*/ | |
void displayMessage(); | |
/*! | |
* Sentence type | |
* | |
* Type of sentence, used to decide how to terminate sentence. | |
*/ | |
enum ESentenceType { | |
eStatement, | |
eExclamation, | |
sQuestion, | |
eCommand | |
}; | |
/*! | |
* Utility class to prevent unintended copying of class instances. | |
*/ | |
class nonCopyable { | |
protected: | |
nonCopyable() { | |
} | |
~nonCopyable() { | |
} | |
private: | |
nonCopyable(const nonCopyable&); | |
const nonCopyable& operator=(const nonCopyable&); | |
}; | |
/*! | |
* Utility function to obtain punctuation mark to end sentence | |
* of specified type. | |
*/ | |
inline char getPunctionMark(ESentenceType sentenceType) { | |
char puncMark = '.'; | |
switch(sentenceType) { | |
case eStatement : puncMark = '.'; break; | |
case eExclamation: puncMark = '!'; break; | |
case sQuestion : puncMark = '?'; break; | |
case eCommand : puncMark = '.'; break; | |
default: { | |
// should never get here | |
assert(false); | |
} | |
} | |
return puncMark; | |
} | |
/*! | |
* Utility class for creation of instances. | |
*/ | |
template<typename TElem> | |
class Creatable { | |
protected: | |
Creatable() { | |
} | |
virtual ~Creatable() { | |
clear(); | |
} | |
public: | |
static TElem* create() { | |
TElem* e = new TElem; | |
return e; | |
} | |
void free() { | |
delete this; | |
} | |
virtual void clear() { | |
} | |
}; | |
template<typename TElem, typename TParam> | |
class CreatableParam { | |
protected: | |
CreatableParam() { | |
} | |
virtual ~CreatableParam() { | |
} | |
public: | |
static TElem* create(TParam p) { | |
TElem* e = new TElem; | |
e->initialize(p); | |
return e; | |
} | |
void free() { | |
finalize(); | |
delete this; | |
} | |
virtual void initialize(TParam /*p*/) { | |
} | |
virtual void finalize() { | |
clear(); | |
} | |
virtual void clear() { | |
} | |
}; | |
/*! | |
* Base class for displayable content | |
*/ | |
class DisplayElem | |
: public nonCopyable { | |
protected: | |
DisplayElem() { | |
} | |
virtual ~DisplayElem() { | |
} | |
public: | |
virtual void display(std::ostream& os) const = 0; | |
}; | |
/*! | |
* STL algorithm for displaying elements | |
*/ | |
class Displayer | |
: public std::unary_function<void, const DisplayElem*> { | |
private: | |
std::ostream& m_os; | |
char m_sep; | |
size_t m_count; | |
public: | |
Displayer(std::ostream& os, char sep = '\0') | |
: m_os(os) | |
, m_sep(sep) | |
, m_count(0) { | |
} | |
~Displayer() { | |
} | |
void operator()(const DisplayElem* e) { | |
if(('\0' != m_sep) && (0 < m_count)) { | |
m_os << m_sep; | |
} | |
e->display(m_os); | |
++m_count; | |
} | |
}; | |
/*! | |
* STL algorithm for freeing display elements | |
*/ | |
template <typename TElem> | |
class Freer | |
: public std::unary_function<void, TElem*> { | |
public: | |
void operator()(TElem* e) { | |
e->free(); | |
} | |
}; | |
/*! | |
* Display element for letter. | |
* | |
* The letter is the fundamental element: it has no substructure. | |
*/ | |
class Letter | |
: public DisplayElem | |
, public CreatableParam<Letter, char> { | |
private: | |
char m_ch; | |
protected: | |
/*virtual*/ ~Letter() { | |
} | |
public: | |
Letter() : m_ch('\0') { | |
} | |
void initialize(char ch) { | |
m_ch = ch; | |
} | |
void finalize() { | |
m_ch = '\0'; | |
} | |
void display(std::ostream& os) const { | |
os << m_ch; | |
// no endLetter() | |
} | |
}; | |
/*! | |
* Display element for word. | |
* | |
* A word is a sequence of letters. | |
*/ | |
class Word | |
: public DisplayElem | |
, public Creatable<Word> { | |
private: | |
std::vector<Letter*> m_letters; | |
protected: | |
/*virtual*/ ~Word() { | |
clear(); | |
} | |
public: | |
Word() { | |
} | |
void clear() { | |
std::for_each(m_letters.begin(), m_letters.end(), Freer<Letter>()); | |
m_letters.clear(); | |
} | |
void addLetter(Letter* s) { | |
m_letters.push_back(s); | |
} | |
/*virtual*/ void display(std::ostream& os) const { | |
std::for_each(m_letters.begin(), m_letters.end(), Displayer(os)); | |
// no endLetter() | |
} | |
}; | |
/*! | |
* Display element for sentence. | |
* | |
* A sentence is a sequence of words. | |
*/ | |
class Sentence | |
: public DisplayElem | |
, public CreatableParam<Sentence, ESentenceType> { | |
private: | |
std::vector<Word*> m_words; | |
ESentenceType m_sentenceType; | |
protected: | |
/*virtual*/ ~Sentence() { | |
clear(); | |
} | |
void endSentence(std::ostream& os) const { | |
const char puncMark = getPunctionMark(m_sentenceType); | |
os << puncMark; | |
} | |
public: | |
Sentence() | |
: m_sentenceType(eStatement) { | |
} | |
void initialize(ESentenceType sentenceType) { | |
m_sentenceType = sentenceType; | |
} | |
void finalize() { | |
m_sentenceType = eStatement; | |
} | |
void clear() { | |
std::for_each(m_words.begin(), m_words.end(), Freer<Word>()); | |
m_words.clear(); | |
} | |
void addWord(Word* w) { | |
m_words.push_back(w); | |
} | |
void display(std::ostream& os) const { | |
std::for_each(m_words.begin(), m_words.end(), Displayer(os, ' ')); | |
endSentence(os); | |
} | |
}; | |
/*! | |
* Display element for message. | |
* | |
* A message is a sequence of sentences. | |
*/ | |
class Message | |
: public DisplayElem | |
, public Creatable<Message> { | |
private: | |
std::vector<Sentence*> m_sentences; | |
protected: | |
/*virtual*/ ~Message() { | |
clear(); | |
} | |
void endMessage(std::ostream& os) const { | |
os << std::endl; | |
} | |
public: | |
Message() { | |
} | |
void clear() { | |
std::for_each(m_sentences.begin(), m_sentences.end(), Freer<Sentence>()); | |
m_sentences.clear(); | |
} | |
void addSentence(Sentence* s) { | |
m_sentences.push_back(s); | |
} | |
void display(std::ostream& os) const { | |
std::for_each(m_sentences.begin(), m_sentences.end(), Displayer(os, ' ')); | |
endMessage(os); | |
} | |
}; | |
/*! | |
* Main entrance point. | |
*/ | |
int main() { | |
displayMessage(); | |
return 0; | |
} | |
/*! | |
* Display message. | |
*/ | |
void displayMessage() { | |
Word* first_word = Word::create(); | |
first_word->addLetter(Letter::create('H')); | |
first_word->addLetter(Letter::create('e')); | |
first_word->addLetter(Letter::create('l')); | |
first_word->addLetter(Letter::create('l')); | |
first_word->addLetter(Letter::create('o')); | |
Word* second_word = Word::create(); | |
second_word->addLetter(Letter::create('w')); | |
second_word->addLetter(Letter::create('o')); | |
second_word->addLetter(Letter::create('r')); | |
second_word->addLetter(Letter::create('l')); | |
second_word->addLetter(Letter::create('d')); | |
Sentence* sentence = Sentence::create(eExclamation); | |
sentence->addWord(first_word); | |
sentence->addWord(second_word); | |
Message* message = Message::create(); | |
message->addSentence(sentence); | |
message->display(std::cout); | |
message->free(); | |
// sentences, etc freed by parent | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment