diff --git a/Allocators/CMakeLists.txt b/Allocators/CMakeLists.txt index 99ec141..fae102e 100644 --- a/Allocators/CMakeLists.txt +++ b/Allocators/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2) set(CMAKE_CXX_STANDARD 23) -project(Allocators) +project(Allocator) ### ---------------------- Static Library --------------------- ### file(GLOB SOURCES "./private/*.cpp") diff --git a/CMakeLists.txt b/CMakeLists.txt index 489a229..d23e6cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,5 +14,4 @@ add_subdirectory(Modules) add_subdirectory(Utils) add_subdirectory(Containers) add_subdirectory(Math) -add_subdirectory(Allocators) -add_subdirectory(Strings) \ No newline at end of file +add_subdirectory(Allocators) \ No newline at end of file diff --git a/Strings/CMakeLists.txt b/Strings/CMakeLists.txt deleted file mode 100644 index e50501e..0000000 --- a/Strings/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ - -cmake_minimum_required(VERSION 3.2) - -set(CMAKE_CXX_STANDARD 23) - -project(Strings) - -### ---------------------- Static Library --------------------- ### -file(GLOB SOURCES "./private/*.cpp") -file(GLOB HEADERS "./public/*.hpp") -add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) -target_include_directories(${PROJECT_NAME} PUBLIC ./public/) -target_link_libraries(${PROJECT_NAME} PUBLIC Allocators Containers) - -### -------------------------- Tests -------------------------- ### -enable_testing() -file(GLOB TEST_SOURCES "./tests/*.cpp") -add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) -target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) -add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) - -install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) \ No newline at end of file diff --git a/Strings/private/Logging.cpp b/Strings/private/Logging.cpp deleted file mode 100644 index 443de68..0000000 --- a/Strings/private/Logging.cpp +++ /dev/null @@ -1,69 +0,0 @@ - -#include "Logging.hpp" -#include "Allocators.hpp" -#include "TextEditor.hpp" - -#include - -namespace tp { - - Logger* gLogger = nullptr; - - ualni Logger::Report::getLineCount() const { - return (ualni)(mLineOffsets.size() - 1); - } - - String Logger::Report::getString() const { - return mData; - } - - void Logger::Report::calcLineCount() { - Input input = { mData.raw(), (ualni) mData.size() }; - input.getLineOffsets(mLineOffsets); - } - - Logger::Report::Report() { - mData = " - "; - } - - Logger::Report::Report(const String& text) : mData(text) { - calcLineCount(); - } - - Logger::Report::Report(const String& text, Type type) : mType(type), mData(text) { - calcLineCount(); - } - - void Logger::write(const String& in, bool post, Report::Type type) { - StringTemplate copy = in; - copy.capture(); - mBuff.pushBack(Report(copy, type)); - - mLineCount += mBuff.last()->data.getLineCount(); - - if (!mCursor) { - mCursor = mBuff.last(); - } - - if (post) { - printf("%s", in.raw()); - } - } - - String Logger::read() { - if (!mCursor) return {}; - const Report& out = mCursor->data; - mCursor = mCursor->next; - return out.getString(); - } - - void Logger::initializeGlobal() { - DEBUG_ASSERT(!gLogger) - gLogger = new Logger(); - } - - void Logger::deinitializeGlobal() { - DEBUG_ASSERT(gLogger) - delete gLogger; - } -} \ No newline at end of file diff --git a/Strings/private/Strings.cpp b/Strings/private/Strings.cpp deleted file mode 100644 index 2d59e4d..0000000 --- a/Strings/private/Strings.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include "Strings.hpp" -#include "Allocators.hpp" -#include "Logging.hpp" - -using namespace tp; - -bool initialize(const ModuleManifest*) { - Logger::initializeGlobal(); - return true; -} - -void deinitialize(const ModuleManifest*) { - Logger::deinitializeGlobal(); -} - -static tp::ModuleManifest* sModuleDependencies[] = { - &tp::gModuleContainers, - &tp::gModuleAllocators, - &tp::gModuleUtils, - nullptr -}; - -ModuleManifest tp::gModuleStrings = ModuleManifest("Strings", initialize, deinitialize, sModuleDependencies); \ No newline at end of file diff --git a/Strings/public/Logging.hpp b/Strings/public/Logging.hpp deleted file mode 100644 index 6616e72..0000000 --- a/Strings/public/Logging.hpp +++ /dev/null @@ -1,59 +0,0 @@ - -#pragma once - -#include "Buffer.hpp" -#include "List.hpp" -#include "Strings.hpp" - -namespace tp { - - class Logger { - public: - - class Report { - String mData; - Buffer mLineOffsets; - - public: - enum Type { INFO, ERR, WARN, SUC } mType = INFO; - - public: - Report(); - explicit Report(const String& text); - Report(const String& text, Type type); - - public: - [[nodiscard]] ualni getLineCount() const; - [[nodiscard]] String getString() const; - - private: - void calcLineCount(); - }; - - private: - List::Node* mCursor = nullptr; - List mBuff; - ualni mLineCount = 0; - - public: - void write(const String& in, bool post = true, Report::Type type = Report::Type::INFO); - - [[nodiscard]] String read(); - [[nodiscard]] const List& getBuff() const { return mBuff; } - [[nodiscard]] ualni getLineCount() const { return mLineCount; } - - public: - static void initializeGlobal(); - static void deinitializeGlobal(); - }; - - extern Logger* gLogger; -} - -#define LOG(val) tp::str::gLogger->write((val), 1) - -#ifdef ENV_BUILD_DEBUG -#define DEBUG_LOG(val) tp::str::gLogger->write((val), 1) -#else -#define DEBUG_LOG(val) (0) -#endif \ No newline at end of file diff --git a/Strings/public/StringLogic.hpp b/Strings/public/StringLogic.hpp deleted file mode 100644 index 488349a..0000000 --- a/Strings/public/StringLogic.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#pragma once - -#include "Utils.hpp" - -namespace tp { - - template - class StringLogic { - public: - - typedef halni Index; - typedef Index LineId; - typedef Index ColumnId; - - static inline bool isNewLineChar(tChar in) { return (in == '\n') || (in == '\r'); } - static inline bool isEndChar(tChar in) { return in == '\0'; } - static constexpr tChar getEndChar() { return '\0'; } - - static ualni calcLength(const tChar* in) { - const tChar* iter = in; - while (*iter != '\0') iter++; - return iter - in; - } - - static tChar* insertLogic(const tChar* cur, const tChar* tar, ualni at, ualni len) { - ualni curLen = calcLength(cur); - ualni allLen = curLen + len; - auto* out = new tChar[allLen + 1]; - - DEBUG_ASSERT(curLen >= 0) - DEBUG_ASSERT(len >= 0) - DEBUG_ASSERT(at < curLen + 1 && at >= 0) - - for (ualni idx = 0; idx < at; idx++) { - out[idx] = cur[idx]; - } - for (ualni idx = 0; idx < len; idx++) { - out[idx + at] = tar[idx]; - } - for (ualni idx = at + len; idx < allLen; idx++) { - out[idx] = cur[idx - len]; - } - out[allLen] = '\0'; - return out; - } - - static tChar* removeLogic(const tChar* cur, ualni start, ualni end) { - ualni curLen = calcLength(cur); - ualni rangeLen = end - start; - ualni newLen = curLen - rangeLen; - auto* out = new tChar[newLen + 1]; - out[newLen] = '\0'; - for (ualni idx = 0; idx < start; idx++) { - out[idx] = cur[idx]; - } - for (ualni idx = end; idx < curLen; idx++) { - out[idx - rangeLen] = cur[idx]; - } - return out; - } - - static bool isEqualLogic(const tChar* left, const tChar* right) { - ualni idx = 0; - LOOP: - if (left[idx] == '\0' || right[idx] == '\0') { - if (left[idx] == '\0' && right[idx] == '\0') { - return true; - } - return false; - } - if (left[idx] != right[idx]) { - return false; - } - idx++; - goto LOOP; - } - - static ualni fromValueLength(alni val, ualni base) { - ualni iter = val; - ualni len = 0; - while (iter /= base) { - len++; - } - bool neg = val < 0; - len += 1 + ualni(neg); - return len; - } - - static tChar* stringFromValue(alni val, tChar* ownBuff, ualni base) { - tChar* out; - bool neg = val < 0; - ualni len = fromValueLength(val, base); - out = ownBuff ? ownBuff : new tChar[len + 1]; - out[len] = '\0'; - val = abs(val); - for (ualni i = len - 1; i >= int(neg); i--) { - out[i] = (tChar) (val % base + 48); - val /= (alni) base; - } - if (neg) { - out[0] = '-'; - } - return out; - } - - static ualni fromValueLength(alnf val, ualni base) { - auto rounded = (alni) val; - ualni mantissa = ( (alni) val - rounded) * 100000; - alni rounded_len = 0; - alni mantissa_len = 0; - while (rounded /= (alni) base) { - rounded_len++; - } - if (!rounded_len) { - rounded_len++; - } - while (mantissa /= base) { - mantissa_len++; - } - bool neg = val < 0; - bool dot = mantissa_len & 1; - alni tot_len = mantissa_len + rounded_len + dot + neg; - return tot_len; - } - - static tChar* fromValue(alnf, ualni, tChar*) { - DEBUG_BREAK(false) - return nullptr; - } - - static ualni fromValueLength(bool val) { - return val ? 4 : 5; - } - - static tChar* fromValue(bool val, tChar* ownBuff) { - alni len = val ? 4 : 5; - tChar* out = ownBuff ? ownBuff : new tChar[len + 1]; - out[len] = '\0'; - memCopy(out, val ? "True" : "False", len); - return out; - } - - static tChar* stringFromValue(int val, ualni base) { - return fromValue((alni) val, nullptr, base); - } - - static tChar* fromValue(tChar val) { - auto* out = new tChar[2]; - out[1] = '\0'; - out[0] = val; - return out; - } - - static bool toValue(const tChar*, alni&, ualni) { - DEBUG_BREAK(false) - return false; - } - - static bool toValue(const tChar*, alnf&, ualni) { - DEBUG_BREAK(false) - return false; - } - - static bool toValue(const tChar* in, bool& val) { - if (!calcLength(in)) return false; - if (isEqual(in, "False") || isEqual(in, "false") || isEqual(in, "0")) { - val = false; - } else { - val = true; - } - return true; - } - }; -} \ No newline at end of file diff --git a/Strings/public/Strings.hpp b/Strings/public/Strings.hpp deleted file mode 100644 index 3fdb5a4..0000000 --- a/Strings/public/Strings.hpp +++ /dev/null @@ -1,248 +0,0 @@ -#pragma once - -#include "PoolAllocator.hpp" -#include "StringLogic.hpp" -#include "TextEditor.hpp" - -namespace tp { - - // Static data - extern ModuleManifest gModuleStrings; - - template - class StringTemplate; - using String = StringTemplate; - - template - class StringTemplate { - typedef StringLogic StringLogic; - - // Hidden slave class - class StringData { - - // allows to edit each string with text editor inplace - class TextEditors { - enum { MAX_EDITED_STRINGS = 65536 }; // 2^16 - do not change mindlessly - typedef uint2 Address; - ChunkAlloc mEditorsPool; - - public: - TextEditors() : mEditorsPool() {} - - TextEditor* get(Address address) { return mEditorsPool.getBuff() + address; } - - Address createTextEditor(const tChar* originalBuffer) { - auto entry = (TextEditor**) mEditorsPool.allocate(0); - *entry = new TextEditor( originalBuffer ); - return Address(entry - mEditorsPool.getBuff()); - } - - void destroyTextEditor(Address address) { - auto entry = mEditorsPool.getBuff() + address; - mEditorsPool.deallocate(entry); - delete entry; - } - }; - - static TextEditors sTextEditors; - - public: - uint2 mIsConst; // source is non-modifiable - uint2 mEditedIdx; // editor id - uint4 mReferenceCount; // number of users of this - tChar* mBuff; // actual string data - - public: - StringData() { - MODULE_SANITY_CHECK(gModuleStrings) - mBuff = (tChar*) "*"; - mReferenceCount = 0; - mIsConst = true; - mEditedIdx = 0; - } - - StringData(const tChar* aBuff, bool aIsConst) { - MODULE_SANITY_CHECK(gModuleStrings) - DEBUG_ASSERT(aBuff) - mBuff = (tChar*) aBuff; - mReferenceCount = 0; - mIsConst = aIsConst; - mEditedIdx = 0; - } - - explicit StringData(const tChar* aBuff) { - MODULE_SANITY_CHECK(gModuleStrings) - DEBUG_ASSERT(aBuff) - auto const len = StringLogic::calcLength(aBuff); - resize(len); - memCopy(mBuff, aBuff, len); - mReferenceCount = 0; - mIsConst = false; - mEditedIdx = 0; - } - - [[nodiscard]] tChar* getBuffer() { - DEBUG_ASSERT(!isEditorMode()) - if (isEditorMode()) return nullptr; - return mBuff; - } - - ~StringData() { - if (!mIsConst) delete[] mBuff; - if (isEditorMode()) sTextEditors.destroyTextEditor(mEditedIdx); - } - - public: - void resize(ualni size) { - DEBUG_ASSERT(!isEditorMode() && mReferenceCount == 1 && !mIsConst) - delete[] mBuff; - mBuff = new tChar[size + 1]; - mBuff[size] = StringLogic::getEndChar(); - } - - public: - [[nodiscard]] bool isEditorMode() const { return mEditedIdx; } - - void createEditor() { - DEBUG_ASSERT(!isEditorMode()) - if (isEditorMode()) mEditedIdx = sTextEditors.createTextEditor(mBuff); - } - - [[nodiscard]] TextEditor* getEditor() const { - DEBUG_ASSERT(isEditorMode()) - if (!isEditorMode()) return nullptr; - return sTextEditors.get(mEditedIdx); - } - - void applyEditor() { - DEBUG_ASSERT(isEditorMode() && mReferenceCount == 1 && !mIsConst) - if (!isEditorMode()) return; - auto editor = sTextEditors.get(mEditedIdx); - resize(editor.textSize()); - for ( auto character : *editor) { - mBuff[character.idx] = character; - } - } - - void destroyEditor() { - DEBUG_ASSERT(isEditorMode()) - if (!isEditorMode()) return; - sTextEditors.destroyTextEditor(mEditedIdx); - } - }; - - private: - class StringData* mStringData; - - private: - enum { STRINGS_POOL_SIZE = 1024, }; - static PoolAlloc* sStringPool; - static StringData sNullString; - - // --------------------------------- Main Interface ---------------------------------// - public: - // Creates null string reference - StringTemplate() { - mStringData = &sNullString; - incReference(mStringData); - } - - // References existing string data - StringTemplate(const StringTemplate& in) { - if (in.isEditorMode()) { - // Copies raw data and claims ownership over it - mStringData = new (sStringPool->allocate(0)) StringData(in.mStringData->mBuff); - incReference(mStringData); - } else { - mStringData = in.mStringData; - incReference(mStringData); - } - } - - // Creates new string data from raw data pointer. - // Does not own string buffer - string buffer will not be freed. Initializes as const memory. - explicit StringTemplate(const tChar* raw) { - mStringData = new (sStringPool->allocate(0)) StringData(raw, true); - incReference(mStringData); - } - - // Copies raw data and claims ownership over it - explicit StringTemplate(tChar* raw) { - mStringData = new (sStringPool->allocate(0)) StringData(raw); - incReference(mStringData); - } - - ~StringTemplate() { - decReference(mStringData); - } - - private: - - [[nodiscard]] bool isEditorMode() const { - return mStringData->isEditorMode(); - } - - static void incReference(StringData* dp) { - dp->mReferenceCount++; - } - - void decReference(StringData* dp) { - dp->mReferenceCount--; - if (!dp->mReferenceCount) { - sStringPool->deallocate(mStringData); - mStringData->~StringData(); - } - } - - public: // Access - // used to read data - [[nodiscard]] const tChar* read() const { - return mStringData->mBuff; - } - - // used to write data - // output will be null if in TextEditing mode - [[nodiscard]] tChar* write() { - makeModifiable(); - return mStringData->getBuffer(); - } - - // output will be null if in TextEditing mode - [[nodiscard]] tChar* resize() { - if (!mStringData->getEditor()) mStringData->resize(); - return mStringData->getBuffer(); - } - - public: // TextEditor Mode - // Enters TextEditor Mode - void createEditor() { mStringData->createEdited(); } - - // Access to TextEditor Context & Interface - [[nodiscard]] TextEditor* getEditor() { return mStringData->getEdited(); } - [[nodiscard]] const TextEditor* getEditor() const { return mStringData->getEdited(); } - - // Applies TextEditor Mode To Current buffer - void applyEditor() { mStringData->applyEditor(); } - - // Leaves TextEditor Mode - void destroyEditor() { mStringData->destroyEditor(); } - - private: - void makeModifiable() { - // We have no rights to modify if someone references that memory too - // So we need to create new copy of StringData - if (mStringData->mReferenceCount > 1) { - mStringData = new (sStringPool->allocate(0)) StringData(mStringData->mBuff); - incReference(mStringData); - return; - } - - // Also if initial raw data was marked as const - create copy of raw data - // Note - raw data will be lost at this point if no other record of such is stored - if (mStringData->mIsConst) { - mStringData = new (sStringPool->allocate(0)) StringData(mStringData->mBuff); - incReference(mStringData); - } - } - }; -} \ No newline at end of file diff --git a/Strings/tests/tests.cpp b/Strings/tests/tests.cpp deleted file mode 100644 index 2e9f769..0000000 --- a/Strings/tests/tests.cpp +++ /dev/null @@ -1,66 +0,0 @@ - - -#include "common.h" - -#include "allocators.h" - -#include "strings.h" - -#include - -#include -#include -#include - -#include "TextEditor.hpp" - -#include "Logging.hpp" - -using namespace tp; - -void test_conversions() { - - for (auto i : tp::Range(1000)) { - - auto sign = bool(std::rand() % 2) ? 1 : -1; - - auto floating = std::rand() / (tp::alnf)std::rand() * sign; - auto tmp = std::to_string(floating); - auto left = tp::string(tmp.c_str()); - auto right = tp::string(floating); - DBG_BREAK(left != right); - auto back = (tp::alnf)right; - //DBG_BREAK(back != floating); - - auto integer = std::rand() * sign; - tmp = std::to_string(integer); - left = tp::string(tmp.c_str()); - right = tp::string(integer); - DBG_BREAK(left != right); - back = (tp::alni)right; - DBG_BREAK(back != integer); - } -} - -void test_editor() { - tp::string str = " initial "; - str.createEdited(); - auto edited = str.getEdited(); - edited->setCursor({0, 4}); - edited->insert({"aaa", 3}); - str.saveEdited(); - str.clearEdited(); - - GLog->write(str, true); -} - -int main() { - tp::alloc_init(); - string::Initialize(); - Logger::init(); - //test_conversions(); - test_editor(); - Logger::deinit(); - string::UnInitialize(); - tp::alloc_uninit(); -} \ No newline at end of file diff --git a/TODO b/TODO index 7ea9460..7811a43 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,7 @@ Containers: Buffer 2d ! Add check copy times AVL dont copy data just swap - More tests on mBuff and avl + More tests on buff and avl Strings: Implement diff --git a/TextEditor/TextEditor.cpp b/TextEditor/TextEditor.cpp deleted file mode 100644 index 1493f76..0000000 --- a/TextEditor/TextEditor.cpp +++ /dev/null @@ -1,554 +0,0 @@ - -#include "TextEditor.hpp" - -using namespace tp; -using namespace str; - -bool tp::str::PiecesDS::Node::mInsertionOperation = false; - -bool tp::str::isNewLineChar(Char character) { - return (character == '\n') || (character == '\r'); -} - -void Input::getLineOffsets(Buffer& out) { - halni lines = 0; - for (auto idx : Range(mLen)) { - if (isNewLineChar(mInput[idx])) { - lines++; - } - } - out.reserve(lines + 2); // plust start and end offsets - lines = 0; - for (auto idx : Range(mLen)) { - if (isNewLineChar(mInput[idx])) { - out[lines + 1] = Index(idx + 1); - lines++; - } - } - out[0] = 0; - out[lines + 1] = mLen; -} - - // ---------------------- Pointer ---------------------- // - -Pointer::Pointer() { - mCol = 0; mLine = 0; -} - -Pointer::Pointer(LineId aLine, ColumnId aCol) { - mLine = aLine; - mCol = aCol; -} - -Pointer::Pointer(const Input& aInput) { - halni lines = 0; - halni col = 0; - for (auto idx : Range(aInput.mLen)) { - if (isNewLineChar(aInput.mInput[idx])) { - lines++; - col = 0; - } - else { - col++; - } - } - mLine = lines; - mCol = col; -} - -void Pointer::operator+=(Char achar) { - if (isNewLineChar(achar)) { - mLine += 1; - mCol = 0; - } - else { - mCol += 1; - } -} - -void Pointer::operator+=(const Pointer& ap) { - *this = operator+(ap); -} - -Pointer Pointer::operator-(const Pointer in) const { - if (mLine == in.mLine) { - return { 0, mCol - in.mCol }; - } - return { mLine - in.mLine, mCol }; -} - -Pointer Pointer::operator+(const Pointer& ap) const { - if (ap.mLine == 0) { - return { mLine, mCol + ap.mCol }; - } - return { mLine + ap.mLine, ap.mCol }; -} - -bool Pointer::operator==(const Pointer& in) const { - return in.mCol == mCol && in.mLine == mLine; -} - -bool Pointer::operator>(const Pointer& in) const { - if (mLine > in.mLine) { - return true; - } - else if (mLine < in.mLine) { - return false; - } - - return mCol > in.mCol; -} - -bool Pointer::operator>=(const Pointer& in) const { - return operator>(in) || in == *this; -} - -Pointer Piece::diffPtr() const { - return mEnd - mStart; -} - -LineId Piece::nLines() const { - return { mEnd.mLine - mStart.mLine }; -} - -// ---------------------- Add Buff ---------------------- // - -AddBuff::AddBuff() { - Input input = { "", 0 }; - Buffer lineoffsets; - input.getLineOffsets(lineoffsets); - mLineOffsets.append(lineoffsets.mBuff(), (Index)lineoffsets.length()); -} - -void AddBuff::append(Input aInput) { - - // TODO : errors here - - Buffer lineoffsets; - aInput.getLineOffsets(lineoffsets); - - if (lineoffsets.length() == 2) { - mLineOffsets[mLineOffsets.len() - 1] += lineoffsets[1] - lineoffsets[0]; - } - else { - - auto last_line_offset = mLineOffsets[mLineOffsets.len() - 1]; - - // offset last line ptr - mLineOffsets[mLineOffsets.len() - 1] += lineoffsets[1]; - - // offset all lines by mLineOffsets.mLast ptr - for (auto offset : lineoffsets) { - offset.data() += last_line_offset; - } - - mLineOffsets.append(&lineoffsets[2], (Index)(lineoffsets.length() - 2)); - } - - mBuff.append(aInput.mInput, aInput.mLen); -} - -Pointer AddBuff::endPtr() { - return { mLineOffsets.len() - 2, mLineOffsets[mLineOffsets.len() - 1] - mLineOffsets[mLineOffsets.len() - 2] }; -} - -// ---------------------- Orig Buff ---------------------- // - -OrigBuff::OrigBuff(Input aOriginal) { - mOriginal = aOriginal; - mOriginal.getLineOffsets(mLineOffsets); - - mPtrStart = { 0, 0 }; - mPtrEnd = mOriginal; -} - -void OrigBuff::makeOwnOriginalInput() { - if (mOwnsInput) { - return; - } - - auto input_copy = new Char[mOriginal.mLen + 1]; - DEBUG_ASSERT(sizeof(Char) == sizeof(uint1)); - memcp(input_copy, mOriginal.mInput, mOriginal.mLen); - input_copy[mOriginal.mLen] = '\0'; - mOriginal.mInput = input_copy; - mOwnsInput = true; -} - -OrigBuff::~OrigBuff() { - if (mOwnsInput) { - delete[] mOriginal.mInput; - } -} - -// ---------------------- Editor ---------------------- // - -PieceCrs TextEditor::findPiece(Pointer ptr) const { - PieceCrs out; - if (!mPieces.nPieces()) { - return out; - } - - if (mPieces.ptrSum() == ptr) { - out.piece = mPieces.maxNode(mPieces.head()); - } else { - out.piece = mPieces.find(ptr); - } - - DBG_BREAK(!out.piece); - out.piece_ptr = out.piece->getFindKey(); - out.ptr = ptr; - out.offset = out.ptr - out.piece_ptr; - return out; -} - -void TextEditor::clampPtr(Pointer& ptr) const { - if (!mPieces.nPieces()) { - ptr = { 0, 0 }; - return; - } - - CLAMP(ptr.mLine, 0, mNLines()); - - auto crs = findPiece(Pointer{ ptr.mLine, 0 }); - Index line_len = getPieceLineLen(crs.piece->mPiece, crs.offset.mLine); - - auto next_piece_ptr = nextPiecePtr(crs.piece, crs.piece_ptr); - auto piece = crs.piece; - while (piece->mNext && ptr.mLine == next_piece_ptr.mLine) { - piece = piece->mNext; - next_piece_ptr = nextPiecePtr(piece, next_piece_ptr); - line_len += getPieceLineLen(piece->mPiece, 0); - } - - if (ptr.mLine != mNLines()) { - line_len -= 1; - } - - CLAMP(ptr.mCol, 0, line_len); -} - -void TextEditor::setCursor(Pointer ptr) { - clampPtr(ptr); - mCursor = ptr; -} - -void TextEditor::setCursorEnd(Pointer ptr) { - clampPtr(ptr); - mCursorEnd = ptr; - mCursor = mCursorEnd; -} - -const Char* TextEditor::getPieceLine(const Piece* piece, LineId offset) const { - const Char* buff; - if (piece->mAddedBuff) { - if (offset == 0) { - buff = &mAddBuff.mBuff[mAddBuff.mLineOffsets[piece->mStart.mLine]] + piece->mStart.mCol; - } - else if (offset > piece->nLines()) { - buff = &mAddBuff.mBuff[mAddBuff.mLineOffsets[piece->mEnd.mLine]] + piece->mEnd.mCol; - } - else { - buff = &mAddBuff.mBuff[mAddBuff.mLineOffsets[piece->mStart.mLine + offset]]; - } - } - else { - if (offset == 0) { - buff = &mOrigBuff.mOriginal.mInput[mOrigBuff.mLineOffsets[piece->mStart.mLine]] + piece->mStart.mCol; - } - else if (offset > piece->nLines()) { - buff = &mOrigBuff.mOriginal.mInput[mOrigBuff.mLineOffsets[piece->mEnd.mLine]] + piece->mEnd.mCol; - } - else { - buff = &mOrigBuff.mOriginal.mInput[mOrigBuff.mLineOffsets[piece->mStart.mLine + offset]]; - } - } - return buff; -} - -const Char* TextEditor::getBuffLine(const Piece* piece, LineId offset) const { - const Char* buff; - if (piece->mAddedBuff) { - buff = &mAddBuff.mBuff[mAddBuff.mLineOffsets[piece->mStart.mLine + offset]]; - } - else { - buff = &mOrigBuff.mOriginal.mInput[mOrigBuff.mLineOffsets[piece->mStart.mLine + offset]]; - } - return buff; -} - -Pointer TextEditor::prevPiecePtr(PiecesDS::Node* piece_node, Pointer aPtr) const { - if (!piece_node->mPrev) { - return { 0, 0 }; - } - - return piece_node->mPrev->getFindKey(); -} - -Pointer TextEditor::nextPiecePtr(PiecesDS::Node* aPiece, Pointer aPtr) const { - if (!aPiece) return { -1, -1 }; - - if (aPiece->mNext) { - return aPiece->mNext->getFindKey(); - } - return aPiece->getFindKey() + aPiece->mDiff; -} - -LineId TextEditor::getPieceLineLen(Piece* aPiece, LineId line) const { - return LineId(getPieceLine(aPiece, line + 1) - getPieceLine(aPiece, line)); -} - -TextEditor::TextEditor(Input original) : mOrigBuff(original) { - DEBUG_ASSERT(original.mLen); - auto new_node = mPieces.insertAfter(0, { false, mOrigBuff.mPtrStart, mOrigBuff.mPtrEnd }); - mPieces.pushUndoPoint(); -} - -TextEditor::TextEditor() : mOrigBuff({ 0, 0 }) { -} - -Index TextEditor::mNLines() const { - return mPieces.ptrSum().mLine; -} - -Pointer TextEditor::getCursor() const { - return mCursor; -} - -Pointer TextEditor::getCursorEnd() const { - return mCursorEnd; -} - -void TextEditor::insert(Input aInput) { - // handle selectiom - remove(true); - - // save input to addbuff - auto start_ref = mAddBuff.endPtr(); - mAddBuff.append(aInput); - auto end_ref = mAddBuff.endPtr(); - auto input_diff = end_ref - start_ref; - - PiecesDS::Node* prev_node = nullptr; - PiecesDS::Node* new_node = nullptr; - - auto crs = findPiece(mCursor); - - if (crs.piece && crs.piece->mPrev && crs.offset == Pointer{ 0, 0 }) { - crs.piece_ptr = prevPiecePtr(crs.piece, crs.piece_ptr); - crs.offset = crs.ptr - crs.piece_ptr; - crs.piece = crs.piece->mPrev; - } - - if (crs.piece) { - if (crs.ptr == crs.piece_ptr) { // start - prev_node = crs.piece->mPrev; - } - else if (crs.offset == crs.piece->mPiece->diffPtr()) { // end - if (mLastInsertionCrs == crs.ptr && crs.piece->mPiece->mAddedBuff && crs.piece->mPiece->mEnd == start_ref) { - crs.piece->mPiece->mEnd += input_diff; - mPieces.update_cache(crs.piece); - goto END; - } - else { - prev_node = crs.piece; - } - } - else { // middle - prev_node = splitPiece(crs.piece, crs.offset); - } - } - - // create the new node - new_node = mPieces.insertAfter(prev_node, { true, start_ref, end_ref }); - - END: - mCursor = mCursor + input_diff; - mCursorEnd = mCursor; - mLastInsertionCrs = mCursor; - mPieces.pushUndoPoint(); -} - -PiecesDS::Node* TextEditor::splitPiece(PiecesDS::Node* piece, Pointer split_ptr) { - auto span = piece->mPiece->diffPtr(); - - if (span == split_ptr || split_ptr == Pointer{ 0, 0 }) { - return nullptr; - } - - // save temp data - auto end_ptr = piece->mPiece->mEnd; - auto left_piece = Piece{ piece->mPiece->mAddedBuff, piece->mPiece->mStart, piece->mPiece->mStart + split_ptr }; - auto left_node = mPieces.insertAfter(piece->mPrev, left_piece); - - // create right half - auto right_node = mPieces.insertAfter(left_node, { left_node->mPiece->mAddedBuff, left_node->mPiece->mEnd, end_ptr }); - - auto line_len = halni(getBuffLine(right_node->mPiece, 1) - getBuffLine(right_node->mPiece, 0)); - if (line_len == right_node->mPiece->mStart.mCol) { - DBG_BREAK(1); - right_node->mPiece->mStart = { right_node->mPiece->mStart.mLine + 1, 0 }; - } - - // remove current node - mPieces.remove(right_node->mNext); - - return left_node; -} - -void TextEditor::remove(bool only_selection, Dir dir, DirUnit unit) { - if (!mPieces.nPieces()) { - return; - } - - if (mCursor == mCursorEnd) { - if (only_selection) { - return; - } - - if (dir == LEFT) { - if (mCursor == Pointer(0, 0)) { - return; - } - - PieceCrs crs; - if (mCursor.mCol == nullptr) { - auto new_ptr = Pointer{ mCursor.mLine - 1, ENV_HALNI_MAX }; - clampPtr(new_ptr); - crs = findPiece(new_ptr); - //crs = findPiece({ crs.ptr.mLine, crs.ptr.mCol - 1 }); - } - else { - crs = findPiece({ mCursor.mLine, mCursor.mCol - 1 }); - } - - mCursorEnd = mCursor; - mCursor = crs.ptr; - } - else if (dir == RIGHT) { - auto crs = findPiece(Pointer{ mCursor.mLine, mCursor.mCol + 1 }); - mCursorEnd = mCursor; - mCursor = crs.ptr; - - if (mCursor == mCursorEnd) { - return; - } - } - else { - return; - } - } - - if (mCursor > mCursorEnd) { - swap(mCursor, mCursorEnd); - } - - auto crs = findPiece(mCursor); - - // first and last pieces to be deleted - PiecesDS::Node* del_start = nullptr, *del_end = nullptr; - - // find left - if (crs.offset == Pointer{ 0, 0 }) { - del_start = crs.piece; - } - else if (crs.piece->mPiece->diffPtr() == crs.offset) { - del_start = crs.piece->mNext; - } - else { - del_start = splitPiece(crs.piece, crs.offset)->mNext; - } - - auto crs_end = findPiece(mCursorEnd); - - // find right - if (crs_end.offset == Pointer{ 0, 0 }) { - del_end = crs_end.piece->mPrev; - } - else if (crs_end.piece->mPiece->diffPtr() == crs_end.offset) { - del_end = crs_end.piece; - } - else { - bool intersect = crs_end.piece == del_start; - del_end = splitPiece(crs_end.piece, crs_end.offset); - if (intersect) { - del_start = del_end; - } - } - - DEBUG_ASSERT(del_start && del_end); - auto end_piece = del_end->mNext ? del_end->mNext->mPiece : nullptr; - - while (del_start && del_start->mPiece != end_piece) { - auto del = del_start; - - // del_start will be reused by the avl-tree after deletion otherwise - // works as we go from left to right - if (!del_start->mNext || del_start->mHeight <= del_start->mNext->mHeight) { - del_start = del_start->mNext; - } - - mPieces.remove(del); - } - mCursorEnd = mCursor; - - mPieces.pushUndoPoint(); -} - -void TextEditor::undo() { - mPieces.undo(); -} - -void TextEditor::redo() { - mPieces.redo(); -} - -TextEditor::~TextEditor() { -} - -// ------------------------------ ITERATOR ------------------------------ // - -Iterator TextEditor::begin() { return Iterator(this); } -alni TextEditor::end() { return nullptr; } - -Iterator::Iterator(const TextEditor* aSelf) { - mSelf = aSelf; - mNode = mSelf->mPieces.first(); - mVal = mSelf->getPieceLine(mNode->mPiece, 0)[0]; -} - -bool Iterator::inputLeft() { - return mNode; -} - -Char Iterator::character() { - return mVal; -} - -void Iterator::operator++() { - auto nl = isNewLineChar(mVal); - auto diff = Pointer{ nl, !nl }; - mPtr += diff; - mOffset += diff; - - if (mOffset == mNode->mPiece->diffPtr()) { - mNode = mNode->mNext; - mOffset = { 0, 0 }; - if (!mNode) { - return; - } - } - - mVal = mSelf->getPieceLine(mNode->mPiece, mOffset.mLine)[mOffset.mCol]; -} - -bool Iterator::operator!=(alni const& iter) { - return inputLeft(); -} - -bool Iterator::operator==(alni const& iter) { - return !inputLeft(); -} - -Char Iterator::operator->() { return mVal; } -const Iterator& Iterator::operator*() { return *this; } diff --git a/TextEditor/TextEditor.hpp b/TextEditor/TextEditor.hpp deleted file mode 100644 index e1b1dc1..0000000 --- a/TextEditor/TextEditor.hpp +++ /dev/null @@ -1,382 +0,0 @@ - -#pragma once - -#include "Strings.hpp" -#include "Buffer.hpp" -#include "Tree.hpp" - -namespace tp { - - class PiecesDS { - - struct Input { - const Char* mInput = nullptr; - Index mLen = 0; - void getLineOffsets(Buffer& out); - }; - - struct Pointer { - LineId mLine; - ColumnId mCol; - - Pointer(); - Pointer(LineId aLine, ColumnId aCol); - Pointer(const Input& aInput); - void operator+=(Char achar); - void operator+=(const Pointer& ap); - Pointer operator-(const Pointer in) const; - Pointer operator+(const Pointer& ap) const; - bool operator==(const Pointer& in) const; - bool operator>(const Pointer& in) const; - bool operator>=(const Pointer& in) const; - }; - - struct Piece { - bool mAddedBuff = false; - Pointer mStart; - Pointer mEnd; - - Pointer diffPtr() const; - LineId nLines() const; - }; - - public: - - // Tree Node : Based on AvlNodeBlueprint - struct Node { - - Node* mLeft = nullptr; - Node* mRight = nullptr; - Node* mParent = nullptr; - halni mHeight = 0; - - Pointer mPtrLeft; - Pointer mPtrRight; - Pointer mDiff; - - Node* mNext = nullptr; - Node* mPrev = nullptr; - Piece* mPiece = nullptr; - - static bool mInsertionOperation; - - Node() {} - Node(Pointer aKey) { - //mVal = aKey; - } - - bool disentRight(Pointer aKey) const { - return aKey > mPtrLeft; - } - - bool disentLeft(Pointer aKey) const { - return mPtrLeft > aKey; - } - - bool exactNode(Pointer aKey) const { - if (mInsertionOperation) { - return aKey > mPtrLeft && mPtrLeft + mDiff > aKey; - } - return aKey >= mPtrLeft && mPtrLeft + mDiff > aKey; - } - - Pointer getFindKey(Node* node = nullptr) const { - // node must be ancestor of this node - - Pointer out = mPtrLeft; - - if (node == this) { - return out; - } - - auto iter = this; - while (iter->mParent != node) { - if (iter == iter->mParent->mRight) { - auto left_sub_tree = iter->mParent->mPtrLeft + iter->mParent->mDiff; - out = left_sub_tree + out; - } - iter = iter->mParent; - } - - if (node) { - if (iter == iter->mParent->mRight) { - auto left_sub_tree = iter->mParent->mPtrLeft + iter->mParent->mDiff; - out = left_sub_tree + out; - } - } - return out; - } - - void copyData(const Node& in) { - mPiece = in.mPiece; - mNext = in.mNext; - mPrev = in.mPrev; - - if (mPrev) { - mPrev->mNext = this; - } - - if (mNext) { - mNext->mPrev = this; - } - } - - Pointer keyInRightSubtree(Pointer key) const { return key - (mPtrLeft + mDiff); } - Pointer keyInLeftSubtree(Pointer key) const { return key; } - - void updateTreeCahceCallBack() { - DEBUG_ASSERT(mPiece); - mDiff = mPiece->diffPtr(); - if (mLeft) { - mPtrLeft = mLeft->sum(); - } - else { - mPtrLeft = { 0, 0 }; - } - - if (mRight) { - mPtrRight = mRight->sum(); - } - else { - mPtrRight = { 0, 0 }; - } - } - - Pointer sum() const { - return (mPtrLeft + mDiff) + mPtrRight; - } - }; - - private: - - AvlTree mTree; - - public: - - PiecesDS() { - } - - Node* find(Pointer ptr) const { - return mTree.find(ptr); - } - - Node* minNode(Node* node) const { - return mTree.minNode(node); - } - - Node* maxNode(Node* node) const { - return mTree.maxNode(node); - } - - Node* head() const { - return mTree.head(); - } - - void insert(const Node& node, Pointer ptr) { - Node::mInsertionOperation = true; - mTree.insert(ptr, node); - Node::mInsertionOperation = false; - } - - Node* insertAfter(Node* node, Piece piece) { - auto key = node ? (node->getFindKey() + node->mDiff) : Pointer{ 0, 0 }; - auto new_node = Node(); - new_node.mPiece = new Piece(piece); - - insert(new_node, key); - -#ifdef _DEBUG - auto err_node = mTree.isInvalid(mTree.head()); - DBG_BREAK(err_node); -#endif - - auto out = mTree.find(key); - - Node* next = out->mRight; - Node* prev = out->mLeft; - - if (!(next || prev) && out->mParent) { - if (out->mParent->mLeft == out) { - next = out->mParent; - } - else { - prev = out->mParent; - } - } - - if (next) { - out->mNext = next; - out->mPrev = next->mPrev; - next->mPrev = out; - if (out->mPrev) out->mPrev->mNext = out; - } - else if (prev) { - out->mPrev = prev; - out->mNext = prev->mNext; - prev->mNext = out; - if (out->mNext) out->mNext->mPrev = out; - } - - return out; - } - - void remove(Node* aNode) { - auto key = aNode->getFindKey(); - - if (aNode->mPrev) { - aNode->mPrev->mNext = aNode->mNext; - } - - if (aNode->mNext) { - aNode->mNext->mPrev = aNode->mPrev; - } - - auto del = aNode->mPiece; - mTree.remove(key); - delete del; - -#ifdef _DEBUG - auto err_node = mTree.isInvalid(mTree.head()); - DBG_BREAK(err_node); -#endif - } - - Node* first() const { - return mTree.minNode(mTree.head()); - } - - Pointer ptrSum() const { - if (mTree.head()) { - return mTree.head()->sum(); - } - return { 0, 0 }; - } - - halni nPieces() const { - return mTree.size(); - } - - void update_cache(Node* node) { - if (node) { - node->updateTreeCahceCallBack(); - update_cache(node->mParent); - } - } - - void undo() {} - void redo() {} - void pushUndoPoint() {} - }; - - struct AddBuff { - Buffer mBuff; - Buffer mLineOffsets; - Index mColumn = 0; - - AddBuff(); - void append(Input aInput); - Pointer endPtr(); - }; - - struct OrigBuff { - bool mOwnsInput = false; - Input mOriginal; - Buffer mLineOffsets; - - Pointer mPtrStart; - Pointer mPtrEnd; - - // does not owns the original input by default - OrigBuff(Input aOriginal); - - void makeOwnOriginalInput(); - - ~OrigBuff(); - }; - - struct PieceCrs { - Pointer piece_ptr; - Pointer offset; - Pointer ptr; - PiecesDS::Node* piece = nullptr; - }; - - class TextEditor { - friend class Iterator; - - class Iterator { - friend TextEditor; - - const TextEditor* mSelf; - PiecesDS::Node* mNode = nullptr; - Pointer mOffset = { 0, 0 }; - Pointer mPtr = { 0, 0 }; - Char mVal = 0; - - Iterator(const TextEditor* mSelf); - bool inputLeft(); - - public: - - Char character(); - void operator++(); - bool operator!=(alni const& iter); - bool operator==(alni const& iter); - Char operator->(); - const Iterator& operator*(); - }; - - public: - - // pieces of strings that construct the text - PiecesDS mPieces; - - // string buffers to wich pieces can reffer - OrigBuff mOrigBuff; - AddBuff mAddBuff; - - // active position on the text - Pointer mCursor; - Pointer mCursorEnd; - - Pointer mLastInsertionCrs; - //private: - - [[nodiscard]] PieceCrs findPiece(Pointer ptr) const; - [[nodiscard]] Pointer prevPiecePtr(PiecesDS::Node* piece_node, Pointer piece_pointer) const; - [[nodiscard]] Pointer nextPiecePtr(PiecesDS::Node* piece_node, Pointer piece_pointer) const; - - [[nodiscard]] const Char* getBuffLine(const Piece*, LineId) const; - [[nodiscard]] const Char* getPieceLine(const Piece*, LineId) const; - [[nodiscard]] PiecesDS::Node* splitPiece(PiecesDS::Node* piece, Pointer split_ptr); - [[nodiscard]] LineId getPieceLineLen(Piece* aPiece, LineId line) const; - - public: - enum Dir : uint1 { LEFT, RIGHT, UP, DOWN }; - enum DirUnit : uint1 { CHAR, WORD, TOK, LINE_END, LINE_START }; - - public: - - TextEditor(); - explicit TextEditor(Input original); - - [[nodiscard]] Index mNLines() const; - void clampPtr(Pointer& ptr) const; - [[nodiscard]] Pointer getCursor() const; - [[nodiscard]] Pointer getCursorEnd() const; - void setCursor(Pointer ptr); - void setCursorEnd(Pointer ptr); - - void insert(Input aInput); - - void remove(bool only_selection = false, Dir dir = LEFT, DirUnit unit = CHAR); - - void undo(); - void redo(); - - Iterator begin(); - alni end(); - - ~TextEditor(); - }; -} \ No newline at end of file