| Index: base/containers/flat_tree.h
 | 
| diff --git a/base/containers/flat_tree.h b/base/containers/flat_tree.h
 | 
| index fc9482df8d476d514ae32f62f44fbf57444ad159..c3a234fa784c4f0e0e151d9711d0265b756473fd 100644
 | 
| --- a/base/containers/flat_tree.h
 | 
| +++ b/base/containers/flat_tree.h
 | 
| @@ -9,8 +9,39 @@
 | 
|  #include <vector>
 | 
|  
 | 
|  namespace base {
 | 
| +
 | 
| +enum FlatContainerDupes {
 | 
| +  KEEP_FIRST_OF_DUPES,
 | 
| +  KEEP_LAST_OF_DUPES,
 | 
| +};
 | 
| +
 | 
|  namespace internal {
 | 
|  
 | 
| +// This algorithm is like unique() from the standard library except it
 | 
| +// selects only the last of consecutive values instead of the first.
 | 
| +template <class Iterator, class BinaryPredicate>
 | 
| +Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) {
 | 
| +  if (first == last)
 | 
| +    return last;
 | 
| +
 | 
| +  Iterator dest = first;
 | 
| +  Iterator cur = first;
 | 
| +  Iterator prev = cur;
 | 
| +  while (++cur != last) {
 | 
| +    if (!compare(*prev, *cur)) {
 | 
| +      // Non-identical one.
 | 
| +      if (dest != prev)
 | 
| +        *dest = std::move(*prev);
 | 
| +      ++dest;
 | 
| +    }
 | 
| +    prev = cur;
 | 
| +  }
 | 
| +
 | 
| +  if (dest != prev)
 | 
| +    *dest = std::move(*prev);
 | 
| +  return ++dest;
 | 
| +}
 | 
| +
 | 
|  // Implementation of a sorted vector for backing flat_set and flat_map. Do not
 | 
|  // use directly.
 | 
|  //
 | 
| @@ -24,7 +55,6 @@ namespace internal {
 | 
|  //   const Key& operator()(const Value&).
 | 
|  template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
|  class flat_tree {
 | 
| - public:
 | 
|   private:
 | 
|    using underlying_type = std::vector<Value>;
 | 
|  
 | 
| @@ -71,21 +101,28 @@ class flat_tree {
 | 
|    // length).
 | 
|    //
 | 
|    // Assume that move constructors invalidate iterators and references.
 | 
| +  //
 | 
| +  // The constructors that take ranges, lists, and vectors do not require that
 | 
| +  // the input be sorted.
 | 
|  
 | 
|    flat_tree();
 | 
|    explicit flat_tree(const key_compare& comp);
 | 
|  
 | 
| -  // Not stable in the presence of duplicates in the initializer list.
 | 
|    template <class InputIterator>
 | 
|    flat_tree(InputIterator first,
 | 
|              InputIterator last,
 | 
| +            FlatContainerDupes dupe_handling,
 | 
|              const key_compare& comp = key_compare());
 | 
|  
 | 
|    flat_tree(const flat_tree&);
 | 
|    flat_tree(flat_tree&&);
 | 
|  
 | 
| -  // Not stable in the presence of duplicates in the initializer list.
 | 
| +  flat_tree(std::vector<value_type> items,
 | 
| +            FlatContainerDupes dupe_handling,
 | 
| +            const key_compare& comp = key_compare());
 | 
| +
 | 
|    flat_tree(std::initializer_list<value_type> ilist,
 | 
| +            FlatContainerDupes dupe_handling,
 | 
|              const key_compare& comp = key_compare());
 | 
|  
 | 
|    ~flat_tree();
 | 
| @@ -97,7 +134,7 @@ class flat_tree {
 | 
|  
 | 
|    flat_tree& operator=(const flat_tree&);
 | 
|    flat_tree& operator=(flat_tree&&);
 | 
| -  // Not stable in the presence of duplicates in the initializer list.
 | 
| +  // Takes the first if there are duplicates in the initializer list.
 | 
|    flat_tree& operator=(std::initializer_list<value_type> ilist);
 | 
|  
 | 
|    // --------------------------------------------------------------------------
 | 
| @@ -276,17 +313,26 @@ class flat_tree {
 | 
|      return std::next(begin(), distance);
 | 
|    }
 | 
|  
 | 
| -  void sort_and_unique() {
 | 
| -    // std::set sorts elements preserving stability because it doesn't have any
 | 
| -    // performance wins in not doing that. We do, so we use an unstable sort.
 | 
| -    std::sort(begin(), end(), impl_.get_value_comp());
 | 
| -    erase(std::unique(begin(), end(),
 | 
| -                      [this](const value_type& lhs, const value_type& rhs) {
 | 
| -                        // lhs is already <= rhs due to sort, therefore
 | 
| -                        // !(lhs < rhs) <=> lhs == rhs.
 | 
| -                        return !impl_.get_value_comp()(lhs, rhs);
 | 
| -                      }),
 | 
| -          end());
 | 
| +  void sort_and_unique(FlatContainerDupes dupes) {
 | 
| +    // Preserve stability for the unique code below.
 | 
| +    std::stable_sort(begin(), end(), impl_.get_value_comp());
 | 
| +
 | 
| +    auto comparator = [this](const value_type& lhs, const value_type& rhs) {
 | 
| +      // lhs is already <= rhs due to sort, therefore
 | 
| +      // !(lhs < rhs) <=> lhs == rhs.
 | 
| +      return !impl_.get_value_comp()(lhs, rhs);
 | 
| +    };
 | 
| +
 | 
| +    iterator erase_after;
 | 
| +    switch (dupes) {
 | 
| +      case KEEP_FIRST_OF_DUPES:
 | 
| +        erase_after = std::unique(begin(), end(), comparator);
 | 
| +        break;
 | 
| +      case KEEP_LAST_OF_DUPES:
 | 
| +        erase_after = LastUnique(begin(), end(), comparator);
 | 
| +        break;
 | 
| +    }
 | 
| +    erase(erase_after, end());
 | 
|    }
 | 
|  
 | 
|    // To support comparators that may not be possible to default-construct, we
 | 
| @@ -325,9 +371,10 @@ template <class InputIterator>
 | 
|  flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
 | 
|      InputIterator first,
 | 
|      InputIterator last,
 | 
| +    FlatContainerDupes dupe_handling,
 | 
|      const KeyCompare& comp)
 | 
|      : impl_(comp, first, last) {
 | 
| -  sort_and_unique();
 | 
| +  sort_and_unique(dupe_handling);
 | 
|  }
 | 
|  
 | 
|  template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
| @@ -340,9 +387,19 @@ flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) =
 | 
|  
 | 
|  template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
|  flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
 | 
| +    std::vector<value_type> items,
 | 
| +    FlatContainerDupes dupe_handling,
 | 
| +    const KeyCompare& comp)
 | 
| +    : impl_(comp, std::move(items)) {
 | 
| +  sort_and_unique(dupe_handling);
 | 
| +}
 | 
| +
 | 
| +template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
| +flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
 | 
|      std::initializer_list<value_type> ilist,
 | 
| +    FlatContainerDupes dupe_handling,
 | 
|      const KeyCompare& comp)
 | 
| -    : flat_tree(std::begin(ilist), std::end(ilist), comp) {}
 | 
| +    : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {}
 | 
|  
 | 
|  template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
|  flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default;
 | 
| @@ -362,7 +419,7 @@ template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
 | 
|  auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
 | 
|      std::initializer_list<value_type> ilist) -> flat_tree& {
 | 
|    impl_.body_ = ilist;
 | 
| -  sort_and_unique();
 | 
| +  sort_and_unique(KEEP_FIRST_OF_DUPES);
 | 
|    return *this;
 | 
|  }
 | 
|  
 | 
| 
 |