about summary refs log tree commit diff
path: root/absl
diff options
context:
space:
mode:
Diffstat (limited to 'absl')
-rw-r--r--absl/base/macros.h7
-rw-r--r--absl/container/BUILD.bazel1
-rw-r--r--absl/container/CMakeLists.txt2
-rw-r--r--absl/container/inlined_vector.h354
-rw-r--r--absl/container/internal/inlined_vector.h90
-rw-r--r--absl/copts/AbseilConfigureCopts.cmake2
-rw-r--r--absl/copts/GENERATED_AbseilCopts.cmake1
-rw-r--r--absl/copts/GENERATED_copts.bzl1
-rw-r--r--absl/copts/copts.py1
-rw-r--r--absl/hash/hash.h4
-rw-r--r--absl/types/BUILD.bazel1
-rw-r--r--absl/types/CMakeLists.txt2
-rw-r--r--absl/types/internal/optional.h364
-rw-r--r--absl/types/optional.h375
14 files changed, 633 insertions, 572 deletions
diff --git a/absl/base/macros.h b/absl/base/macros.h
index 5b43d7c2bf3b..ca6207927e75 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -191,10 +191,11 @@ enum LinkerInitialized {
 // This macro is inspired by
 // https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
 #if defined(NDEBUG)
-#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
+#define ABSL_ASSERT(expr) \
+  (false ? static_cast<void>(expr) : static_cast<void>(0))
 #else
-#define ABSL_ASSERT(expr)              \
-  (ABSL_PREDICT_TRUE((expr)) ? (void)0 \
+#define ABSL_ASSERT(expr)                           \
+  (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
                              : [] { assert(false && #expr); }())  // NOLINT
 #endif
 
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 066a98862d5f..f25a9ff96b0b 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -123,6 +123,7 @@ cc_library(
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
+        ":compressed_tuple",
         "//absl/meta:type_traits",
     ],
 )
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 292fea2a8383..3c44bd0ef160 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -115,6 +115,7 @@ absl_cc_library(
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::compressed_tuple
     absl::type_traits
   PUBLIC
 )
@@ -129,6 +130,7 @@ absl_cc_library(
   DEPS
     absl::algorithm
     absl::core_headers
+    absl::inlined_vector_internal
     absl::throw_delegate
     absl::memory
   PUBLIC
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 9b699b57a49a..c59fb9386e0b 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -70,8 +70,6 @@ class InlinedVector {
       N > 0, "InlinedVector cannot be instantiated with `0` inlined elements.");
 
   using Storage = inlined_vector_internal::Storage<InlinedVector>;
-  using Tag = typename Storage::Tag;
-  using AllocatorAndTag = typename Storage::AllocatorAndTag;
   using Allocation = typename Storage::Allocation;
 
   template <typename Iterator>
@@ -162,18 +160,19 @@ class InlinedVector {
 
   // Creates a copy of an `other` inlined vector using `other`'s allocator.
   InlinedVector(const InlinedVector& other)
-      : InlinedVector(other, other.allocator()) {}
+      : InlinedVector(other, other.storage_.GetAllocator()) {}
 
   // Creates a copy of an `other` inlined vector using a specified allocator.
   InlinedVector(const InlinedVector& other, const allocator_type& alloc)
       : storage_(alloc) {
     reserve(other.size());
-    if (allocated()) {
-      UninitializedCopy(other.begin(), other.end(), allocated_space());
-      tag().set_allocated_size(other.size());
+    if (storage_.GetIsAllocated()) {
+      UninitializedCopy(other.begin(), other.end(),
+                        storage_.GetAllocatedData());
+      storage_.SetAllocatedSize(other.size());
     } else {
-      UninitializedCopy(other.begin(), other.end(), inlined_space());
-      tag().set_inline_size(other.size());
+      UninitializedCopy(other.begin(), other.end(), storage_.GetInlinedData());
+      storage_.SetInlinedSize(other.size());
     }
   }
 
@@ -195,19 +194,20 @@ class InlinedVector {
   InlinedVector(InlinedVector&& other) noexcept(
       absl::allocator_is_nothrow<allocator_type>::value ||
       std::is_nothrow_move_constructible<value_type>::value)
-      : storage_(other.allocator()) {
-    if (other.allocated()) {
+      : storage_(other.storage_.GetAllocator()) {
+    if (other.storage_.GetIsAllocated()) {
       // We can just steal the underlying buffer from the source.
       // That leaves the source empty, so we clear its size.
-      init_allocation(other.allocation());
-      tag().set_allocated_size(other.size());
-      other.tag() = Tag();
+      storage_.InitAllocation(other.storage_.GetAllocation());
+      storage_.SetAllocatedSize(other.size());
+      other.storage_.SetInlinedSize(0);
     } else {
       UninitializedCopy(
-          std::make_move_iterator(other.inlined_space()),
-          std::make_move_iterator(other.inlined_space() + other.size()),
-          inlined_space());
-      tag().set_inline_size(other.size());
+          std::make_move_iterator(other.storage_.GetInlinedData()),
+          std::make_move_iterator(other.storage_.GetInlinedData() +
+                                  other.size()),
+          storage_.GetInlinedData());
+      storage_.SetInlinedSize(other.size());
     }
   }
 
@@ -227,26 +227,27 @@ class InlinedVector {
   InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
       absl::allocator_is_nothrow<allocator_type>::value)
       : storage_(alloc) {
-    if (other.allocated()) {
-      if (alloc == other.allocator()) {
+    if (other.storage_.GetIsAllocated()) {
+      if (alloc == other.storage_.GetAllocator()) {
         // We can just steal the allocation from the source.
-        tag() = other.tag();
-        init_allocation(other.allocation());
-        other.tag() = Tag();
+        storage_.SetAllocatedSize(other.size());
+        storage_.InitAllocation(other.storage_.GetAllocation());
+        other.storage_.SetInlinedSize(0);
       } else {
         // We need to use our own allocator
         reserve(other.size());
         UninitializedCopy(std::make_move_iterator(other.begin()),
                           std::make_move_iterator(other.end()),
-                          allocated_space());
-        tag().set_allocated_size(other.size());
+                          storage_.GetAllocatedData());
+        storage_.SetAllocatedSize(other.size());
       }
     } else {
       UninitializedCopy(
-          std::make_move_iterator(other.inlined_space()),
-          std::make_move_iterator(other.inlined_space() + other.size()),
-          inlined_space());
-      tag().set_inline_size(other.size());
+          std::make_move_iterator(other.storage_.GetInlinedData()),
+          std::make_move_iterator(other.storage_.GetInlinedData() +
+                                  other.size()),
+          storage_.GetInlinedData());
+      storage_.SetInlinedSize(other.size());
     }
   }
 
@@ -264,7 +265,7 @@ class InlinedVector {
   // `InlinedVector::size()`
   //
   // Returns the number of elements in the inlined vector.
-  size_type size() const noexcept { return tag().size(); }
+  size_type size() const noexcept { return storage_.GetSize(); }
 
   // `InlinedVector::max_size()`
   //
@@ -286,7 +287,8 @@ class InlinedVector {
   // will no longer be inlined and `capacity()` will equal its capacity on the
   // allocated heap.
   size_type capacity() const noexcept {
-    return allocated() ? allocation().capacity() : static_cast<size_type>(N);
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
+                                     : static_cast<size_type>(N);
   }
 
   // `InlinedVector::data()`
@@ -295,14 +297,16 @@ class InlinedVector {
   // used to access and modify the contained elements.
   // Only results within the range [`0`, `size()`) are defined.
   pointer data() noexcept {
-    return allocated() ? allocated_space() : inlined_space();
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+                                     : storage_.GetInlinedData();
   }
 
   // Overload of `InlinedVector::data()` to return a `const_pointer` to elements
   // of the inlined vector. This pointer can be used to access (but not modify)
   // the contained elements.
   const_pointer data() const noexcept {
-    return allocated() ? allocated_space() : inlined_space();
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+                                     : storage_.GetInlinedData();
   }
 
   // `InlinedVector::operator[]()`
@@ -436,7 +440,7 @@ class InlinedVector {
   // `InlinedVector::get_allocator()`
   //
   // Returns a copy of the allocator of the inlined vector.
-  allocator_type get_allocator() const { return allocator(); }
+  allocator_type get_allocator() const { return storage_.GetAllocator(); }
 
   // ---------------------------------------------------------------------------
   // InlinedVector Member Mutators
@@ -477,13 +481,13 @@ class InlinedVector {
   InlinedVector& operator=(InlinedVector&& other) {
     if (ABSL_PREDICT_FALSE(this == std::addressof(other))) return *this;
 
-    if (other.allocated()) {
+    if (other.storage_.GetIsAllocated()) {
       clear();
-      tag().set_allocated_size(other.size());
-      init_allocation(other.allocation());
-      other.tag() = Tag();
+      storage_.SetAllocatedSize(other.size());
+      storage_.InitAllocation(other.storage_.GetAllocation());
+      other.storage_.SetInlinedSize(0);
     } else {
-      if (allocated()) clear();
+      if (storage_.GetIsAllocated()) clear();
       // Both are inlined now.
       if (size() < other.size()) {
         auto mid = std::make_move_iterator(other.begin() + size());
@@ -494,7 +498,7 @@ class InlinedVector {
                                  std::make_move_iterator(other.end()), begin());
         Destroy(new_end, end());
       }
-      tag().set_inline_size(other.size());
+      storage_.SetInlinedSize(other.size());
     }
     return *this;
   }
@@ -511,12 +515,14 @@ class InlinedVector {
     // Grow
     reserve(n);
     std::fill_n(begin(), size(), v);
-    if (allocated()) {
-      UninitializedFill(allocated_space() + size(), allocated_space() + n, v);
-      tag().set_allocated_size(n);
+    if (storage_.GetIsAllocated()) {
+      UninitializedFill(storage_.GetAllocatedData() + size(),
+                        storage_.GetAllocatedData() + n, v);
+      storage_.SetAllocatedSize(n);
     } else {
-      UninitializedFill(inlined_space() + size(), inlined_space() + n, v);
-      tag().set_inline_size(n);
+      UninitializedFill(storage_.GetInlinedData() + size(),
+                        storage_.GetInlinedData() + n, v);
+      storage_.SetInlinedSize(n);
     }
   }
 
@@ -564,12 +570,14 @@ class InlinedVector {
     assert(capacity() >= n);
 
     // Fill new space with elements constructed in-place.
-    if (allocated()) {
-      UninitializedFill(allocated_space() + s, allocated_space() + n);
-      tag().set_allocated_size(n);
+    if (storage_.GetIsAllocated()) {
+      UninitializedFill(storage_.GetAllocatedData() + s,
+                        storage_.GetAllocatedData() + n);
+      storage_.SetAllocatedSize(n);
     } else {
-      UninitializedFill(inlined_space() + s, inlined_space() + n);
-      tag().set_inline_size(n);
+      UninitializedFill(storage_.GetInlinedData() + s,
+                        storage_.GetInlinedData() + n);
+      storage_.SetInlinedSize(n);
     }
   }
 
@@ -586,12 +594,14 @@ class InlinedVector {
     assert(capacity() >= n);
 
     // Fill new space with copies of `v`.
-    if (allocated()) {
-      UninitializedFill(allocated_space() + s, allocated_space() + n, v);
-      tag().set_allocated_size(n);
+    if (storage_.GetIsAllocated()) {
+      UninitializedFill(storage_.GetAllocatedData() + s,
+                        storage_.GetAllocatedData() + n, v);
+      storage_.SetAllocatedSize(n);
     } else {
-      UninitializedFill(inlined_space() + s, inlined_space() + n, v);
-      tag().set_inline_size(n);
+      UninitializedFill(storage_.GetInlinedData() + s,
+                        storage_.GetInlinedData() + n, v);
+      storage_.SetInlinedSize(n);
     }
   }
 
@@ -688,12 +698,12 @@ class InlinedVector {
       return GrowAndEmplaceBack(std::forward<Args>(args)...);
     }
     pointer space;
-    if (allocated()) {
-      tag().set_allocated_size(s + 1);
-      space = allocated_space();
+    if (storage_.GetIsAllocated()) {
+      storage_.SetAllocatedSize(s + 1);
+      space = storage_.GetAllocatedData();
     } else {
-      tag().set_inline_size(s + 1);
-      space = inlined_space();
+      storage_.SetInlinedSize(s + 1);
+      space = storage_.GetInlinedData();
     }
     return Construct(space + s, std::forward<Args>(args)...);
   }
@@ -716,12 +726,13 @@ class InlinedVector {
   void pop_back() noexcept {
     assert(!empty());
     size_type s = size();
-    if (allocated()) {
-      Destroy(allocated_space() + s - 1, allocated_space() + s);
-      tag().set_allocated_size(s - 1);
+    if (storage_.GetIsAllocated()) {
+      Destroy(storage_.GetAllocatedData() + s - 1,
+              storage_.GetAllocatedData() + s);
+      storage_.SetAllocatedSize(s - 1);
     } else {
-      Destroy(inlined_space() + s - 1, inlined_space() + s);
-      tag().set_inline_size(s - 1);
+      Destroy(storage_.GetInlinedData() + s - 1, storage_.GetInlinedData() + s);
+      storage_.SetInlinedSize(s - 1);
     }
   }
 
@@ -757,12 +768,12 @@ class InlinedVector {
     ptrdiff_t erase_gap = std::distance(range_start, range_end);
     if (erase_gap > 0) {
       pointer space;
-      if (allocated()) {
-        space = allocated_space();
-        tag().set_allocated_size(s - erase_gap);
+      if (storage_.GetIsAllocated()) {
+        space = storage_.GetAllocatedData();
+        storage_.SetAllocatedSize(s - erase_gap);
       } else {
-        space = inlined_space();
-        tag().set_inline_size(s - erase_gap);
+        space = storage_.GetInlinedData();
+        storage_.SetInlinedSize(s - erase_gap);
       }
       std::move(range_end, space + s, range_start);
       Destroy(space + s - erase_gap, space + s);
@@ -776,13 +787,13 @@ class InlinedVector {
   // deallocates the heap allocation if the inlined vector was allocated.
   void clear() noexcept {
     size_type s = size();
-    if (allocated()) {
-      Destroy(allocated_space(), allocated_space() + s);
-      allocation().Dealloc(allocator());
+    if (storage_.GetIsAllocated()) {
+      Destroy(storage_.GetAllocatedData(), storage_.GetAllocatedData() + s);
+      storage_.GetAllocation().Dealloc(storage_.GetAllocator());
     } else if (s != 0) {  // do nothing for empty vectors
-      Destroy(inlined_space(), inlined_space() + s);
+      Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + s);
     }
-    tag() = Tag();
+    storage_.SetInlinedSize(0);
   }
 
   // `InlinedVector::reserve()`
@@ -814,7 +825,8 @@ class InlinedVector {
   // smaller heap allocation.
   void shrink_to_fit() {
     const auto s = size();
-    if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return;
+    if (ABSL_PREDICT_FALSE(!storage_.GetIsAllocated() || s == capacity()))
+      return;
 
     if (s <= N) {
       // Move the elements to the inlined storage.
@@ -829,9 +841,9 @@ class InlinedVector {
     // Reallocate storage and move elements.
     // We can't simply use the same approach as above, because `assign()` would
     // call into `reserve()` internally and reserve larger capacity than we need
-    Allocation new_allocation(allocator(), s);
-    UninitializedCopy(std::make_move_iterator(allocated_space()),
-                      std::make_move_iterator(allocated_space() + s),
+    Allocation new_allocation(storage_.GetAllocator(), s);
+    UninitializedCopy(std::make_move_iterator(storage_.GetAllocatedData()),
+                      std::make_move_iterator(storage_.GetAllocatedData() + s),
                       new_allocation.buffer());
     ResetAllocation(new_allocation, s);
   }
@@ -849,67 +861,24 @@ class InlinedVector {
   template <typename H, typename TheT, size_t TheN, typename TheA>
   friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
 
-  const Tag& tag() const { return storage_.allocator_and_tag_.tag(); }
-
-  Tag& tag() { return storage_.allocator_and_tag_.tag(); }
-
-  Allocation& allocation() {
-    return reinterpret_cast<Allocation&>(
-        storage_.rep_.allocation_storage.allocation);
-  }
-
-  const Allocation& allocation() const {
-    return reinterpret_cast<const Allocation&>(
-        storage_.rep_.allocation_storage.allocation);
-  }
-
-  void init_allocation(const Allocation& allocation) {
-    new (static_cast<void*>(std::addressof(
-        storage_.rep_.allocation_storage.allocation))) Allocation(allocation);
-  }
-
-  // TODO(absl-team): investigate whether the reinterpret_cast is appropriate.
-  pointer inlined_space() {
-    return reinterpret_cast<pointer>(
-        std::addressof(storage_.rep_.inlined_storage.inlined[0]));
-  }
-
-  const_pointer inlined_space() const {
-    return reinterpret_cast<const_pointer>(
-        std::addressof(storage_.rep_.inlined_storage.inlined[0]));
-  }
-
-  pointer allocated_space() { return allocation().buffer(); }
-
-  const_pointer allocated_space() const { return allocation().buffer(); }
-
-  const allocator_type& allocator() const {
-    return storage_.allocator_and_tag_.allocator();
-  }
-
-  allocator_type& allocator() {
-    return storage_.allocator_and_tag_.allocator();
-  }
-
-  bool allocated() const { return tag().allocated(); }
-
   void ResetAllocation(Allocation new_allocation, size_type new_size) {
-    if (allocated()) {
-      Destroy(allocated_space(), allocated_space() + size());
-      assert(begin() == allocated_space());
-      allocation().Dealloc(allocator());
-      allocation() = new_allocation;
+    if (storage_.GetIsAllocated()) {
+      Destroy(storage_.GetAllocatedData(),
+              storage_.GetAllocatedData() + size());
+      assert(begin() == storage_.GetAllocatedData());
+      storage_.GetAllocation().Dealloc(storage_.GetAllocator());
+      storage_.GetAllocation() = new_allocation;
     } else {
-      Destroy(inlined_space(), inlined_space() + size());
-      init_allocation(new_allocation);  // bug: only init once
+      Destroy(storage_.GetInlinedData(), storage_.GetInlinedData() + size());
+      storage_.InitAllocation(new_allocation);  // bug: only init once
     }
-    tag().set_allocated_size(new_size);
+    storage_.SetAllocatedSize(new_size);
   }
 
   template <typename... Args>
   reference Construct(pointer p, Args&&... args) {
     std::allocator_traits<allocator_type>::construct(
-        allocator(), p, std::forward<Args>(args)...);
+        storage_.GetAllocator(), p, std::forward<Args>(args)...);
     return *p;
   }
 
@@ -926,7 +895,8 @@ class InlinedVector {
   // Destroy [`from`, `to`) in place.
   void Destroy(pointer from, pointer to) {
     for (pointer cur = from; cur != to; ++cur) {
-      std::allocator_traits<allocator_type>::destroy(allocator(), cur);
+      std::allocator_traits<allocator_type>::destroy(storage_.GetAllocator(),
+                                                     cur);
     }
 #if !defined(NDEBUG)
     // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
@@ -946,7 +916,7 @@ class InlinedVector {
     const size_type s = size();
     assert(s <= capacity());
 
-    size_type target = (std::max)(N, s + delta);
+    size_type target = (std::max)(static_cast<size_type>(N), s + delta);
 
     // Compute new capacity by repeatedly doubling current capacity
     // TODO(psrc): Check and avoid overflow?
@@ -955,7 +925,7 @@ class InlinedVector {
       new_capacity <<= 1;
     }
 
-    Allocation new_allocation(allocator(), new_capacity);
+    Allocation new_allocation(storage_.GetAllocator(), new_capacity);
 
     UninitializedCopy(std::make_move_iterator(data()),
                       std::make_move_iterator(data() + s),
@@ -987,7 +957,7 @@ class InlinedVector {
       }
       // Move everyone into the new allocation, leaving a gap of `n` for the
       // requested shift.
-      Allocation new_allocation(allocator(), new_capacity);
+      Allocation new_allocation(storage_.GetAllocator(), new_capacity);
       size_type index = position - begin();
       UninitializedCopy(std::make_move_iterator(data()),
                         std::make_move_iterator(data() + index),
@@ -1026,7 +996,7 @@ class InlinedVector {
       start_used = pos;
       start_raw = pos + new_elements_in_used_space;
     }
-    tag().add_size(n);
+    storage_.AddSize(n);
     return std::make_pair(start_used, start_raw);
   }
 
@@ -1035,7 +1005,7 @@ class InlinedVector {
     assert(size() == capacity());
     const size_type s = size();
 
-    Allocation new_allocation(allocator(), 2 * capacity());
+    Allocation new_allocation(storage_.GetAllocator(), 2 * capacity());
 
     reference new_element =
         Construct(new_allocation.buffer() + s, std::forward<Args>(args)...);
@@ -1049,26 +1019,30 @@ class InlinedVector {
   }
 
   void InitAssign(size_type n) {
-    if (n > N) {
-      Allocation new_allocation(allocator(), n);
-      init_allocation(new_allocation);
-      UninitializedFill(allocated_space(), allocated_space() + n);
-      tag().set_allocated_size(n);
+    if (n > static_cast<size_type>(N)) {
+      Allocation new_allocation(storage_.GetAllocator(), n);
+      storage_.InitAllocation(new_allocation);
+      UninitializedFill(storage_.GetAllocatedData(),
+                        storage_.GetAllocatedData() + n);
+      storage_.SetAllocatedSize(n);
     } else {
-      UninitializedFill(inlined_space(), inlined_space() + n);
-      tag().set_inline_size(n);
+      UninitializedFill(storage_.GetInlinedData(),
+                        storage_.GetInlinedData() + n);
+      storage_.SetInlinedSize(n);
     }
   }
 
   void InitAssign(size_type n, const_reference v) {
-    if (n > N) {
-      Allocation new_allocation(allocator(), n);
-      init_allocation(new_allocation);
-      UninitializedFill(allocated_space(), allocated_space() + n, v);
-      tag().set_allocated_size(n);
+    if (n > static_cast<size_type>(N)) {
+      Allocation new_allocation(storage_.GetAllocator(), n);
+      storage_.InitAllocation(new_allocation);
+      UninitializedFill(storage_.GetAllocatedData(),
+                        storage_.GetAllocatedData() + n, v);
+      storage_.SetAllocatedSize(n);
     } else {
-      UninitializedFill(inlined_space(), inlined_space() + n, v);
-      tag().set_inline_size(n);
+      UninitializedFill(storage_.GetInlinedData(),
+                        storage_.GetInlinedData() + n, v);
+      storage_.SetInlinedSize(n);
     }
   }
 
@@ -1087,12 +1061,12 @@ class InlinedVector {
     reserve(length);
     iterator out = begin();
     for (; out != end(); ++first, ++out) *out = *first;
-    if (allocated()) {
+    if (storage_.GetIsAllocated()) {
       UninitializedCopy(first, last, out);
-      tag().set_allocated_size(length);
+      storage_.SetAllocatedSize(length);
     } else {
       UninitializedCopy(first, last, out);
-      tag().set_inline_size(length);
+      storage_.SetInlinedSize(length);
     }
   }
 
@@ -1102,12 +1076,12 @@ class InlinedVector {
 
     auto length = std::distance(first, last);
     reserve(size() + length);
-    if (allocated()) {
-      UninitializedCopy(first, last, allocated_space() + size());
-      tag().set_allocated_size(size() + length);
+    if (storage_.GetIsAllocated()) {
+      UninitializedCopy(first, last, storage_.GetAllocatedData() + size());
+      storage_.SetAllocatedSize(size() + length);
     } else {
-      UninitializedCopy(first, last, inlined_space() + size());
-      tag().set_inline_size(size() + length);
+      UninitializedCopy(first, last, storage_.GetInlinedData() + size());
+      storage_.SetInlinedSize(size() + length);
     }
   }
 
@@ -1145,14 +1119,19 @@ class InlinedVector {
   void SwapImpl(InlinedVector& other) {
     using std::swap;  // Augment ADL with `std::swap`.
 
-    if (allocated() && other.allocated()) {
+    bool is_allocated = storage_.GetIsAllocated();
+    bool other_is_allocated = other.storage_.GetIsAllocated();
+
+    if (is_allocated && other_is_allocated) {
       // Both out of line, so just swap the tag, allocation, and allocator.
-      swap(tag(), other.tag());
-      swap(allocation(), other.allocation());
-      swap(allocator(), other.allocator());
+      storage_.SwapSizeAndIsAllocated(other.storage_);
+      swap(storage_.GetAllocation(), other.storage_.GetAllocation());
+      swap(storage_.GetAllocator(), other.storage_.GetAllocator());
+
       return;
     }
-    if (!allocated() && !other.allocated()) {
+
+    if (!is_allocated && !other_is_allocated) {
       // Both inlined: swap up to smaller size, then move remaining elements.
       InlinedVector* a = this;
       InlinedVector* b = std::addressof(other);
@@ -1164,18 +1143,21 @@ class InlinedVector {
       const size_type b_size = b->size();
       assert(a_size >= b_size);
       // `a` is larger. Swap the elements up to the smaller array size.
-      std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size,
-                       b->inlined_space());
+      std::swap_ranges(a->storage_.GetInlinedData(),
+                       a->storage_.GetInlinedData() + b_size,
+                       b->storage_.GetInlinedData());
 
       // Move the remaining elements:
       //   [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b`
-      b->UninitializedCopy(a->inlined_space() + b_size,
-                           a->inlined_space() + a_size,
-                           b->inlined_space() + b_size);
-      a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
+      b->UninitializedCopy(a->storage_.GetInlinedData() + b_size,
+                           a->storage_.GetInlinedData() + a_size,
+                           b->storage_.GetInlinedData() + b_size);
+      a->Destroy(a->storage_.GetInlinedData() + b_size,
+                 a->storage_.GetInlinedData() + a_size);
+
+      storage_.SwapSizeAndIsAllocated(other.storage_);
+      swap(storage_.GetAllocator(), other.storage_.GetAllocator());
 
-      swap(a->tag(), b->tag());
-      swap(a->allocator(), b->allocator());
       assert(b->size() == a_size);
       assert(a->size() == b_size);
       return;
@@ -1188,31 +1170,35 @@ class InlinedVector {
     // the tags.
     InlinedVector* a = this;
     InlinedVector* b = std::addressof(other);
-    if (a->allocated()) {
+    if (a->storage_.GetIsAllocated()) {
       swap(a, b);
     }
-    assert(!a->allocated());
-    assert(b->allocated());
+
+    assert(!a->storage_.GetIsAllocated());
+    assert(b->storage_.GetIsAllocated());
+
     const size_type a_size = a->size();
     const size_type b_size = b->size();
     // In an optimized build, `b_size` would be unused.
     static_cast<void>(b_size);
 
-    // Made Local copies of `size()`, don't need `tag()` accurate anymore
-    swap(a->tag(), b->tag());
+    // Made Local copies of `size()`, these can now be swapped
+    a->storage_.SwapSizeAndIsAllocated(b->storage_);
 
     // Copy `b_allocation` out before `b`'s union gets clobbered by
     // `inline_space`
-    Allocation b_allocation = b->allocation();
+    Allocation b_allocation = b->storage_.GetAllocation();
 
-    b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
-                         b->inlined_space());
-    a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
+    b->UninitializedCopy(a->storage_.GetInlinedData(),
+                         a->storage_.GetInlinedData() + a_size,
+                         b->storage_.GetInlinedData());
+    a->Destroy(a->storage_.GetInlinedData(),
+               a->storage_.GetInlinedData() + a_size);
 
-    a->allocation() = b_allocation;
+    a->storage_.GetAllocation() = b_allocation;
 
-    if (a->allocator() != b->allocator()) {
-      swap(a->allocator(), b->allocator());
+    if (a->storage_.GetAllocator() != b->storage_.GetAllocator()) {
+      swap(a->storage_.GetAllocator(), b->storage_.GetAllocator());
     }
 
     assert(b->size() == a_size);
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index 24059d94c876..7aa05b6a9974 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -18,7 +18,9 @@
 #include <cstddef>
 #include <iterator>
 #include <memory>
+#include <utility>
 
+#include "absl/container/internal/compressed_tuple.h"
 #include "absl/meta/type_traits.h"
 
 namespace absl {
@@ -31,6 +33,8 @@ template <template <typename, size_t, typename> class InlinedVector, typename T,
           size_t N, typename A>
 class Storage<InlinedVector<T, N, A>> {
  public:
+  class Allocation;  // TODO(johnsoncj): Remove after migration
+
   using allocator_type = A;
   using value_type = typename allocator_type::value_type;
   using pointer = typename allocator_type::pointer;
@@ -45,38 +49,63 @@ class Storage<InlinedVector<T, N, A>> {
   using reverse_iterator = std::reverse_iterator<iterator>;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
-  explicit Storage(const allocator_type& a) : allocator_and_tag_(a) {}
+  explicit Storage(const allocator_type& alloc)
+      : metadata_(alloc, /* empty and inlined */ 0) {}
 
-  // TODO(johnsoncj): Make the below types and members private after migration
+  size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; }
 
-  // Holds whether the vector is allocated or not in the lowest bit and the size
-  // in the high bits:
-  //   `size_ = (size << 1) | is_allocated;`
-  class Tag {
-    size_type size_;
+  bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
 
-   public:
-    Tag() : size_(0) {}
-    size_type size() const { return size_ / 2; }
-    void add_size(size_type n) { size_ += n * 2; }
-    void set_inline_size(size_type n) { size_ = n * 2; }
-    void set_allocated_size(size_type n) { size_ = (n * 2) + 1; }
-    bool allocated() const { return size_ % 2; }
-  };
+  Allocation& GetAllocation() {
+    return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation);
+  }
 
-  // Derives from `allocator_type` to use the empty base class optimization.
-  // If the `allocator_type` is stateless, we can store our instance for free.
-  class AllocatorAndTag : private allocator_type {
-    Tag tag_;
+  const Allocation& GetAllocation() const {
+    return reinterpret_cast<const Allocation&>(
+        rep_.allocation_storage.allocation);
+  }
 
-   public:
-    explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {}
-    Tag& tag() { return tag_; }
-    const Tag& tag() const { return tag_; }
-    allocator_type& allocator() { return *this; }
-    const allocator_type& allocator() const { return *this; }
-  };
+  pointer GetInlinedData() {
+    return reinterpret_cast<pointer>(
+        std::addressof(rep_.inlined_storage.inlined[0]));
+  }
+
+  const_pointer GetInlinedData() const {
+    return reinterpret_cast<const_pointer>(
+        std::addressof(rep_.inlined_storage.inlined[0]));
+  }
+
+  pointer GetAllocatedData() { return GetAllocation().buffer(); }
+
+  const_pointer GetAllocatedData() const { return GetAllocation().buffer(); }
+
+  size_type GetAllocatedCapacity() const { return GetAllocation().capacity(); }
 
+  allocator_type& GetAllocator() { return metadata_.template get<0>(); }
+
+  const allocator_type& GetAllocator() const {
+    return metadata_.template get<0>();
+  }
+
+  void SetAllocatedSize(size_type size) {
+    GetSizeAndIsAllocated() = (size << 1) | static_cast<size_type>(1);
+  }
+
+  void SetInlinedSize(size_type size) { GetSizeAndIsAllocated() = size << 1; }
+
+  void AddSize(size_type count) { GetSizeAndIsAllocated() += count << 1; }
+
+  void InitAllocation(const Allocation& allocation) {
+    new (static_cast<void*>(std::addressof(rep_.allocation_storage.allocation)))
+        Allocation(allocation);
+  }
+
+  void SwapSizeAndIsAllocated(Storage& other) {
+    using std::swap;
+    swap(GetSizeAndIsAllocated(), other.GetSizeAndIsAllocated());
+  }
+
+  // TODO(johnsoncj): Make the below types private after migration
   class Allocation {
     size_type capacity_;
     pointer buffer_;
@@ -95,6 +124,13 @@ class Storage<InlinedVector<T, N, A>> {
     }
   };
 
+ private:
+  size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
+
+  const size_type& GetSizeAndIsAllocated() const {
+    return metadata_.template get<1>();
+  }
+
   // Stores either the inlined or allocated representation
   union Rep {
     using ValueTypeBuffer =
@@ -116,7 +152,7 @@ class Storage<InlinedVector<T, N, A>> {
     AllocatedRep allocation_storage;
   };
 
-  AllocatorAndTag allocator_and_tag_;
+  container_internal::CompressedTuple<allocator_type, size_type> metadata_;
   Rep rep_;
 };
 
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
index ae29d9e9a045..eaef30b0e591 100644
--- a/absl/copts/AbseilConfigureCopts.cmake
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -16,11 +16,11 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
     set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
     set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}")
+    set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
   else()
     set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
     set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
     set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}")
-    set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
     if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
       # AppleClang doesn't have lsan
       # https://developer.apple.com/documentation/code_diagnostics
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
index 16cf9feaee8e..cf38ec1247cf 100644
--- a/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -211,4 +211,5 @@ list(APPEND ABSL_MSVC_TEST_FLAGS
     "/wd4018"
     "/wd4101"
     "/wd4503"
+    "/DNOMINMAX"
 )
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
index 0669c7242e72..52e1a949f2d3 100644
--- a/absl/copts/GENERATED_copts.bzl
+++ b/absl/copts/GENERATED_copts.bzl
@@ -212,4 +212,5 @@ ABSL_MSVC_TEST_FLAGS = [
     "/wd4018",
     "/wd4101",
     "/wd4503",
+    "/DNOMINMAX",
 ]
diff --git a/absl/copts/copts.py b/absl/copts/copts.py
index cd56890671e5..880ff991bda4 100644
--- a/absl/copts/copts.py
+++ b/absl/copts/copts.py
@@ -183,6 +183,7 @@ COPT_VARS = {
         "/wd4018",  # signed/unsigned mismatch
         "/wd4101",  # unreferenced local variable
         "/wd4503",  # decorated name length exceeded, name was truncated
+        "/DNOMINMAX",  # disable the min() and max() macros from <windows.h>
     ],
     "ABSL_MSVC_EXCEPTIONS_FLAGS":
         MSVC_STYLE_EXCEPTIONS_FLAGS,
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index c0ede35ad523..339b685ffd20 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -36,6 +36,10 @@
 // framework by simply combining its state with the state of known, hashable
 // types. Hashing of that combined state is separately done by `absl::Hash`.
 //
+// One should assume that a hash algorithm is chosen randomly at the start of
+// each process.  E.g., absl::Hash<int>()(9) in one process and
+// absl::Hash<int>()(9) in another process are likely to differ.
+//
 // Example:
 //
 //   // Suppose we have a class `Circle` for which we want to add hashing
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index feac34b1c9f9..a25487184bc1 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -173,6 +173,7 @@ cc_test(
 
 cc_library(
     name = "optional",
+    srcs = ["internal/optional.h"],
     hdrs = ["optional.h"],
     copts = ABSL_DEFAULT_COPTS,
     linkopts = ABSL_DEFAULT_LINKOPTS,
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index 56f9fffd6f92..9da94eb56120 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -174,6 +174,8 @@ absl_cc_library(
     optional
   HDRS
     "optional.h"
+  SRCS
+    "internal/optional.h"
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
diff --git a/absl/types/internal/optional.h b/absl/types/internal/optional.h
new file mode 100644
index 000000000000..562c84ef5af7
--- /dev/null
+++ b/absl/types/internal/optional.h
@@ -0,0 +1,364 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_
+#define ABSL_TYPES_INTERNAL_OPTIONAL_H_
+
+#include <functional>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/inline_variable.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+
+// Forward declaration
+template <typename T>
+class optional;
+
+namespace optional_internal {
+
+// This tag type is used as a constructor parameter type for `nullopt_t`.
+struct init_t {
+  explicit init_t() = default;
+};
+
+struct empty_struct {};
+
+// This class stores the data in optional<T>.
+// It is specialized based on whether T is trivially destructible.
+// This is the specialization for non trivially destructible type.
+template <typename T, bool unused = std::is_trivially_destructible<T>::value>
+class optional_data_dtor_base {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use an array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    dummy_type dummy_;
+    T data_;
+  };
+
+  void destruct() noexcept {
+    if (engaged_) {
+      data_.~T();
+      engaged_ = false;
+    }
+  }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+
+  ~optional_data_dtor_base() { destruct(); }
+};
+
+// Specialization for trivially destructible type.
+template <typename T>
+class optional_data_dtor_base<T, true> {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    dummy_type dummy_;
+    T data_;
+  };
+  void destruct() noexcept { engaged_ = false; }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+};
+
+template <typename T>
+class optional_data_base : public optional_data_dtor_base<T> {
+ protected:
+  using base = optional_data_dtor_base<T>;
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using base::base;
+#else
+  optional_data_base() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data_base(in_place_t t, Args&&... args)
+      : base(t, absl::forward<Args>(args)...) {}
+#endif
+
+  template <typename... Args>
+  void construct(Args&&... args) {
+    // Use dummy_'s address to work around casting cv-qualified T* to void*.
+    ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
+    this->engaged_ = true;
+  }
+
+  template <typename U>
+  void assign(U&& u) {
+    if (this->engaged_) {
+      this->data_ = std::forward<U>(u);
+    } else {
+      construct(std::forward<U>(u));
+    }
+  }
+};
+
+// TODO(absl-team): Add another class using
+// std::is_trivially_move_constructible trait when available to match
+// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
+// have trivial move but nontrivial copy.
+// Also, we should be checking is_trivially_copyable here, which is not
+// supported now, so we use is_trivially_* traits instead.
+template <typename T,
+          bool unused = absl::is_trivially_copy_constructible<T>::value&&
+              absl::is_trivially_copy_assignable<typename std::remove_cv<
+                  T>::type>::value&& std::is_trivially_destructible<T>::value>
+class optional_data;
+
+// Trivially copyable types
+template <typename T>
+class optional_data<T, true> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  optional_data() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+};
+
+template <typename T>
+class optional_data<T, false> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+
+  optional_data() = default;
+
+  optional_data(const optional_data& rhs) : optional_data_base<T>() {
+    if (rhs.engaged_) {
+      this->construct(rhs.data_);
+    }
+  }
+
+  optional_data(optional_data&& rhs) noexcept(
+      absl::default_allocator_is_nothrow::value ||
+      std::is_nothrow_move_constructible<T>::value)
+      : optional_data_base<T>() {
+    if (rhs.engaged_) {
+      this->construct(std::move(rhs.data_));
+    }
+  }
+
+  optional_data& operator=(const optional_data& rhs) {
+    if (rhs.engaged_) {
+      this->assign(rhs.data_);
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  optional_data& operator=(optional_data&& rhs) noexcept(
+      std::is_nothrow_move_assignable<T>::value&&
+          std::is_nothrow_move_constructible<T>::value) {
+    if (rhs.engaged_) {
+      this->assign(std::move(rhs.data_));
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+};
+
+// Ordered by level of restriction, from low to high.
+// Copyable implies movable.
+enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
+
+// Base class for enabling/disabling copy/move constructor.
+template <copy_traits>
+class optional_ctor_base;
+
+template <>
+class optional_ctor_base<copy_traits::copyable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = default;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = delete;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+// Base class for enabling/disabling copy/move assignment.
+template <copy_traits>
+class optional_assign_base;
+
+template <>
+class optional_assign_base<copy_traits::copyable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = default;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = delete;
+};
+
+template <typename T>
+struct ctor_copy_traits {
+  static constexpr copy_traits traits =
+      std::is_copy_constructible<T>::value
+          ? copy_traits::copyable
+          : std::is_move_constructible<T>::value ? copy_traits::movable
+                                                 : copy_traits::non_movable;
+};
+
+template <typename T>
+struct assign_copy_traits {
+  static constexpr copy_traits traits =
+      absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
+          ? copy_traits::copyable
+          : absl::is_move_assignable<T>::value &&
+                    std::is_move_constructible<T>::value
+                ? copy_traits::movable
+                : copy_traits::non_movable;
+};
+
+// Whether T is constructible or convertible from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_from_optional
+    : std::integral_constant<
+          bool, std::is_constructible<T, optional<U>&>::value ||
+                    std::is_constructible<T, optional<U>&&>::value ||
+                    std::is_constructible<T, const optional<U>&>::value ||
+                    std::is_constructible<T, const optional<U>&&>::value ||
+                    std::is_convertible<optional<U>&, T>::value ||
+                    std::is_convertible<optional<U>&&, T>::value ||
+                    std::is_convertible<const optional<U>&, T>::value ||
+                    std::is_convertible<const optional<U>&&, T>::value> {};
+
+// Whether T is constructible or convertible or assignable from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_assignable_from_optional
+    : std::integral_constant<
+          bool, is_constructible_convertible_from_optional<T, U>::value ||
+                    std::is_assignable<T&, optional<U>&>::value ||
+                    std::is_assignable<T&, optional<U>&&>::value ||
+                    std::is_assignable<T&, const optional<U>&>::value ||
+                    std::is_assignable<T&, const optional<U>&&>::value> {};
+
+// Helper function used by [optional.relops], [optional.comp_with_t],
+// for checking whether an expression is convertible to bool.
+bool convertible_to_bool(bool);
+
+// Base class for std::hash<absl::optional<T>>:
+// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
+// compute the hash; Otherwise, it is disabled.
+// Reference N4659 23.14.15 [unord.hash].
+template <typename T, typename = size_t>
+struct optional_hash_base {
+  optional_hash_base() = delete;
+  optional_hash_base(const optional_hash_base&) = delete;
+  optional_hash_base(optional_hash_base&&) = delete;
+  optional_hash_base& operator=(const optional_hash_base&) = delete;
+  optional_hash_base& operator=(optional_hash_base&&) = delete;
+};
+
+template <typename T>
+struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
+                                 std::declval<absl::remove_const_t<T> >()))> {
+  using argument_type = absl::optional<T>;
+  using result_type = size_t;
+  size_t operator()(const absl::optional<T>& opt) const {
+    absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
+    if (opt) {
+      return std::hash<absl::remove_const_t<T> >()(*opt);
+    } else {
+      return static_cast<size_t>(0x297814aaad196e6dULL);
+    }
+  }
+};
+
+}  // namespace optional_internal
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 6806160dff7f..17f789847386 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -35,8 +35,7 @@
 #ifndef ABSL_TYPES_OPTIONAL_H_
 #define ABSL_TYPES_OPTIONAL_H_
 
-#include "absl/base/config.h"
-#include "absl/memory/memory.h"
+#include "absl/base/config.h"   // TODO(calabrese) IWYU removal?
 #include "absl/utility/utility.h"
 
 #ifdef ABSL_HAVE_STD_OPTIONAL
@@ -56,7 +55,6 @@ using std::nullopt;
 #include <cassert>
 #include <functional>
 #include <initializer_list>
-#include <new>
 #include <type_traits>
 #include <utility>
 
@@ -64,6 +62,7 @@ using std::nullopt;
 #include "absl/base/internal/inline_variable.h"
 #include "absl/meta/type_traits.h"
 #include "absl/types/bad_optional_access.h"
+#include "absl/types/internal/optional.h"
 
 // ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
 //
@@ -95,6 +94,22 @@ using std::nullopt;
 
 namespace absl {
 
+// nullopt_t
+//
+// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
+// that does not contain a value.
+struct nullopt_t {
+  // It must not be default-constructible to avoid ambiguity for opt = {}.
+  explicit constexpr nullopt_t(optional_internal::init_t) noexcept {}
+};
+
+// nullopt
+//
+// A tag constant of type `absl::nullopt_t` used to indicate an empty
+// `absl::optional` in certain functions, such as construction or assignment.
+ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
+                               nullopt_t(optional_internal::init_t()));
+
 // -----------------------------------------------------------------------------
 // absl::optional
 // -----------------------------------------------------------------------------
@@ -124,361 +139,7 @@ namespace absl {
 //       a) move constructors should only throw due to allocation failure and
 //       b) if T's move constructor allocates, it uses the same allocation
 //          function as the default allocator.
-template <typename T>
-class optional;
-
-namespace optional_internal {
-
-// This tag type is used as a constructor parameter type for `nullopt_t`.
-struct init_t {
-  explicit init_t() = default;
-};
-
-}  // namespace optional_internal
-
-// nullopt_t
-//
-// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
-// that does not contain a value.
-struct nullopt_t {
-  // It must not be default-constructible to avoid ambiguity for opt = {}.
-  explicit constexpr nullopt_t(optional_internal::init_t) noexcept {}
-};
-
-// nullopt
 //
-// A tag constant of type `absl::nullopt_t` used to indicate an empty
-// `absl::optional` in certain functions, such as construction or assignment.
-ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
-                               nullopt_t(optional_internal::init_t()));
-
-namespace optional_internal {
-
-struct empty_struct {};
-// This class stores the data in optional<T>.
-// It is specialized based on whether T is trivially destructible.
-// This is the specialization for non trivially destructible type.
-template <typename T, bool unused = std::is_trivially_destructible<T>::value>
-class optional_data_dtor_base {
-  struct dummy_type {
-    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
-    // Use an array to avoid GCC 6 placement-new warning.
-    empty_struct data[sizeof(T) / sizeof(empty_struct)];
-  };
-
- protected:
-  // Whether there is data or not.
-  bool engaged_;
-  // Data storage
-  union {
-    dummy_type dummy_;
-    T data_;
-  };
-
-  void destruct() noexcept {
-    if (engaged_) {
-      data_.~T();
-      engaged_ = false;
-    }
-  }
-
-  // dummy_ must be initialized for constexpr constructor.
-  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
-
-  template <typename... Args>
-  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
-      : engaged_(true), data_(absl::forward<Args>(args)...) {}
-
-  ~optional_data_dtor_base() { destruct(); }
-};
-
-// Specialization for trivially destructible type.
-template <typename T>
-class optional_data_dtor_base<T, true> {
-  struct dummy_type {
-    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
-    // Use array to avoid GCC 6 placement-new warning.
-    empty_struct data[sizeof(T) / sizeof(empty_struct)];
-  };
-
- protected:
-  // Whether there is data or not.
-  bool engaged_;
-  // Data storage
-  union {
-    dummy_type dummy_;
-    T data_;
-  };
-  void destruct() noexcept { engaged_ = false; }
-
-  // dummy_ must be initialized for constexpr constructor.
-  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
-
-  template <typename... Args>
-  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
-      : engaged_(true), data_(absl::forward<Args>(args)...) {}
-};
-
-template <typename T>
-class optional_data_base : public optional_data_dtor_base<T> {
- protected:
-  using base = optional_data_dtor_base<T>;
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
-  using base::base;
-#else
-  optional_data_base() = default;
-
-  template <typename... Args>
-  constexpr explicit optional_data_base(in_place_t t, Args&&... args)
-      : base(t, absl::forward<Args>(args)...) {}
-#endif
-
-  template <typename... Args>
-  void construct(Args&&... args) {
-    // Use dummy_'s address to work around casting cv-qualified T* to void*.
-    ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
-    this->engaged_ = true;
-  }
-
-  template <typename U>
-  void assign(U&& u) {
-    if (this->engaged_) {
-      this->data_ = std::forward<U>(u);
-    } else {
-      construct(std::forward<U>(u));
-    }
-  }
-};
-
-// TODO(absl-team): Add another class using
-// std::is_trivially_move_constructible trait when available to match
-// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
-// have trivial move but nontrivial copy.
-// Also, we should be checking is_trivially_copyable here, which is not
-// supported now, so we use is_trivially_* traits instead.
-template <typename T,
-          bool unused = absl::is_trivially_copy_constructible<T>::value&&
-              absl::is_trivially_copy_assignable<typename std::remove_cv<
-                  T>::type>::value&& std::is_trivially_destructible<T>::value>
-class optional_data;
-
-// Trivially copyable types
-template <typename T>
-class optional_data<T, true> : public optional_data_base<T> {
- protected:
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
-  using optional_data_base<T>::optional_data_base;
-#else
-  optional_data() = default;
-
-  template <typename... Args>
-  constexpr explicit optional_data(in_place_t t, Args&&... args)
-      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
-#endif
-};
-
-template <typename T>
-class optional_data<T, false> : public optional_data_base<T> {
- protected:
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
-  using optional_data_base<T>::optional_data_base;
-#else
-  template <typename... Args>
-  constexpr explicit optional_data(in_place_t t, Args&&... args)
-      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
-#endif
-
-  optional_data() = default;
-
-  optional_data(const optional_data& rhs) : optional_data_base<T>() {
-    if (rhs.engaged_) {
-      this->construct(rhs.data_);
-    }
-  }
-
-  optional_data(optional_data&& rhs) noexcept(
-      absl::default_allocator_is_nothrow::value ||
-      std::is_nothrow_move_constructible<T>::value)
-      : optional_data_base<T>() {
-    if (rhs.engaged_) {
-      this->construct(std::move(rhs.data_));
-    }
-  }
-
-  optional_data& operator=(const optional_data& rhs) {
-    if (rhs.engaged_) {
-      this->assign(rhs.data_);
-    } else {
-      this->destruct();
-    }
-    return *this;
-  }
-
-  optional_data& operator=(optional_data&& rhs) noexcept(
-      std::is_nothrow_move_assignable<T>::value&&
-          std::is_nothrow_move_constructible<T>::value) {
-    if (rhs.engaged_) {
-      this->assign(std::move(rhs.data_));
-    } else {
-      this->destruct();
-    }
-    return *this;
-  }
-};
-
-// Ordered by level of restriction, from low to high.
-// Copyable implies movable.
-enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
-
-// Base class for enabling/disabling copy/move constructor.
-template <copy_traits>
-class optional_ctor_base;
-
-template <>
-class optional_ctor_base<copy_traits::copyable> {
- public:
-  constexpr optional_ctor_base() = default;
-  optional_ctor_base(const optional_ctor_base&) = default;
-  optional_ctor_base(optional_ctor_base&&) = default;
-  optional_ctor_base& operator=(const optional_ctor_base&) = default;
-  optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-template <>
-class optional_ctor_base<copy_traits::movable> {
- public:
-  constexpr optional_ctor_base() = default;
-  optional_ctor_base(const optional_ctor_base&) = delete;
-  optional_ctor_base(optional_ctor_base&&) = default;
-  optional_ctor_base& operator=(const optional_ctor_base&) = default;
-  optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-template <>
-class optional_ctor_base<copy_traits::non_movable> {
- public:
-  constexpr optional_ctor_base() = default;
-  optional_ctor_base(const optional_ctor_base&) = delete;
-  optional_ctor_base(optional_ctor_base&&) = delete;
-  optional_ctor_base& operator=(const optional_ctor_base&) = default;
-  optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-// Base class for enabling/disabling copy/move assignment.
-template <copy_traits>
-class optional_assign_base;
-
-template <>
-class optional_assign_base<copy_traits::copyable> {
- public:
-  constexpr optional_assign_base() = default;
-  optional_assign_base(const optional_assign_base&) = default;
-  optional_assign_base(optional_assign_base&&) = default;
-  optional_assign_base& operator=(const optional_assign_base&) = default;
-  optional_assign_base& operator=(optional_assign_base&&) = default;
-};
-
-template <>
-class optional_assign_base<copy_traits::movable> {
- public:
-  constexpr optional_assign_base() = default;
-  optional_assign_base(const optional_assign_base&) = default;
-  optional_assign_base(optional_assign_base&&) = default;
-  optional_assign_base& operator=(const optional_assign_base&) = delete;
-  optional_assign_base& operator=(optional_assign_base&&) = default;
-};
-
-template <>
-class optional_assign_base<copy_traits::non_movable> {
- public:
-  constexpr optional_assign_base() = default;
-  optional_assign_base(const optional_assign_base&) = default;
-  optional_assign_base(optional_assign_base&&) = default;
-  optional_assign_base& operator=(const optional_assign_base&) = delete;
-  optional_assign_base& operator=(optional_assign_base&&) = delete;
-};
-
-template <typename T>
-struct ctor_copy_traits {
-  static constexpr copy_traits traits =
-      std::is_copy_constructible<T>::value
-          ? copy_traits::copyable
-          : std::is_move_constructible<T>::value ? copy_traits::movable
-                                                 : copy_traits::non_movable;
-};
-
-template <typename T>
-struct assign_copy_traits {
-  static constexpr copy_traits traits =
-      absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
-          ? copy_traits::copyable
-          : absl::is_move_assignable<T>::value &&
-                    std::is_move_constructible<T>::value
-                ? copy_traits::movable
-                : copy_traits::non_movable;
-};
-
-// Whether T is constructible or convertible from optional<U>.
-template <typename T, typename U>
-struct is_constructible_convertible_from_optional
-    : std::integral_constant<
-          bool, std::is_constructible<T, optional<U>&>::value ||
-                    std::is_constructible<T, optional<U>&&>::value ||
-                    std::is_constructible<T, const optional<U>&>::value ||
-                    std::is_constructible<T, const optional<U>&&>::value ||
-                    std::is_convertible<optional<U>&, T>::value ||
-                    std::is_convertible<optional<U>&&, T>::value ||
-                    std::is_convertible<const optional<U>&, T>::value ||
-                    std::is_convertible<const optional<U>&&, T>::value> {};
-
-// Whether T is constructible or convertible or assignable from optional<U>.
-template <typename T, typename U>
-struct is_constructible_convertible_assignable_from_optional
-    : std::integral_constant<
-          bool, is_constructible_convertible_from_optional<T, U>::value ||
-                    std::is_assignable<T&, optional<U>&>::value ||
-                    std::is_assignable<T&, optional<U>&&>::value ||
-                    std::is_assignable<T&, const optional<U>&>::value ||
-                    std::is_assignable<T&, const optional<U>&&>::value> {};
-
-// Helper function used by [optional.relops], [optional.comp_with_t],
-// for checking whether an expression is convertible to bool.
-bool convertible_to_bool(bool);
-
-// Base class for std::hash<absl::optional<T>>:
-// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
-// compute the hash; Otherwise, it is disabled.
-// Reference N4659 23.14.15 [unord.hash].
-template <typename T, typename = size_t>
-struct optional_hash_base {
-  optional_hash_base() = delete;
-  optional_hash_base(const optional_hash_base&) = delete;
-  optional_hash_base(optional_hash_base&&) = delete;
-  optional_hash_base& operator=(const optional_hash_base&) = delete;
-  optional_hash_base& operator=(optional_hash_base&&) = delete;
-};
-
-template <typename T>
-struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
-                                 std::declval<absl::remove_const_t<T> >()))> {
-  using argument_type = absl::optional<T>;
-  using result_type = size_t;
-  size_t operator()(const absl::optional<T>& opt) const {
-    absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
-    if (opt) {
-      return std::hash<absl::remove_const_t<T> >()(*opt);
-    } else {
-      return static_cast<size_t>(0x297814aaad196e6dULL);
-    }
-  }
-};
-
-}  // namespace optional_internal
-
-// -----------------------------------------------------------------------------
-// absl::optional class definition
-// -----------------------------------------------------------------------------
-
 template <typename T>
 class optional : private optional_internal::optional_data<T>,
                  private optional_internal::optional_ctor_base<