1 // { dg-do run } 2 3 using size_t = __SIZE_TYPE__; 4 new(size_t,void * p)5inline void* operator new(size_t, void* p) noexcept 6 { return p; } 7 delete(void *,void *)8inline void operator delete(void*, void*) 9 { } 10 11 struct long_t 12 { 13 size_t is_short : 1; 14 size_t length : (__SIZEOF_SIZE_T__ * __CHAR_BIT__ - 1); 15 size_t capacity; 16 char* pointer; 17 }; 18 19 struct short_header 20 { 21 unsigned char is_short : 1; 22 unsigned char length : (__CHAR_BIT__ - 1); 23 }; 24 25 struct short_t 26 { 27 short_header h; 28 char data[23]; 29 }; 30 31 union repr_t 32 { 33 long_t r; 34 short_t s; 35 short_repr()36 const short_t& short_repr() const 37 { return s; } 38 long_repr()39 const long_t& long_repr() const 40 { return r; } 41 short_repr()42 short_t& short_repr() 43 { return s; } 44 long_repr()45 long_t& long_repr() 46 { return r; } 47 }; 48 49 class string 50 { 51 public: string()52 string() 53 { 54 short_t& s = m_repr.short_repr(); 55 s.h.is_short = 1; 56 s.h.length = 0; 57 s.data[0] = '\0'; 58 } 59 string(const char * str)60 string(const char* str) 61 { 62 size_t length = __builtin_strlen(str); 63 if (length + 1 > 23) { 64 long_t& l = m_repr.long_repr(); 65 l.is_short = 0; 66 l.length = length; 67 l.capacity = length + 1; 68 l.pointer = new char[l.capacity]; 69 __builtin_memcpy(l.pointer, str, length + 1); 70 } else { 71 short_t& s = m_repr.short_repr(); 72 s.h.is_short = 1; 73 s.h.length = length; 74 __builtin_memcpy(s.data, str, length + 1); 75 } 76 } 77 string(string && other)78 string(string&& other) 79 : string{} 80 { 81 swap_data(other); 82 } 83 ~string()84 ~string() 85 { 86 if (!is_short()) { 87 delete[] m_repr.long_repr().pointer; 88 } 89 } 90 length()91 size_t length() const 92 { return is_short() ? short_length() : long_length(); } 93 94 private: is_short()95 bool is_short() const 96 { return m_repr.s.h.is_short != 0; } 97 short_length()98 size_t short_length() const 99 { return m_repr.short_repr().h.length; } 100 long_length()101 size_t long_length() const 102 { return m_repr.long_repr().length; } 103 swap_data(string & other)104 void swap_data(string& other) 105 { 106 if (is_short()) { 107 if (other.is_short()) { 108 repr_t tmp(m_repr); 109 m_repr = other.m_repr; 110 other.m_repr = tmp; 111 } else { 112 short_t short_backup(m_repr.short_repr()); 113 m_repr.short_repr().~short_t(); 114 ::new(&m_repr.long_repr()) long_t(other.m_repr.long_repr()); 115 other.m_repr.long_repr().~long_t(); 116 ::new(&other.m_repr.short_repr()) short_t(short_backup); 117 } 118 } else { 119 if (other.is_short()) { 120 short_t short_backup(other.m_repr.short_repr()); 121 other.m_repr.short_repr().~short_t(); 122 ::new(&other.m_repr.long_repr()) long_t(m_repr.long_repr()); 123 m_repr.long_repr().~long_t(); 124 ::new(&m_repr.short_repr()) short_t(short_backup); 125 } else { 126 long_t tmp(m_repr.long_repr()); 127 m_repr.long_repr() = other.m_repr.long_repr(); 128 other.m_repr.long_repr() = tmp; 129 } 130 } 131 } 132 133 repr_t m_repr; 134 }; 135 136 struct foo 137 { 138 __attribute__((noinline)) foofoo139 foo(string str) 140 : m_str{static_cast<string&&>(str)}, 141 m_len{m_str.length()} 142 { } 143 144 string m_str; 145 size_t m_len; 146 }; 147 main()148int main() 149 { 150 foo f{"the quick brown fox jumps over the lazy dog"}; 151 if (f.m_len == 0) { 152 __builtin_abort(); 153 } 154 return 0; 155 } 156