Design Pattern Examples
Overview of object-oriented design patterns
State_Class.cpp
Go to the documentation of this file.
1
10
11#include <iostream>
12#include <stdexcept>
13#include <exception>
14#include <map>
15#include <memory>
16#include <sstream>
17
18#include "helpers/formatstring.h"
19
20#include "State_Class.h"
21
22namespace // Anonymous
23{
24 using namespace DesignPatternExamples_cpp;
25
32 std::string _CurrentStateToString(CurrentState state)
33 {
34 std::string stateAsString;
35
36 switch (state)
37 {
38 case CurrentState::Initial:
39 stateAsString = "Initial";
40 break;
41
42 case CurrentState::NormalText:
43 stateAsString = "NormalText";
44 break;
45
46 case CurrentState::DoubleQuotedText:
47 stateAsString = "DoubleQuotedText";
48 break;
49
50 case CurrentState::SingleQuotedText:
51 stateAsString = "SingleQuotedText";
52 break;
53
54 case CurrentState::EscapedDoubleQuoteText:
55 stateAsString = "EscapedDoubleQuoteText";
56 break;
57
58 case CurrentState::EscapedSingleQuoteText:
59 stateAsString = "EscapedSingleQuoteText";
60 break;
61
62 case CurrentState::StartComment:
63 stateAsString = "StartComment";
64 break;
65
66 case CurrentState::LineComment:
67 stateAsString = "LineComment";
68 break;
69
70 case CurrentState::BlockComment:
71 stateAsString = "BlockComment";
72 break;
73
74 case CurrentState::EndBlockComment:
75 stateAsString = "EndBlockComment";
76 break;
77
78 case CurrentState::Done:
79 stateAsString = "Done";
80 break;
81
82 default:
83 stateAsString = Helpers::formatstring("Unknown (%d)", static_cast<int>(state));
84 break;
85 }
86
87
88 return stateAsString;
89 }
90
91
92 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
93 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
94 // State class definitions
95 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
96 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
97
98
108 class State_NormalText : public IStateBehavior
109 {
110 public:
121 {
123 char character = context->GetNextCharacter();
124
125 switch (character)
126 {
127 case EOF_CHAR:
128 nextState = CurrentState::Done;
129 break;
130
131 case '"':
132 context->OutputCharacter(character);
134 break;
135
136 case '\'':
137 context->OutputCharacter(character);
139 break;
140
141 case '/':
142 nextState = CurrentState::StartComment;
143 break;
144
145 default:
146 context->OutputCharacter(character);
147 break;
148 }
149
150 return nextState;
151 }
152 };
153
154
155 //########################################################################
156 //########################################################################
157
158
169 {
170 public:
181 {
183
184 char character = context->GetNextCharacter();
185
186 switch (character)
187 {
188 case EOF_CHAR:
189 nextState = CurrentState::Done;
190 break;
191
192 case '"':
193 context->OutputCharacter(character);
194 nextState = CurrentState::NormalText;
195 break;
196
197 case '\\':
198 context->OutputCharacter(character);
200 break;
201
202 default:
203 context->OutputCharacter(character);
204 break;
205 }
206
207 return nextState;
208 }
209 };
210
211
212 //########################################################################
213 //########################################################################
214
215
226 {
237 {
239
240 char character = context->GetNextCharacter();
241
242 switch (character)
243 {
244 case EOF_CHAR:
245 nextState = CurrentState::Done;
246 break;
247
248 case '\'':
249 context->OutputCharacter(character);
250 nextState = CurrentState::NormalText;
251 break;
252
253 case '\\':
254 context->OutputCharacter(character);
256 break;
257
258 default:
259 context->OutputCharacter(character);
260 break;
261 }
262
263 return nextState;
264 }
265 };
266
267
268 //########################################################################
269 //########################################################################
270
271
283 {
294 {
296
297 char character = context->GetNextCharacter();
298
299 switch (character)
300 {
301 case EOF_CHAR:
302 nextState = CurrentState::Done;
303 break;
304
305 default:
306 context->OutputCharacter(character);
307 break;
308 }
309
310 return nextState;
311 }
312 };
313
314
315 //########################################################################
316 //########################################################################
317
318
330 {
341 {
343
344 char character = context->GetNextCharacter();
345
346 switch (character)
347 {
348 case EOF_CHAR:
349 nextState = CurrentState::Done;
350 break;
351
352 default:
353 context->OutputCharacter(character);
354 break;
355 }
356
357 return nextState;
358 }
359 };
360
361
362 //########################################################################
363 //########################################################################
364
365
376 {
387 {
389
390 char character = context->GetNextCharacter();
391
392 switch (character)
393 {
394 case EOF_CHAR:
395 nextState = CurrentState::Done;
396 break;
397
398 case '/':
399 nextState = CurrentState::LineComment;
400 break;
401
402 case '*':
403 nextState = CurrentState::BlockComment;
404 break;
405
406 default:
407 // Not the start of a comment so output the leading slash
408 // that led to the state followed by the character we just
409 // processed.
410 context->OutputCharacter('/');
411 context->OutputCharacter(character);
412 nextState = CurrentState::NormalText;
413 break;
414 }
415
416 return nextState;
417 }
418 };
419
420
421 //########################################################################
422 //########################################################################
423
424
432 class State_LineComment : public IStateBehavior
433 {
444 {
446
447 char character = context->GetNextCharacter();
448
449 switch (character)
450 {
451 case EOF_CHAR:
452 nextState = CurrentState::Done;
453 break;
454
455 case '\n':
456 context->OutputCharacter(character);
457 nextState = CurrentState::NormalText;
458 break;
459
460 default:
461 // We are in a comment to be removed, so do nothing here.
462 break;
463 }
464
465 return nextState;
466 }
467 };
468
469
470 //########################################################################
471 //########################################################################
472
473
482 {
493 {
495
496 char character = context->GetNextCharacter();
497
498 switch (character)
499 {
500 case EOF_CHAR:
501 nextState = CurrentState::Done;
502 break;
503
504 case '*':
506 break;
507
508 default:
509 // We are in a comment to be removed, so do nothing here.
510 break;
511 }
512
513 return nextState;
514 }
515 };
516
517
518 //########################################################################
519 //########################################################################
520
521
531 {
542 {
544
545 char character = context->GetNextCharacter();
546
547 switch (character)
548 {
549 case EOF_CHAR:
550 nextState = CurrentState::Done;
551 break;
552
553 case '/':
554 nextState = CurrentState::NormalText;
555 break;
556
557 default:
558 // We are still in a block comment to be removed, so do nothing here.
559 break;
560 }
561
562 return nextState;
563 }
564 };
565
566
567 //########################################################################
568 //########################################################################
569
570
577 class State_Done : public IStateBehavior
578 {
585 CurrentState GoNext(IStateContext* /*context*/)
586 {
587 // Do nothing (Yes! Another Null Object example!)
588 return CurrentState::Done;
589 }
590 };
591
592
593 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
594 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
595 // State class factory definition
596 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
597 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
598
599
603 class State_Factory
604 {
605 public:
612 static IStateBehavior::shared_ptr_t CreateState(CurrentState state)
613 {
614 IStateBehavior::shared_ptr_t stateBehavior;
615 switch (state)
616 {
617 case CurrentState::NormalText:
618 stateBehavior = std::make_shared<State_NormalText>();
619 break;
620
621 case CurrentState::DoubleQuotedText:
622 stateBehavior = std::make_shared<State_DoubleQuotedText>();
623 break;
624
625 case CurrentState::SingleQuotedText:
626 stateBehavior = std::make_shared<State_SingleQuotedText>();
627 break;
628
629 case CurrentState::EscapedDoubleQuoteText:
630 stateBehavior = std::make_shared<State_EscapedDoubleQuoteText>();
631 break;
632
633 case CurrentState::EscapedSingleQuoteText:
634 stateBehavior = std::make_shared<State_EscapedSingleQuoteText>();
635 break;
636
637 case CurrentState::StartComment:
638 stateBehavior = std::make_shared<State_StartComment>();
639 break;
640
641 case CurrentState::LineComment:
642 stateBehavior = std::make_shared<State_LineComment>();
643 break;
644
645 case CurrentState::BlockComment:
646 stateBehavior = std::make_shared<State_BlockComment>();
647 break;
648
649 case CurrentState::EndBlockComment:
650 stateBehavior = std::make_shared<State_EndBlockComment>();
651 break;
652
653 case CurrentState::Done:
654 stateBehavior = std::make_shared<State_Done>();
655 break;
656
657 default:
658 {
659 std::string msg = Helpers::formatstring("Unknown state: %s. Cannot create a state class.",
660 _CurrentStateToString(state).c_str());
661 throw std::runtime_error(msg.c_str());
662 }
663 }
664
665 return stateBehavior;
666 }
667 };
668
669
670 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
671 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
672 // State Context implementation class definition
673 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
674 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
675
676
685 class StateContext_ClassImpl : public IStateContext
686 {
687 private:
691 std::string _inputText;
692
696 size_t _textIndex;
697
701 std::ostringstream _outputText;
702
703 using StateMapping = std::map<CurrentState, IStateBehavior::shared_ptr_t>;
704
709 StateMapping _stateBehaviors;
710
714 CurrentState _currentState;
715
720 IStateBehavior::shared_ptr_t _currentStateBehavior;
721
722
723 private:
724 //--------------------------------------------------------------------
725 // StateContext_Class implementation.
726 //--------------------------------------------------------------------
727
736 void _SetNextState(CurrentState newState)
737
738 {
739 if (newState != _currentState)
740 {
741 StateMapping::const_iterator foundIter = _stateBehaviors.find(newState);
742
743 if (foundIter == std::cend(_stateBehaviors))
744 {
745 _stateBehaviors[newState] = State_Factory::CreateState(newState);
746 }
747
748 std::cout
749 << Helpers::formatstring(" --> State Transition: %s -> %s",
750 _CurrentStateToString(_currentState).c_str(),
751 _CurrentStateToString(newState).c_str())
752 << std::endl;
753
754 _currentStateBehavior = _stateBehaviors[newState];
755 _currentState = newState;
756 }
757 }
758
759
760 public:
764 StateContext_ClassImpl()
765 : _textIndex(0)
766 , _currentState(CurrentState::Initial)
767 {
768 }
769
770
771 //--------------------------------------------------------------------
772 // StateContext_Class public entry points.
773 //--------------------------------------------------------------------
774
781 std::string RemoveComments(std::string text)
782 {
783 _inputText = text;
784 _textIndex = 0;
785 _outputText.str("");
786 _outputText.clear();
787 _currentState = CurrentState::Initial;
788 _SetNextState(CurrentState::NormalText);
789
790 while (_currentState != CurrentState::Done)
791 {
792 CurrentState nextState = _currentStateBehavior->GoNext(this);
793 _SetNextState(nextState);
794 }
795
796 return _outputText.str();
797 }
798
799
800 //--------------------------------------------------------------------
801 // IStateContext interface implementation.
802 //--------------------------------------------------------------------
803
809 char GetNextCharacter()
810 {
811 char character = EOF_CHAR;
812
813 if (_textIndex < _inputText.size())
814 {
815 character = _inputText[_textIndex];
816 ++_textIndex;
817 }
818 return character;
819 }
820
825 void OutputCharacter(char character)
826 {
827 if (character != EOF_CHAR)
828 {
829 _outputText << character;
830 }
831 }
832 };
833
834}
835
836
839
840
842{
843 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
844 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
845 // State Context public class definition
846 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
847 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
848
849
851 : _stateContextimpl(std::make_unique<StateContext_ClassImpl>())
852 {
853 }
854
855
856 std::string StateContext_Class::RemoveComments(std::string text)
857 {
858 StateContext_ClassImpl* stateImpl = dynamic_cast<StateContext_ClassImpl*>(_stateContextimpl.get());
859 if (stateImpl != nullptr)
860 {
861 return stateImpl->RemoveComments(text);
862 }
863 return std::string();
864 }
865
866} // end namespace
Declaration of the IStateContext and IStateBehavior interfaces, as well as the StateContext_Class cla...
@ State_Done
Indicates processing is done.
@ State_StartComment
/ transitions to LineComment, * transitions to BlockComment, EOF_CHAR transitions to Done,...
@ State_NormalText
" transitions to QuotedText, / transitions to StartComment, EOF_CHAR transitions to Done
@ State_BlockComment
* transitions to EndBlockComment, EOF_CHAR transitions to Done
@ State_EscapedSingleQuoteText
\ transitions to SingleQuotedText, EOF_CHAR transitions to Done
@ State_DoubleQuotedText
\ transitions to EscapedDoubleQuoteText, " transitions to NormalText, EOF_CHAR transitions to Done
@ State_EscapedDoubleQuoteText
\ transitions to QuotedText, EOF_CHAR transitions to Done
@ State_EndBlockComment
/ transitions to NormalText, EOF_CHAR transitions to Done, all else transitions to BlockComment
@ State_SingleQuotedText
' transitions to EscapedSingleQuoteText, \ transitions to NormalText, EOF_CHAR transitions to Done
@ State_LineComment
\n transitions to NormalText, EOF_CHAR transitions to Done
static bool _SetNextState(StateContext *context, CurrentState newState)
Helper method to transition the state machine to the specified state. Does nothing if the new state i...
static const char * _CurrentStateToString(CurrentState state)
Convert the CurrentState enumeration to a string for output purposes.
std::string RemoveComments(std::string text)
Entry point for callers to filter text. Removes C++-style line and block comments from the text.
std::unique_ptr< IStateContext > _stateContextimpl
Pointer to the actual implementation.
Definition: State_Class.h:144
The namespace containing all Design Pattern Examples implemented in C++.
const char EOF_CHAR
Indicates End-of-file (no more data available).
Definition: State_Class.h:47
CurrentState
Represents the current state of the state machine.
Definition: State_Class.h:23
@ SingleQuotedText
‘’` transitions to EscapedSingleQuoteText, \ transitions to NormalText, EOF_CHAR transitions to Done
Definition: State_Class.h:27
@ DoubleQuotedText
\ transitions to EscapedDoubleQuoteText, " transitions to NormalText, EOF_CHAR transitions to Done
Definition: State_Class.h:26
@ BlockComment
* transitions to EndBlockComment, EOF_CHAR transitions to Done
Definition: State_Class.h:32
@ Initial
State before the state machine actually starts. transitions to NormalText.
Definition: State_Class.h:24
@ EndBlockComment
/ transitions to NormalText, EOF_CHAR transitions to Done, all else transitions to BlockComment
Definition: State_Class.h:33
@ LineComment
\\n transitions to NormalText, EOF_CHAR transitions to Done
Definition: State_Class.h:31
@ Done
Indicates processing is done.
Definition: State_Class.h:34
@ StartComment
/ transitions to LineComment, * transitions to BlockComment, EOF_CHAR transitions to Done,...
Definition: State_Class.h:30
@ NormalText
" transitions to QuotedText, / transitions to StartComment, EOF_CHAR transitions to Done
Definition: State_Class.h:25
@ EscapedDoubleQuoteText
\ transitions to QuotedText, EOF_CHAR transitions to Done
Definition: State_Class.h:28
@ EscapedSingleQuoteText
\ transitions to SingleQuotedText, EOF_CHAR transitions to Done
Definition: State_Class.h:29
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....
Represents a class that implements one state of the state machine.
Definition: State_Class.h:103
std::shared_ptr< IStateBehavior > shared_ptr_t
Alias to make using a shared pointer easier.
Definition: State_Class.h:107
virtual CurrentState GoNext(IStateContext *context)=0
Represents the context as passed to each state class.
Definition: State_Class.h:61
virtual void OutputCharacter(char character)=0
Write the character to the context-> This is how the parser accumulates the filtered text.
virtual char GetNextCharacter()=0
Get the next character from the input.