This patch introduces an alternative layout for basic_string which when the string is short, the data pointer will be word-aligned.  It can be activated with -D_LIBCPP_ALTERNATE_STRING_LAYOUT.  These two different layouts (the default and _LIBCPP_ALTERNATE_STRING_LAYOUT) are not ABI compatible with each other.  Once one is chosen for a given platform, it is disruptive to change it.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@180811 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/string b/include/string
index fa44f68..85eb463 100644
--- a/include/string
+++ b/include/string
@@ -1036,6 +1036,21 @@
 #pragma warning( pop )
 #endif // _MSC_VER
 
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
+template <class _CharT, size_t = sizeof(_CharT)>
+struct __padding
+{
+    unsigned char __xx[sizeof(_CharT)-1];
+};
+
+template <class _CharT>
+struct __padding<_CharT, 1>
+{
+};
+
+#endif  // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
 template<class _CharT, class _Traits, class _Allocator>
 class _LIBCPP_TYPE_VIS basic_string
     : private __basic_string_common<true>
@@ -1069,6 +1084,39 @@
     typedef _VSTD::reverse_iterator<const_iterator>       const_reverse_iterator;
 
 private:
+
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
+    struct __long
+    {
+        pointer   __data_;
+        size_type __size_;
+        size_type __cap_;
+    };
+
+#if _LIBCPP_BIG_ENDIAN
+    enum {__short_mask = 0x01};
+    enum {__long_mask  = 0x1ul};
+#else  // _LIBCPP_BIG_ENDIAN
+    enum {__short_mask = 0x80};
+    enum {__long_mask  = ~(size_type(~0) >> 1)};
+#endif  // _LIBCPP_BIG_ENDIAN
+
+    enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
+                      (sizeof(__long) - 1)/sizeof(value_type) : 2};
+
+    struct __short
+    {
+        value_type __data_[__min_cap];
+        struct
+            : __padding<value_type>
+        {
+            unsigned char __size_;
+        };
+    };
+
+#else
+
     struct __long
     {
         size_type __cap_;
@@ -1084,8 +1132,6 @@
     enum {__long_mask  = 0x1ul};
 #endif  // _LIBCPP_BIG_ENDIAN
 
-    enum {__mask = size_type(~0) >> 1};
-
     enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
                       (sizeof(__long) - 1)/sizeof(value_type) : 2};
 
@@ -1099,6 +1145,8 @@
         value_type __data_[__min_cap];
     };
 
+#endif  // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
     union __lx{__long __lx; __short __lxx;};
 
     enum {__n_words = sizeof(__lx) / sizeof(size_type)};
@@ -1475,20 +1523,44 @@
     const allocator_type& __alloc() const _NOEXCEPT
         {return __r_.second();}
 
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
     _LIBCPP_INLINE_VISIBILITY
     void __set_short_size(size_type __s) _NOEXCEPT
-#if _LIBCPP_BIG_ENDIAN
-        {__r_.first().__s.__size_ = (unsigned char)(__s);}
-#else
+#   if _LIBCPP_BIG_ENDIAN
         {__r_.first().__s.__size_ = (unsigned char)(__s << 1);}
-#endif
+#   else
+        {__r_.first().__s.__size_ = (unsigned char)(__s);}
+#   endif
+
     _LIBCPP_INLINE_VISIBILITY
     size_type __get_short_size() const _NOEXCEPT
-#if _LIBCPP_BIG_ENDIAN
-        {return __r_.first().__s.__size_;}
-#else
+#   if _LIBCPP_BIG_ENDIAN
         {return __r_.first().__s.__size_ >> 1;}
-#endif
+#   else
+        {return __r_.first().__s.__size_;}
+#   endif
+
+#else  // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
+    _LIBCPP_INLINE_VISIBILITY
+    void __set_short_size(size_type __s) _NOEXCEPT
+#   if _LIBCPP_BIG_ENDIAN
+        {__r_.first().__s.__size_ = (unsigned char)(__s);}
+#   else
+        {__r_.first().__s.__size_ = (unsigned char)(__s << 1);}
+#   endif
+
+    _LIBCPP_INLINE_VISIBILITY
+    size_type __get_short_size() const _NOEXCEPT
+#   if _LIBCPP_BIG_ENDIAN
+        {return __r_.first().__s.__size_;}
+#   else
+        {return __r_.first().__s.__size_ >> 1;}
+#   endif
+
+#endif  // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
     _LIBCPP_INLINE_VISIBILITY
     void __set_long_size(size_type __s) _NOEXCEPT
         {__r_.first().__l.__size_ = __s;}
@@ -2316,14 +2388,37 @@
 void
 basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
 {
-    size_type __cap = capacity();
-    size_type __sz = size();
+    bool __is_short = !__is_long();
+    size_type __cap;
+    size_type __sz;
+    if (__is_short)
+    {
+        __cap = __min_cap - 1;
+        __sz = __get_short_size();
+    }
+    else
+    {
+        __cap = __get_long_cap() - 1;
+        __sz = __get_long_size();
+    }
     if (__sz == __cap)
+    {
         __grow_by(__cap, 1, __sz, __sz, 0);
-    pointer __p = __get_pointer() + __sz;
+        __is_short = !__is_long();
+    }
+    pointer __p;
+    if (__is_short)
+    {
+        __p = __get_short_pointer() + __sz;
+        __set_short_size(__sz+1);
+    }
+    else
+    {
+        __p = __get_long_pointer() + __sz;
+        __set_long_size(__sz+1);
+    }
     traits_type::assign(*__p, __c);
     traits_type::assign(*++__p, value_type());
-    __set_size(__sz+1);
 }
 
 template <class _CharT, class _Traits, class _Allocator>