1//! @file behavioral.cpp
2//! @author ryftchen
3//! @brief The definitions (behavioral) in the data structure module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#include "behavioral.hpp"
8
9#include <algorithm>
10#include <iomanip>
11
12namespace design_pattern::behavioral
13{
14//! @brief Function version number.
15//! @return version number (major.minor.patch)
16const char* version() noexcept
17{
18 static const char* const ver = "0.1.0";
19 return ver;
20}
21
22namespace chain_of_responsibility
23{
24void Handler::setHandler(std::shared_ptr<Handler> handler)
25{
26 successor = std::move(handler);
27}
28
29void Handler::handleRequest()
30{
31 if (successor)
32 {
33 successor->handleRequest();
34 }
35}
36
37void ConcreteHandler1::handleRequest()
38{
39 if (canHandle())
40 {
41 output() << "handled by concrete handler 1\n";
42 }
43 else
44 {
45 output() << "cannot be handled by handler 1\n";
46 Handler::handleRequest();
47 }
48}
49
50bool ConcreteHandler1::canHandle() const // NOLINT(readability-convert-member-functions-to-static)
51{
52 return false;
53}
54
55void ConcreteHandler2::handleRequest()
56{
57 if (canHandle())
58 {
59 output() << "handled by handler 2\n";
60 }
61 else
62 {
63 output() << "cannot be handled by handler 2\n";
64 Handler::handleRequest();
65 }
66}
67
68bool ConcreteHandler2::canHandle() const // NOLINT(readability-convert-member-functions-to-static)
69{
70 return true;
71}
72
73//! @brief Output stream for the chain of responsibility pattern. Need to be cleared manually.
74//! @return reference of the output stream object, which is on string based
75std::ostringstream& output() noexcept
76{
77 static std::ostringstream process{};
78 return process;
79}
80} // namespace chain_of_responsibility
81
82namespace command
83{
84void Receiver::action() const // NOLINT(readability-convert-member-functions-to-static)
85{
86 output() << "receiver: execute action\n";
87}
88
89void ConcreteCommand::execute()
90{
91 receiver->action();
92}
93
94void Invoker::set(std::shared_ptr<Command> c)
95{
96 command = std::move(c);
97}
98
99void Invoker::confirm()
100{
101 if (command)
102 {
103 command->execute();
104 }
105}
106
107//! @brief Output stream for the command pattern. Need to be cleared manually.
108//! @return reference of the output stream object, which is on string based
109std::ostringstream& output() noexcept
110{
111 static std::ostringstream process{};
112 return process;
113}
114} // namespace command
115
116namespace interpreter
117{
118void Context::set(const std::string& expr, const bool val)
119{
120 vars.emplace(args: expr, args: val);
121}
122
123bool Context::get(const std::string& expr)
124{
125 return vars.at(k: expr);
126}
127
128bool AbstractExpression::interpret(const std::shared_ptr<Context>& /*context*/)
129{
130 return false;
131}
132
133bool TerminalExpression::interpret(const std::shared_ptr<Context>& context)
134{
135 return context->get(expr: value);
136}
137
138bool NonTerminalExpression::interpret(const std::shared_ptr<Context>& context)
139{
140 return leftOp->interpret(context) && rightOp->interpret(context);
141}
142
143//! @brief Output stream for the interpreter pattern. Need to be cleared manually.
144//! @return reference of the output stream object, which is on string based
145std::ostringstream& output() noexcept
146{
147 static std::ostringstream process{};
148 return process;
149}
150} // namespace interpreter
151
152namespace iterator
153{
154ConcreteAggregate::ConcreteAggregate(const std::uint32_t size) : count{size}
155{
156 list = std::make_unique<int[]>(num: size);
157 std::fill_n(first: list.get(), n: size, value: 1);
158}
159
160std::shared_ptr<Iterator> ConcreteAggregate::createIterator()
161{
162 return std::make_shared<ConcreteIterator>(args: shared_from_this());
163}
164
165std::uint32_t ConcreteAggregate::size() const
166{
167 return count;
168}
169
170int ConcreteAggregate::at(const std::uint32_t index)
171{
172 return list[index];
173}
174
175void ConcreteIterator::first()
176{
177 index = 0;
178}
179
180void ConcreteIterator::next()
181{
182 ++index;
183}
184
185bool ConcreteIterator::isDone() const
186{
187 return index >= aggregate->size();
188}
189
190int ConcreteIterator::currentItem() const
191{
192 return isDone() ? -1 : aggregate->at(index);
193}
194
195//! @brief Output stream for the iterator pattern. Need to be cleared manually.
196//! @return reference of the output stream object, which is on string based
197std::ostringstream& output() noexcept
198{
199 static std::ostringstream process{};
200 return process;
201}
202} // namespace iterator
203
204namespace mediator
205{
206void ConcreteMediator::add(const std::shared_ptr<Colleague>& colleague)
207{
208 colleagues.emplace_back(args: colleague);
209}
210
211void ConcreteMediator::distribute(const std::shared_ptr<Colleague>& sender, const std::string_view msg)
212{
213 std::ranges::for_each(
214 colleagues,
215 [&sender, &msg](const auto& colleague)
216 {
217 if (const auto c = colleague.lock(); c && (c->getId() != sender->getId()))
218 {
219 c->receive(msg);
220 }
221 });
222}
223
224std::uint32_t Colleague::getId() const
225{
226 return id;
227}
228
229void ConcreteColleague::send(const std::string_view msg)
230{
231 output() << "message " << std::quoted(sv: msg) << " sent by colleague " << id << '\n';
232 mediator.lock()->distribute(sender: shared_from_this(), msg);
233}
234
235void ConcreteColleague::receive(const std::string_view msg)
236{
237 output() << "message " << std::quoted(sv: msg) << " received by colleague " << id << '\n';
238}
239
240//! @brief Output stream for the mediator pattern. Need to be cleared manually.
241//! @return reference of the output stream object, which is on string based
242std::ostringstream& output() noexcept
243{
244 static std::ostringstream process{};
245 return process;
246}
247} // namespace mediator
248
249namespace memento
250{
251void Memento::setState(const int s)
252{
253 state = s;
254}
255
256int Memento::getState() const
257{
258 return state;
259}
260
261void Originator::setState(const int s)
262{
263 output() << "set state to " << s << '\n';
264 state = s;
265}
266
267int Originator::getState() const
268{
269 return state;
270}
271
272void Originator::setMemento(const std::shared_ptr<Memento>& memento)
273{
274 state = memento->getState();
275}
276
277std::shared_ptr<Memento> Originator::createMemento() const
278{
279 return std::shared_ptr<Memento>(::new Memento(state));
280}
281
282void CareTaker::save()
283{
284 output() << "save state\n";
285 history.emplace_back(args: originator->createMemento());
286}
287
288void CareTaker::undo()
289{
290 if (history.empty())
291 {
292 output() << "unable to undo state\n";
293 return;
294 }
295
296 std::shared_ptr<Memento> memento = history.back();
297 originator->setMemento(memento);
298 output() << "undo state\n";
299
300 history.pop_back();
301 memento.reset();
302}
303
304//! @brief Output stream for the memento pattern. Need to be cleared manually.
305//! @return reference of the output stream object, which is on string based
306std::ostringstream& output() noexcept
307{
308 static std::ostringstream process{};
309 return process;
310}
311} // namespace memento
312
313namespace observer
314{
315void Subject::attach(const std::shared_ptr<Observer>& observer)
316{
317 observers.emplace_back(args: observer);
318}
319
320void Subject::detach(const int index)
321{
322 observers.erase(position: observers.cbegin() + index);
323}
324
325void Subject::notify()
326{
327 std::ranges::for_each(
328 observers,
329 [this](const auto& observer)
330 {
331 if (const auto obs = observer.lock())
332 {
333 obs->update(weak_from_this());
334 }
335 });
336}
337
338int ConcreteObserver::getState() const
339{
340 return observerState;
341}
342
343void ConcreteObserver::update(const std::weak_ptr<Subject>& subject)
344{
345 if (const auto sub = subject.lock())
346 {
347 observerState = sub->getState();
348 output() << "observer state updated\n";
349 }
350}
351
352int ConcreteSubject::getState() const
353{
354 return subjectState;
355}
356
357void ConcreteSubject::setState(const int s)
358{
359 subjectState = s;
360}
361
362//! @brief Output stream for the observer pattern. Need to be cleared manually.
363//! @return reference of the output stream object, which is on string based
364std::ostringstream& output() noexcept
365{
366 static std::ostringstream process{};
367 return process;
368}
369} // namespace observer
370
371namespace state
372{
373void ConcreteStateA::handle()
374{
375 output() << "state A handled\n";
376}
377
378void ConcreteStateB::handle()
379{
380 output() << "state B handled\n";
381}
382
383void Context::setState(std::unique_ptr<State> s)
384{
385 state = std::move(s);
386}
387
388void Context::request()
389{
390 state->handle();
391}
392
393//! @brief Output stream for the state pattern. Need to be cleared manually.
394//! @return reference of the output stream object, which is on string based
395std::ostringstream& output() noexcept
396{
397 static std::ostringstream process{};
398 return process;
399}
400} // namespace state
401
402namespace strategy
403{
404void ConcreteStrategyA::algorithmInterface()
405{
406 output() << "concrete strategy A\n";
407}
408
409void ConcreteStrategyB::algorithmInterface()
410{
411 output() << "concrete strategy B\n";
412}
413
414void Context::contextInterface()
415{
416 strategy->algorithmInterface();
417}
418
419//! @brief Output stream for the strategy pattern. Need to be cleared manually.
420//! @return reference of the output stream object, which is on string based
421std::ostringstream& output() noexcept
422{
423 static std::ostringstream process{};
424 return process;
425}
426} // namespace strategy
427
428namespace template_method
429{
430void AbstractClass::templateMethod()
431{
432 primitiveOperation1();
433 primitiveOperation2();
434}
435
436void ConcreteClass::primitiveOperation1()
437{
438 output() << "primitive operation 1\n";
439}
440
441void ConcreteClass::primitiveOperation2()
442{
443 output() << "primitive operation 2\n";
444}
445
446//! @brief Output stream for the template method pattern. Need to be cleared manually.
447//! @return reference of the output stream object, which is on string based
448std::ostringstream& output() noexcept
449{
450 static std::ostringstream process{};
451 return process;
452}
453} // namespace template_method
454
455namespace visitor
456{
457void ConcreteVisitor1::visitElementA(const std::shared_ptr<ConcreteElementA>& /*element*/)
458{
459 output() << "concrete visitor 1: element A visited\n";
460}
461
462void ConcreteVisitor1::visitElementB(const std::shared_ptr<ConcreteElementB>& /*element*/)
463{
464 output() << "concrete visitor 1: element B visited\n";
465}
466
467void ConcreteVisitor2::visitElementA(const std::shared_ptr<ConcreteElementA>& /*element*/)
468{
469 output() << "concrete visitor 2: element A visited\n";
470}
471
472void ConcreteVisitor2::visitElementB(const std::shared_ptr<ConcreteElementB>& /*element*/)
473{
474 output() << "concrete visitor 2: element B visited\n";
475}
476
477void ConcreteElementA::accept(Visitor& visitor)
478{
479 visitor.visitElementA(element: shared_from_this());
480}
481
482void ConcreteElementB::accept(Visitor& visitor)
483{
484 visitor.visitElementB(element: shared_from_this());
485}
486
487//! @brief Output stream for the visitor pattern. Need to be cleared manually.
488//! @return reference of the output stream object, which is on string based
489std::ostringstream& output() noexcept
490{
491 static std::ostringstream process{};
492 return process;
493}
494} // namespace visitor
495} // namespace design_pattern::behavioral
496