From 2de37d3a45ccb6cb291891b8aa55baedac3284be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Tue, 26 May 2020 05:48:22 -0300 Subject: [PATCH] More improvements to the UICodeEditor and TextDocument. Improved the SyntaxHighligther. --- README.md | 2 + include/eepp/core/string.hpp | 4 +- include/eepp/ui/doc/syntaxhighlighter.hpp | 12 +- include/eepp/ui/doc/textdocument.hpp | 72 +- include/eepp/ui/uicodeeditor.hpp | 7 + projects/linux/ee.creator.user | 2 +- src/eepp/core/string.cpp | 9 +- src/eepp/ui/doc/syntaxhighlighter.cpp | 55 +- src/eepp/ui/doc/textdocument.cpp | 65 +- src/eepp/ui/uicodeeditor.cpp | 84 +- src/thirdparty/crc/CRC.h | 1705 +++++++++++++++++++++ src/tools/codeeditor/codeeditor.cpp | 71 +- 12 files changed, 1986 insertions(+), 102 deletions(-) create mode 100644 src/thirdparty/crc/CRC.h diff --git a/README.md b/README.md index f62aa68ee..742c41e77 100644 --- a/README.md +++ b/README.md @@ -614,6 +614,8 @@ Probably deprecate the Maps module, since I will focus my efforts on the UI syst * Jason Perkins for [premake](https://premake.github.io/) +* Daniel Bahr for [CRC++](https://github.com/d-bahr/CRCpp) + * Martín Lucas Golini ( me ) and all the several contributors for [SOIL2](https://github.com/SpartanJ/SOIL2) and [efsw](https://github.com/SpartanJ/efsw) * The Xiph open source community for [libogg](https://xiph.org/ogg/) and [libvorbis](https://xiph.org/vorbis/) diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 66d66743a..cd616c07d 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -449,7 +449,7 @@ class EE_API String { ** @param index Index of the character to get ** @return Character at position \a index **/ - StringBaseType operator[]( std::size_t index ) const; + const StringBaseType& operator[]( std::size_t index ) const; /** @brief Overload of [] operator to access a character by its position ** This function provides read and write access to characters. @@ -465,7 +465,7 @@ class EE_API String { *actual position in the string. ** @return The character at position pos in the string. */ - StringBaseType at( std::size_t index ) const; + const StringBaseType& at( std::size_t index ) const; /** @brief clear the string ** This function removes all the characters from the string. diff --git a/include/eepp/ui/doc/syntaxhighlighter.hpp b/include/eepp/ui/doc/syntaxhighlighter.hpp index d6e48be3e..5472ba0dd 100644 --- a/include/eepp/ui/doc/syntaxhighlighter.hpp +++ b/include/eepp/ui/doc/syntaxhighlighter.hpp @@ -9,7 +9,7 @@ namespace EE { namespace UI { namespace Doc { struct TokenizedLine { int initState; - String text; + Uint32 hash; std::vector tokens; int state; }; @@ -20,11 +20,21 @@ class EE_API SyntaxHighlighter { void reset(); + void invalidate( Int64 lineIndex ); + const std::vector& getLine( const size_t& index ); + Int64 getFirstInvalidLine() const; + + Int64 getMaxWantedLine() const; + + bool updateDirty( int visibleLinesCount = 40 ); + protected: TextDocument* mDoc; std::map mLines; + Int64 mFirstInvalidLine; + Int64 mMaxWantedLine; TokenizedLine tokenizeLine( const size_t& line, const int& state ); }; diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 15f58c16a..3e803a3fb 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -16,6 +16,63 @@ using namespace EE::System; namespace EE { namespace UI { namespace Doc { +class EE_API TextDocumentLine { + public: + TextDocumentLine( const String& text ) : mText( text ) { updateHash(); } + + void setText( const String& text ) { + mText = text; + updateHash(); + } + + const String& getText() const { return mText; } + + void operator=( const std::string& right ) { setText( right ); } + + String::StringBaseType operator[]( std::size_t index ) const { return mText[index]; } + + void insertChar( const unsigned int& pos, const String::StringBaseType& tchar ) { + mText.insert( mText.begin() + pos, tchar ); + updateHash(); + } + + void append( const String& text ) { + mText.append( text ); + updateHash(); + } + + void append( const String::StringBaseType& code ) { + mText.append( code ); + updateHash(); + } + + String substr( std::size_t pos = 0, std::size_t n = String::StringType::npos ) const { + return mText.substr( pos, n ); + } + + String::Iterator insert( String::Iterator p, const String::StringBaseType& c ) { + auto it = mText.insert( p, c ); + updateHash(); + return it; + } + + bool empty() const { return mText.empty(); } + + size_t size() const { return mText.size(); } + + size_t length() const { return mText.length(); } + + const Uint32& getHash() const { return mHash; } + + std::string toUtf8() const { return mText.toUtf8(); } + + protected: + String mText; + Uint32 mHash; + + void updateHash() { mHash = mText.getHash(); } +}; + class EE_API TextDocument { public: class EE_API Client { @@ -26,6 +83,7 @@ class EE_API TextDocument { virtual void onDocumentSelectionChange( const TextRange& ) = 0; virtual void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount ) = 0; + virtual void onDocumentLineChanged( const Int64& lineIndex ) = 0; }; enum IndentType { IndentSpaces, IndentTabs }; @@ -56,13 +114,13 @@ class EE_API TextDocument { const TextRange& getSelection() const; - String& line( const size_t& index ); + TextDocumentLine& line( const size_t& index ); - const String& line( const size_t& index ) const; + const TextDocumentLine& line( const size_t& index ) const; size_t linesCount() const; - std::vector& lines(); + std::vector& lines(); bool hasSelection() const; @@ -219,7 +277,7 @@ class EE_API TextDocument { friend class UndoStack; UndoStack mUndoStack; std::string mFilePath; - std::vector mLines; + std::vector mLines; TextRange mSelection; std::unordered_set mClients; bool mIsCLRF{false}; @@ -241,9 +299,11 @@ class EE_API TextDocument { void notifyLineCountChanged( const size_t& lastCount, const size_t& newCount ); - void insertAtStartOfSelectedLines( String text, bool skipEmpty ); + void notifyLineChanged( const Int64& lineIndex ); - void removeFromStartOfSelectedLines( String text, bool skipEmpty ); + void insertAtStartOfSelectedLines( const String& text, bool skipEmpty ); + + void removeFromStartOfSelectedLines( const String& text, bool skipEmpty ); void remove( TextRange range, UndoStackContainer& undoStack, const Time& time ); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 200360f66..02f3fab52 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -112,6 +112,10 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { virtual Float getColXOffset( TextPosition position ); + const bool& isLocked() const; + + void setLocked( bool locked ); + protected: struct LastXOffset { TextPosition position; @@ -126,6 +130,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { bool mCursorVisible; bool mMouseDown; bool mShowLineNumber; + bool mLocked; Uint32 mTabWidth; Int64 mLastColOffset; Vector2f mScroll; @@ -176,6 +181,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount ); + void onDocumentLineChanged( const Int64& lineIndex ); + std::pair getVisibleLineRange(); int getVisibleLinesCount(); diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index ed26a2da4..5c22a656d 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 817654ef7..b0e60cdd0 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -4,6 +4,9 @@ #include #include #include +#include + +static CRC::Table CRC_TABLE(CRC::CRC_32()); namespace EE { @@ -29,7 +32,7 @@ Uint32 String::hash( const std::string& str ) { } Uint32 String::hash( const String& str ) { - return String::hash( (const Uint8*)str.c_str() ); + return CRC::Calculate( (void*)str.c_str(), sizeof(StringBaseType)*str.size(), CRC_TABLE ); } bool String::isCharacter( const int& value ) { @@ -594,7 +597,7 @@ String& String::operator+=( const StringBaseType& right ) { return *this; } -String::StringBaseType String::operator[]( std::size_t index ) const { +const String::StringBaseType& String::operator[]( std::size_t index ) const { return mString[index]; } @@ -602,7 +605,7 @@ String::StringBaseType& String::operator[]( std::size_t index ) { return mString[index]; } -String::StringBaseType String::at( std::size_t index ) const { +const String::StringBaseType& String::at( std::size_t index ) const { return mString.at( index ); } diff --git a/src/eepp/ui/doc/syntaxhighlighter.cpp b/src/eepp/ui/doc/syntaxhighlighter.cpp index 17b244af0..8206f7d88 100644 --- a/src/eepp/ui/doc/syntaxhighlighter.cpp +++ b/src/eepp/ui/doc/syntaxhighlighter.cpp @@ -3,29 +3,37 @@ namespace EE { namespace UI { namespace Doc { -SyntaxHighlighter::SyntaxHighlighter( TextDocument* doc ) : mDoc( doc ) { +SyntaxHighlighter::SyntaxHighlighter( TextDocument* doc ) : + mDoc( doc ), mFirstInvalidLine( 0 ), mMaxWantedLine( 0 ) { reset(); } void SyntaxHighlighter::reset() { mLines.clear(); + mFirstInvalidLine = 0; + mMaxWantedLine = 0; +} + +void SyntaxHighlighter::invalidate( Int64 lineIndex ) { + mFirstInvalidLine = lineIndex; + mMaxWantedLine = eemin( mMaxWantedLine, (Int64)mDoc->linesCount() - 1 ); } TokenizedLine SyntaxHighlighter::tokenizeLine( const size_t& line, const int& state ) { TokenizedLine tokenizedLine; tokenizedLine.initState = state; - tokenizedLine.text = mDoc->line( line ); + tokenizedLine.hash = mDoc->line( line ).getHash(); std::pair, int> res = SyntaxTokenizer::tokenize( - mDoc->getSyntaxDefinition(), tokenizedLine.text.toUtf8(), state ); + mDoc->getSyntaxDefinition(), mDoc->line( line ).toUtf8(), state ); tokenizedLine.tokens = std::move( res.first ); tokenizedLine.state = std::move( res.second ); return tokenizedLine; } const std::vector& SyntaxHighlighter::getLine( const size_t& index ) { - auto it = mLines.find( index ); + const auto& it = mLines.find( index ); if ( it == mLines.end() || - ( index < mDoc->linesCount() && mDoc->line( index ) != it->second.text ) ) { + ( index < mDoc->linesCount() && mDoc->line( index ).getHash() != it->second.hash ) ) { int prevState = SYNTAX_TOKENIZER_STATE_NONE; if ( index > 0 ) { auto prevIt = mLines.find( index - 1 ); @@ -36,7 +44,44 @@ const std::vector& SyntaxHighlighter::getLine( const size_t& index mLines[index] = tokenizeLine( index, prevState ); return mLines[index].tokens; } + mMaxWantedLine = eemax( mMaxWantedLine, index ); return it->second.tokens; } +Int64 SyntaxHighlighter::getFirstInvalidLine() const { + return mFirstInvalidLine; +} + +Int64 SyntaxHighlighter::getMaxWantedLine() const { + return mMaxWantedLine; +} + +bool SyntaxHighlighter::updateDirty( int visibleLinesCount ) { + if ( mFirstInvalidLine > mMaxWantedLine ) { + mMaxWantedLine = 0; + } else { + bool changed = false; + Int64 max = eemin( mFirstInvalidLine + visibleLinesCount, mMaxWantedLine ); + + for ( Int64 index = mFirstInvalidLine; index <= max; index++ ) { + int state = SYNTAX_TOKENIZER_STATE_NONE; + if ( index > 0 ) { + auto prevIt = mLines.find( index - 1 ); + if ( prevIt != mLines.end() ) { + state = prevIt->second.state; + } + } + const auto& it = mLines.find( index ); + if ( it != mLines.end() && it->second.initState != state ) { + mLines[index] = tokenizeLine( index, state ); + changed = true; + } + } + + mFirstInvalidLine = max + 1; + return changed; + } + return false; +} + }}} // namespace EE::UI::Doc diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 6a8b7a81d..4e4ae5daf 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -62,13 +62,13 @@ void TextDocument::loadFromPath( const std::string& path ) { line = line.substr( 0, line.size() - 1 ); mIsCLRF = true; } - mLines.emplace_back( String( line + "\n" ) ); + mLines.emplace_back( TextDocumentLine( line + "\n" ) ); } if ( mLines.empty() ) { - mLines.emplace_back( String( "\n" ) ); + mLines.emplace_back( TextDocumentLine( "\n" ) ); } else if ( mLines[mLines.size() - 1][mLines[mLines.size() - 1].size() - 1] != '\n' ) { - mLines[mLines.size() - 1] += '\n'; + mLines[mLines.size() - 1].append( '\n' ); } } @@ -93,9 +93,8 @@ bool TextDocument::save( IOStreamFile& stream, const bool& utf8bom ) { } size_t lastLine = mLines.size() - 1; for ( size_t i = 0; i <= lastLine; i++ ) { - String& line = mLines[i]; - std::string utf8( line.toUtf8() ); - if ( i == lastLine && line.size() > 1 ) { + std::string utf8( mLines[i].toUtf8() ); + if ( i == lastLine && utf8.size() > 1 && utf8[utf8.size() - 1] == '\n' ) { // Last \n is added by the document but it's not part of the document. utf8.pop_back(); } @@ -160,11 +159,11 @@ const TextRange& TextDocument::getSelection() const { return mSelection; } -String& TextDocument::line( const size_t& index ) { +TextDocumentLine& TextDocument::line( const size_t& index ) { return mLines[index]; } -const String& TextDocument::line( const size_t& index ) const { +const TextDocumentLine& TextDocument::line( const size_t& index ) const { return mLines[index]; } @@ -172,7 +171,7 @@ size_t TextDocument::linesCount() const { return mLines.size(); } -std::vector& TextDocument::lines() { +std::vector& TextDocument::lines() { return mLines; } @@ -188,7 +187,7 @@ String TextDocument::getText( const TextRange& range ) const { } std::vector lines = {mLines[nrange.start().line()].substr( nrange.start().column() )}; for ( auto i = nrange.start().line() + 1; i <= nrange.end().line() - 1; i++ ) { - lines.emplace_back( mLines[i] ); + lines.emplace_back( mLines[i].getText() ); } lines.emplace_back( mLines[nrange.end().line()].substr( 0, nrange.end().column() ) ); return String::join( lines, -1 ); @@ -240,27 +239,30 @@ TextPosition TextDocument::insert( TextPosition position, const String::StringBa for ( size_t i = position.column(); i < line( row ).length(); i++ ) line_content.append( line( row )[i] ); mLines.insert( mLines.begin() + position.line() + ( atTail ? 1 : 0 ), String( "\n" ) ); + notifyLineChanged( position.line() ); return atTail ? TextPosition( position.line() + 1, line( position.line() + 1 ).length() ) : TextPosition( position.line() + 1, 0 ); } - String newLine = - line( position.line() ) - .substr( position.column(), line( position.line() ).length() - position.column() ); - String& oldLine = line( position.line() ); - oldLine = line( position.line() ).substr( 0, position.column() ); + TextDocumentLine newLine( line( position.line() ) + .substr( position.column(), line( position.line() ).length() - + position.column() ) ); + TextDocumentLine& oldLine = line( position.line() ); + oldLine.setText( line( position.line() ).substr( 0, position.column() ) ); // TODO: Investigate why this is needed when undo is used. // This fixes the case when a line ends up without an \n at the end of it. if ( oldLine.empty() || oldLine[oldLine.size() - 1] != '\n' ) { - oldLine += '\n'; + oldLine.append( '\n' ); } if ( newLine.empty() || newLine[newLine.size() - 1] != '\n' ) { - newLine += '\n'; + newLine.append( '\n' ); } mLines.insert( mLines.begin() + position.line() + 1, std::move( newLine ) ); + notifyLineChanged( position.line() ); return {position.line() + 1, 0}; } - line( position.line() ).insert( line( position.line() ).begin() + position.column(), ch ); + line( position.line() ).insertChar( position.column(), ch ); + notifyLineChanged( position.line() ); return {position.line(), position.column() + 1}; } @@ -295,7 +297,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const if ( range.start().line() == range.end().line() ) { // Delete within same line. - String& line = this->line( range.start().line() ); + TextDocumentLine& line = this->line( range.start().line() ); bool wholeLineIsSelected = range.start().column() == 0 && range.end().column() == (Int64)line.length(); @@ -313,13 +315,13 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const if ( afterSelection.empty() || afterSelection[afterSelection.size() - 1] != '\n' ) afterSelection += '\n'; - line.assign( beforeSelection + afterSelection ); + line.setText( beforeSelection + afterSelection ); } } else { // Delete across a newline, merging lines. eeASSERT( range.start().line() == range.end().line() - 1 ); - auto& firstLine = line( range.start().line() ); - auto& secondLine = line( range.end().line() ); + TextDocumentLine& firstLine = line( range.start().line() ); + TextDocumentLine& secondLine = line( range.end().line() ); auto beforeSelection = firstLine.substr( 0, range.start().column() ); auto afterSelection = !secondLine.empty() ? secondLine.substr( range.end().column(), @@ -331,7 +333,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const if ( afterSelection.empty() || afterSelection[afterSelection.size() - 1] != '\n' ) afterSelection += '\n'; - firstLine.assign( beforeSelection + afterSelection ); + firstLine.setText( beforeSelection + afterSelection ); mLines.erase( mLines.begin() + range.end().line() ); } @@ -339,6 +341,7 @@ void TextDocument::remove( TextRange range, UndoStackContainer& undoStack, const mLines.emplace_back( String( "\n" ) ); } notifyTextChanged(); + notifyLineChanged( range.start().line() ); } TextPosition TextDocument::positionOffset( TextPosition position, int columnOffset ) const { @@ -647,7 +650,7 @@ void TextDocument::newLine() { String input( "\n" ); TextPosition start = getSelection().start(); if ( start.line() >= 0 && start.line() < (Int64)mLines.size() ) { - String& ln = line( start.line() ); + const String& ln = line( start.line() ).getText(); size_t to = eemin( ln.size(), start.column() ); int indent = 0; for ( size_t i = 0; i < to; i++ ) { @@ -664,12 +667,12 @@ void TextDocument::newLine() { textInput( input ); } -void TextDocument::insertAtStartOfSelectedLines( String text, bool skipEmpty ) { +void TextDocument::insertAtStartOfSelectedLines( const String& text, bool skipEmpty ) { TextPosition prevStart = getSelection().start(); TextRange range = getSelection( true ); bool swap = prevStart != range.start(); for ( auto i = range.start().line(); i <= range.end().line(); i++ ) { - const String& line = this->line( i ); + const String& line = this->line( i ).getText(); if ( !skipEmpty || line.length() != 1 ) { insert( {i, 0}, text ); } @@ -678,12 +681,12 @@ void TextDocument::insertAtStartOfSelectedLines( String text, bool skipEmpty ) { TextPosition( range.end().line(), range.end().column() + text.size() ), swap ); } -void TextDocument::removeFromStartOfSelectedLines( String text, bool skipEmpty ) { +void TextDocument::removeFromStartOfSelectedLines( const String& text, bool skipEmpty ) { TextPosition prevStart = getSelection().start(); TextRange range = getSelection( true ); bool swap = prevStart != range.start(); for ( auto i = range.start().line(); i <= range.end().line(); i++ ) { - const String& line = this->line( i ); + const String& line = this->line( i ).getText(); if ( !skipEmpty || line.length() != 1 ) { if ( line.substr( 0, text.length() ) == text ) { remove( {{i, 0}, {i, static_cast( text.length() )}} ); @@ -814,6 +817,12 @@ void TextDocument::notifyLineCountChanged( const size_t& lastCount, const size_t } } +void TextDocument::notifyLineChanged( const Int64& lineIndex ) { + for ( auto& client : mClients ) { + client->onDocumentLineChanged( lineIndex ); + } +} + TextDocument::Client::~Client() {} }}} // namespace EE::UI::Doc diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index bd95624a6..04227ec07 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -23,6 +23,7 @@ UICodeEditor::UICodeEditor() : mCursorVisible( false ), mMouseDown( false ), mShowLineNumber( true ), + mLocked( false ), mTabWidth( 4 ), mLastColOffset( 0 ), mMouseWheelScroll( 50 ), @@ -95,10 +96,12 @@ void UICodeEditor::draw() { Primitives primitives; TextPosition cursor( mDoc.getSelection().start() ); - primitives.setColor( mCurrentLineBackgroundColor ); - primitives.drawRectangle( - Rectf( Vector2f( startScroll.x + mScroll.x, startScroll.y + cursor.line() * lineHeight ), - Sizef( mSize.getWidth(), lineHeight ) ) ); + if ( !mLocked ) { + primitives.setColor( mCurrentLineBackgroundColor ); + primitives.drawRectangle( Rectf( + Vector2f( startScroll.x + mScroll.x, startScroll.y + cursor.line() * lineHeight ), + Sizef( mSize.getWidth(), lineHeight ) ) ); + } if ( mDoc.hasSelection() ) { primitives.setColor( mFontStyleConfig.getFontSelectionBackColor() ); @@ -109,7 +112,7 @@ void UICodeEditor::draw() { int endLine = eemin( lineRange.second, selection.end().line() ); for ( auto ln = startLine; ln <= endLine; ln++ ) { - const String& line = mDoc.line( ln ); + const String& line = mDoc.line( ln ).getText(); Rectf selRect; selRect.Top = startScroll.y + ln * lineHeight; selRect.Bottom = selRect.Top + lineHeight; @@ -137,21 +140,23 @@ void UICodeEditor::draw() { for ( int i = lineRange.first; i <= lineRange.second; i++ ) { Vector2f curPos( startScroll.x, startScroll.y + lineHeight * i ); auto& tokens = mHighlighter.getLine( i ); - Text line( "", mFont, charSize ); - line.setStyleConfig( mFontStyleConfig ); for ( auto& token : tokens ) { Float textWidth = getTextWidth( token.text ); if ( curPos.x + textWidth >= mScreenPos.x && curPos.x <= mScreenPos.x + mSize.getWidth() ) { + Text line( "", mFont, charSize ); + line.setStyleConfig( mFontStyleConfig ); line.setString( token.text ); line.setColor( mColorScheme.getColor( token.type ) ); line.draw( curPos.x, curPos.y ); + } else if ( curPos.x > mScreenPos.x + mSize.getWidth() ) { + break; } curPos.x += textWidth; } } - if ( mCursorVisible ) { + if ( mCursorVisible && !mLocked ) { Vector2f cursorPos( startScroll.x + getXOffsetCol( cursor ), startScroll.y + cursor.line() * lineHeight ); @@ -188,6 +193,10 @@ void UICodeEditor::scheduledUpdate( const Time& ) { mMouseDown = false; getUISceneNode()->getWindow()->getInput()->captureMouse( false ); } + + if ( mHighlighter.updateDirty( getVisibleLinesCount() ) ) { + invalidateDraw(); + } } void UICodeEditor::reset() { @@ -391,7 +400,7 @@ Uint32 UICodeEditor::onFocusLoss() { } Uint32 UICodeEditor::onTextInput( const TextInputEvent& event ) { - if ( NULL == mFont ) + if ( mLocked || NULL == mFont ) return 1; if ( !getUISceneNode()->getWindow()->getInput()->isControlPressed() ) { @@ -404,6 +413,14 @@ Uint32 UICodeEditor::onKeyDown( const KeyEvent& event ) { if ( NULL == mFont ) return 1; + // Allow copy selection on locked mode + if ( mLocked ) { + if ( event.getKeyCode() == KEY_C && ( event.getMod() & KEYMOD_CTRL ) ) { + getUISceneNode()->getWindow()->getClipboard()->setText( mDoc.getSelectedText() ); + } + return 1; + } + switch ( event.getKeyCode() ) { case KEY_BACKSPACE: { if ( event.getMod() & KEYMOD_CTRL ) { @@ -662,7 +679,7 @@ Uint32 UICodeEditor::onMouseUp( const Vector2i& position, const Uint32& flags ) } Uint32 UICodeEditor::onMouseDoubleClick( const Vector2i&, const Uint32& flags ) { - if ( NULL == mFont ) + if ( !mLocked || NULL == mFont ) return 1; if ( flags & EE_BUTTON_LMASK ) { @@ -672,7 +689,7 @@ Uint32 UICodeEditor::onMouseDoubleClick( const Vector2i&, const Uint32& flags ) } Uint32 UICodeEditor::onMouseOver( const Vector2i& position, const Uint32& flags ) { - getUISceneNode()->setCursor( Cursor::IBeam ); + getUISceneNode()->setCursor( !mLocked ? Cursor::IBeam : Cursor::Arrow ); return UIWidget::onMouseOver( position, flags ); } @@ -728,6 +745,10 @@ void UICodeEditor::onDocumentLineCountChange( const size_t&, const size_t& ) { updateScrollBar(); } +void UICodeEditor::onDocumentLineChanged( const Int64& lineIndex ) { + mHighlighter.invalidate( lineIndex ); +} + std::pair UICodeEditor::getVisibleLineRange() { Float lineHeight = getLineHeight(); Float minLine = eemax( 0.f, eefloor( mScroll.y / lineHeight ) ); @@ -775,7 +796,7 @@ void UICodeEditor::setScrollY( const Float& val, bool emmitEvent ) { } Float UICodeEditor::getXOffsetCol( const TextPosition& position ) const { - const String& line = mDoc.line( position.line() ); + const String& line = mDoc.line( position.line() ).getText(); Float glyphWidth = getGlyphWidth(); Float x = 0; for ( auto i = 0; i < position.column(); i++ ) { @@ -792,37 +813,42 @@ Float UICodeEditor::getTextWidth( const String& line ) const { Float glyphWidth = getGlyphWidth(); size_t len = line.length(); Float x = 0; - for ( size_t i = 0; i < len; i++ ) { - if ( line[i] == '\t' ) { - x += glyphWidth * mTabWidth; - } else if ( line[i] != '\n' && line[i] != '\r' ) { - x += glyphWidth; - } - } + for ( size_t i = 0; i < len; i++ ) + x += ( line[i] == '\t' ) ? glyphWidth * mTabWidth : glyphWidth; return x; } Float UICodeEditor::getColXOffset( TextPosition position ) { - position = mDoc.sanitizePosition( position ); + position.setLine( eeclamp( position.line(), 0L, mDoc.linesCount() - 1 ) ); + // This is different from sanitizePosition, sinze allows the last character. + position.setColumn( eeclamp( position.column(), 0L, + eemax( 0, mDoc.line( position.line() ).size() ) ) ); return getTextWidth( mDoc.line( position.line() ).substr( 0, position.column() ) ); } +const bool& UICodeEditor::isLocked() const { + return mLocked; +} + +void UICodeEditor::setLocked( bool locked ) { + if ( mLocked != locked ) { + mLocked = locked; + invalidateDraw(); + } +} + Int64 UICodeEditor::getColFromXOffset( Int64 lineNumber, const Float& offset ) const { if ( offset <= 0 ) return 0; TextPosition pos = mDoc.sanitizePosition( TextPosition( lineNumber, 0 ) ); - const String& line = mDoc.line( pos.line() ); + const String& line = mDoc.line( pos.line() ).getText(); + size_t len = line.length(); Float glyphWidth = getGlyphWidth(); Float x = 0; - for ( size_t i = 0; i < line.size(); i++ ) { - if ( line[i] == '\t' ) { - x += glyphWidth * mTabWidth; - } else if ( line[i] != '\n' && line[i] != '\r' ) { - x += glyphWidth; - } - if ( x >= offset ) { + for ( size_t i = 0; i < len; i++ ) { + x += ( line[i] == '\t' ) ? glyphWidth * mTabWidth : glyphWidth; + if ( x >= offset ) return i; - } } return static_cast( line.size() ) - 1; } diff --git a/src/thirdparty/crc/CRC.h b/src/thirdparty/crc/CRC.h new file mode 100644 index 000000000..3a7dc64d4 --- /dev/null +++ b/src/thirdparty/crc/CRC.h @@ -0,0 +1,1705 @@ +/** + @file CRC.h + @author Daniel Bahr + @version 1.0.1.0 + @copyright + @parblock + CRC++ + Copyright (c) 2020, Daniel Bahr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of CRC++ nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + @endparblock +*/ + +/* + CRC++ can be configured by setting various #defines before #including this header file: + + #define crcpp_uint8 - Specifies the type used to store CRCs that have a width of 8 bits or less. + This type is not used in CRC calculations. Defaults to ::std::uint8_t. + #define crcpp_uint16 - Specifies the type used to store CRCs that have a width between 9 and 16 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint16_t. + #define crcpp_uint32 - Specifies the type used to store CRCs that have a width between 17 and 32 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint32_t. + #define crcpp_uint64 - Specifies the type used to store CRCs that have a width between 33 and 64 bits (inclusive). + This type is not used in CRC calculations. Defaults to ::std::uint64_t. + #define crcpp_size - This type is used for loop iteration and function signatures only. Defaults to ::std::size_t. + #define CRCPP_USE_NAMESPACE - Define to place all CRC++ code within the ::CRCPP namespace. + #define CRCPP_BRANCHLESS - Define to enable a branchless CRC implementation. The branchless implementation uses a single integer + multiplication in the bit-by-bit calculation instead of a small conditional. The branchless implementation + may be faster on processor architectures which support single-instruction integer multiplication. + #define CRCPP_USE_CPP11 - Define to enables C++11 features (move semantics, constexpr, static_assert, etc.). + #define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS - Define to include definitions for little-used CRCs. +*/ + +#ifndef CRCPP_CRC_H_ +#define CRCPP_CRC_H_ + +#include // Includes CHAR_BIT +#ifdef CRCPP_USE_CPP11 +#include // Includes ::std::size_t +#include // Includes ::std::uint8_t, ::std::uint16_t, ::std::uint32_t, ::std::uint64_t +#else +#include // Includes size_t +#include // Includes uint8_t, uint16_t, uint32_t, uint64_t +#endif +#include // Includes ::std::numeric_limits +#include // Includes ::std::move + +#ifndef crcpp_uint8 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint8 ::std::uint8_t +# else + /// @brief Unsigned 8-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint8 uint8_t +# endif +#endif + +#ifndef crcpp_uint16 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint16 ::std::uint16_t +# else + /// @brief Unsigned 16-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint16 uint16_t +# endif +#endif + +#ifndef crcpp_uint32 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint32 ::std::uint32_t +# else + /// @brief Unsigned 32-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint32 uint32_t +# endif +#endif + +#ifndef crcpp_uint64 +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint64 ::std::uint64_t +# else + /// @brief Unsigned 64-bit integer definition, used primarily for parameter definitions. +# define crcpp_uint64 uint64_t +# endif +#endif + +#ifndef crcpp_size +# ifdef CRCPP_USE_CPP11 + /// @brief Unsigned size definition, used for specifying data sizes. +# define crcpp_size ::std::size_t +# else + /// @brief Unsigned size definition, used for specifying data sizes. +# define crcpp_size size_t +# endif +#endif + +#ifdef CRCPP_USE_CPP11 + /// @brief Compile-time expression definition. +# define crcpp_constexpr constexpr +#else + /// @brief Compile-time expression definition. +# define crcpp_constexpr const +#endif + +#ifdef CRCPP_USE_NAMESPACE +namespace CRCPP +{ +#endif + +/** + @brief Static class for computing CRCs. + @note This class supports computation of full and multi-part CRCs, using a bit-by-bit algorithm or a + byte-by-byte lookup table. The CRCs are calculated using as many optimizations as is reasonable. + If compiling with C++11, the constexpr keyword is used liberally so that many calculations are + performed at compile-time instead of at runtime. +*/ +class CRC +{ +public: + // Forward declaration + template + struct Table; + + /** + @brief CRC parameters. + */ + template + struct Parameters + { + CRCType polynomial; ///< CRC polynomial + CRCType initialValue; ///< Initial CRC value + CRCType finalXOR; ///< Value to XOR with the final CRC + bool reflectInput; ///< true to reflect all input bytes + bool reflectOutput; ///< true to reflect the output CRC (reflection occurs before the final XOR) + + Table MakeTable() const; + }; + + /** + @brief CRC lookup table. After construction, the CRC parameters are fixed. + @note A CRC table can be used for multiple CRC calculations. + */ + template + struct Table + { + // Constructors are intentionally NOT marked explicit. + Table(const Parameters & parameters); + +#ifdef CRCPP_USE_CPP11 + Table(Parameters && parameters); +#endif + + const Parameters & GetParameters() const; + + const CRCType * GetTable() const; + + CRCType operator[](unsigned char index) const; + + private: + void InitTable(); + + Parameters parameters; ///< CRC parameters used to construct the table + CRCType table[1 << CHAR_BIT]; ///< CRC lookup table + }; + + // The number of bits in CRCType must be at least as large as CRCWidth. + // CRCType must be an unsigned integer type or a custom type with operator overloads. + template + static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable); + + template + static CRCType Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc); + + // Common CRCs up to 64 bits. + // Note: Check values are the computed CRCs when given an ASCII input of "123456789" (without null terminator) +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters< crcpp_uint8, 4> & CRC_4_ITU(); + static const Parameters< crcpp_uint8, 5> & CRC_5_EPC(); + static const Parameters< crcpp_uint8, 5> & CRC_5_ITU(); + static const Parameters< crcpp_uint8, 5> & CRC_5_USB(); + static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000A(); + static const Parameters< crcpp_uint8, 6> & CRC_6_CDMA2000B(); + static const Parameters< crcpp_uint8, 6> & CRC_6_ITU(); + static const Parameters< crcpp_uint8, 7> & CRC_7(); +#endif + static const Parameters< crcpp_uint8, 8> & CRC_8(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters< crcpp_uint8, 8> & CRC_8_EBU(); + static const Parameters< crcpp_uint8, 8> & CRC_8_MAXIM(); + static const Parameters< crcpp_uint8, 8> & CRC_8_WCDMA(); + static const Parameters & CRC_10(); + static const Parameters & CRC_10_CDMA2000(); + static const Parameters & CRC_11(); + static const Parameters & CRC_12_CDMA2000(); + static const Parameters & CRC_12_DECT(); + static const Parameters & CRC_12_UMTS(); + static const Parameters & CRC_13_BBC(); + static const Parameters & CRC_15(); + static const Parameters & CRC_15_MPT1327(); +#endif + static const Parameters & CRC_16_ARC(); + static const Parameters & CRC_16_BUYPASS(); + static const Parameters & CRC_16_CCITTFALSE(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_16_CDMA2000(); + static const Parameters & CRC_16_CMS(); + static const Parameters & CRC_16_DECTR(); + static const Parameters & CRC_16_DECTX(); + static const Parameters & CRC_16_DNP(); +#endif + static const Parameters & CRC_16_GENIBUS(); + static const Parameters & CRC_16_KERMIT(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_16_MAXIM(); + static const Parameters & CRC_16_MODBUS(); + static const Parameters & CRC_16_T10DIF(); + static const Parameters & CRC_16_USB(); +#endif + static const Parameters & CRC_16_X25(); + static const Parameters & CRC_16_XMODEM(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_17_CAN(); + static const Parameters & CRC_21_CAN(); + static const Parameters & CRC_24(); + static const Parameters & CRC_24_FLEXRAYA(); + static const Parameters & CRC_24_FLEXRAYB(); + static const Parameters & CRC_30(); +#endif + static const Parameters & CRC_32(); + static const Parameters & CRC_32_BZIP2(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_32_C(); +#endif + static const Parameters & CRC_32_MPEG2(); + static const Parameters & CRC_32_POSIX(); +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + static const Parameters & CRC_32_Q(); + static const Parameters & CRC_40_GSM(); + static const Parameters & CRC_64(); +#endif + +#ifdef CRCPP_USE_CPP11 + CRC() = delete; + CRC(const CRC & other) = delete; + CRC & operator=(const CRC & other) = delete; + CRC(CRC && other) = delete; + CRC & operator=(CRC && other) = delete; +#endif + +private: +#ifndef CRCPP_USE_CPP11 + CRC(); + CRC(const CRC & other); + CRC & operator=(const CRC & other); +#endif + + template + static IntegerType Reflect(IntegerType value, crcpp_uint16 numBits); + + template + static CRCType Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); + + template + static CRCType UndoFinalize(CRCType remainder, CRCType finalXOR, bool reflectOutput); + + template + static CRCType CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder); + + template + static CRCType CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder); +}; + +/** + @brief Returns a CRC lookup table construct using these CRC parameters. + @note This function primarily exists to allow use of the auto keyword instead of instantiating + a table directly, since template parameters are not inferred in constructors. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC lookup table +*/ +template +inline CRC::Table CRC::Parameters::MakeTable() const +{ + // This should take advantage of RVO and optimize out the copy. + return CRC::Table(*this); +} + +/** + @brief Constructs a CRC table from a set of CRC parameters + @param[in] params CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline CRC::Table::Table(const Parameters & params) : + parameters(params) +{ + InitTable(); +} + +#ifdef CRCPP_USE_CPP11 +/** + @brief Constructs a CRC table from a set of CRC parameters + @param[in] params CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline CRC::Table::Table(Parameters && params) : + parameters(::std::move(params)) +{ + InitTable(); +} +#endif + +/** + @brief Gets the CRC parameters used to construct the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC parameters +*/ +template +inline const CRC::Parameters & CRC::Table::GetParameters() const +{ + return parameters; +} + +/** + @brief Gets the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC table +*/ +template +inline const CRCType * CRC::Table::GetTable() const +{ + return table; +} + +/** + @brief Gets an entry in the CRC table + @param[in] index Index into the CRC table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC table entry +*/ +template +inline CRCType CRC::Table::operator[](unsigned char index) const +{ + return table[index]; +} + +/** + @brief Initializes a CRC table. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC +*/ +template +inline void CRC::Table::InitTable() +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK((CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1))); + + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + CRCType crc; + unsigned char byte = 0; + + // Loop over each dividend (each possible number storable in an unsigned char) + do + { + crc = CRC::CalculateRemainder(&byte, sizeof(byte), parameters, CRCType(0)); + + // This mask might not be necessary; all unit tests pass with this line commented out, + // but that might just be a coincidence based on the CRC parameters used for testing. + // In any case, this is harmless to leave in and only adds a single machine instruction per loop iteration. + crc &= BIT_MASK; + + if (!parameters.reflectInput && CRCWidth < CHAR_BIT) + { + // Undo the special operation at the end of the CalculateRemainder() + // function for non-reflected CRCs < CHAR_BIT. + crc = static_cast(crc << SHIFT); + } + + table[byte] = crc; + } + while (++byte); +} + +/** + @brief Computes a CRC. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data + @param[in] parameters CRC parameters + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters) +{ + CRCType remainder = CalculateRemainder(data, size, parameters, parameters.initialValue); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} +/** + @brief Appends additional data to a previous CRC calculation. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data + @param[in] parameters CRC parameters + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Parameters & parameters, CRCType crc) +{ + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + remainder = CalculateRemainder(data, size, parameters, remainder); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Computes a CRC via a lookup table. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data + @param[in] lookupTable CRC lookup table + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = CalculateRemainder(data, size, lookupTable, parameters.initialValue); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Appends additional data to a previous CRC calculation using a lookup table. + @note This function can be used to compute multi-part CRCs. + @param[in] data Data over which CRC will be computed + @param[in] size Size of the data + @param[in] lookupTable CRC lookup table + @param[in] crc CRC from a previous calculation + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC +*/ +template +inline CRCType CRC::Calculate(const void * data, crcpp_size size, const Table & lookupTable, CRCType crc) +{ + const Parameters & parameters = lookupTable.GetParameters(); + + CRCType remainder = UndoFinalize(crc, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); + + remainder = CalculateRemainder(data, size, lookupTable, remainder); + + // No need to mask the remainder here; the mask will be applied in the Finalize() function. + + return Finalize(remainder, parameters.finalXOR, parameters.reflectInput != parameters.reflectOutput); +} + +/** + @brief Reflects (i.e. reverses the bits within) an integer value. + @param[in] value Value to reflect + @param[in] numBits Number of bits in the integer which will be reflected + @tparam IntegerType Integer type of the value being reflected + @return Reflected value +*/ +template +inline IntegerType CRC::Reflect(IntegerType value, crcpp_uint16 numBits) +{ + IntegerType reversedValue(0); + + for (crcpp_uint16 i = 0; i < numBits; ++i) + { + reversedValue = static_cast((reversedValue << 1) | (value & 1)); + value = static_cast(value >> 1); + } + + return reversedValue; +} + +/** + @brief Computes the final reflection and XOR of a CRC remainder. + @param[in] remainder CRC remainder to reflect and XOR + @param[in] finalXOR Final value to XOR with the remainder + @param[in] reflectOutput true to reflect each byte of the remainder before the XOR + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return Final CRC +*/ +template +inline CRCType CRC::Finalize(CRCType remainder, CRCType finalXOR, bool reflectOutput) +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); + + if (reflectOutput) + { + remainder = Reflect(remainder, CRCWidth); + } + + return (remainder ^ finalXOR) & BIT_MASK; +} + +/** + @brief Undoes the process of computing the final reflection and XOR of a CRC remainder. + @note This function allows for computation of multi-part CRCs + @note Calling UndoFinalize() followed by Finalize() (or vice versa) will always return the original remainder value: + + CRCType x = ...; + CRCType y = Finalize(x, finalXOR, reflectOutput); + CRCType z = UndoFinalize(y, finalXOR, reflectOutput); + assert(x == z); + + @param[in] crc Reflected and XORed CRC + @param[in] finalXOR Final value XORed with the remainder + @param[in] reflectOutput true if the remainder is to be reflected + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return Un-finalized CRC remainder +*/ +template +inline CRCType CRC::UndoFinalize(CRCType crc, CRCType finalXOR, bool reflectOutput) +{ + // For masking off the bits for the CRC (in the event that the number of bits in CRCType is larger than CRCWidth) + static crcpp_constexpr CRCType BIT_MASK = (CRCType(1) << (CRCWidth - CRCType(1))) | + ((CRCType(1) << (CRCWidth - CRCType(1))) - CRCType(1)); + + crc = (crc & BIT_MASK) ^ finalXOR; + + if (reflectOutput) + { + crc = Reflect(crc, CRCWidth); + } + + return crc; +} + +/** + @brief Computes a CRC remainder. + @param[in] data Data over which the remainder will be computed + @param[in] size Size of the data + @param[in] parameters CRC parameters + @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC remainder +*/ +template +inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Parameters & parameters, CRCType remainder) +{ +#ifdef CRCPP_USE_CPP11 + // This static_assert is put here because this function will always be compiled in no matter what + // the template parameters are and whether or not a table lookup or bit-by-bit algorithm is used. + static_assert(::std::numeric_limits::digits >= CRCWidth, "CRCType is too small to contain a CRC of width CRCWidth."); +#else + // Catching this compile-time error is very important. Sadly, the compiler error will be very cryptic, but it's + // better than nothing. + enum { static_assert_failed_CRCType_is_too_small_to_contain_a_CRC_of_width_CRCWidth = 1 / (::std::numeric_limits::digits >= CRCWidth ? 1 : 0) }; +#endif + + const unsigned char * current = reinterpret_cast(data); + + // Slightly different implementations based on the parameters. The current implementations try to eliminate as much + // computation from the inner loop (looping over each bit) as possible. + if (parameters.reflectInput) + { + CRCType polynomial = CRC::Reflect(parameters.polynomial, CRCWidth); + while (size--) + { + remainder = static_cast(remainder ^ *current++); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & 1) + // remainder = (remainder >> 1) ^ polynomial; + // else + // remainder >>= 1; + remainder = static_cast((remainder >> 1) ^ ((remainder & 1) * polynomial)); +#else + remainder = static_cast((remainder & 1) ? ((remainder >> 1) ^ polynomial) : (remainder >> 1)); +#endif + } + } + } + else if (CRCWidth >= CHAR_BIT) + { + static crcpp_constexpr CRCType CRC_WIDTH_MINUS_ONE(CRCWidth - CRCType(1)); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CRC_HIGHEST_BIT_MASK(CRCType(1) << CRC_WIDTH_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast(CRCWidth - CHAR_BIT) : 0); + + while (size--) + { + remainder = static_cast(remainder ^ (static_cast(*current++) << SHIFT)); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CRC_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ parameters.polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CRC_WIDTH_MINUS_ONE) & 1) * parameters.polynomial)); +#else + remainder = static_cast((remainder & CRC_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ parameters.polynomial) : (remainder << 1)); +#endif + } + } + } + else + { + static crcpp_constexpr CRCType CHAR_BIT_MINUS_ONE(CHAR_BIT - 1); +#ifndef CRCPP_BRANCHLESS + static crcpp_constexpr CRCType CHAR_BIT_HIGHEST_BIT_MASK(CRCType(1) << CHAR_BIT_MINUS_ONE); +#endif + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + CRCType polynomial = static_cast(parameters.polynomial << SHIFT); + remainder = static_cast(remainder << SHIFT); + + while (size--) + { + remainder = static_cast(remainder ^ *current++); + + // An optimizing compiler might choose to unroll this loop. + for (crcpp_size i = 0; i < CHAR_BIT; ++i) + { +#ifdef CRCPP_BRANCHLESS + // Clever way to avoid a branch at the expense of a multiplication. This code is equivalent to the following: + // if (remainder & CHAR_BIT_HIGHEST_BIT_MASK) + // remainder = (remainder << 1) ^ polynomial; + // else + // remainder <<= 1; + remainder = static_cast((remainder << 1) ^ (((remainder >> CHAR_BIT_MINUS_ONE) & 1) * polynomial)); +#else + remainder = static_cast((remainder & CHAR_BIT_HIGHEST_BIT_MASK) ? ((remainder << 1) ^ polynomial) : (remainder << 1)); +#endif + } + } + + remainder = static_cast(remainder >> SHIFT); + } + + return remainder; +} + +/** + @brief Computes a CRC remainder using lookup table. + @param[in] data Data over which the remainder will be computed + @param[in] size Size of the data + @param[in] lookupTable CRC lookup table + @param[in] remainder Running CRC remainder. Can be an initial value or the result of a previous CRC remainder calculation. + @tparam CRCType Integer type for storing the CRC result + @tparam CRCWidth Number of bits in the CRC + @return CRC remainder +*/ +template +inline CRCType CRC::CalculateRemainder(const void * data, crcpp_size size, const Table & lookupTable, CRCType remainder) +{ + const unsigned char * current = reinterpret_cast(data); + + if (lookupTable.GetParameters().reflectInput) + { + while (size--) + { +#if defined(WIN32) || defined(_WIN32) || defined(WINCE) + // Disable warning about data loss when doing (remainder >> CHAR_BIT) when + // remainder is one byte long. The algorithm is still correct in this case, + // though it's possible that one additional machine instruction will be executed. +# pragma warning (push) +# pragma warning (disable : 4333) +#endif + remainder = static_cast((remainder >> CHAR_BIT) ^ lookupTable[static_cast(remainder ^ *current++)]); +#if defined(WIN32) || defined(_WIN32) || defined(WINCE) +# pragma warning (pop) +#endif + } + } + else if (CRCWidth >= CHAR_BIT) + { + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CRCWidth >= CHAR_BIT) ? static_cast(CRCWidth - CHAR_BIT) : 0); + + while (size--) + { + remainder = static_cast((remainder << CHAR_BIT) ^ lookupTable[static_cast((remainder >> SHIFT) ^ *current++)]); + } + } + else + { + // The conditional expression is used to avoid a -Wshift-count-overflow warning. + static crcpp_constexpr CRCType SHIFT((CHAR_BIT >= CRCWidth) ? static_cast(CHAR_BIT - CRCWidth) : 0); + + remainder = static_cast(remainder << SHIFT); + + while (size--) + { + // Note: no need to mask here since remainder is guaranteed to fit in a single byte. + remainder = lookupTable[static_cast(remainder ^ *current++)]; + } + + remainder = static_cast(remainder >> SHIFT); + } + + return remainder; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-4 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-4 ITU has the following parameters and check value: + - polynomial = 0x3 + - initial value = 0x0 + - final XOR = 0x0 + - reflect input = true + - reflect output = true + - check value = 0x7 + @return CRC-4 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_4_ITU() +{ + static const Parameters parameters = { 0x3, 0x0, 0x0, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 EPC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 EPC has the following parameters and check value: + - polynomial = 0x09 + - initial value = 0x09 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x00 + @return CRC-5 EPC parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_EPC() +{ + static const Parameters parameters = { 0x09, 0x09, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 ITU has the following parameters and check value: + - polynomial = 0x15 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x07 + @return CRC-5 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_ITU() +{ + static const Parameters parameters = { 0x15, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-5 USB. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-5 USB has the following parameters and check value: + - polynomial = 0x05 + - initial value = 0x1F + - final XOR = 0x1F + - reflect input = true + - reflect output = true + - check value = 0x19 + @return CRC-5 USB parameters +*/ +inline const CRC::Parameters & CRC::CRC_5_USB() +{ + static const Parameters parameters = { 0x05, 0x1F, 0x1F, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 CDMA2000-A. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 CDMA2000-A has the following parameters and check value: + - polynomial = 0x27 + - initial value = 0x3F + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x0D + @return CRC-6 CDMA2000-A parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_CDMA2000A() +{ + static const Parameters parameters = { 0x27, 0x3F, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 CDMA2000-B. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 CDMA2000-A has the following parameters and check value: + - polynomial = 0x07 + - initial value = 0x3F + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x3B + @return CRC-6 CDMA2000-B parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_CDMA2000B() +{ + static const Parameters parameters = { 0x07, 0x3F, 0x00, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-6 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-6 ITU has the following parameters and check value: + - polynomial = 0x03 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x06 + @return CRC-6 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_6_ITU() +{ + static const Parameters parameters = { 0x03, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-7 JEDEC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-7 JEDEC has the following parameters and check value: + - polynomial = 0x09 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0x75 + @return CRC-7 JEDEC parameters +*/ +inline const CRC::Parameters & CRC::CRC_7() +{ + static const Parameters parameters = { 0x09, 0x00, 0x00, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-8 SMBus. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 SMBus has the following parameters and check value: + - polynomial = 0x07 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = false + - reflect output = false + - check value = 0xF4 + @return CRC-8 SMBus parameters +*/ +inline const CRC::Parameters & CRC::CRC_8() +{ + static const Parameters parameters = { 0x07, 0x00, 0x00, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-8 EBU (aka CRC-8 AES). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 EBU has the following parameters and check value: + - polynomial = 0x1D + - initial value = 0xFF + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x97 + @return CRC-8 EBU parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_EBU() +{ + static const Parameters parameters = { 0x1D, 0xFF, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-8 MAXIM (aka CRC-8 DOW-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 MAXIM has the following parameters and check value: + - polynomial = 0x31 + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0xA1 + @return CRC-8 MAXIM parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_MAXIM() +{ + static const Parameters parameters = { 0x31, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-8 WCDMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-8 WCDMA has the following parameters and check value: + - polynomial = 0x9B + - initial value = 0x00 + - final XOR = 0x00 + - reflect input = true + - reflect output = true + - check value = 0x25 + @return CRC-8 WCDMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_8_WCDMA() +{ + static const Parameters parameters = { 0x9B, 0x00, 0x00, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-10 ITU. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-10 ITU has the following parameters and check value: + - polynomial = 0x233 + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x199 + @return CRC-10 ITU parameters +*/ +inline const CRC::Parameters & CRC::CRC_10() +{ + static const Parameters parameters = { 0x233, 0x000, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-10 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-10 CDMA2000 has the following parameters and check value: + - polynomial = 0x3D9 + - initial value = 0x3FF + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x233 + @return CRC-10 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_10_CDMA2000() +{ + static const Parameters parameters = { 0x3D9, 0x3FF, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-11 FlexRay. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-11 FlexRay has the following parameters and check value: + - polynomial = 0x385 + - initial value = 0x01A + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0x5A3 + @return CRC-11 FlexRay parameters +*/ +inline const CRC::Parameters & CRC::CRC_11() +{ + static const Parameters parameters = { 0x385, 0x01A, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 CDMA2000 has the following parameters and check value: + - polynomial = 0xF13 + - initial value = 0xFFF + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0xD4D + @return CRC-12 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_CDMA2000() +{ + static const Parameters parameters = { 0xF13, 0xFFF, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 DECT (aka CRC-12 X-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 DECT has the following parameters and check value: + - polynomial = 0x80F + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = false + - check value = 0xF5B + @return CRC-12 DECT parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_DECT() +{ + static const Parameters parameters = { 0x80F, 0x000, 0x000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-12 UMTS (aka CRC-12 3GPP). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-12 UMTS has the following parameters and check value: + - polynomial = 0x80F + - initial value = 0x000 + - final XOR = 0x000 + - reflect input = false + - reflect output = true + - check value = 0xDAF + @return CRC-12 UMTS parameters +*/ +inline const CRC::Parameters & CRC::CRC_12_UMTS() +{ + static const Parameters parameters = { 0x80F, 0x000, 0x000, false, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-13 BBC. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-13 BBC has the following parameters and check value: + - polynomial = 0x1CF5 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x04FA + @return CRC-13 BBC parameters +*/ +inline const CRC::Parameters & CRC::CRC_13_BBC() +{ + static const Parameters parameters = { 0x1CF5, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-15 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-15 CAN has the following parameters and check value: + - polynomial = 0x4599 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x059E + @return CRC-15 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_15() +{ + static const Parameters parameters = { 0x4599, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-15 MPT1327. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-15 MPT1327 has the following parameters and check value: + - polynomial = 0x6815 + - initial value = 0x0000 + - final XOR = 0x0001 + - reflect input = false + - reflect output = false + - check value = 0x2566 + @return CRC-15 MPT1327 parameters +*/ +inline const CRC::Parameters & CRC::CRC_15_MPT1327() +{ + static const Parameters parameters = { 0x6815, 0x0000, 0x0001, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 ARC (aka CRC-16 IBM, CRC-16 LHA). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 ARC has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0xBB3D + @return CRC-16 ARC parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_ARC() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0x0000, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 BUYPASS (aka CRC-16 VERIFONE, CRC-16 UMTS). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 BUYPASS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xFEE8 + @return CRC-16 BUYPASS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_BUYPASS() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 CCITT FALSE. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CCITT FALSE has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x29B1 + @return CRC-16 CCITT FALSE parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CCITTFALSE() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-16 CDMA2000. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CDMA2000 has the following parameters and check value: + - polynomial = 0xC867 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x4C06 + @return CRC-16 CDMA2000 parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CDMA2000() +{ + static const Parameters parameters = { 0xC867, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 CMS. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 CMS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xAEE7 + @return CRC-16 CMS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_CMS() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DECT-R (aka CRC-16 R-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DECT-R has the following parameters and check value: + - polynomial = 0x0589 + - initial value = 0x0000 + - final XOR = 0x0001 + - reflect input = false + - reflect output = false + - check value = 0x007E + @return CRC-16 DECT-R parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DECTR() +{ + static const Parameters parameters = { 0x0589, 0x0000, 0x0001, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DECT-X (aka CRC-16 X-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DECT-X has the following parameters and check value: + - polynomial = 0x0589 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x007F + @return CRC-16 DECT-X parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DECTX() +{ + static const Parameters parameters = { 0x0589, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 DNP. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 DNP has the following parameters and check value: + - polynomial = 0x3D65 + - initial value = 0x0000 + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0xEA82 + @return CRC-16 DNP parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_DNP() +{ + static const Parameters parameters = { 0x3D65, 0x0000, 0xFFFF, true, true }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 GENIBUS (aka CRC-16 EPC, CRC-16 I-CODE, CRC-16 DARC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 GENIBUS has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = false + - reflect output = false + - check value = 0xD64E + @return CRC-16 GENIBUS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_GENIBUS() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 KERMIT (aka CRC-16 CCITT, CRC-16 CCITT-TRUE). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 KERMIT has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0x2189 + @return CRC-16 KERMIT parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_KERMIT() +{ + static const Parameters parameters = { 0x1021, 0x0000, 0x0000, true, true }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-16 MAXIM. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 MAXIM has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0x0000 + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0x44C2 + @return CRC-16 MAXIM parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_MAXIM() +{ + static const Parameters parameters = { 0x8005, 0x0000, 0xFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 MODBUS. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 MODBUS has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0x0000 + - reflect input = true + - reflect output = true + - check value = 0x4B37 + @return CRC-16 MODBUS parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_MODBUS() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0x0000, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 T10-DIF. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 T10-DIF has the following parameters and check value: + - polynomial = 0x8BB7 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0xD0DB + @return CRC-16 T10-DIF parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_T10DIF() +{ + static const Parameters parameters = { 0x8BB7, 0x0000, 0x0000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 USB. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 USB has the following parameters and check value: + - polynomial = 0x8005 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0xB4C8 + @return CRC-16 USB parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_USB() +{ + static const Parameters parameters = { 0x8005, 0xFFFF, 0xFFFF, true, true }; + return parameters; +} + +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-16 X-25 (aka CRC-16 IBM-SDLC, CRC-16 ISO-HDLC, CRC-16 B). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 X-25 has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0xFFFF + - final XOR = 0xFFFF + - reflect input = true + - reflect output = true + - check value = 0x906E + @return CRC-16 X-25 parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_X25() +{ + static const Parameters parameters = { 0x1021, 0xFFFF, 0xFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-16 XMODEM (aka CRC-16 ZMODEM, CRC-16 ACORN, CRC-16 LTE). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-16 XMODEM has the following parameters and check value: + - polynomial = 0x1021 + - initial value = 0x0000 + - final XOR = 0x0000 + - reflect input = false + - reflect output = false + - check value = 0x31C3 + @return CRC-16 XMODEM parameters +*/ +inline const CRC::Parameters & CRC::CRC_16_XMODEM() +{ + static const Parameters parameters = { 0x1021, 0x0000, 0x0000, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-17 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-17 CAN has the following parameters and check value: + - polynomial = 0x1685B + - initial value = 0x00000 + - final XOR = 0x00000 + - reflect input = false + - reflect output = false + - check value = 0x04F03 + @return CRC-17 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_17_CAN() +{ + static const Parameters parameters = { 0x1685B, 0x00000, 0x00000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-21 CAN. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-21 CAN has the following parameters and check value: + - polynomial = 0x102899 + - initial value = 0x000000 + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x0ED841 + @return CRC-21 CAN parameters +*/ +inline const CRC::Parameters & CRC::CRC_21_CAN() +{ + static const Parameters parameters = { 0x102899, 0x000000, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 OPENPGP. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 OPENPGP has the following parameters and check value: + - polynomial = 0x864CFB + - initial value = 0xB704CE + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x21CF02 + @return CRC-24 OPENPGP parameters +*/ +inline const CRC::Parameters & CRC::CRC_24() +{ + static const Parameters parameters = { 0x864CFB, 0xB704CE, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 FlexRay-A. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 FlexRay-A has the following parameters and check value: + - polynomial = 0x5D6DCB + - initial value = 0xFEDCBA + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x7979BD + @return CRC-24 FlexRay-A parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_FLEXRAYA() +{ + static const Parameters parameters = { 0x5D6DCB, 0xFEDCBA, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-24 FlexRay-B. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-24 FlexRay-B has the following parameters and check value: + - polynomial = 0x5D6DCB + - initial value = 0xABCDEF + - final XOR = 0x000000 + - reflect input = false + - reflect output = false + - check value = 0x1F23B8 + @return CRC-24 FlexRay-B parameters +*/ +inline const CRC::Parameters & CRC::CRC_24_FLEXRAYB() +{ + static const Parameters parameters = { 0x5D6DCB, 0xABCDEF, 0x000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-30 CDMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-30 CDMA has the following parameters and check value: + - polynomial = 0x2030B9C7 + - initial value = 0x3FFFFFFF + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x3B3CB540 + @return CRC-30 CDMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_30() +{ + static const Parameters parameters = { 0x2030B9C7, 0x3FFFFFFF, 0x00000000, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +/** + @brief Returns a set of parameters for CRC-32 (aka CRC-32 ADCCP, CRC-32 PKZip). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = true + - reflect output = true + - check value = 0xCBF43926 + @return CRC-32 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-32 BZIP2 (aka CRC-32 AAL5, CRC-32 DECT-B, CRC-32 B-CRC). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 BZIP2 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0xFC891918 + @return CRC-32 BZIP2 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_BZIP2() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-32 C (aka CRC-32 ISCSI, CRC-32 Castagnoli, CRC-32 Interlaken). + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 C has the following parameters and check value: + - polynomial = 0x1EDC6F41 + - initial value = 0xFFFFFFFF + - final XOR = 0xFFFFFFFF + - reflect input = true + - reflect output = true + - check value = 0xE3069283 + @return CRC-32 C parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_C() +{ + static const Parameters parameters = { 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true }; + return parameters; +} +#endif + +/** + @brief Returns a set of parameters for CRC-32 MPEG-2. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 MPEG-2 has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0xFFFFFFFF + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x0376E6E7 + @return CRC-32 MPEG-2 parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_MPEG2() +{ + static const Parameters parameters = { 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-32 POSIX. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 POSIX has the following parameters and check value: + - polynomial = 0x04C11DB7 + - initial value = 0x00000000 + - final XOR = 0xFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0x765E7680 + @return CRC-32 POSIX parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_POSIX() +{ + static const Parameters parameters = { 0x04C11DB7, 0x00000000, 0xFFFFFFFF, false, false }; + return parameters; +} + +#ifdef CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS +/** + @brief Returns a set of parameters for CRC-32 Q. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-32 Q has the following parameters and check value: + - polynomial = 0x814141AB + - initial value = 0x00000000 + - final XOR = 0x00000000 + - reflect input = false + - reflect output = false + - check value = 0x3010BF7F + @return CRC-32 Q parameters +*/ +inline const CRC::Parameters & CRC::CRC_32_Q() +{ + static const Parameters parameters = { 0x814141AB, 0x00000000, 0x00000000, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-40 GSM. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-40 GSM has the following parameters and check value: + - polynomial = 0x0004820009 + - initial value = 0x0000000000 + - final XOR = 0xFFFFFFFFFF + - reflect input = false + - reflect output = false + - check value = 0xD4164FC646 + @return CRC-40 GSM parameters +*/ +inline const CRC::Parameters & CRC::CRC_40_GSM() +{ + static const Parameters parameters = { 0x0004820009, 0x0000000000, 0xFFFFFFFFFF, false, false }; + return parameters; +} + +/** + @brief Returns a set of parameters for CRC-64 ECMA. + @note The parameters are static and are delayed-constructed to reduce memory footprint. + @note CRC-64 ECMA has the following parameters and check value: + - polynomial = 0x42F0E1EBA9EA3693 + - initial value = 0x0000000000000000 + - final XOR = 0x0000000000000000 + - reflect input = false + - reflect output = false + - check value = 0x6C40DF5F0B497347 + @return CRC-64 ECMA parameters +*/ +inline const CRC::Parameters & CRC::CRC_64() +{ + static const Parameters parameters = { 0x42F0E1EBA9EA3693, 0x0000000000000000, 0x0000000000000000, false, false }; + return parameters; +} +#endif // CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS + +#ifdef CRCPP_USE_NAMESPACE +} +#endif + +#endif // CRCPP_CRC_H_ diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index cf5c87aea..b7ba55f86 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -4,6 +4,7 @@ EE::Window::Window* win = NULL; UISceneNode* uiSceneNode = NULL; UICodeEditor* codeEditor = NULL; +Console* console = NULL; std::string curFile = "untitled"; const std::string& windowTitle = "eepp - Code Editor"; bool docDirtyState = false; @@ -47,41 +48,52 @@ void openFileDialog() { } void mainLoop() { - if ( codeEditor->isDirty() != docDirtyState ) { - docDirtyState = codeEditor->isDirty(); - setAppTitle( docDirtyState ? curFile + "*" : curFile ); - } - Input* input = win->getInput(); input->update(); - if ( ( input->isControlPressed() && input->isKeyUp( KEY_O ) ) || input->isKeyUp( KEY_F2 ) ) { - openFileDialog(); - } + if ( win->isActive() ) { + if ( codeEditor->isDirty() != docDirtyState ) { + docDirtyState = codeEditor->isDirty(); + setAppTitle( docDirtyState ? curFile + "*" : curFile ); + } - if ( input->isControlPressed() && input->isKeyUp( KEY_S ) ) { - codeEditor->save(); - } + if ( ( input->isControlPressed() && input->isKeyUp( KEY_O ) ) || + input->isKeyUp( KEY_F2 ) ) { + openFileDialog(); + } - if ( input->isKeyUp( KEY_F6 ) ) { - uiSceneNode->setHighlightOver( !uiSceneNode->getHighlightOver() ); - } + if ( input->isControlPressed() && input->isKeyUp( KEY_S ) ) { + codeEditor->save(); + } - if ( input->isKeyUp( KEY_F7 ) ) { - uiSceneNode->setDrawBoxes( !uiSceneNode->getDrawBoxes() ); - } + if ( input->isKeyUp( KEY_F6 ) ) { + uiSceneNode->setHighlightOver( !uiSceneNode->getHighlightOver() ); + } - if ( input->isKeyUp( KEY_F8 ) ) { - uiSceneNode->setDrawDebugData( !uiSceneNode->getDrawDebugData() ); - } + if ( input->isKeyUp( KEY_F7 ) ) { + uiSceneNode->setDrawBoxes( !uiSceneNode->getDrawBoxes() ); + } - if ( input->isKeyUp( KEY_ESCAPE ) && NULL == MsgBox && onCloseRequestCallback( win ) ) { - win->close(); - } + if ( input->isKeyUp( KEY_F8 ) ) { + uiSceneNode->setDrawDebugData( !uiSceneNode->getDrawDebugData() ); + } - if ( input->isAltPressed() && input->isKeyUp( KEY_RETURN ) ) { - win->toggleFullscreen(); + if ( input->isKeyUp( KEY_ESCAPE ) && NULL == MsgBox && onCloseRequestCallback( win ) ) { + win->close(); + } + + if ( input->isAltPressed() && input->isKeyUp( KEY_RETURN ) ) { + win->toggleFullscreen(); + } + + if ( input->isKeyUp( KEY_F3 ) ) { + console->toggle(); + } + + if ( input->isControlPressed() && input->isKeyUp( KEY_L ) ) { + codeEditor->setLocked( !codeEditor->isLocked() ); + } } SceneManager::instance()->update(); @@ -89,9 +101,10 @@ void mainLoop() { if ( SceneManager::instance()->getUISceneNode()->invalidated() ) { win->clear(); SceneManager::instance()->draw(); + console->draw(); win->display(); } else { - Sys::sleep( Milliseconds( win->isVisible() ? 1 : 8 ) ); + Sys::sleep( Milliseconds( win->isVisible() ? 1 : 16 ) ); } } @@ -143,7 +156,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { uiSceneNode->getUIThemeManager()->setDefaultFont( FontTrueType::New( "NotoSans-Regular", "assets/fonts/NotoSans-Regular.ttf" ) ); - FontTrueType::New( "monospace", "assets/fonts/DejaVuSansMono.ttf" ); + Font* fontMono = FontTrueType::New( "monospace", "assets/fonts/DejaVuSansMono.ttf" ); SceneManager::instance()->add( uiSceneNode ); @@ -171,9 +184,13 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { loadFileFromPath( file.Get() ); } + console = eeNew( Console, ( fontMono, true, true, 1024 * 1000, 0, win ) ); + win->runMainLoop( &mainLoop ); } + eeSAFE_DELETE( console ); + Engine::destroySingleton(); MemoryManager::showResults();