diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 27b121b0cccc4..2864c6843633c 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -1356,21 +1356,22 @@ base::expected AssetManager2::GetResourceId( void AssetManager2::RebuildFilterList() { for (PackageGroup& group : package_groups_) { - for (ConfiguredPackage& impl : group.packages_) { - impl.filtered_configs_.clear(); - + for (ConfiguredPackage& package : group.packages_) { + package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); }); // Create the filters here. - impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) { + package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) { FilteredConfigGroup* group = nullptr; for (const auto& type_entry : type_spec.type_entries) { if (type_entry.config.match(configuration_)) { if (!group) { - group = &impl.filtered_configs_.editItemAt(type_id - 1); + group = &package.filtered_configs_.editItemAt(type_id - 1); } group->type_entries.push_back(&type_entry); } } }); + package.filtered_configs_.trimBuckets( + [](const auto& fcg) { return fcg.type_entries.empty(); }); } } } diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h index 05a2c4db8fe96..ca0a9eda9caaa 100644 --- a/libs/androidfw/include/androidfw/ByteBucketArray.h +++ b/libs/androidfw/include/androidfw/ByteBucketArray.h @@ -17,6 +17,7 @@ #ifndef __BYTE_BUCKET_ARRAY_H #define __BYTE_BUCKET_ARRAY_H +#include #include #include @@ -36,15 +37,11 @@ class ByteBucketArray { } ~ByteBucketArray() { - clear(); + deleteBuckets(); } void clear() { - for (size_t i = 0; i < kNumBuckets; i++) { - if (buckets_[i] != NULL) { - delete[] buckets_[i]; - } - } + deleteBuckets(); memset(buckets_, 0, sizeof(buckets_)); } @@ -59,7 +56,7 @@ class ByteBucketArray { uint8_t bucket_index = static_cast(index) >> 4; T* bucket = buckets_[bucket_index]; - if (bucket == NULL) { + if (bucket == nullptr) { return default_; } return bucket[0x0f & static_cast(index)]; @@ -70,9 +67,9 @@ class ByteBucketArray { << ") with size=" << size(); uint8_t bucket_index = static_cast(index) >> 4; - T* bucket = buckets_[bucket_index]; - if (bucket == NULL) { - bucket = buckets_[bucket_index] = new T[kBucketSize](); + T*& bucket = buckets_[bucket_index]; + if (bucket == nullptr) { + bucket = new T[kBucketSize](); } return bucket[0x0f & static_cast(index)]; } @@ -86,9 +83,42 @@ class ByteBucketArray { return true; } + template + void forEachItem(Func f) { + for (size_t i = 0; i < kNumBuckets; i++) { + const auto bucket = buckets_[i]; + if (bucket != nullptr) { + for (size_t j = 0; j < kBucketSize; j++) { + f((i << 4) | j, bucket[j]); + } + } + } + } + + template + void trimBuckets(Func isEmptyFunc) { + for (size_t i = 0; i < kNumBuckets; i++) { + const auto bucket = buckets_[i]; + if (bucket != nullptr) { + if (std::all_of(bucket, bucket + kBucketSize, isEmptyFunc)) { + delete[] bucket; + buckets_[i] = nullptr; + } + } + } + } + private: enum { kNumBuckets = 16, kBucketSize = 16 }; + void deleteBuckets() { + for (size_t i = 0; i < kNumBuckets; i++) { + if (buckets_[i] != nullptr) { + delete[] buckets_[i]; + } + } + } + T* buckets_[kNumBuckets]; static inline const T default_ = {}; }; diff --git a/libs/androidfw/tests/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp index 5d464c7dc0f75..9c36cfb212c53 100644 --- a/libs/androidfw/tests/ByteBucketArray_test.cpp +++ b/libs/androidfw/tests/ByteBucketArray_test.cpp @@ -52,4 +52,57 @@ TEST(ByteBucketArrayTest, TestSparseInsertion) { } } +TEST(ByteBucketArrayTest, TestForEach) { + ByteBucketArray bba; + ASSERT_TRUE(bba.set(0, 1)); + ASSERT_TRUE(bba.set(10, 2)); + ASSERT_TRUE(bba.set(26, 3)); + ASSERT_TRUE(bba.set(129, 4)); + ASSERT_TRUE(bba.set(234, 5)); + + int count = 0; + bba.forEachItem([&count](auto i, auto val) { + ++count; + switch (i) { + case 0: + EXPECT_EQ(1, val); + break; + case 10: + EXPECT_EQ(2, val); + break; + case 26: + EXPECT_EQ(3, val); + break; + case 129: + EXPECT_EQ(4, val); + break; + case 234: + EXPECT_EQ(5, val); + break; + default: + EXPECT_EQ(0, val); + break; + } + }); + ASSERT_EQ(4 * 16, count); +} + +TEST(ByteBucketArrayTest, TestTrimBuckets) { + ByteBucketArray bba; + ASSERT_TRUE(bba.set(0, 1)); + ASSERT_TRUE(bba.set(255, 2)); + { + bba.trimBuckets([](auto val) { return val < 2; }); + int count = 0; + bba.forEachItem([&count](auto, auto) { ++count; }); + ASSERT_EQ(1 * 16, count); + } + { + bba.trimBuckets([](auto val) { return val < 3; }); + int count = 0; + bba.forEachItem([&count](auto, auto) { ++count; }); + ASSERT_EQ(0, count); + } +} + } // namespace android