1
- // Str v0.32
1
+ // Str v0.33
2
2
// Simple C++ string type with an optional local buffer, by Omar Cornut
3
3
// https://github.com/ocornut/str
4
4
@@ -70,6 +70,7 @@ All StrXXX types derives from Str and instance hold the local buffer capacity. S
70
70
71
71
/*
72
72
CHANGELOG
73
+ 0.33 - fixed capacity() return value to match standard. e.g. a Str256's capacity() now returns 255, not 256.
73
74
0.32 - added owned() accessor.
74
75
0.31 - fixed various warnings.
75
76
0.30 - turned into a single header file, removed Str.cpp.
138
139
class STR_API Str
139
140
{
140
141
char * Data; // Point to LocalBuf() or heap allocated
141
- int Capacity : 21 ; // Max 2 MB
142
+ int Capacity : 21 ; // Max 2 MB. Exclude zero terminator.
142
143
int LocalBufSize : 10 ; // Max 1023 bytes
143
144
unsigned int Owned : 1 ; // Set when we have ownership of the pointed data (most common, unless using set_ref() method or StrRef constructor)
144
145
@@ -212,7 +213,7 @@ class STR_API Str
212
213
STR_ASSERT (local_buf_size < 1024 );
213
214
Data = local_buf ();
214
215
Data[0 ] = ' \0 ' ;
215
- Capacity = local_buf_size;
216
+ Capacity = local_buf_size ? local_buf_size - 1 : 0 ;
216
217
LocalBufSize = local_buf_size;
217
218
Owned = 1 ;
218
219
}
@@ -226,40 +227,40 @@ void Str::set(const char* src)
226
227
clear ();
227
228
return ;
228
229
}
229
- int buf_len = (int )strlen (src)+ 1 ;
230
+ int buf_len = (int )strlen (src);
230
231
if (Capacity < buf_len)
231
232
reserve_discard (buf_len);
232
- memcpy (Data, src, (size_t )buf_len);
233
+ memcpy (Data, src, (size_t )( buf_len + 1 ) );
233
234
Owned = 1 ;
234
235
}
235
236
236
237
void Str::set (const char * src, const char * src_end)
237
238
{
238
239
STR_ASSERT (src != NULL && src_end >= src);
239
- int buf_len = (int )(src_end- src)+ 1 ;
240
+ int buf_len = (int )(src_end - src);
240
241
if ((int )Capacity < buf_len)
241
242
reserve_discard (buf_len);
242
- memcpy (Data, src, (size_t )( buf_len - 1 ) );
243
- Data[buf_len- 1 ] = 0 ;
243
+ memcpy (Data, src, (size_t )buf_len);
244
+ Data[buf_len] = 0 ;
244
245
Owned = 1 ;
245
246
}
246
247
247
248
void Str::set (const Str& src)
248
249
{
249
- int buf_len = (int )strlen (src.c_str ())+ 1 ;
250
+ int buf_len = (int )strlen (src.c_str ());
250
251
if ((int )Capacity < buf_len)
251
252
reserve_discard (buf_len);
252
- memcpy (Data, src.c_str (), (size_t )buf_len);
253
+ memcpy (Data, src.c_str (), (size_t )( buf_len + 1 ) );
253
254
Owned = 1 ;
254
255
}
255
256
256
257
#if STR_SUPPORT_STD_STRING
257
258
void Str::set (const std::string& src)
258
259
{
259
- int buf_len = (int )src.length ()+ 1 ;
260
+ int buf_len = (int )src.length ();
260
261
if ((int )Capacity < buf_len)
261
262
reserve_discard (buf_len);
262
- memcpy (Data, src.c_str (), (size_t )buf_len);
263
+ memcpy (Data, src.c_str (), (size_t )( buf_len + 1 ) );
263
264
Owned = 1 ;
264
265
}
265
266
#endif
@@ -413,7 +414,7 @@ void Str::clear()
413
414
{
414
415
Data = local_buf ();
415
416
Data[0 ] = ' \0 ' ;
416
- Capacity = LocalBufSize;
417
+ Capacity = LocalBufSize - 1 ;
417
418
Owned = 1 ;
418
419
}
419
420
else
@@ -425,31 +426,32 @@ void Str::clear()
425
426
}
426
427
427
428
// Reserve memory, preserving the current of the buffer
429
+ // Capacity doesn't include the zero terminator, so reserve(5) is enough to store "hello".
428
430
void Str::reserve (int new_capacity)
429
431
{
430
432
if (new_capacity <= Capacity)
431
433
return ;
432
434
433
435
char * new_data;
434
- if (new_capacity < LocalBufSize)
436
+ if (new_capacity <= LocalBufSize - 1 )
435
437
{
436
438
// Disowned -> LocalBuf
437
439
new_data = local_buf ();
438
- new_capacity = LocalBufSize;
440
+ new_capacity = LocalBufSize - 1 ;
439
441
}
440
442
else
441
443
{
442
444
// Disowned or LocalBuf -> Heap
443
- new_data = (char *)STR_MEMALLOC ((size_t )new_capacity * sizeof (char ));
445
+ new_data = (char *)STR_MEMALLOC ((size_t )( new_capacity + 1 ) * sizeof (char ));
444
446
}
445
447
446
448
// string in Data might be longer than new_capacity if it wasn't owned, don't copy too much
447
449
#ifdef _MSC_VER
448
- strncpy_s (new_data, (size_t )new_capacity, Data, (size_t )new_capacity - 1 );
450
+ strncpy_s (new_data, (size_t )new_capacity + 1 , Data, (size_t )new_capacity);
449
451
#else
450
- strncpy (new_data, Data, (size_t )new_capacity - 1 );
452
+ strncpy (new_data, Data, (size_t )new_capacity);
451
453
#endif
452
- new_data[new_capacity - 1 ] = 0 ;
454
+ new_data[new_capacity] = 0 ;
453
455
454
456
if (Owned && !is_using_local_buf ())
455
457
STR_MEMFREE (Data);
@@ -468,16 +470,16 @@ void Str::reserve_discard(int new_capacity)
468
470
if (Owned && !is_using_local_buf ())
469
471
STR_MEMFREE (Data);
470
472
471
- if (new_capacity < LocalBufSize)
473
+ if (new_capacity <= LocalBufSize - 1 )
472
474
{
473
475
// Disowned -> LocalBuf
474
476
Data = local_buf ();
475
- Capacity = LocalBufSize;
477
+ Capacity = LocalBufSize - 1 ;
476
478
}
477
479
else
478
480
{
479
481
// Disowned or LocalBuf -> Heap
480
- Data = (char *)STR_MEMALLOC ((size_t )new_capacity * sizeof (char ));
482
+ Data = (char *)STR_MEMALLOC ((size_t )( new_capacity + 1 ) * sizeof (char ));
481
483
Capacity = new_capacity;
482
484
}
483
485
Owned = 1 ;
@@ -487,12 +489,12 @@ void Str::shrink_to_fit()
487
489
{
488
490
if (!Owned || is_using_local_buf ())
489
491
return ;
490
- int new_capacity = length () + 1 ;
492
+ int new_capacity = length ();
491
493
if (Capacity <= new_capacity)
492
494
return ;
493
495
494
- char * new_data = (char *)STR_MEMALLOC ((size_t )new_capacity * sizeof (char ));
495
- memcpy (new_data, Data, (size_t )new_capacity);
496
+ char * new_data = (char *)STR_MEMALLOC ((size_t )( new_capacity + 1 ) * sizeof (char ));
497
+ memcpy (new_data, Data, (size_t )( new_capacity + 1 ) );
496
498
STR_MEMFREE (Data);
497
499
Data = new_data;
498
500
Capacity = new_capacity;
@@ -511,17 +513,17 @@ int Str::setfv(const char* fmt, va_list args)
511
513
int len = vsnprintf (NULL , 0 , fmt, args);
512
514
STR_ASSERT (len >= 0 );
513
515
514
- if (Capacity < len + 1 )
515
- reserve_discard (len + 1 );
516
- len = vsnprintf (Data, len + 1 , fmt, args2);
516
+ if (Capacity < len)
517
+ reserve_discard (len);
518
+ len = vsnprintf (Data, ( size_t ) len + 1 , fmt, args2);
517
519
#else
518
520
// First try
519
- int len = vsnprintf (Owned ? Data : NULL , Owned ? (size_t )Capacity : 0 , fmt, args);
521
+ int len = vsnprintf (Owned ? Data : NULL , Owned ? (size_t )( Capacity + 1 ) : 0 , fmt, args);
520
522
STR_ASSERT (len >= 0 );
521
523
522
- if (Capacity < len + 1 )
524
+ if (Capacity < len)
523
525
{
524
- reserve_discard (len + 1 );
526
+ reserve_discard (len);
525
527
len = vsnprintf (Data, (size_t )len + 1 , fmt, args2);
526
528
}
527
529
#endif
@@ -546,10 +548,10 @@ int Str::setfv_nogrow(const char* fmt, va_list args)
546
548
if (Capacity == 0 )
547
549
return 0 ;
548
550
549
- int w = vsnprintf (Data, (size_t )Capacity, fmt, args);
550
- Data[Capacity - 1 ] = 0 ;
551
+ int w = vsnprintf (Data, (size_t )( Capacity + 1 ) , fmt, args);
552
+ Data[Capacity] = 0 ;
551
553
Owned = 1 ;
552
- return (w == -1 ) ? Capacity - 1 : w;
554
+ return (w == -1 ) ? Capacity : w;
553
555
}
554
556
555
557
int Str::setf_nogrow (const char * fmt, ...)
@@ -564,8 +566,8 @@ int Str::setf_nogrow(const char* fmt, ...)
564
566
int Str::append_from (int idx, char c)
565
567
{
566
568
int add_len = 1 ;
567
- if (Capacity < idx + add_len + 1 )
568
- reserve (idx + add_len + 1 );
569
+ if (Capacity < idx + add_len)
570
+ reserve (idx + add_len);
569
571
Data[idx] = c;
570
572
Data[idx + add_len] = 0 ;
571
573
STR_ASSERT (Owned);
@@ -577,10 +579,10 @@ int Str::append_from(int idx, const char* s, const char* s_end)
577
579
if (!s_end)
578
580
s_end = s + strlen (s);
579
581
int add_len = (int )(s_end - s);
580
- if (Capacity < idx + add_len + 1 )
581
- reserve (idx + add_len + 1 );
582
+ if (Capacity < idx + add_len)
583
+ reserve (idx + add_len);
582
584
memcpy (Data + idx, (const void *)s, (size_t )add_len);
583
- Data[idx + add_len] = 0 ; // Our source data isn't necessarily zero- terminated
585
+ Data[idx + add_len] = 0 ; // Our source data isn't necessarily zero terminated
584
586
STR_ASSERT (Owned);
585
587
return add_len;
586
588
}
@@ -598,17 +600,17 @@ int Str::appendfv_from(int idx, const char* fmt, va_list args)
598
600
int add_len = vsnprintf (NULL , 0 , fmt, args);
599
601
STR_ASSERT (add_len >= 0 );
600
602
601
- if (Capacity < idx + add_len + 1 )
602
- reserve (idx + add_len + 1 );
603
+ if (Capacity < idx + add_len)
604
+ reserve (idx + add_len);
603
605
add_len = vsnprintf (Data + idx, add_len + 1 , fmt, args2);
604
606
#else
605
607
// First try
606
- int add_len = vsnprintf (Owned ? Data + idx : NULL , Owned ? (size_t )(Capacity - idx) : 0 , fmt, args);
608
+ int add_len = vsnprintf (Owned ? Data + idx : NULL , Owned ? (size_t )(Capacity + 1 - idx) : 0 , fmt, args);
607
609
STR_ASSERT (add_len >= 0 );
608
610
609
- if (Capacity < idx + add_len + 1 )
611
+ if (Capacity < idx + add_len)
610
612
{
611
- reserve (idx + add_len + 1 );
613
+ reserve (idx + add_len);
612
614
add_len = vsnprintf (Data + idx, (size_t )add_len + 1 , fmt, args2);
613
615
}
614
616
#endif
0 commit comments