edbee - Qt Editor Library v0.11.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gapvector.h
Go to the documentation of this file.
1// edbee - Copyright (c) 2012-2025 by Rick Blommers and contributors
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include "edbee/exports.h"
7
8#include <QChar>
9#include <QString>
10
11//#define GAP_VECTOR_CLEAR_GAP
12
13namespace edbee {
14
15
18template <typename T>
20public:
21 GapVector( int capacity=16 ) : items_(nullptr), capacity_(0), gapBegin_(0), gapEnd_(0) {
22 items_ = new T[capacity];
24 gapBegin_ = 0;
26 growSize_ = 16;
27 }
28
30 delete[] items_;
31 }
32
34 inline int length() const { return capacity_ - gapEnd_ + gapBegin_; }
35 inline int gapSize() const { return gapEnd_ - gapBegin_; }
36 inline int gapBegin() const { return gapBegin_; }
37 inline int gapEnd() const { return gapEnd_; }
38 inline int capacity() const { return capacity_; }
39
40
42 void clear()
43 {
44 delete[] items_;
45 capacity_ = 16;
46 items_ = new T[capacity_];
47 gapBegin_ = 0;
49 growSize_ = 16;
50 }
51
52
53protected:
60 void replace( int offset, int length, const T* data ) {
61//qlog_info() << "** replace: " << offset << "," << length << ": gapBegin:" << gapBegin();
62 // copy the first part
63 if( offset < gapBegin() ) {
64 int len = qMin( gapBegin_-offset, length ); // issue 141, added -offset
65//qlog_info() << "** A) len:"<<len;
66 memcpy( items_ + offset, data, sizeof(T)*len );
67 data += len; // increase the pointer
68 offset += len;
69 length -= len;
70 }
71
72 if( 0 < length ) {
73//qlog_info() << "** B) offset:"<<offset+",gapSize:"<<gapSize()<<",length:"<<length;
74 memcpy( items_ + offset + gapSize(), data, sizeof(T)*length );
75 }
76 }
77
84 void fill( int offset, int length, const T& data ) {
85
86 // copy the first part
87 if( offset < gapBegin() ) {
88 int len = qMin( gapBegin_-offset, length );
89 for( int i=0; i<len; ++i ) { items_ [offset + i] = data; }
90 offset += len;
91 length -= len;
92 }
93
94 if( 0 < length ) {
95 offset += gapSize();
96 for( int i=0; i<length; ++i ) { items_ [offset + i] = data; }
97 }
98 }
99
100public:
101
102
108 void replace( int offset, int length, const T* data, int newLength ) {
109 int currentLength=this->length();
110 Q_ASSERT( 0 <= offset && ((offset+length) <= currentLength) );
111 Q_UNUSED(currentLength);
112// Q_ASSERT(data && "You probably mean fill :)" );
113
114//if( debug ) {
115//qlog_info() << "REPLACE: " << offset << length << newLength;
116//}
117 int gapSize = this->gapSize();
118
119 // Is it a 'delete' or 'insert' or 'replace' operation
120
121 // a replace operation (do not perform gap moving)
122 if( length == newLength ) {
123 replace( offset, length, data );
124
125 // insert operation
126 } else if( length < newLength ) {
127 int gapSizeRequired = newLength - length;
128 ensureGapSize( gapSizeRequired );
129 moveGapTo( offset + length );
130 memcpy( items_ + offset, data, sizeof(T) * newLength );
131 gapBegin_ = offset + newLength;
132
133 // delete operation
134 } else {
135 moveGapTo( offset );
136 memcpy( items_ + offset, data, sizeof(T) * newLength );
137 gapBegin_ = offset + newLength;
138 gapEnd_ = offset + gapSize + length;
139 }
140
141 Q_ASSERT( gapBegin_ <= gapEnd_ );
142 Q_ASSERT( this->gapSize() <= capacity_ );
143 Q_ASSERT( this->length() <= capacity_ );
144
145 }
146
151 void fill( int offset, int length, const T& data, int newLength ) {
152 int currentLength=this->length();
153 Q_ASSERT( 0 <= offset && ((offset+length) <= currentLength) );
154 Q_UNUSED(currentLength);
155
156 int gapSize = this->gapSize();
157
158 // Is it a 'delete' or 'insert' or 'replace' operation
159
160 // a replace operation (do not perform gap moving)
161 if( length == newLength ) {
162 fill( offset, length, data );
163
164 // insert operation
165 } else if( length < newLength ) {
166 int gapSizeRequired = newLength - length;
167 ensureGapSize( gapSizeRequired );
168 moveGapTo( offset + length );
169 for( int i=0; i<newLength; ++i ) { items_[offset+i] = data; }
170 gapBegin_ = offset + newLength;
171
172 // delete operation
173 } else {
174 moveGapTo( offset );
175 for( int i=0; i<newLength; ++i ) { items_[offset+i] = data; }
176 gapBegin_ = offset + newLength;
177 gapEnd_ = offset + gapSize + length;
178 }
179
180 Q_ASSERT( gapBegin_ <= gapEnd_ );
181 Q_ASSERT( this->gapSize() <= capacity_ );
182 Q_ASSERT( this->length() <= capacity_ );
183
184 }
185
187 void append( T t ) {
188 replace( length(), 0, &t, 1 );
189 }
190
192 void append( const T* t, int length ) {
193 replace( this->length(), 0, t, length );
194 }
195
196
198 T at( int offset ) const {
199 Q_ASSERT( 0 <= offset && offset < length() );
200 if( offset < gapBegin_ ) {
201 return items_[offset];
202 } else {
203 return items_[gapEnd_ + offset - gapBegin_];
204 }
205 }
206
208 void set( int offset, const T& value ) {
209 Q_ASSERT( 0 <= offset && offset < length() );
210 if( offset < gapBegin_ ) {
211 items_[offset] = value;
212 } else {
213 items_[gapEnd_ + offset - gapBegin_] = value;
214 }
215 }
216
217
219 T& operator[]( int offset ) {
220 Q_ASSERT( 0 <= offset && offset < length() );
221 if( offset < gapBegin_ ) {
222 return items_[offset];
223 } else {
224 return items_[gapEnd_ + offset - gapBegin_];
225 }
226 }
227
230 T& rawAt( int index ) {
231 Q_ASSERT(index < capacity_);
232 return items_[index];
233 }
234
235
237 void copyRange( QChar* data, int offset, int length ) const {
238
239//AB__CD"
240//qlog_info() << "copyRange" << offset << length;
241 if( !length ) { return; }
242 Q_ASSERT( 0 <= offset && offset < this->length() );
243 Q_ASSERT( (offset+length) <= this->length() );
244
245 // copy the first part
246 if( offset < gapBegin() ) {
247 int len = qMin( gapBegin_-offset, length );
248//qlog_info() << " - 1: memcpy: offset=" << offset << ", len=" << len << items_[offset];
249 memcpy( data, items_ + offset, sizeof(T)*len );
250 data += len; // increase the pointer
251 offset += len;
252 length -= len;
253 }
254
255 if( length > 0 ) {
256//qlog_info() << " - 2: memcpy: offset="<<offset << "gapSize=" << gapSize()<< ", length=" << length << items_[offset + gapSize()];
257 memcpy( data, items_ + offset + gapSize(), sizeof(T)*length );
258 }
259 }
260
261
265 T* data() {
266 ensureGapSize(1);
267 moveGapTo( length() );
268 items_[length()] = QChar(); // a \0 character
269 return items_;
270 }
271
272
273
276 void moveGapTo( int offset ) {
277 Q_ASSERT( offset <= capacity_);
278 Q_ASSERT( offset <= length() );
279 if( offset != gapBegin_ ) {
280//qlog_info() << "BEGIN moveGapTo: offset=" << offset << "/ gapBegin_"; // << gapBegin_ << getUnitTestString();
281 int gapSize = this->gapSize();
282
283 // move the the data right after the gap
284 if (offset < gapBegin_ ) {
285//qlog_info() << "- move" << offset << "," << gapBegin_ << "(charcount:" << (gapBegin_ - offset)<<")";
286 memmove( items_ + offset + gapSize, items_ + offset, sizeof(T) * (gapBegin_ - offset)); // memmove( target, source, size )
287
288 } else {
289//qlog_info() << "- move2: gapBegin_" << gapBegin_ << ", gapEnd_" << gapEnd_ << ", capacity_" << capacity_ << ", gapSize" << gapSize << "(charcount:"<<(offset - gapBegin_)<<")";
290 memmove( items_ + gapBegin_, items_ + gapEnd_, sizeof(T) * (offset - gapBegin_ )); // memmove( target, source, size )
291 }
292 gapBegin_ = offset;
293 gapEnd_ = gapBegin_ + gapSize; //qMin( gapBegin_ + gapSize, capacity_ );
294
295 }
296 Q_ASSERT( gapBegin_ <= gapEnd_ );
297
298#ifdef GAP_VECTOR_CLEAR_GAP
299 memset( items_+gapBegin_, 0, sizeof(T)*(gapEnd_-gapBegin_));
300#endif
301 }
302
303
305 void ensureGapSize( int requiredSize ) {
306 if( gapSize() < requiredSize ) {
307 while( growSize_ < capacity_ / 6) { growSize_ *= 2; }
308 resize(capacity_ + requiredSize + growSize_ - gapSize() );
309 }
310 }
311
312
314 void resize(int newSize)
315 {
316 if( capacity_ >= newSize) return;
317 int lengte = length();
318 Q_ASSERT( lengte <= capacity_);
322//qlog_info() << "BEGIN resize: capacity =" << capacity_<< " => " << newSize;
323
324
325 moveGapTo( lengte );
326 T *newChars = new T[ newSize ];
327
328 if( capacity_ > 0 ) {
329 memmove( newChars, items_, sizeof(T)*lengte );
330 delete[] items_;
331 }
332 items_ = newChars;
333 capacity_ = newSize;
334 gapEnd_ = newSize;
335
336 // DEBUG gapsize
337#ifdef GAP_VECTOR_CLEAR_GAP
338 memset( items_+gapBegin_, 0, sizeof(T)*(gapEnd_-gapBegin_));
339#endif
340
341//qlog_info() << "END resize";
342 }
343
344
346 void setGrowSize( int size ) { growSize_=size; }
347
349 int growSize() { return growSize_; }
350
351
353 QString getUnitTestString( QChar gapChar = '_' ) const {
354 QString s;
355 int gapBegin = this->gapBegin();
356 int gapEnd = this->gapEnd();
357 int capacity = this->capacity();
358
359 for( int i=0; i<gapBegin; ++i ) {
360 if( items_[i].isNull() ) {
361 s.append("@");
362 } else {
363 s.append( items_[i] );
364 }
365 }
366 s.append( "[" );
367 for( int i=gapBegin; i<gapEnd; ++i ) {
368 s.append( gapChar );
369 }
370 s.append( ">" );
371 for( int i=gapEnd; i<capacity; ++i ) {
372 if( items_[i].isNull() ) {
373 s.append("@");
374 } else {
375 s.append( items_[i] );
376 }
377 }
378
379 return s;
380 }
381
383 QString getUnitTestString2( ) const {
384 QString s;
385 int gapBegin = this->gapBegin();
386 int gapEnd = this->gapEnd();
387 int capacity = this->capacity();
388
389 for( int i=0; i<capacity;i++ ) {
390 if( i ) { s.append(","); }
391 if( gapEnd == i) s.append(">");
392 s.append( QStringLiteral("%1").arg( "X" ));
393 if( gapBegin==i ) s.append("[");
394 }
395 return s;
396 }
397
398
399protected:
400
406};
407
408
411{
412public:
413
414 QCharGapVector( int size=16 ) : GapVector<QChar>(size){}
415
417 QCharGapVector( const QString& data, int gapSize ) : GapVector<QChar>( data.length() + gapSize )
418 {
419 memcpy( items_, data.constData(), sizeof(QChar)*data.length() );
420 gapBegin_ = data.length();
422 }
423
424
426 void init( const QString& data, int gapSize )
427 {
428 delete items_;
429 capacity_ = data.length() + gapSize;
430 items_ = new QChar[capacity_];
431 memcpy( items_, data.constData(), sizeof(QChar)*data.length() );
432 gapBegin_ = data.length();
434 growSize_ = 16;
435 }
436
438 void replaceString( int offset, int length, const QString& data ) {
439
440// qlog_info() << "replace(" << offset << length << data << ") : " << getUnitTestString().replace("\n","|");
441
442 replace( offset, length, data.constData(), data.length() );
443
444// qlog_info() << " ==> " << getUnitTestString().replace("\n","|");
445 }
446
448 QString mid( int offset, int length ) const
449 {
450 Q_ASSERT( length >= 0 );
451
452// QString str( length, QChar() );
453// this->copyRange( str.data(), offset, length );
454
455 QChar* data = new QChar[length];
456 copyRange( data, offset, length );
457 QString str( data, length );
458 delete[] data;
459
460//qlog_info() << "mid(" << offset << "," << length << ") => " << str.replace("\n","|") << " // " << getUnitTestString().replace("\n","|");
461 return str;
462 }
463
464
465
466};
467
468
472template <typename T>
474public:
476 Q_UNUSED(capacity);
477 }
478
480 }
481
483 inline int length() const { return items_.size(); }
484 inline int gapSize() const { return 0; }
485 inline int gapBegin() const { return 0; }
486 inline int gapEnd() const { return 0; }
487 inline int capacity() const { return items_.capacity(); }
488
489
491 void clear()
492 {
493 items_.clear();
494 }
495
496
497
498public:
499
500
506 void replace( int offset, int length, const T* data, int newLength ) {
507 items_.remove(offset,length);
508 for( int i=0; i < newLength; i++ ) {
509 items_.insert(offset+i,data[i]);
510 }
511 }
512
517 void fill( int offset, int length, const T& data, int newLength ) {
518 items_.remove(offset,length);
519 for( int i=0; i < newLength; i++ ) {
520 items_.insert(offset+i,data);
521 }
522
523 }
524
526 void append( T t ) {
527 items_.append(t);
528 }
529
531 void append( const T* t, int length ) {
532 for( int i=0; i < length; i++ ) {
533 items_.append(t[i]);
534 }
535 }
536
537
539 T at( int offset ) const {
540 return items_.at(offset);
541 }
542
544 void set( int offset, const T& value ) {
545 items_.replace(offset,value);
546 }
547
548
550 T& operator[]( int offset ) {
551 return items_[offset];
552 }
553
554/*
556 void copyRange( QChar* data, int offset, int length ) const {
557
558//AB__CD"
559//qlog_info() << "copyRange" << offset << length;
560 if( !length ) { return; }
561 Q_ASSERT( 0 <= offset && offset < this->length() );
562 Q_ASSERT( (offset+length) <= this->length() );
563
564 // copy the first part
565 if( offset < gapBegin() ) {
566 int len = qMin( gapBegin_-offset, length );
567//qlog_info() << " - 1: memcpy: offset=" << offset << ", len=" << len << items_[offset];
568 memcpy( data, items_ + offset, sizeof(T)*len );
569 data += len; // increase the pointer
570 offset += len;
571 length -= len;
572 }
573
574 if( length > 0 ) {
575//qlog_info() << " - 2: memcpy: offset="<<offset << "gapSize=" << gapSize()<< ", length=" << length << items_[offset + gapSize()];
576 memcpy( data, items_ + offset + gapSize(), sizeof(T)*length );
577 }
578 }
579*/
580
584/*
585 T* data() {
586 ensureGapSize(1);
587 moveGapTo( length() );
588 items_[length()] = QChar(); // a \0 character
589 return items_;
590 }
591*/
592
593
596/*
597 void moveGapTo( int offset ) {
598 Q_ASSERT( offset <= capacity_);
599 Q_ASSERT( offset <= length() );
600 if( offset != gapBegin_ ) {
601//qlog_info() << "BEGIN moveGapTo: offset=" << offset << "/ gapBegin_"; // << gapBegin_ << getUnitTestString();
602 int gapSize = this->gapSize();
603
604 // move the the data right after the gap
605 if (offset < gapBegin_ ) {
606//qlog_info() << "- move" << offset << "," << gapBegin_ << "(charcount:" << (gapBegin_ - offset)<<")";
607 memmove( items_ + offset + gapSize, items_ + offset, sizeof(T) * (gapBegin_ - offset)); // memmove( target, source, size )
608
609 } else {
610//qlog_info() << "- move2: gapBegin_" << gapBegin_ << ", gapEnd_" << gapEnd_ << ", capacity_" << capacity_ << ", gapSize" << gapSize << "(charcount:"<<(offset - gapBegin_)<<")";
611 memmove( items_ + gapBegin_, items_ + gapEnd_, sizeof(T) * (offset - gapBegin_ )); // memmove( target, source, size )
612 }
613 gapBegin_ = offset;
614 gapEnd_ = gapBegin_ + gapSize; //qMin( gapBegin_ + gapSize, capacity_ );
615 }
616 Q_ASSERT( gapBegin_ <= gapEnd_ );
617
618 }
619
620
622 void ensureGapSize( int requiredSize ) {
623 if( gapSize() < requiredSize ) {
624 while( growSize_ < capacity_ / 6) { growSize_ *= 2; }
625 resize(capacity_ + requiredSize + growSize_ - gapSize() );
626 }
627 }
628
629
631 void resize(int newSize)
632 {
633 if( capacity_ >= newSize) return;
634 int lengte = length();
635 Q_ASSERT( lengte <= capacity_);
639//qlog_info() << "BEGIN resize: capacity =" << capacity_<< " => " << newSize;
640
641
642 moveGapTo( lengte );
643 T *newChars = new T[ newSize ];
644
645 if( capacity_ > 0 ) {
646 memmove( newChars, items_, sizeof(T)*lengte );
647 delete[] items_;
648 }
649 items_ = newChars;
650 capacity_ = newSize;
651 gapEnd_ = newSize;
652//qlog_info() << "END resize";
653 }
654
655
657 void setGrowSize( int size ) { growSize_=size; }
658
660 int growSize() { return growSize_; }
661
662
664 QString getUnitTestString( QChar gapChar = '_' ) const {
665 QString s;
666 int gapBegin = this->gapBegin();
667 int gapEnd = this->gapEnd();
668 int capacity = this->capacity();
669
670 for( int i=0; i<gapBegin; ++i ) {
671 if( items_[i].isNull() ) {
672 s.append("@");
673 } else {
674 s.append( items_[i] );
675 }
676 }
677 s.append( "[" );
678 for( int i=gapBegin; i<gapEnd; ++i ) {
679 s.append( gapChar );
680 }
681 s.append( ">" );
682 for( int i=gapEnd; i<capacity; ++i ) {
683 if( items_[i].isNull() ) {
684 s.append("@");
685 } else {
686 s.append( items_[i] );
687 }
688 }
689
690 return s;
691 }
692*/
693
694
695protected:
696
697 QVector<T> items_;
698};
699
700
701
702} // edbee
void set(int offset, const T &value)
This method sets an item at the given index.
Definition gapvector.h:208
void copyRange(QChar *data, int offset, int length) const
This method copies the given range to the data pointer.
Definition gapvector.h:237
void resize(int newSize)
resizes the array of data
Definition gapvector.h:314
void ensureGapSize(int requiredSize)
this method makes sure there's enough room for the insertation
Definition gapvector.h:305
int gapEnd() const
Definition gapvector.h:37
int growSize_
The size to grow extra.
Definition gapvector.h:405
void append(T t)
convenient append method
Definition gapvector.h:187
void append(const T *t, int length)
another append method
Definition gapvector.h:192
T * data()
This method returns a direct pointer to the 0-terminated buffer This pointer is only valid as long as...
Definition gapvector.h:265
void replace(int offset, int length, const T *data)
this method replaces the given text with the given data. because the length of the source and target ...
Definition gapvector.h:60
T at(int offset) const
This method returns the item at the given index.
Definition gapvector.h:198
int growSize()
returns the growsize
Definition gapvector.h:349
QString getUnitTestString(QChar gapChar='_') const
Converts the 'gap-buffer' to a unit-test debugging string.
Definition gapvector.h:353
int gapEnd_
The end of the gap.
Definition gapvector.h:404
int gapBegin() const
Definition gapvector.h:36
QString getUnitTestString2() const
Converts the 'gap-buffer' to a unit-test debugging string.
Definition gapvector.h:383
T * items_
The item data.
Definition gapvector.h:401
int capacity_
The number of reserved bytes.
Definition gapvector.h:402
int gapBegin_
The start of the gap.
Definition gapvector.h:403
int gapSize() const
Definition gapvector.h:35
void fill(int offset, int length, const T &data, int newLength)
this method replaces the given items with a single data item
Definition gapvector.h:151
void clear()
clears the data
Definition gapvector.h:42
int length() const
returns the used length of the data
Definition gapvector.h:34
void moveGapTo(int offset)
Definition gapvector.h:276
void replace(int offset, int length, const T *data, int newLength)
this method replaces the given items
Definition gapvector.h:108
T & rawAt(int index)
This method returns the 'raw' element at the given location This method does NOT take in account the ...
Definition gapvector.h:230
~GapVector()
Definition gapvector.h:29
T & operator[](int offset)
This method return an index.
Definition gapvector.h:219
void setGrowSize(int size)
sets the growsize. The growsize if the amount to reserve extra
Definition gapvector.h:346
int capacity() const
Definition gapvector.h:38
GapVector(int capacity=16)
Definition gapvector.h:21
void fill(int offset, int length, const T &data)
this method replaces the given text with the given data. because the length of the source and target ...
Definition gapvector.h:84
int gapBegin() const
Definition gapvector.h:485
int capacity() const
Definition gapvector.h:487
void append(T t)
convenient append method
Definition gapvector.h:526
QVector< T > items_
This method returns a direct pointer to the 0-terminated buffer This pointer is only valid as long as...
Definition gapvector.h:697
void append(const T *t, int length)
another append method
Definition gapvector.h:531
T & operator[](int offset)
This method return an index.
Definition gapvector.h:550
int length() const
returns the used length of the data
Definition gapvector.h:483
void clear()
clears the data
Definition gapvector.h:491
~NoGapVector()
Definition gapvector.h:479
NoGapVector(int capacity=16)
Definition gapvector.h:475
void set(int offset, const T &value)
This method sets an item at the given index.
Definition gapvector.h:544
T at(int offset) const
This method returns the item at the given index.
Definition gapvector.h:539
void replace(int offset, int length, const T *data, int newLength)
this method replaces the given items
Definition gapvector.h:506
int gapEnd() const
Definition gapvector.h:486
void fill(int offset, int length, const T &data, int newLength)
this method replaces the given items with a single data item
Definition gapvector.h:517
int gapSize() const
Definition gapvector.h:484
void replaceString(int offset, int length, const QString &data)
a convenient string replace function
Definition gapvector.h:438
QString mid(int offset, int length) const
a convenient method to retrieve a QString part
Definition gapvector.h:448
QCharGapVector(const QString &data, int gapSize)
initializes the vector with a given string
Definition gapvector.h:417
void init(const QString &data, int gapSize)
Initializes the gapvector.
Definition gapvector.h:426
QCharGapVector(int size=16)
Definition gapvector.h:414
#define EDBEE_EXPORT
Definition exports.h:15
QT Acessibility has an issue with reporting blank lines between elements lines. defining 'WINDOWS_EMP...
Definition commentcommand.cpp:20