Panini 1.4.0
Header-only library for generating C++, written in C++17
Writer.hpp
Go to the documentation of this file.
1/*
2 MIT No Attribution
3
4 Copyright 2021-2023 Mr. Hands
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to
8 deal in the Software without restriction, including without limitation the
9 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 sell copies of the Software, and to permit persons to whom the Software is
11 furnished to do so.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 DEALINGS IN THE SOFTWARE.
20*/
21
22#pragma once
23
24#include "commands/Command.hpp"
27#include "commands/NextLine.hpp"
28#include "data/WriterConfig.hpp"
29
30namespace panini
31{
32
43 class Writer
44 {
45
46 public:
47 virtual ~Writer() = default;
48
54 virtual const WriterConfig& GetConfig() const = 0;
55
62
68 virtual IncludeStyle GetIncludeStyle() const = 0;
69
76 virtual bool IsOnNewLine() const = 0;
77
85 virtual Writer& operator << (const std::string& chunk) = 0;
86
94 virtual Writer& operator << (const char* chunkString) = 0;
95
103 virtual Writer& operator << (const NextLine& command) = 0;
104
112 virtual Writer& operator << (const IndentPush& command) = 0;
113
122 virtual Writer& operator << (const IndentPop& command) = 0;
123
133 virtual Writer& operator << (Command&& command) = 0;
134
139 virtual void SetIsInCommentBlock(bool value) = 0;
140
145 virtual bool IsChanged() const = 0;
146
156 virtual bool Commit(bool force) = 0;
157
158 protected:
162 virtual void Write(const std::string& chunk) = 0;
163
167 virtual void WriteNewLine() = 0;
168
172 virtual bool OnCommit(bool force = false) = 0;
173
174 };
175
182 template <typename TConfig>
184 : public Writer
185 {
186
187 static_assert(std::is_base_of<WriterConfig, TConfig>::value, "TConfig must inherit from WriterConfig");
188
189 public:
193 inline explicit ConfiguredWriter(const TConfig& config = TConfig{})
194 : m_config(config)
195 {
196 // reserve cached strings
197
198 const size_t indentReserveSize = 8 * m_config.chunkIndent.size();
199 m_lineIndentCached.reserve(indentReserveSize);
200 m_commentIndentCached.reserve(indentReserveSize);
201
202 // inherit is not allowed on the config
203
204 if (m_config.braceBreakingStyle == BraceBreakingStyle::Inherit)
205 {
206 TConfig defaultConfig;
207 m_config.braceBreakingStyle = defaultConfig.braceBreakingStyle;
208 }
209
210 if (m_config.includeStyle == IncludeStyle::Inherit)
211 {
212 WriterConfig defaultConfig;
213 m_config.includeStyle = defaultConfig.includeStyle;
214 }
215 }
216
217 virtual ~ConfiguredWriter() = default;
218
224 inline const WriterConfig& GetConfig() const override
225 {
226 return static_cast<const WriterConfig&>(m_config);
227 }
228
238 {
239 return m_config.braceBreakingStyle;
240 }
241
250 inline IncludeStyle GetIncludeStyle() const override
251 {
252 return m_config.includeStyle;
253 }
254
261 inline bool IsOnNewLine() const override
262 {
263 return m_state == State::NewLine;
264 }
265
273 inline Writer& operator << (const std::string& chunk) override
274 {
275 if (m_state == State::NewLine)
276 {
277 if (!m_lineIndentCached.empty())
278 {
279 Write(m_lineIndentCached);
280 }
281 else
282 {
283 // allow writers to act on new lines
284
285 Write("");
286 }
287
288 m_state = State::Chunk;
289
290 if (m_isInCommentBlock)
291 {
292 Write(" * ");
293
294 if (!m_commentIndentCached.empty())
295 {
296 Write(m_commentIndentCached);
297 }
298 }
299 }
300
301 Write(chunk);
302
303 m_lineChunkCountWritten += chunk.size();
304
305 return *this;
306 }
307
315 inline Writer& operator << (const char* chunkString) override
316 {
317 return *this << std::string(chunkString);
318 }
319
327 inline Writer& operator << (const NextLine& command) override
328 {
329 (void)command;
330
331 // edge-case for empty lines within a comment block
332
333 if (m_isInCommentBlock &&
334 m_lineChunkCountWritten == 0)
335 {
336 Write(" *");
337 }
338
339 WriteNewLine();
340
341 m_state = State::NewLine;
342
343 m_lineChunkCountWritten = 0;
344
345 return *this;
346 }
347
355 inline Writer& operator << (const IndentPush& command) override
356 {
357 (void)command;
358
359 if (!m_isInCommentBlock)
360 {
361 CacheIndentation(m_lineIndentCached, ++m_lineIndentCount);
362 }
363 else
364 {
365 CacheIndentation(m_commentIndentCached, ++m_commentIndentCount);
366 }
367
368 return *this;
369 }
370
379 inline Writer& operator << (const IndentPop& command) override
380 {
381 (void)command;
382
383 if (!m_isInCommentBlock)
384 {
385 if (m_lineIndentCount > 0)
386 {
387 CacheIndentation(
388 m_lineIndentCached,
389 --m_lineIndentCount
390 );
391 }
392 }
393 else
394 {
395 if (m_commentIndentCount > 0)
396 {
397 CacheIndentation(
398 m_commentIndentCached,
399 --m_commentIndentCount
400 );
401 }
402 }
403
404 return *this;
405 }
406
416 inline Writer& operator << (Command&& command) override
417 {
418 command.Visit(*this);
419
420 return *this;
421 }
422
427 inline void SetIsInCommentBlock(bool value) override
428 {
429 m_isInCommentBlock = value;
430
431 m_commentIndentCount = 0;
432 m_commentIndentCached.clear();
433 }
434
439 inline virtual bool IsChanged() const override
440 {
441 return false;
442 }
443
453 inline bool Commit(bool force = false) override
454 {
455 return (force || IsChanged()) && OnCommit(force);
456 }
457
458 protected:
462 void WriteNewLine() override
463 {
464 Write(m_config.chunkNewLine);
465 }
466
467 protected:
468 TConfig m_config;
469
470 private:
474 inline void CacheIndentation(std::string& target, int32_t count)
475 {
476 target.clear();
477
478 for (int32_t i = 0; i < count; ++i)
479 {
480 target += m_config.chunkIndent;
481 }
482 }
483
484 private:
485 size_t m_lineChunkCountWritten = 0;
486
487 int32_t m_lineIndentCount = 0;
488 std::string m_lineIndentCached;
489
490 enum class State
491 {
492 NewLine,
493 Chunk
494 };
495 State m_state = State::NewLine;
496
497 bool m_isInCommentBlock = false;
498 int32_t m_commentIndentCount = 0;
499 std::string m_commentIndentCached;
500
501 };
502
505
506};
Base class for commands.
Definition: Command.hpp:44
Base class implementation for writers.
Definition: Writer.hpp:185
IncludeStyle GetIncludeStyle() const override
Definition: Writer.hpp:250
virtual bool IsChanged() const override
Definition: Writer.hpp:439
void SetIsInCommentBlock(bool value) override
Definition: Writer.hpp:427
bool Commit(bool force=false) override
Definition: Writer.hpp:453
BraceBreakingStyle GetBraceBreakingStyle() const override
Definition: Writer.hpp:237
virtual ~ConfiguredWriter()=default
Writer & operator<<(const std::string &chunk) override
Definition: Writer.hpp:273
const WriterConfig & GetConfig() const override
Definition: Writer.hpp:224
ConfiguredWriter(const TConfig &config=TConfig{})
Definition: Writer.hpp:193
bool IsOnNewLine() const override
Definition: Writer.hpp:261
void WriteNewLine() override
Definition: Writer.hpp:462
TConfig m_config
Definition: Writer.hpp:468
Pure virtual interface for writers.
Definition: Writer.hpp:44
virtual bool OnCommit(bool force=false)=0
virtual void SetIsInCommentBlock(bool value)=0
virtual bool IsOnNewLine() const =0
virtual void WriteNewLine()=0
virtual Writer & operator<<(const std::string &chunk)=0
virtual const WriterConfig & GetConfig() const =0
virtual ~Writer()=default
virtual bool Commit(bool force)=0
virtual IncludeStyle GetIncludeStyle() const =0
virtual BraceBreakingStyle GetBraceBreakingStyle() const =0
virtual void Write(const std::string &chunk)=0
virtual bool IsChanged() const =0
BraceBreakingStyle
Brace breaking style to use when writing to output.
Definition: BraceBreakingStyle.hpp:34
IncludeStyle
Include style to use when writing to output.
Definition: IncludeStyle.hpp:36
@ Inherit
Inherit setting from the config, not valid on Writer.
@ Inherit
Inherit setting from the config, not valid on Writer.
Definition: Braces.hpp:29
Command for decrementing the indentation level on the writer.
Definition: IndentPop.hpp:36
Command for incrementing the indentation level on the writer.
Definition: IndentPush.hpp:36
Command for outtputing a new line chunk.
Definition: NextLine.hpp:36
Global configuration applied to writers.
Definition: WriterConfig.hpp:39