1 // { dg-do run }
2 
3 using size_t = __SIZE_TYPE__;
4 
new(size_t,void * p)5 inline void* operator new(size_t, void* p) noexcept
6 { return p; }
7 
delete(void *,void *)8 inline 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()148 int 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