Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8df928ec authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I8cc8287c,Icc13d1dc

* changes:
  FTL: Parametrize SmallMap key equality
  FTL: Add clear() to containers
parents c7cb23c9 18748965
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <functional>
#include <tuple>
#include <utility>

@@ -65,18 +66,18 @@ struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
  std::tuple<Types...> tuple;
};

template <typename K, typename V>
template <typename K, typename V, typename KeyEqual = std::equal_to<K>>
struct KeyValue {};

// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
// with the latter.
template <typename K, typename V, std::size_t... Sizes, typename... Types>
struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
struct InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...> {
  // Accumulate the three arguments to std::pair's piecewise constructor.
  template <typename... Args>
  [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
      KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
      KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
      std::tuple<K&&>, std::tuple<Args&&...>> {
    return {std::tuple_cat(
        std::move(tuple),
@@ -94,9 +95,9 @@ template <typename T, typename... Args>
  return InitializerList<T>{}(std::forward<Args>(args)...);
}

template <typename K, typename V, typename... Args>
template <typename K, typename V, typename E = std::equal_to<K>, typename... Args>
[[nodiscard]] constexpr auto map(Args&&... args) {
  return list<KeyValue<K, V>>(std::forward<Args>(args)...);
  return list<KeyValue<K, V, E>>(std::forward<Args>(args)...);
}

template <typename K, typename V>
+17 −10
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ namespace android::ftl {
//
//   assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
//
template <typename K, typename V, std::size_t N>
template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>>
class SmallMap final {
  using Map = SmallVector<std::pair<const K, V>, N>;

@@ -153,7 +153,7 @@ class SmallMap final {
  auto get(const key_type& key, F f) const
      -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
    for (auto& [k, v] : *this) {
      if (k == key) {
      if (KeyEqual{}(k, key)) {
        if constexpr (std::is_void_v<R>) {
          f(v);
          return true;
@@ -237,9 +237,16 @@ class SmallMap final {
  //
  bool erase(const key_type& key) { return erase(key, begin()); }

  // Removes all mappings.
  //
  // All iterators are invalidated.
  //
  void clear() { map_.clear(); }

 private:
  iterator find(const key_type& key, iterator first) {
    return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; });
    return std::find_if(first, end(),
                        [&key](const auto& pair) { return KeyEqual{}(pair.first, key); });
  }

  bool erase(const key_type& key, iterator first) {
@@ -261,13 +268,13 @@ class SmallMap final {
};

// Deduction guide for in-place constructor.
template <typename K, typename V, std::size_t... Sizes, typename... Types>
SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
    -> SmallMap<K, V, sizeof...(Sizes)>;
template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&)
    -> SmallMap<K, V, sizeof...(Sizes), E>;

// Returns whether the key-value pairs of two maps are equal.
template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
  if (lhs.size() != rhs.size()) return false;

  for (const auto& [k, v] : lhs) {
@@ -281,8 +288,8 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
}

// TODO: Remove in C++20.
template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
  return !(lhs == rhs);
}

+10 −9
Original line number Diff line number Diff line
@@ -151,8 +151,6 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
  DISPATCH(reference, back, noexcept)
  DISPATCH(const_reference, back, const)

#undef DISPATCH

  reference operator[](size_type i) {
    return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i];
  }
@@ -214,13 +212,15 @@ class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
  //
  // The last() and end() iterators are invalidated.
  //
  void pop_back() {
    if (dynamic()) {
      std::get<Dynamic>(vector_).pop_back();
    } else {
      std::get<Static>(vector_).pop_back();
    }
  }
  DISPATCH(void, pop_back, noexcept)

  // Removes all elements.
  //
  // All iterators are invalidated.
  //
  DISPATCH(void, clear, noexcept)

#undef DISPATCH

  // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
  // this moves the last element to the slot of the erased element.
@@ -345,6 +345,7 @@ class SmallVector<T, 0> final : ArrayTraits<T>,
    return true;
  }

  using Impl::clear;
  using Impl::pop_back;

  void unstable_erase(iterator it) {
+10 −2
Original line number Diff line number Diff line
@@ -189,8 +189,7 @@ class StaticVector final : ArrayTraits<T>,
  }

  StaticVector& operator=(StaticVector&& other) {
    std::destroy(begin(), end());
    size_ = 0;
    clear();
    swap<true>(other);
    return *this;
  }
@@ -280,6 +279,15 @@ class StaticVector final : ArrayTraits<T>,
  //
  void pop_back() { unstable_erase(last()); }

  // Removes all elements.
  //
  // All iterators are invalidated.
  //
  void clear() {
    std::destroy(begin(), end());
    size_ = 0;
  }

  // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
  // this moves the last element to the slot of the erased element.
  //
+37 −0
Original line number Diff line number Diff line
@@ -345,4 +345,41 @@ TEST(SmallMap, Erase) {
  }
}

TEST(SmallMap, Clear) {
  SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3');

  map.clear();

  EXPECT_TRUE(map.empty());
  EXPECT_FALSE(map.dynamic());

  map = ftl::init::map(1, '1')(2, '2')(3, '3');
  map.try_emplace(4, '4');

  map.clear();

  EXPECT_TRUE(map.empty());
  EXPECT_TRUE(map.dynamic());
}

TEST(SmallMap, KeyEqual) {
  struct KeyEqual {
    bool operator()(int lhs, int rhs) const { return lhs % 10 == rhs % 10; }
  };

  SmallMap<int, char, 1, KeyEqual> map;

  EXPECT_TRUE(map.try_emplace(3, '3').second);
  EXPECT_FALSE(map.try_emplace(13, '3').second);

  EXPECT_TRUE(map.try_emplace(22, '2').second);
  EXPECT_TRUE(map.contains(42));

  EXPECT_TRUE(map.try_emplace(111, '1').second);
  EXPECT_EQ(map.get(321), '1');

  map.erase(123);
  EXPECT_EQ(map, SmallMap(ftl::init::map<int, char, KeyEqual>(1, '1')(2, '2')));
}

}  // namespace android::test
Loading