/* Copyright David Abrahams 2004. Distributed under the Boost */ /* Software License, Version 1.0. (See accompanying */ /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include "jam.h" #include "strings.h" #include #include #include #include #ifndef NDEBUG # define JAM_STRING_MAGIC ((char)0xcf) # define JAM_STRING_MAGIC_SIZE 4 static void assert_invariants( string* self ) { int i; if ( self->value == 0 ) { assert( self->size == 0 ); assert( self->capacity == 0 ); assert( self->opt[0] == 0 ); return; } assert( self->size < self->capacity ); assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) ); assert( strlen( self->value ) == self->size ); for (i = 0; i < 4; ++i) { assert( self->magic[i] == JAM_STRING_MAGIC ); assert( self->value[self->capacity + i] == JAM_STRING_MAGIC ); } } #else # define JAM_STRING_MAGIC_SIZE 0 # define assert_invariants(x) do {} while (0) #endif void string_new( string* s ) { s->value = s->opt; s->size = 0; s->capacity = sizeof(s->opt); s->opt[0] = 0; #ifndef NDEBUG memset(s->magic, JAM_STRING_MAGIC, sizeof(s->magic)); #endif assert_invariants( s ); } void string_free( string* s ) { assert_invariants( s ); if ( s->value != s->opt ) BJAM_FREE( s->value ); string_new( s ); } static void string_reserve_internal( string* self, size_t capacity ) { if ( self->value == self->opt ) { self->value = (char*)BJAM_MALLOC_ATOMIC( capacity + JAM_STRING_MAGIC_SIZE ); self->value[0] = 0; strncat( self->value, self->opt, sizeof(self->opt) ); assert( strlen( self->value ) <= self->capacity ); /* This is a regression test */ } else { self->value = (char*)BJAM_REALLOC( self->value, capacity + JAM_STRING_MAGIC_SIZE ); } #ifndef NDEBUG memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE ); #endif self->capacity = capacity; } void string_reserve( string* self, size_t capacity ) { assert_invariants( self ); if ( capacity <= self->capacity ) return; string_reserve_internal( self, capacity ); assert_invariants( self ); } static void extend_full( string* self, char const* start, char const* finish ) { size_t new_size = self->capacity + ( finish - start ); size_t new_capacity = self->capacity; size_t old_size = self->capacity; while ( new_capacity < new_size + 1) new_capacity <<= 1; string_reserve_internal( self, new_capacity ); memcpy( self->value + old_size, start, new_size - old_size ); self->value[new_size] = 0; self->size = new_size; } void string_append( string* self, char const* rhs ) { char* p = self->value + self->size; char* end = self->value + self->capacity; assert_invariants( self ); while ( *rhs && p != end) *p++ = *rhs++; if ( p != end ) { *p = 0; self->size = p - self->value; } else { extend_full( self, rhs, rhs + strlen(rhs) ); } assert_invariants( self ); } void string_append_range( string* self, char const* start, char const* finish ) { char* p = self->value + self->size; char* end = self->value + self->capacity; assert_invariants( self ); while ( p != end && start != finish ) *p++ = *start++; if ( p != end ) { *p = 0; self->size = p - self->value; } else { extend_full( self, start, finish ); } assert_invariants( self ); } void string_copy( string* s, char const* rhs ) { string_new( s ); string_append( s, rhs ); } void string_truncate( string* self, size_t n ) { assert_invariants( self ); assert( n <= self->capacity ); self->value[self->size = n] = 0; assert_invariants( self ); } void string_pop_back( string* self ) { string_truncate( self, self->size - 1 ); } void string_push_back( string* self, char x ) { string_append_range( self, &x, &x + 1 ); } char string_back( string* self ) { assert_invariants( self ); return self->value[self->size - 1]; } #ifndef NDEBUG void string_unit_test() { string s[1]; int i; char buffer[sizeof(s->opt) * 2 + 2]; int limit = sizeof(buffer) > 254 ? 254 : sizeof(buffer); string_new(s); for (i = 0; i < limit; ++i) { string_push_back( s, (char)(i + 1) ); }; for (i = 0; i < limit; ++i) { assert( i < s->size ); assert( s->value[i] == (char)(i + 1)); } string_free(s); } #endif