diff options
author | elfmz <fenix1905@tut.by> | 2021-12-31 12:15:36 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2021-12-31 12:21:48 +0300 |
commit | 6b7b5f7fe480107373a6ef3cbd6ee41378c93642 (patch) | |
tree | 1af3f15ecc76c47749f74f38302cb33e0a3796e1 /far2l/src/base | |
parent | a14dc1a81c797928d4f1b7d6a6b46ecc63f98308 (diff) |
split /aux to /mix and /base
Diffstat (limited to 'far2l/src/base')
-rw-r--r-- | far2l/src/base/CriticalSections.hpp | 69 | ||||
-rw-r--r-- | far2l/src/base/DList.cpp | 121 | ||||
-rw-r--r-- | far2l/src/base/DList.hpp | 125 | ||||
-rw-r--r-- | far2l/src/base/FARString.cpp | 550 | ||||
-rw-r--r-- | far2l/src/base/FARString.hpp | 241 | ||||
-rw-r--r-- | far2l/src/base/array.hpp | 473 | ||||
-rw-r--r-- | far2l/src/base/bitflags.hpp | 62 | ||||
-rw-r--r-- | far2l/src/base/farqueue.cpp | 157 | ||||
-rw-r--r-- | far2l/src/base/farqueue.hpp | 66 | ||||
-rw-r--r-- | far2l/src/base/farrtl.cpp | 69 | ||||
-rw-r--r-- | far2l/src/base/farrtl.hpp | 18 | ||||
-rw-r--r-- | far2l/src/base/noncopyable.hpp | 52 |
12 files changed, 2003 insertions, 0 deletions
diff --git a/far2l/src/base/CriticalSections.hpp b/far2l/src/base/CriticalSections.hpp new file mode 100644 index 00000000..db2bfcaf --- /dev/null +++ b/far2l/src/base/CriticalSections.hpp @@ -0,0 +1,69 @@ +#pragma once + +/* +CriticalSections.hpp + +Критические секции +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "noncopyable.hpp" +#include <mutex> +#include <memory> + +class CriticalSection +{ + private: + std::shared_ptr<std::recursive_mutex> _mutex; + +public: + CriticalSection() : _mutex(std::make_shared<std::recursive_mutex>()) + { + } + + public: +#if 1 + void Enter() { _mutex->lock(); } + void Leave() { _mutex->unlock(); } +#else + void Enter() { if (!_mutex->try_lock()) { fprintf(stderr, "CriticalSection:%p - locking by %p\n", this, pthread_self()); _mutex->lock(); } fprintf(stderr, "CriticalSection:%p - locked by %p\n", this, pthread_self()); } + void Leave() { fprintf(stderr, "CriticalSection:%p - unlocked by %p\n", this, pthread_self()); _mutex->unlock(); } +#endif +}; + +class CriticalSectionLock:public NonCopyable +{ + private: + CriticalSection &_object; + + public: + CriticalSectionLock(CriticalSection &object): _object(object) { _object.Enter(); } + ~CriticalSectionLock() { _object.Leave(); } +}; + diff --git a/far2l/src/base/DList.cpp b/far2l/src/base/DList.cpp new file mode 100644 index 00000000..f037523b --- /dev/null +++ b/far2l/src/base/DList.cpp @@ -0,0 +1,121 @@ +/* +DList.cpp + +двусвязный список +*/ +/* +Copyright (c) 2009 lort +Copyright (c) 2009 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "headers.hpp" + + +#include "DList.hpp" + +CDList::CDList(): + count(0) +{ + root.next=&root; + root.prev=&root; +} + +void CDList::Clear() +{ + Node *f=root.next; + + while (f!=&root) + { + Node *f1=f; + f=f->next; + DeleteNode(f1); + } + + count=0; + root.next=&root; + root.prev=&root; +} +void CDList::CSwap(CDList &l) +{ + Node *pr=root.prev; + root.next->prev=&l.root; + pr->next=&l.root; + pr=l.root.prev; + l.root.next->prev=&root; + pr->next=&root; + size_t tcount=count; + Node troot=root; + count=l.count; + root=l.root; + l.count=tcount; + l.root=troot; +} +void *CDList::CInsertBefore(void *b, void *item) +{ + Node *Before=b ? (Node*)((BYTE*)b-sizeof(Node)) : &root; + Node *node=AllocNode(item); + node->prev=Before->prev; + node->next=Before; + Before->prev->next=node; + Before->prev=node; + ++count; + return ((BYTE*)node)+sizeof(Node); +} +void *CDList::CInsertAfter(void *a, void *item) +{ + Node *After=a ? (Node*)((BYTE*)a-sizeof(Node)) : &root; + return CInsertBefore((BYTE*)After->next+sizeof(Node), item); +} +void CDList::CMoveBefore(void *b, void *item) +{ + if (!item) return; + if (item == b) return; + Node *Before=b ? (Node*)((BYTE*)b-sizeof(Node)) : &root; + Node *node=(Node*)((BYTE*)item-sizeof(Node)); + node->prev->next = node->next; + node->next->prev = node->prev; + node->prev=Before->prev; + node->next=Before; + Before->prev->next=node; + Before->prev=node; +} +void CDList::CMoveAfter(void *a, void *item) +{ + if (item == a) return; + Node *After=a ? (Node*)((BYTE*)a-sizeof(Node)) : &root; + CMoveBefore((BYTE*)After->next+sizeof(Node), item); +} +void *CDList::CDelete(void *item) +{ + Node *node=(Node*)((BYTE*)item-sizeof(Node)); + Node *pr=node->prev; + Node *nx=node->next; + pr->next=nx; + nx->prev=pr; + --count; + DeleteNode(node); + return pr==&root ? nullptr : ((BYTE*)pr)+sizeof(Node); +} diff --git a/far2l/src/base/DList.hpp b/far2l/src/base/DList.hpp new file mode 100644 index 00000000..9e65ff87 --- /dev/null +++ b/far2l/src/base/DList.hpp @@ -0,0 +1,125 @@ +#pragma once + +/* +DList.hpp +Шаблон работы с двусвязным списком. +Type должен иметь конструктор по умолчанию, если используются методы +Push, Unshift, InsertBefore или InsertAfter с item должен так же +существовать оператор копирования: + const Type& operator=(const Type &) +*/ +/* +Copyright (c) 2009 lort +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include <WinCompat.h> + +class CDList +{ + size_t count; + protected: + struct Node + { + Node *next; + Node *prev; + }; + CDList(); + void *CInsertBefore(void *b, void *item); + void *CInsertAfter(void *a, void *item); + void CMoveBefore(void *b, void *item); + void CMoveAfter(void *a, void *item); + void *CDelete(void *item); + void CSwap(CDList &l); + Node root; + + virtual Node *AllocNode(void *key)=0; + virtual void DeleteNode(Node *node)=0; + + public: + void Clear(); + size_t Count()const {return count;}; + bool Empty()const {return !count;}; +}; + +template <typename Type> +class DList : public CDList +{ + struct TNode : Node + { + Type type; + TNode(Type *t) {if (t) type=*t;} + }; + Node *AllocNode(void *key) {return new TNode((Type*)key);} + void DeleteNode(Node *node) {delete(TNode*)node;} + + Type *Node2Type(Node *node) {return node!=&root ? (Type*)((BYTE*)node+sizeof(Node)) : nullptr;} + Node *Type2Node(const Type *item) {return item ? (Node*)((BYTE*)item-sizeof(Node)) : &root;} + + public: + ~DList() {Clear();}; + + //создать новый элемент и поместить его в конец списка + //возвращает указатель на созданный элемент + Type *Push(const Type *item=nullptr) {return (Type*)CInsertBefore(nullptr, (void*)item);} + + //создать новый элемент и поместить его в начало списка + //возвращает указатель на созданный элемент + Type *Unshift(const Type *item=nullptr) {return (Type*)CInsertAfter(nullptr, (void*)item);} + + //создать новый элемент и поместить его в списке перед before + //если before==nullptr элемент помещается в конец списка + //возвращает указатель на созданный элемент + Type *InsertBefore(const Type *before, const Type *item=nullptr) {return (Type*)CInsertBefore((void*)before, (void*)item);} + + //создать новый элемент и поместить его в списке после after + //если after==nullptr элемент помещается в начало списка + //возвращает указатель на созданный элемент + Type *InsertAfter(const Type *after, const Type *item=nullptr) {return (Type*)CInsertAfter((void*)after, (void*)item);} + + void MoveBefore(const Type *before, const Type *item) {CMoveBefore((void*)before, (void*)item);} + void MoveAfter(const Type *after, const Type *item) {CMoveAfter((void*)after, (void*)item);} + + //удалить элемент item из списка, возвращается указатель на предыдущий элемент, + //если удалялся первый элемент возвращается nullptr + Type *Delete(Type *item) {return (Type*)CDelete(item);} + + //возвращает первый элемент списка или nullptr если список пустой + Type *First() {return Node2Type(root.next);} + + //возвращает последний элемент списка или nullptr если список пустой + Type *Last() {return Node2Type(root.prev);} + + //возвращает элемент следующий за item или nullptr если item последний элемент. + //Next(nullptr) возвращает первый элемент + Type *Next(const Type *item) {return Node2Type(Type2Node(item)->next);} + + //возвращает элемент идущий в списке перед item или nullptr если item первый элемент. + //Prev(nullptr) возвращает последний элемент + Type *Prev(const Type *item) {return Node2Type(Type2Node(item)->prev);} + + //меняет местами содержимое списков + void Swap(DList<Type> &l) {CSwap(l);} +}; diff --git a/far2l/src/base/FARString.cpp b/far2l/src/base/FARString.cpp new file mode 100644 index 00000000..b1a55411 --- /dev/null +++ b/far2l/src/base/FARString.cpp @@ -0,0 +1,550 @@ +/* +FARString.hpp + +Unicode строки +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "headers.hpp" + +#include <StackHeapArray.hpp> +#include <stdarg.h> +#include <assert.h> +#include <limits> + +/// change to 1 to enable stats & leaks detection (slow!) +#if 0 +#include <mutex> +#include <set> + +struct DbgStr +{ + std::mutex Mtx; + unsigned long long Addrefs = 0; + std::set<void *> Instances; +}; + +static DbgStr &DBGSTR() +{ + static DbgStr s_out; + return s_out; +} + +void __attribute__((noinline)) dbgStrCreated(void *c, unsigned int Capacity) +{ + std::lock_guard<std::mutex> lock(DBGSTR().Mtx); + if (!DBGSTR().Instances.insert(c).second) abort(); +// fprintf(stderr, "dbgStrCreated: Instances=%lu Addrefs=%llu [%u]\n", +// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Capacity); +} + +void __attribute__((noinline)) dbgStrDestroyed(void *c, unsigned int Capacity) +{ + std::lock_guard<std::mutex> lock(DBGSTR().Mtx); + if (!DBGSTR().Instances.erase(c)) abort(); +// fprintf(stderr, "dbgStrDestroyed: Instances=%lu Addrefs=%llu [%u]\n", +// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Capacity); +} + +void __attribute__((noinline)) dbgStrAddref(const wchar_t *Data) +{ + std::lock_guard<std::mutex> lock(DBGSTR().Mtx); + ++DBGSTR().Addrefs; +// fprintf(stderr, "dbgStrAddref: Instances=%lu Addrefs=%llu '%ls'\n", +// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Data); +} + +static std::set<void *> s_PrevStrings; + +void FARString::ScanForLeaks() +{ + std::lock_guard<std::mutex> lock(DBGSTR().Mtx); + const auto &strs = DBGSTR().Instances; + fprintf(stderr, "========= %s: Count=%lu Addrefs=%llu\n", + __FUNCTION__, (unsigned long)strs.size(), DBGSTR().Addrefs); + +// fprintf(stderr, "dbgStrAddref: Instances=%lu Addrefs=%llu '%ls'\n", +// (unsigned long)DBGSTR().Instances.size(), DBGSTR().Addrefs, Data); + + if (!s_PrevStrings.empty()) + { + for (const auto &p : strs) if (s_PrevStrings.find(p) == s_PrevStrings.end()) + { + FARString::Content *c = (FARString::Content *)p; + fprintf(stderr, " + refs=%u cap=%u len=%u data='%ls'\n", + c->GetRefs(), (unsigned int)c->GetCapacity(), (unsigned int)c->GetLength(), c->GetData()); + } + } + + s_PrevStrings = strs; +} + +#else +# define dbgStrCreated(c, Capacity) +# define dbgStrDestroyed(c, Capacity) +# define dbgStrAddref(Data) +void FARString::ScanForLeaks() { } +#endif + +FARString::Content FARString::Content::sEmptyData{}; // all fields zero inited by loader + +FARString::Content *FARString::Content::Create(size_t nCapacity) +{ + if (UNLIKELY(!nCapacity)) + return EmptySingleton(); + + Content *out = (Content *)malloc(sizeof(Content) + sizeof(wchar_t) * nCapacity); + //Так как ни где выше в коде мы не готовы на случай что памяти не хватит + //то уж лучше и здесь не проверять, а сразу падать + out->m_nRefCount = 1; + out->m_nCapacity = (unsigned int)std::min(nCapacity, (size_t)std::numeric_limits<unsigned int>::max()); + out->m_nLength = 0; + out->m_Data[0] = 0; + + dbgStrCreated(out, out->m_nCapacity); + return out; +} + +FARString::Content *FARString::Content::Create(size_t nCapacity, const wchar_t *SrcData, size_t SrcLen) +{ + Content *out = Content::Create(nCapacity); + out->m_nLength = (unsigned int)std::min(std::min(nCapacity, SrcLen), (size_t)std::numeric_limits<unsigned int>::max()); + wmemcpy(out->m_Data, SrcData, out->m_nLength); + out->m_Data[out->m_nLength] = 0; + return out; +} + +void __attribute__((noinline)) FARString::Content::Destroy(Content *c) +{ + dbgStrDestroyed(c, c->m_nCapacity); + + if (LIKELY(c != EmptySingleton())) + free(c); + else + abort(); +} + +void FARString::Content::AddRef() +{ + if (LIKELY(m_nCapacity)) // only empty singletone has zero capacity + { + dbgStrAddref(m_Data); + __atomic_add_fetch(&m_nRefCount, 1, __ATOMIC_RELAXED); + } +} + +void FARString::Content::DecRef() +{ + // __atomic_load_n(relaxed) usually doesn't use any HW interlocking + // thus its a fast path for empty or single-owner strings + unsigned int n = __atomic_load_n(&m_nRefCount, __ATOMIC_RELAXED); + if (LIKELY(n == 0)) + { // (only) empty singletone has always-zero m_nRefCount + return; + } + + if (LIKELY(n != 1)) + { + if (LIKELY(__atomic_sub_fetch(&m_nRefCount, 1, __ATOMIC_RELEASE) != 0)) + return; + } + + Destroy(this); +} + +void FARString::Content::SetLength(size_t nLength) +{ + m_nLength = std::min(nLength, (size_t)m_nCapacity); + m_Data[m_nLength] = 0; +} + +////////////////////////// + +void FARString::PrepareForModify(size_t nCapacity) +{ + if (m_pContent->GetRefs() != 1 || nCapacity > m_pContent->GetCapacity()) + { + size_t NewCapacity = nCapacity; + if (m_pContent->GetCapacity() > 0 && NewCapacity > m_pContent->GetCapacity()) + NewCapacity+= std::max(NewCapacity - m_pContent->GetCapacity(), (size_t)16); + + Content *pNewData = + Content::Create(NewCapacity, m_pContent->GetData(), m_pContent->GetLength()); + pNewData->SetLength(m_pContent->GetLength()); + m_pContent->DecRef(); + m_pContent = pNewData; + } +} + +void FARString::PrepareForModify() +{ + // invoke PrepareForModify with current length but not capacity intentially + // so in case of single owner this will not alter things but in case of + // not single owner then new copy will be alloced with capacity == length + PrepareForModify(m_pContent->GetLength()); +} + +size_t FARString::GetCharString(char *lpszStr, size_t nSize, UINT CodePage) const +{ + if (!lpszStr || !nSize) + return 0; + + int SrcLen; + for (SrcLen = (int)m_pContent->GetLength(); SrcLen; --SrcLen) + { + int DstLen = WINPORT(WideCharToMultiByte)(CodePage, 0, + m_pContent->GetData(), SrcLen, nullptr, 0, nullptr, nullptr); + if (DstLen < (int)nSize) + { + DstLen = WINPORT(WideCharToMultiByte)(CodePage, 0, + m_pContent->GetData(), SrcLen, lpszStr, (int)nSize, nullptr, nullptr); + if (DstLen >= 0 && DstLen < (int)nSize) + { + lpszStr[DstLen] = 0; + return DstLen + 1; + } + } + } + + *lpszStr = 0; + return 1; +} + +FARString& FARString::Replace(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen) +{ + // Pos & Len must be valid + assert(Pos <= m_pContent->GetLength()); + assert(Len <= m_pContent->GetLength()); + assert(Pos + Len <= m_pContent->GetLength()); + + // Data and *this must not intersect (but Data can be located entirely within *this) + const bool DataStartsInside = (Data >= CPtr() && Data < CEnd()); + const bool DataEndsInside = (Data + DataLen > CPtr() && Data + DataLen <= CEnd()); + assert(DataStartsInside == DataEndsInside); + + if (!Len && !DataLen) + return *this; + + const size_t NewLength = m_pContent->GetLength() + DataLen - Len; + if (!DataStartsInside && m_pContent->GetRefs() == 1 && NewLength <= m_pContent->GetCapacity()) + { + wmemmove(m_pContent->GetData() + Pos + DataLen, + m_pContent->GetData() + Pos + Len, m_pContent->GetLength() - Pos - Len); + wmemcpy(m_pContent->GetData() + Pos, Data, DataLen); + } + else + { + Content *NewData = Content::Create(NewLength); + wmemcpy(NewData->GetData(), m_pContent->GetData(), Pos); + wmemcpy(NewData->GetData() + Pos, Data, DataLen); + wmemcpy(NewData->GetData() + Pos + DataLen, m_pContent->GetData() + Pos + Len, m_pContent->GetLength() - Pos - Len); + m_pContent->DecRef(); + m_pContent = NewData; + } + + m_pContent->SetLength(NewLength); + + return *this; +} + +FARString& FARString::Append(const char *lpszAdd, UINT CodePage) +{ + if (lpszAdd && *lpszAdd) + { + int nAddSize = WINPORT(MultiByteToWideChar)(CodePage,0,lpszAdd,-1,nullptr,0); + if (nAddSize > 0) { + size_t nNewLength = m_pContent->GetLength() + nAddSize - 1; // minus NUL char that implicitely there + PrepareForModify(nNewLength); + WINPORT(MultiByteToWideChar)(CodePage, 0, lpszAdd, -1, m_pContent->GetData() + m_pContent->GetLength(), nAddSize); + m_pContent->SetLength(nNewLength); + } + } + + return *this; +} + +FARString& FARString::Copy(const FARString &Str) +{ + auto prev_pContent = m_pContent; + m_pContent = Str.m_pContent; + m_pContent->AddRef(); + prev_pContent->DecRef(); + + return *this; +} + +FARString& FARString::Copy(const char *lpszData, UINT CodePage) +{ + m_pContent->DecRef(); + + if (!lpszData || !*lpszData) + { + Init(); + } + else + { + int nSize = WINPORT(MultiByteToWideChar)(CodePage,0,lpszData,-1,nullptr,0); + if (nSize > 0) { + m_pContent = Content::Create(nSize - 1); + WINPORT(MultiByteToWideChar)(CodePage, 0, lpszData, -1, m_pContent->GetData(), nSize); + m_pContent->SetLength(nSize - 1); + + } else + Init(); + } + + return *this; +} + +FARString FARString::SubStr(size_t Pos, size_t Len) +{ + if (Pos >= GetLength()) + return FARString(); + if (Len == static_cast<size_t>(-1) || Len > GetLength() || Pos + Len > GetLength()) + Len = GetLength() - Pos; + return FARString(m_pContent->GetData() + Pos, Len); +} + +bool FARString::Equal(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen) const +{ + if (Pos >= m_pContent->GetLength()) + Len = 0; + else if (Len >= m_pContent->GetLength() || Pos + Len >= m_pContent->GetLength()) + Len = m_pContent->GetLength() - Pos; + + if (Len != DataLen) + return false; + + return !wmemcmp(m_pContent->GetData() + Pos, Data, Len); +} + +bool FARString::operator<(const FARString& Str) const +{ + return wmemcmp(CPtr(), Str.CPtr(), std::min(GetLength(), Str.GetLength()) + 1 ) < 0; +} + +FARString operator+(const FARString &strSrc1, const FARString &strSrc2) +{ + FARString out = strSrc1.Clone(); + out.Append(strSrc2); + return out; +} + +FARString operator+(const FARString &strSrc1, const char *lpszSrc2) +{ + FARString out = strSrc1.Clone(); + out.Append(lpszSrc2); + return out; +} + +FARString operator+(const FARString &strSrc1, const wchar_t *lpwszSrc2) +{ + FARString out = strSrc1.Clone(); + out.Append(lpwszSrc2); + return out; +} + +wchar_t *FARString::GetBuffer(size_t nLength) +{ + if (nLength == (size_t)-1) + nLength = m_pContent->GetLength(); + + PrepareForModify(nLength); + return m_pContent->GetData(); +} + +void FARString::ReleaseBuffer(size_t nLength) +{ + if (nLength == (size_t)-1) + nLength = wcsnlen(m_pContent->GetData(), m_pContent->GetCapacity()); + else if (nLength > m_pContent->GetCapacity()) + nLength = m_pContent->GetCapacity(); + + PrepareForModify(nLength); + m_pContent->SetLength(nLength); +} + +size_t FARString::Truncate(size_t nLength) +{ + if (nLength < m_pContent->GetLength()) + { + if (!nLength) + { + m_pContent->DecRef(); + Init(); + } + else + { + PrepareForModify(nLength); + m_pContent->SetLength(nLength); + } + } + + return m_pContent->GetLength(); +} + +FARString& FARString::Clear() +{ + Truncate(0); + + return *this; +} + + +static void FARStringFmt(FARString &str, bool append, const wchar_t *format, va_list argptr) +{ + const size_t StartSize = 0x200; // 512 bytes ought to be enough for mosts + const size_t MaxSize = 0x1000000; // 16 megs ought to be enough for anybody + size_t Size; + + for (Size = StartSize; Size <= MaxSize; Size<<= 1) + { + StackHeapArray<wchar_t, StartSize> buf(Size); + if (UNLIKELY(!buf.Get())) + break; + + va_list argptr_copy; + va_copy(argptr_copy, argptr); + int retValue = vswprintf(buf.Get(), Size, format, argptr_copy); + va_end(argptr_copy); + + if (retValue >= 0 && size_t(retValue) < Size) + { + if (append) + str.Append(buf.Get(), retValue); + else + str.Copy(buf.Get(), retValue); + return; + } + } + + fprintf(stderr, "%s: failed; Size=%lu format='%ls'\n", __FUNCTION__, (unsigned long)Size, format); +} + +FARString& FARString::Format(const wchar_t * format, ...) +{ + va_list argptr; + va_start(argptr, format); + FARStringFmt(*this, false, format, argptr); + va_end(argptr); + return *this; +} + +FARString& FARString::AppendFormat(const wchar_t * format, ...) +{ + va_list argptr; + va_start(argptr, format); + FARStringFmt(*this, true, format, argptr); + va_end(argptr); + return *this; +} + +FARString& FARString::Lower(size_t nStartPos, size_t nLength) +{ + PrepareForModify(); + WINPORT(CharLowerBuff)(m_pContent->GetData() + nStartPos, + DWORD((nLength == (size_t)-1) ? m_pContent->GetLength() - nStartPos : nLength)); + return *this; +} + +FARString& FARString::Upper(size_t nStartPos, size_t nLength) +{ + PrepareForModify(); + WINPORT(CharUpperBuff)(m_pContent->GetData() + nStartPos, + DWORD((nLength == (size_t)-1) ? m_pContent->GetLength() - nStartPos : nLength)); + return *this; +} + +bool FARString::Pos(size_t &nPos, wchar_t Ch, size_t nStartPos) const +{ + const wchar_t *lpwszData = m_pContent->GetData(); + const wchar_t *lpFound = wcschr(lpwszData + nStartPos, Ch); + + if (lpFound) + { + nPos = lpFound - lpwszData; + return true; + } + + return false; +} + +bool FARString::Pos(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos) const +{ + const wchar_t *lpwszData = m_pContent->GetData(); + const wchar_t *lpFound = wcsstr(lpwszData + nStartPos, lpwszFind); + + if (lpFound) + { + nPos = lpFound - lpwszData; + return true; + } + + return false; +} + +bool FARString::PosI(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos) const +{ + const wchar_t *lpwszData = m_pContent->GetData(); + const wchar_t *lpFound = StrStrI(lpwszData + nStartPos, lpwszFind); + + if (lpFound) + { + nPos = lpFound - lpwszData; + return true; + } + + return false; +} + +bool FARString::RPos(size_t &nPos, wchar_t Ch, size_t nStartPos) const +{ + const wchar_t *lpwszData = m_pContent->GetData(); + const wchar_t *lpwszStrStart = lpwszData + nStartPos; + const wchar_t *lpwszStrScan = lpwszData + m_pContent->GetLength(); + + for (;;--lpwszStrScan) + { + if (*lpwszStrScan == Ch) + { + nPos = lpwszStrScan - lpwszData; + return true; + } + + if (lpwszStrScan == lpwszStrStart) + return false; + } +} + +std::string FARString::GetMB() const +{ + std::string out; + Wide2MB(CPtr(), GetLength(), out); + return out; +} diff --git a/far2l/src/base/FARString.hpp b/far2l/src/base/FARString.hpp new file mode 100644 index 00000000..9585db03 --- /dev/null +++ b/far2l/src/base/FARString.hpp @@ -0,0 +1,241 @@ +#pragma once + +/* +FARString.hpp + +Unicode строка +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include <sys/types.h> +#include <string.h> +#include <WinCompat.h> +#include "locale.hpp" +#include "headers.hpp" // for NullToEmpty + +/*********************************************************************************************************** + * This is a FARString - homegrew reference-counted string widely used in this project. + * This puts some restrictions on how this string may be used: + * - Don't write into const pointer returned by CPtr(), doing that may affect data used by irrelevant code. + * Use GetBuffer/ReleaseBuffer or simple plain assignment instead. + * - Don't modify single FARString instance from different threads without serialization. + * Create per-thread copies of FARString and modifying them from that threads is perfectly fine however. + * - Avoid excessive copying. While its doesn't copy string content, it performs still slow HW-interlocked + * reference counter manipulations, so better use passing-by-reference and std::move where possible. + */ + +class FARString +{ + /* <Content> represents actual content of string that may be shared across different FARStrings + * and it must be trivial cuz there is sEmptyData singletone shared across all empty strings and + * thus it may be accessed during early static objects initialization; using Meyer's singletone + * implementaion for it would cause compiler to include local static strapping code that has some + * runtime overhead. Using trivial class makes possible just to create global static variable that + * will be resided in BSS and thus will have all fields zero-initialized by linker and ready to use + * just upon app loading without using initializing c-tor. This is also main reason why cannot use + * virtual methods, std::atomic<> instead of __atomic_* etc */ + + class Content + { + static Content sEmptyData; //для оптимизации создания пустых FARString + + volatile unsigned int m_nRefCount; + unsigned int m_nCapacity; // not including final NULL char + unsigned int m_nLength; // not including final NULL char + wchar_t m_Data[1]; + + static void Destroy(Content *c); + + public: + static inline Content *EmptySingleton() { return &sEmptyData; } + + static Content *Create(size_t nCapacity); + static Content *Create(size_t nCapacity, const wchar_t *SrcData, size_t SrcLen); + + void AddRef(); + void DecRef(); + unsigned int GetRefs() const { return __atomic_load_n(&m_nRefCount, __ATOMIC_RELAXED); } + + void SetLength(size_t nLength); + inline wchar_t *GetData() { return m_Data; } + inline size_t GetCapacity() const { return m_nCapacity; } + inline size_t GetLength() const { return m_nLength; } + + } *m_pContent; + + inline void Init() + { + m_pContent = Content::EmptySingleton(); + } + + inline void Init(const wchar_t *SrcData, size_t SrcLen) + { + m_pContent = LIKELY(SrcLen) + ? Content::Create(SrcLen, SrcData, SrcLen) + : Content::EmptySingleton(); + } + + inline void Init(const wchar_t *SrcData) + { + if (LIKELY(SrcData)) + Init(SrcData, wcslen(SrcData)); + else + Init(); + } + + void PrepareForModify(size_t nCapacity); + void PrepareForModify(); + +public: + static void ScanForLeaks(); + + inline FARString() { Init(); } + + inline FARString(FARString &&strOriginal) : m_pContent(strOriginal.m_pContent) { strOriginal.Init(); } + inline FARString(const FARString &strCopy) : m_pContent(strCopy.m_pContent) { m_pContent->AddRef(); } + inline FARString(const wchar_t *lpwszData) { Init(lpwszData); } + inline FARString(const wchar_t *lpwszData, size_t nLength) { Init(lpwszData, nLength); } + inline FARString(const std::wstring &strData) { Init(strData.c_str(), strData.size()); } + + inline FARString(const char *lpszData, UINT CodePage=CP_UTF8) { Init(); Copy(lpszData, CodePage); } + inline FARString(const std::string &strData, UINT CodePage=CP_UTF8) { Init(); Copy(strData.c_str(), CodePage); } + + inline ~FARString() { /*if (m_pContent) он не должен быть nullptr*/ m_pContent->DecRef(); } + + // Returns copy of *this string but that copy uses OWN, not shared with *this, content. + inline FARString Clone() const { return FARString(CPtr(), GetLength()); } + + wchar_t *GetBuffer(size_t nLength = (size_t)-1); + void ReleaseBuffer(size_t nLength = (size_t)-1); + + inline size_t GetLength() const { return m_pContent->GetLength(); } + size_t Truncate(size_t nLength); + + inline wchar_t At(size_t nIndex) const { return m_pContent->GetData()[nIndex]; } + + inline bool IsEmpty() const { return !(m_pContent->GetLength() && *m_pContent->GetData()); } + + size_t GetCharString(char *lpszStr, size_t nSize, UINT CodePage=CP_UTF8) const; + std::string GetMB() const; + inline std::wstring GetWide() const { return std::wstring(CPtr(), GetLength()); } + + FARString& Format(const wchar_t * format, ...); + FARString& AppendFormat(const wchar_t * format, ...); + + FARString& Replace(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen); + FARString& Replace(size_t Pos, size_t Len, const FARString& Str) { return Replace(Pos, Len, Str.CPtr(), Str.GetLength()); } + FARString& Replace(size_t Pos, size_t Len, const wchar_t* Str) { return Replace(Pos, Len, Str, StrLength(NullToEmpty(Str))); } + FARString& Replace(size_t Pos, size_t Len, wchar_t Ch) { return Replace(Pos, Len, &Ch, 1); } + + FARString& Append(const wchar_t* Str, size_t StrLen) { return Replace(GetLength(), 0, Str, StrLen); } + FARString& Append(const FARString& Str) { return Append(Str.CPtr(), Str.GetLength()); } + FARString& Append(const wchar_t* Str) { return Append(Str, StrLength(NullToEmpty(Str))); } + FARString& Append(wchar_t Ch) { return Append(&Ch, 1); } + FARString& Append(const char *lpszAdd, UINT CodePage=CP_UTF8); + + FARString& Insert(size_t Pos, const wchar_t* Str, size_t StrLen) { return Replace(Pos, 0, Str, StrLen); } + FARString& Insert(size_t Pos, const FARString& Str) { return Insert(Pos, Str.CPtr(), Str.GetLength()); } + FARString& Insert(size_t Pos, const wchar_t* Str) { return Insert(Pos, Str, StrLength(NullToEmpty(Str))); } + FARString& Insert(size_t Pos, wchar_t Ch) { return Insert(Pos, &Ch, 1); } + + FARString& Copy(const wchar_t *Str, size_t StrLen) { return Replace(0, GetLength(), Str, StrLen); } + FARString& Copy(const wchar_t *Str) { return Copy(Str, StrLength(NullToEmpty(Str))); } + FARString& Copy(wchar_t Ch) { return Copy(&Ch, 1); } + FARString& Copy(const FARString &Str); + FARString& Copy(const char *lpszData, UINT CodePage=CP_UTF8); + + FARString& Remove(size_t Pos, size_t Len = 1) { return Replace(Pos, Len, nullptr, 0); } + FARString& LShift(size_t nShiftCount, size_t nStartPos=0) { return Remove(nStartPos, nShiftCount); } + + FARString& Clear(); + + inline const wchar_t *CPtr() const { return m_pContent->GetData(); } + inline const wchar_t *CEnd() const { return m_pContent->GetData() + m_pContent->GetLength(); } + inline operator const wchar_t *() const { return m_pContent->GetData(); } + + FARString SubStr(size_t Pos, size_t Len = -1); + + inline FARString& operator=(FARString &&strOriginal) { std::swap(m_pContent, strOriginal.m_pContent); return *this; } + inline FARString& operator=(const FARString &strCopy) { return Copy(strCopy); } + inline FARString& operator=(const char *lpszData) { return Copy(lpszData); } + inline FARString& operator=(const wchar_t *lpwszData) { return Copy(lpwszData); } + inline FARString& operator=(wchar_t chData) { return Copy(chData); } + inline FARString& operator=(const std::string &strSrc) { return Copy(strSrc.c_str(), CP_UTF8); } + inline FARString& operator=(const std::wstring &strSrc) { return Copy(strSrc.c_str()); } + + inline FARString& operator+=(const FARString &strAdd) { return Append(strAdd); } + inline FARString& operator+=(const char *lpszAdd) { return Append(lpszAdd); } + inline FARString& operator+=(const wchar_t *lpwszAdd) { return Append(lpwszAdd); } + inline FARString& operator+=(wchar_t chAdd) { return Append(chAdd); } + + bool Equal(size_t Pos, size_t Len, const wchar_t* Data, size_t DataLen) const; + inline bool Equal(size_t Pos, const wchar_t* Str, size_t StrLen) const { return Equal(Pos, StrLen, Str, StrLen); } + inline bool Equal(size_t Pos, const wchar_t* Str) const { return Equal(Pos, StrLength(Str), Str, StrLength(Str)); } + inline bool Equal(size_t Pos, const FARString& Str) const { return Equal(Pos, Str.GetLength(), Str.CPtr(), Str.GetLength()); } + inline bool Equal(size_t Pos, wchar_t Ch) const { return Equal(Pos, 1, &Ch, 1); } + inline bool operator==(const FARString& Str) const { return Equal(0, GetLength(), Str.CPtr(), Str.GetLength()); } + inline bool operator==(const wchar_t* Str) const { return Equal(0, GetLength(), Str, StrLength(Str)); } + inline bool operator==(wchar_t Ch) const { return Equal(0, GetLength(), &Ch, 1); } + + inline bool operator!=(const FARString& Str) const { return !Equal(0, GetLength(), Str.CPtr(), Str.GetLength()); } + inline bool operator!=(const wchar_t* Str) const { return !Equal(0, GetLength(), Str, StrLength(Str)); } + inline bool operator!=(wchar_t Ch) const { return !Equal(0, GetLength(), &Ch, 1); } + + bool operator<(const FARString& Str) const; + + FARString& Lower(size_t nStartPos=0, size_t nLength=(size_t)-1); + FARString& Upper(size_t nStartPos=0, size_t nLength=(size_t)-1); + + bool Pos(size_t &nPos, wchar_t Ch, size_t nStartPos=0) const; + bool Pos(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos=0) const; + bool PosI(size_t &nPos, const wchar_t *lpwszFind, size_t nStartPos=0) const; + bool RPos(size_t &nPos, wchar_t Ch, size_t nStartPos=0) const; + + bool Contains(wchar_t Ch, size_t nStartPos=0) const { return !wcschr(m_pContent->GetData()+nStartPos,Ch) ? false : true; } + bool Contains(const wchar_t *lpwszFind, size_t nStartPos=0) const { return !wcsstr(m_pContent->GetData()+nStartPos,lpwszFind) ? false : true; } + + inline bool Begins(wchar_t Ch) const + { return m_pContent->GetLength() > 0 && *m_pContent->GetData() == Ch; } + + inline bool Begins(const FARString &strFind) const + { return m_pContent->GetLength() >= strFind.m_pContent->GetLength() && wmemcmp(m_pContent->GetData(), strFind.m_pContent->GetData(), strFind.m_pContent->GetLength()) == 0; } + + inline bool Begins(const wchar_t *lpwszFind) const + { return m_pContent->GetLength() > 0 && wcsncmp(m_pContent->GetData(), lpwszFind, wcslen(lpwszFind)) == 0; } + + template <typename CharT> + bool ContainsAnyOf(const CharT *needles) + { + return FindAnyOfChars(CPtr(), CPtr() + GetLength(), needles) != nullptr; + } +}; + +FARString operator+(const FARString &strSrc1, const FARString &strSrc2); +FARString operator+(const FARString &strSrc1, const char *lpszSrc2); +FARString operator+(const FARString &strSrc1, const wchar_t *lpwszSrc2); diff --git a/far2l/src/base/array.hpp b/far2l/src/base/array.hpp new file mode 100644 index 00000000..c2317318 --- /dev/null +++ b/far2l/src/base/array.hpp @@ -0,0 +1,473 @@ +#pragma once + +/* +array.hpp + +Шаблон работы с массивом + + TArray<Object> Array; + // Object должен иметь конструктор по умолчанию и следующие операторы + // bool operator==(const Object &) const + // bool operator<(const Object &) const + // const Object& operator=(const Object &) + + TPointerArray<Object> Array; + Object должен иметь конструктор по умолчанию. + Класс для тупой но прозрачной работы с массивом понтеров на класс Object +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include <new> // for std::nothrow +#include <WinCompat.h> +#include "farrtl.hpp" + +#ifdef __GNUC__ +typedef int __cdecl(*TARRAYCMPFUNC)(const void *el1,const void *el2); +#else +typedef int (*TARRAYCMPFUNC)(const void *el1,const void *el2); +#endif + +template <class Object> +class TArray +{ + private: + size_t internalCount, Count, Delta; + Object **items; + + private: + static int __cdecl CmpItems(const Object **el1, const Object **el2); + bool deleteItem(size_t index); + + public: + TArray(size_t Delta=8); + TArray<Object>(const TArray<Object> &rhs); + ~TArray() { Free(); } + + public: + TArray& operator=(const TArray<Object> &rhs); + + public: + void Free(); + void setDelta(size_t newDelta); + bool setSize(size_t newSize); + + Object *setItem(size_t index, const Object &newItem); + Object *getItem(size_t index); + const Object *getConstItem(size_t index) const; + int getIndex(const Object &item, int start=-1); + + // сортировка массива. Offset - сколько первых пунктов пропустить + void Sort(TARRAYCMPFUNC user_cmp_func=nullptr,size_t Offset=0); + + // упаковать массив - вместо нескольких одинаковых элементов, + /* + идущих подряд, оставить только один. Возвращает, false, + если изменений массива не производилось. + Вызов Pack() после Sort(nullptr) приведет к устранению + дубликатов + */ + bool Pack(); + + public: // inline + size_t getSize() const { return Count; } + Object *addItem(const Object &newItem) { return setItem(Count,newItem); } +}; + +template <class Object> +TArray<Object>::TArray(size_t delta): + internalCount(0), Count(0), items(nullptr) +{ + setDelta(delta); +} + +template <class Object> +void TArray<Object>::Free() +{ + if (items) + { + for (unsigned i=0; i<Count; ++i) + delete items[i]; + + free(items); + items=nullptr; + } + + Count=internalCount=0; +} + +template <class Object> +Object *TArray<Object>::setItem(size_t index, const Object &newItem) +{ + bool set=true; + + if (index<Count) + deleteItem(index); + else + set=setSize(index+(index==Count)); + + if (set) + { + items[index]=new(std::nothrow) Object; + + if (items[index]) + *items[index]=newItem; + + return items[index]; + } + + return nullptr; +} + +template <class Object> +Object *TArray<Object>::getItem(size_t index) +{ + return (index<Count)?items[index]:nullptr; +} + +template <class Object> +const Object *TArray<Object>::getConstItem(size_t index) const +{ + return (index<Count)?items[index]:nullptr; +} + +template <class Object> +void TArray<Object>::Sort(TARRAYCMPFUNC user_cmp_func,size_t Offset) +{ + if (Count) + { + if (!user_cmp_func) + user_cmp_func=reinterpret_cast<TARRAYCMPFUNC>(CmpItems); + + far_qsort(reinterpret_cast<char*>(items+Offset),Count-Offset,sizeof(Object*),user_cmp_func); + } +} + +template <class Object> +bool TArray<Object>::Pack() +{ + bool was_changed=false; + + for (size_t index=1; index<Count; ++index) + { + if (*items[index-1]==*items[index]) + { + deleteItem(index); + was_changed=true; + --Count; + + if (index<Count) + { + memmove(&items[index], &items[index+1], sizeof(Object*)*(Count-index)); + --index; + } + } + } + + return was_changed; +} + +template <class Object> +bool TArray<Object>::deleteItem(size_t index) +{ + if (index<Count) + { + delete items[index]; + items[index]=nullptr; + return true; + } + + return false; +} + +template <class Object> +bool TArray<Object>::setSize(size_t newSize) +{ + bool rc=false; + + if (newSize < Count) // уменьшение размера + { + for (size_t i=newSize; i<Count; ++i) + { + delete items[i]; + items[i]=nullptr; + } + + Count=newSize; + rc=true; + } + else if (newSize < internalCount) // увеличение, но в рамках имеющегося + { + for (size_t i=Count; i<newSize; ++i) + items[i]=nullptr; + + Count=newSize; + rc=true; + } + else // увеличение размера + { + size_t Remainder=newSize%Delta; + size_t newCount=Remainder?(newSize+Delta)-Remainder: + newSize?newSize:Delta; + Object **newItems=static_cast<Object**>(malloc(newCount*sizeof(Object*))); + + if (newItems) + { + if (items) + { + memcpy(newItems,items,Count*sizeof(Object*)); + free(items); + } + + items=newItems; + internalCount=newCount; + + for (size_t i=Count; i<newSize; ++i) + items[i]=nullptr; + + Count=newSize; + rc=true; + } + } + + return rc; +} + +template <class Object> +int __cdecl TArray<Object>::CmpItems(const Object **el1, const Object **el2) +{ + if (el1==el2) + return 0; + else if (**el1==**el2) + return 0; + else if (**el1<**el2) + return -1; + else + return 1; +} + +template <class Object> +TArray<Object>::TArray(const TArray<Object> &rhs): + items(nullptr), Count(0), internalCount(0) +{ + *this=rhs; +} + +template <class Object> +TArray<Object>& TArray<Object>::operator=(const TArray<Object> &rhs) +{ + if (this == &rhs) + return *this; + + setDelta(rhs.Delta); + + if (setSize(rhs.Count)) + { + for (unsigned i=0; i<Count; ++i) + { + if (rhs.items[i]) + { + if (!items[i]) + items[i]=new Object; + + if (items[i]) + *items[i]=*rhs.items[i]; + else + { + Free(); + break; + } + } + else + { + delete items[i]; + items[i]=nullptr; + } + } + } + + return *this; +} + +template <class Object> +void TArray<Object>::setDelta(size_t newDelta) +{ + if (newDelta<4) + newDelta=4; + + Delta=newDelta; +} + +template <class Object> +int TArray<Object>::getIndex(const Object &item, int start) +{ + int rc=-1; + + if (start==-1) + start=0; + + for (size_t i=start; i<Count; ++i) + { + if (items[i] && item==*items[i]) + { + rc=i; + break; + } + } + + return rc; +} + +template <class Object> +class TPointerArray +{ + private: + size_t internalCount, Count, Delta; + Object **items; + + private: + bool setSize(size_t newSize) + { + bool rc=false; + + if (newSize < Count) // уменьшение размера + { + Count=newSize; + rc=true; + } + else if (newSize < internalCount) // увеличение, но в рамках имеющегося + { + for (size_t i=Count; i<newSize; i++) + items[i]=nullptr; + + Count=newSize; + rc=true; + } + else // увеличение размера + { + size_t Remainder=newSize%Delta; + size_t newCount=Remainder?(newSize+Delta)-Remainder:(newSize?newSize:Delta); + Object **newItems=static_cast<Object**>(realloc(items,newCount*sizeof(Object*))); + + if (newItems) + { + items=newItems; + internalCount=newCount; + + for (size_t i=Count; i<newSize; i++) + items[i]=nullptr; + + Count=newSize; + rc=true; + } + } + + return rc; + } + + public: + TPointerArray(size_t delta=1) { items=nullptr; Count=internalCount=0; setDelta(delta); } + ~TPointerArray() { Free(); } + + void Free() + { + if (items) + { + for (size_t i=0; i<Count; ++i) + delete items[i]; + + free(items); + items=nullptr; + } + + Count=internalCount=0; + } + + void setDelta(size_t newDelta) { if (newDelta<1) newDelta=1; Delta=newDelta; } + + Object *getItem(size_t index) { return (index<Count)?items[index]:nullptr; } + + const Object *getConstItem(size_t index) const { return (index<Count)?items[index]:nullptr; } + + Object *lastItem() { return Count?items[Count-1]:nullptr; } + + Object *addItem() { return insertItem(Count); } + + Object *insertItem(size_t index) + { + if (index>Count) + return nullptr; + + Object *newItem = new(std::nothrow) Object; + + if (newItem && setSize(Count+1)) + { + for (size_t i=Count-1; i>index; i--) + items[i]=items[i-1]; + + items[index]= newItem; + return items[index]; + } + + if (newItem) + delete newItem; + + return nullptr; + } + + bool deleteItem(size_t index) + { + if (index<Count) + { + delete items[index]; + + for (size_t i=index+1; i<Count; i++) + items[i-1]=items[i]; + + setSize(Count-1); + return true; + } + + return false; + } + + bool swapItems(size_t index1, size_t index2) + { + if (index1<Count && index2<Count) + { + Object *temp = items[index1]; + items[index1] = items[index2]; + items[index2] = temp; + return true; + } + + return false; + } + + size_t getCount() const { return Count; } +}; diff --git a/far2l/src/base/bitflags.hpp b/far2l/src/base/bitflags.hpp new file mode 100644 index 00000000..1a99b757 --- /dev/null +++ b/far2l/src/base/bitflags.hpp @@ -0,0 +1,62 @@ +#pragma once + +/* +bitflags.hpp + +Флаги +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include <WinCompat.h> + +class BitFlags +{ + public: + DWORD Flags; + + public: + BitFlags() {Flags=0;} + BitFlags(DWORD Fl) {Flags=Fl;} + + ~BitFlags() {} + + public: + // установить набор флагов + DWORD Set(DWORD NewFlags) { Flags|=NewFlags; return Flags;} + // сбросить набор флагов + DWORD Clear(DWORD NewFlags) { Flags&=~NewFlags; return Flags; } + // проверить набор флагов + BOOL Check(DWORD NewFlags) const { return Flags&NewFlags?TRUE:FALSE; } + // изменить состояние набора флагов в заивисмости от Status + DWORD Change(DWORD NewFlags,BOOL Status) { if (Status) Flags|=NewFlags; else Flags&=~NewFlags; return Flags;} + // инвертировать состояние флагов + DWORD Swap(DWORD SwapedFlags) { if (Flags&SwapedFlags) Flags&=~SwapedFlags; else Flags|=SwapedFlags; return Flags;} + //сбросить все флаги + void ClearAll() {Flags=0;} +}; diff --git a/far2l/src/base/farqueue.cpp b/far2l/src/base/farqueue.cpp new file mode 100644 index 00000000..32b28e9c --- /dev/null +++ b/far2l/src/base/farqueue.cpp @@ -0,0 +1,157 @@ +/* +farqueue.cpp + +Шаблон работы с очередью +Использование: + FarQueue<int> *q; + q=new FarQueue<int>(10); + + for( int j = 0; j < 5; j++ ) + { + for( int i = 0; i < 5; i++ ) + q->Put( i ); + + while( !q->isEmpty( ) ) + cout << q->Get( ) << endl; + } +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "headers.hpp" + + +#include "farqueue.hpp" + +template <class Object> +FarQueue<Object>::FarQueue(int SizeQueue): + Array(nullptr) +{ + Init(SizeQueue); +} + +template <class Object> +FarQueue<Object>::~FarQueue() +{ + if (Array) + delete[] Array; +} + + +template <class Object> +BOOL FarQueue<Object>::isEmpty() const +{ + return !CurrentSize; +} + +template <class Object> +BOOL FarQueue<Object>::isFull() const +{ + return CurrentSize == Size; +} + +template <class Object> +int FarQueue<Object>::Init(int SizeQueue) +{ + if (Array) + delete[] Array; + + Array=new(std::nothrow) Object[Size=SizeQueue]; + + if (!Array) + Size=0; + + CurrentSize=0; + Front=0; + Back=-1; + return Size ; +} + +template <class Object> +Object FarQueue<Object>::Peek() const +{ + if (isEmpty()) + return 0; + + return Array[Front]; +} + +template <class Object> +Object FarQueue<Object>::Get() +{ + if (isEmpty()) + return 0; + + CurrentSize--; + Object FrontItem = Array[Front]; + increment(Front); + return FrontItem; +} + +template <class Object> +int FarQueue<Object>::Put(const Object& x) +{ + if (isFull()) + return FALSE; + + increment(Back); + Array[Back] = x; + CurrentSize++; + return TRUE; +} + +template <class Object> +void FarQueue<Object>::increment(int& x) +{ + if (++x == Size) + x=0; +} + +//#ifdef _MSC_VER +template class FarQueue<DWORD>; +//#endif + +#if 0 +#include <iostream.h> +void main() +{ + FarQueue<int> *q; + q=new FarQueue<int>(1); + + for (int j = 0; j < 5; j++) + { + for (int i = 0; i < 5; i++) + q->Put(i); + + while (!q->isEmpty()) + cout << q->Get() << endl; + } + + delete q; +} +#endif diff --git a/far2l/src/base/farqueue.hpp b/far2l/src/base/farqueue.hpp new file mode 100644 index 00000000..6fb77ab6 --- /dev/null +++ b/far2l/src/base/farqueue.hpp @@ -0,0 +1,66 @@ +#pragma once + +/* +farqueue.hpp + +Шаблон работы с очередью +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include <WinCompat.h> + +template <class Object> +class FarQueue +{ + private: + Object *Array; + int Size; + int CurrentSize; + int Front; + int Back; + + private: + void increment(int& x); + + public: + FarQueue(int SizeQueue=64); + ~FarQueue(); + + public: + int Init(int SizeQueue); + + BOOL isEmpty() const; + BOOL isFull() const; + + Object Peek() const; + + + Object Get(); + int Put(const Object& x); +}; diff --git a/far2l/src/base/farrtl.cpp b/far2l/src/base/farrtl.cpp new file mode 100644 index 00000000..29a4845c --- /dev/null +++ b/far2l/src/base/farrtl.cpp @@ -0,0 +1,69 @@ +/* +farrtl.cpp + +Переопределение различных CRT функций +*/ + +#include "headers.hpp" + +// dest и src НЕ ДОЛЖНЫ пересекаться +char * __cdecl far_strncpy(char * dest,const char * src,size_t DestSize) +{ + char *tmpsrc = dest; + + while (DestSize>1 && (*dest++ = *src++)) + { + DestSize--; + } + + *dest = 0; + return tmpsrc; +} + +wchar_t * __cdecl far_wcsncpy(wchar_t * dest,const wchar_t * src,size_t DestSize) +{ + wchar_t *tmpsrc = dest; + + while (DestSize>1 && (*dest++ = *src++)) + DestSize--; + + *dest = 0; + return tmpsrc; +} + +#if defined(__APPLE__) || defined(__FreeBSD__) +struct QSortExAdapterArg +{ + int (*__cdecl comp)(const void *, const void *, void *); + void *ctx; +}; + +static int QSortExAdapter(void *a, const void *left, const void *right) +{ + struct QSortExAdapterArg *aa = (struct QSortExAdapterArg *)a; + return aa->comp(left, right, aa->ctx); +} + +void __cdecl far_qsortex(void *base, size_t num, size_t width, + int (*__cdecl comp)(const void *, const void *, void *), void *ctx) +{ + struct QSortExAdapterArg aa = { comp, ctx }; + qsort_r(base, num, width, &aa, QSortExAdapter); +} + +#else + +void __cdecl far_qsortex(void *base, size_t num, size_t width, + int (*__cdecl comp)(const void *, const void *, void *), void *ctx) +{ + qsort_r(base, num, width, comp, ctx); +} + +#endif + +void __cdecl far_qsort(void *base, size_t num, size_t width, + int (*__cdecl comp)(const void *, const void *) +) +{ + qsort(base, num, width, comp); +} diff --git a/far2l/src/base/farrtl.hpp b/far2l/src/base/farrtl.hpp new file mode 100644 index 00000000..0789d87c --- /dev/null +++ b/far2l/src/base/farrtl.hpp @@ -0,0 +1,18 @@ +#pragma once + +/* +farrtl.cpp + +Переопределение различных CRT функций +*/ + +#include <WinCompat.h> + +char * __cdecl far_strncpy(char * dest,const char * src,size_t DestSize); +wchar_t * __cdecl far_wcsncpy(wchar_t * dest,const wchar_t * src,size_t DestSize); + +void __cdecl far_qsortex(void *base, size_t num, size_t width, + int (__cdecl *comp_fp)(const void *, const void *, void *), void *ctx); + +void __cdecl far_qsort(void *base, size_t num, size_t width, + int (__cdecl *comp)(const void *, const void *) ); diff --git a/far2l/src/base/noncopyable.hpp b/far2l/src/base/noncopyable.hpp new file mode 100644 index 00000000..5d56d980 --- /dev/null +++ b/far2l/src/base/noncopyable.hpp @@ -0,0 +1,52 @@ +#pragma once + +/* +noncopyable.hpp +Класс для бысторого запрета оператора присваивания и конструктора копирования. + +Пример использования: + +#include "noncopyable.hpp" +class YourClass : private NonCopyable +{ +}; + +*/ +/* +Copyright (c) 2009 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +class NonCopyable +{ + private: + NonCopyable(const NonCopyable &); + NonCopyable & operator=(const NonCopyable &); + + protected: + NonCopyable() {}; + ~NonCopyable() {}; + +}; |