// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Core/Types/String.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Core/NonCopyable.h" #include "Engine/Platform/StringUtils.h" /// /// Helper class to fast ANSI text processing (tokenization, reading, streaming etc.) /// class FLAXENGINE_API TextProcessing : public NonCopyable { public: /// /// Separator structure /// struct SeparatorData { public: char C0; char C1; public: SeparatorData() : C0(0) , C1(0) { } SeparatorData(char c0) : C0(c0) , C1(0) { } SeparatorData(char c0, char c1) : C0(c0) , C1(c1) { } SeparatorData(const SeparatorData& other) : C0(other.C0) , C1(other.C1) { } public: bool IsWhiteSpace() const { return *this == SeparatorData('\r', '\n') || *this == SeparatorData('\n') || *this == SeparatorData('\t') || *this == SeparatorData(' '); } public: bool operator==(const SeparatorData& other) const { return C0 == other.C0 && C1 == other.C1; } bool operator!=(const SeparatorData& other) const { return C0 != other.C0 || C1 != other.C1; } }; /// /// Token structure /// struct Token { public: const char* Start; int32 Length; SeparatorData Separator; public: Token() : Start(nullptr) , Length(0) , Separator() { } explicit Token(const char* text) : Start(text) , Length(StringUtils::Length(text)) , Separator() { } explicit Token(const StringAnsi& text) : Start(text.Get()) , Length(text.Length()) , Separator() { } Token(const char* text, int32 length) : Start(text) , Length(length) , Separator() { } Token(const char* text, int32 length, const SeparatorData& separator) : Start(text) , Length(length) , Separator(separator) { } Token(const Token& other) : Start(other.Start) , Length(other.Length) , Separator(other.Separator) { } /*Token& operator=(const Token& other) const { return Token(other); }*/ public: StringAnsi ToString() const { return StringAnsi(Start, Length); } public: FORCE_INLINE bool Equals(const Token& other) const { return Equals(other.Start, other.Length); } FORCE_INLINE bool Equals(const char* text) const { return Equals(text, StringUtils::Length(text)); } bool Equals(const char* text, int32 length) const { return Length == length && StringUtils::Compare(Start, text, Length) == 0; } public: FORCE_INLINE bool EqualsIgnoreCase(const Token& other) const { return EqualsIgnoreCase(other.Start, other.Length); } FORCE_INLINE bool EqualsIgnoreCase(const char* text) const { return EqualsIgnoreCase(text, StringUtils::Length(text)); } bool EqualsIgnoreCase(const char* text, int32 length) const { return Length == length && StringUtils::CompareIgnoreCase(Start, text, Length) == 0; } public: FORCE_INLINE bool operator==(const char* text) const { auto token = Token(text); return Equals(token); } FORCE_INLINE bool operator==(const Token& other) const { return Equals(other); } FORCE_INLINE bool operator!=(const Token& other) const { return !Equals(other); } }; private: const char* _buffer; int32 _length; char* _cursor; int32 _position; int32 _line; public: /// /// Init /// /// Input ANSI text buffer to process /// Input data length TextProcessing(const char* input, int32 length); public: /// /// Array with all token separators /// Array Separators; /// /// /// Array with all white characters /// Array Whitespaces; public: /// /// Set separators and white chars for HLSL language /// void Setup_HLSL(); public: /// /// Returns true if there are still characters in the buffer and can read data from it /// /// True if can read data, otherwise false FORCE_INLINE bool CanRead() const { return _position < _length; } /// /// Peeks single character without moving forward in the buffer /// /// First character FORCE_INLINE char PeekChar() const { return *_cursor; } /// /// Gets current line number /// /// Current line number FORCE_INLINE int32 GetLine() const { return _line; } public: /// /// Read single character from the buffer /// /// Character char ReadChar(); /// /// Read all whitespace chars like spaces, tabs, new lines /// void EatWhiteSpaces(); /// /// Reads next token /// /// Output token void ReadToken(Token* token); /// /// Read whole line until new line char '\n' /// /// Read token void ReadLine(Token* token); /// /// Read whole line until new line char '\n' /// void ReadLine(); private: char moveForward(); char moveBack(); };