#pragma once #include #include #include #include #include "allocator.h" constexpr U32 strlen_ct( const char* str ) { U32 len = 0; for( ; !!str[len]; ++len ); return len; } template struct ARRSTR { char data[N]{ 0 }; enum { size = N }; ARRSTR() { memset( data, 0, N ); } ARRSTR( const char* str ) { memcpy( data, str, strlen_ct( str ) ); } ARRSTR( const ARRSTR& str ) { memcpy( data, str.data, N ); } template auto operator+( const ARRSTR& rhs ) { const U32 l1 = strlen_ct( data ); const U32 l2 = strlen_ct( rhs.data ); if( l1 + l2 >= N ) { dlog( "STR::operator+(): string overflow" ); abort(); return *this; } memcpy( data + l1, rhs.data, l2 ); data[l1 + l2] = '\0'; return *this; } template auto concat( const ARRSTR& str ) { return *this + str; } operator char*() { return data; } }; template struct __str : public LIST { __str() : LIST() {} __str( U32 count, const CT* str ) : LIST() { this->reserve( count * 2 ); memcpy( this->data, str, count ); this->size = count; this->data[this->size] = 0; } __str( const CT* fmt, ... ) : LIST() { va_list args; va_start( args, fmt ); va_list args2; va_copy( args2, args ); if constexpr( sizeof( CT ) == 1 ) { U32 c = vsnprintf( 0, 0, fmt, args ); va_end( args ); this->reserve( c * 2 ); vsnprintf( this->data, c + 1, fmt, args2 ); this->data[c] = 0; this->size = c; } else { U32 c = vswprintf( 0, 0, fmt, args ); va_end( args ); this->reserve( c * 2 ); vswprintf( this->data, c + 1, fmt, args2 ); this->data[c] = 0; this->size = c; } va_end( args2 ); } __str( const __str& rhs ) : LIST( rhs ) { this->data[this->size] = 0; } __str& operator=( const __str& other ) { if( this == &other ) return *this; if( this->data && this->data != other.data ) free( this->data ); if( !other.capacity || !other.size ) { this->capacity = 1; this->size = 0; this->data = (CT*)malloc( sizeof(CT) ); memset( this->data, 0, sizeof(CT) ); return *this; } this->data = (CT*)malloc( other.capacity * sizeof( CT ) ); memcpy( this->data, other.data, (other.size + 1) * sizeof( CT ) ); this->size = other.size; this->capacity = other.capacity; return *this; } const bool operator==( const __str& rhs ) { return this->equals( rhs ); } const bool operator!=( const __str& rhs ) { return !(*this == rhs); } const bool operator==( const CT* rhs ) { return this->equals( rhs ); } const bool operator!=( const CT* rhs ) { return !(*this == rhs); } __str operator+( const __str& rhs ) { __str ret = *this; return ret.append( rhs ); } __str operator+( const CT* rhs ) { __str ret = *this; return ret.append( rhs ); } __str operator+( const CT rhs ) { __str ret = *this; ret.push( rhs ); return ret; } __str& operator+=( const __str& rhs ) { return this->append( rhs ); } __str& operator+=( const CT* rhs ) { return this->append( rhs ); } __str& operator+=( const CT rhs ) { this->push( rhs ); return *this; } operator const CT*() { return this->data; } operator CT*() { return this->data; } CT operator[]( U32 i ) { return this->data[i]; } U8 equals( const __str& rhs ) { if( rhs.size != this->size ) return 0; if( !!memcmp( this->data, rhs.data, this->size ) ) return 0; return 1; } U8 equals( const CT* rhs ) { for( U32 i = 0; i < this->size + 1; ++i ) { if( !rhs[i] || this->data[i] != rhs[i] ) return 0; } return 1; } __str& fmt( const CT* fmt, ... ) { va_list args; va_start( args, fmt ); va_list args2; va_copy( args2, args ); if constexpr( sizeof( CT ) == 1 ) { U32 c = this->size + vsnprintf( 0, 0, fmt, args ); va_end( args ); if( c > this->capacity ) this->reserve( c * 2 ); vsnprintf( this->data + this->size, c + 1, fmt, args2 ); this->data[c] = 0; this->size = c; } else { U32 c = this->size + vswprintf( 0, 0, fmt, args ); va_end( args ); if( c > this->capacity ) this->reserve( c * 2 ); vswprintf( this->data + this->size, c + 1, fmt, args2 ); this->data[c] = 0; this->size = c; } va_end( args2 ); return *this; } __str& append( const CT* str ) { U32 len; for( len = 0; !!str[len]; ++len ); if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); memcpy( this->data + this->size, str, len * sizeof(CT) ); this->size += len; this->data[this->size] = 0; return *this; } __str& append( const __str& str ) { U32 len = str.size; if( this->size + len + 1 >= this->capacity ) this->reserve( this->size + len + 1 ); memcpy( this->data + this->size, str.data, len * sizeof(CT) ); this->size += len; this->data[this->size] = 0; return *this; } CT* push( const CT& item ) { if( this->capacity <= this->size + 1 ) this->grow(); this->data[this->size++] = item; this->data[this->size] = 0; return &this->data[this->size - 1]; } U32 idx_of( const CT* str ) { return idx_of( str, 0 ); } U32 idx_of( const CT* str, I32 offset ) { if( offset < 0 ) offset = this->size + offset; for( U32 i = offset; i < this->size; ++i ) { U8 found = 1; for( U32 i2 = 0; !!str[i2] && i + i2 < this->size; ++i2 ) { if( this->data[i + i2] != str[i2] ) { found = 0; break; } } if( found ) return i; } return -1; } CT* find( const CT* str ) { for( U32 i = 0; i < this->size; ++i ) { U8 found = 1; for( U32 i2 = 0; !!str[i2] && i + i2 < this->size; ++i2 ) { if( this->data[i + i2] != str[i2] ) { found = 0; break; } } if( found ) return this->data + i; } return 0; } LIST<__str> split( const char* where ) { LIST<__str> ret; U32 slen = strlen_ct( where ); U32 last = 0; for( U32 i = 0; i < this->size; ++i ) { for( U32 i2 = 0; i2 < slen; ++i2 ) { if( this->data[i + i2] != where[i2] ) break; if( i2 == slen - 1 ) { if( !(last - i) ) ret.push( "" ); else ret.push( __str( i - last, this->data + last ) ); i += slen; last = i; } } } if( last < this->size - slen ) { if( !( this->size - last ) ) ret.push( "" ); else ret.push( __str( this->size - last, this->data + last ) ); } return ret; } // can take negative input as offset from end __str substr( I32 start, I32 end ) { if( start < 0 ) start = this->size + start; if( end < 0 ) end = this->size + end; return __str( end - start, this->data + start ); } LIST_ITERATOR end() { return LIST_ITERATOR( this->data + this->size ); } }; using STR = __str; using WSTR = __str; inline STR to_str( F32 f ) { return STR( "%.02f", f ); } inline STR to_str( F64 f ) { return STR( "%.02g", f ); } inline STR to_str( I32 i ) { return STR( "%d", i ); } inline STR to_str( I64 i ) { return STR( "%lld", i ); } inline STR to_str( U32 u ) { return STR( "%u", u ); } inline STR to_str( U64 u ) { return STR( "%llu", u ); } inline STR to_str( void* p ) { return STR( "%llx", (U64)p ); }