Introduce constexpr flat containers.

These containers offer `constexpr` construction, by creating a sorted array at compile time, and provide read-only lookup of values.

They have a very minimal API surface, sufficient for Mozc's use, and deliberately diverge from the standard STL API for simplicity.

*   `FlatSet` has `bool contains(K)`:  The standard C++ interface for sets.
*   `FlatMap` has `const T* FindOrNull(K)`, not `iterator find(K)`:  No iterator involved.
*   `FlatMultiMap` has `absl::Span<const Entry<K, V>> EqualSpan(K)`, not `pair<iterator, iterator> equal_range(K)`: No iterator, or no `std::pair` that lacks necessary `constexpr` support (yet).

These are meant for replacing patterns like `const auto *map = new std::map<...>(...)` in the codebase, reducing runtime startup work and eliminating leaked heap allocations, which is particularly important when linked in the Windows DLL.

PiperOrigin-RevId: 729741608
This commit is contained in:
Tomoki Nakagawa
2025-02-22 03:40:10 +00:00
committed by Hiroyuki Komatsu
parent f215eaf71a
commit 992b1f49f1
10 changed files with 816 additions and 0 deletions

View File

@ -53,6 +53,80 @@ mozc_cc_test(
], ],
) )
mozc_cc_library(
name = "entry",
hdrs = ["entry.h"],
)
mozc_cc_library(
name = "flat_internal",
hdrs = ["flat_internal.h"],
deps = [
"@com_google_absl//absl/log",
"@com_google_absl//absl/types:span",
],
)
mozc_cc_library(
name = "flat_map",
hdrs = ["flat_map.h"],
deps = [
":entry",
":flat_internal",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/types:span",
],
)
mozc_cc_test(
name = "flat_map_test",
srcs = ["flat_map_test.cc"],
deps = [
":flat_map",
"//testing:gunit_main",
"@com_google_absl//absl/strings",
],
)
mozc_cc_library(
name = "flat_multimap",
hdrs = ["flat_multimap.h"],
deps = [
":entry",
":flat_internal",
"@com_google_absl//absl/types:span",
],
)
mozc_cc_test(
name = "flat_multimap_test",
srcs = ["flat_multimap_test.cc"],
deps = [
":flat_multimap",
"//testing:gunit_main",
"@com_google_absl//absl/strings",
],
)
mozc_cc_library(
name = "flat_set",
hdrs = ["flat_set.h"],
deps = [
":flat_internal",
"@com_google_absl//absl/types:span",
],
)
mozc_cc_test(
name = "flat_set_test",
srcs = ["flat_set_test.cc"],
deps = [
":flat_set",
"//testing:gunit_main",
"@com_google_absl//absl/strings",
],
)
mozc_cc_library( mozc_cc_library(
name = "freelist", name = "freelist",
hdrs = ["freelist.h"], hdrs = ["freelist.h"],

View File

@ -0,0 +1,46 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_BASE_CONTAINER_ENTRY_H_
#define MOZC_BASE_CONTAINER_ENTRY_H_
namespace mozc {
// Represents an entry in a map.
//
// We need constexpr copy/move, which `std::pair` doesn't get until C++20.
template <class K, class V>
struct Entry {
K key;
V value;
};
} // namespace mozc
#endif // MOZC_BASE_CONTAINER_ENTRY_H_

View File

@ -0,0 +1,128 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_BASE_CONTAINER_FLAT_INTERNAL_H_
#define MOZC_BASE_CONTAINER_FLAT_INTERNAL_H_
#include <stddef.h>
#include <algorithm>
#include <array>
#include <functional>
#include <type_traits>
#include <utility>
#include "absl/log/log.h"
#include "absl/types/span.h"
namespace mozc::internal {
// Sorts the given span in place.
// C++17 backport of constexpr `std::sort` from C++20.
template <class T, class Compare = std::less<>>
constexpr void Sort(absl::Span<T> span, const Compare &cmp = {}) {
// Since we're dealing with compile-time constants, expected to be small,
// we use insertion sort. It's faster for small inputs, and easier to
// implement :)
for (int i = 1; i < span.size(); ++i) {
if (!cmp(span[i], span[i - 1])) continue;
T tmp = std::move(span[i]);
int j = i;
do {
span[j] = std::move(span[j - 1]);
--j;
} while (j > 0 && cmp(tmp, span[j - 1]));
span[j] = std::move(tmp);
}
}
template <class T, size_t N, size_t... I>
constexpr std::array<std::remove_cv_t<T>, N> ToArrayImpl(
T (&&a)[N], std::index_sequence<I...>) {
return {std::move(a[I])...};
}
// Converts a C-style array to a `std::array`.
// C++17 backport of `std::to_array` from C++20.
template <class T, size_t N>
constexpr std::array<std::remove_cv_t<T>, N> ToArray(T (&&a)[N]) {
return ToArrayImpl(std::move(a), std::make_index_sequence<N>());
}
// Finds the first element satisfying the given predicate, or `span.end()` if
// none exists.
//
// `pred` must be non-decreasing in `span`: if `l <= r`, then
// `pred(span[l]) <= pred(span[r])`, where `false < true`.
//
// NOTE: To use `std::lower_bound`, we'd need an iterator adapter that extracts
// the first element of each pair, which would be more code than a custom binary
// search.
template <class T, class Predicate>
constexpr typename absl::Span<const T>::iterator FindFirst(
absl::Span<const T> span, Predicate pred) {
if (span.empty()) return span.end();
if (pred(span.front())) return span.begin();
// Invariant: `pred(span[l])` is false and `pred(span[r])` is true (virtually
// assuming `pred(span[span.size()])` is true). Note that `mid` will never be
// `span.size()` (which would be out-of-bound access), because the largest
// possible `mid` occurs when `(l, r) = (span.size() - 2, span.size())`,
// resulting in `mid = span.size() - 1`.
int l = 0;
int r = span.size();
while (r - l > 1) {
int mid = l + (r - l) / 2;
(pred(span[mid]) ? r : l) = mid;
}
return span.begin() + r;
}
// Non-constexpr function to be called when a duplicate entry is found, causing
// a compile-time error.
inline void DuplicateEntryFound() { LOG(FATAL) << "Duplicate entry found"; }
// Sorts the given span in place, and verifies that the elements are unique
// according to `cmp`.
template <class T, class Compare = std::less<>>
constexpr void SortAndVerifyUnique(absl::Span<T> span,
const Compare &cmp = {}) {
Sort(span, cmp);
for (int i = 0; i + i < span.size(); ++i) {
if (!cmp(span[i], span[i + 1]) && !cmp(span[i + 1], span[i])) {
DuplicateEntryFound();
}
}
}
} // namespace mozc::internal
#endif // MOZC_BASE_CONTAINER_FLAT_INTERNAL_H_

View File

@ -0,0 +1,98 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_BASE_CONTAINER_FLAT_MAP_H_
#define MOZC_BASE_CONTAINER_FLAT_MAP_H_
#include <stddef.h>
#include <algorithm>
#include <array>
#include <functional>
#include <utility>
#include "absl/base/nullability.h"
#include "absl/types/span.h"
#include "base/container/entry.h"
#include "base/container/flat_internal.h"
namespace mozc {
// Read-only map that is backed by `constexpr`-sorted array.
template <class K, class V, class CompareKey, size_t N>
class FlatMap {
public:
// Consider calling `CreateFlatMap` instead, so you don't have to manually
// specify the number of entries, `N`.
constexpr FlatMap(std::array<Entry<K, V>, N> entries,
const CompareKey &cmp_key = {})
: entries_(std::move(entries)), cmp_key_(cmp_key) {
internal::SortAndVerifyUnique(
absl::MakeSpan(entries_),
[&](const Entry<K, V> &a, const Entry<K, V> &b) {
return cmp_key_(a.key, b.key);
});
}
// Finds the value associated with the given key, or `nullptr` if not found.
constexpr absl::Nullable<const V *> FindOrNull(const K &key) const {
auto lb = internal::FindFirst(
absl::MakeSpan(entries_),
[&](const Entry<K, V> &e) { return !cmp_key_(e.key, key); });
return lb == entries_.end() || cmp_key_(key, lb->key) ? nullptr
: &lb->value;
}
private:
std::array<Entry<K, V>, N> entries_;
CompareKey cmp_key_;
};
// Creates a `FlatMap` from a C-style array of `Entry`s.
//
// Example:
//
// constexpr auto kMap = CreateFlatMap<int, absl::string_view>({
// {1, "one"},
// {2, "two"},
// {3, "three"},
// });
//
// Declare the variable as auto and use `CreateFlatMap`. The actual type is
// complex and explicitly declaring it would leak the number of entries, `N`.
template <class K, class V, class CompareKey = std::less<>, size_t N>
constexpr auto CreateFlatMap(Entry<K, V> (&&entries)[N],
const CompareKey &cmp_key = {}) {
return FlatMap<K, V, CompareKey, N>(internal::ToArray(std::move(entries)),
cmp_key);
}
} // namespace mozc
#endif // MOZC_BASE_CONTAINER_FLAT_MAP_H_

View File

@ -0,0 +1,78 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/container/flat_map.h"
#include <functional>
#include "absl/strings/string_view.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace mozc {
namespace {
using ::testing::Eq;
using ::testing::IsNull;
using ::testing::Pointee;
TEST(FlatMapTest, FindOrNull) {
constexpr auto kMap = CreateFlatMap<int, absl::string_view>({
{1, "one"},
{3, "three"},
{5, "five"},
});
EXPECT_THAT(kMap.FindOrNull(0), IsNull());
EXPECT_THAT(kMap.FindOrNull(1), Pointee(Eq("one")));
EXPECT_THAT(kMap.FindOrNull(2), IsNull());
EXPECT_THAT(kMap.FindOrNull(3), Pointee(Eq("three")));
EXPECT_THAT(kMap.FindOrNull(4), IsNull());
EXPECT_THAT(kMap.FindOrNull(5), Pointee(Eq("five")));
EXPECT_THAT(kMap.FindOrNull(6), IsNull());
}
TEST(FlatMapTest, CustomerCompare) {
constexpr auto kMap = CreateFlatMap<int, absl::string_view, std::greater<>>({
{1, "one"},
{3, "three"},
{5, "five"},
});
EXPECT_THAT(kMap.FindOrNull(0), IsNull());
EXPECT_THAT(kMap.FindOrNull(1), Pointee(Eq("one")));
EXPECT_THAT(kMap.FindOrNull(2), IsNull());
EXPECT_THAT(kMap.FindOrNull(3), Pointee(Eq("three")));
EXPECT_THAT(kMap.FindOrNull(4), IsNull());
EXPECT_THAT(kMap.FindOrNull(5), Pointee(Eq("five")));
EXPECT_THAT(kMap.FindOrNull(6), IsNull());
}
} // namespace
} // namespace mozc

View File

@ -0,0 +1,107 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_BASE_CONTAINER_FLAT_MULTIMAP_H_
#define MOZC_BASE_CONTAINER_FLAT_MULTIMAP_H_
#include <stddef.h>
#include <algorithm>
#include <array>
#include <functional>
#include <utility>
#include "absl/types/span.h"
#include "base/container/entry.h"
#include "base/container/flat_internal.h"
namespace mozc {
// Read-only multimap that is backed by `constexpr`-sorted array.
template <class K, class V, class CompareKey, size_t N>
class FlatMultimap {
public:
// Consider calling `CreateFlatMultimap` instead, so you don't have to
// manually specify the number of entries, `N`.
constexpr FlatMultimap(std::array<Entry<K, V>, N> entries,
const CompareKey &cmp_key = {})
: entries_(std::move(entries)), cmp_key_(cmp_key) {
internal::Sort(absl::MakeSpan(entries_),
[&](const Entry<K, V> &a, const Entry<K, V> &b) {
return cmp_key_(a.key, b.key);
});
}
// Returns a span of entries with the given key.
//
// IMPORTANT: The order of the returned span is not guaranteed to be the
// same as the order of the entries given when the map was created.
//
// NOTE: The current implementation actually preserves the order, but this
// will change once we switch to `std::sort`, which is not stable (and
// `std::stable_sort` is not planned to receive constexpr support).
constexpr absl::Span<const Entry<K, V>> EqualSpan(const K &key) const {
auto lb = internal::FindFirst(
absl::MakeSpan(entries_),
[&](const Entry<K, V> &e) { return !cmp_key_(e.key, key); });
auto ub = internal::FindFirst(
absl::MakeSpan(entries_),
[&](const Entry<K, V> &e) { return cmp_key_(key, e.key); });
return absl::MakeConstSpan(lb, ub);
}
private:
std::array<Entry<K, V>, N> entries_;
CompareKey cmp_key_;
};
// Creates a `FlatMultimap` from a C-style array of `Entry`s.
//
// Example:
//
// constexpr auto kMultimap = CreateFlatMultimap<int, absl::string_view>({
// {1, "one"},
// {1, "ichi"},
// {2, "two"},
// {2, "ni"},
// {3, "three"},
// {3, "san"},
// });
// Declare the variable as auto and use `CreateFlatMultimap`. The actual type is
// complex and explicitly declaring it would leak the number of entries, `N`.
template <class K, class V, class CompareKey = std::less<>, size_t N>
constexpr auto CreateFlatMultimap(Entry<K, V> (&&entries)[N],
const CompareKey &cmp_key = {}) {
return FlatMultimap<K, V, CompareKey, N>(
internal::ToArray(std::move(entries)), cmp_key);
}
} // namespace mozc
#endif // MOZC_BASE_CONTAINER_FLAT_MULTIMAP_H_

View File

@ -0,0 +1,98 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/container/flat_multimap.h"
#include <functional>
#include "absl/strings/string_view.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace mozc {
namespace {
using ::testing::Eq;
using ::testing::FieldsAre;
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
TEST(FlatMultimapTest, EqualSpan) {
constexpr auto kMultimap = CreateFlatMultimap<int, absl::string_view>({
{1, "one"},
{3, "three"},
{5, "five"},
{1, "ichi"},
{3, "san"},
{5, "go"},
});
EXPECT_THAT(kMultimap.EqualSpan(0), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(1),
UnorderedElementsAre(FieldsAre(Eq(1), Eq("one")),
FieldsAre(Eq(1), Eq("ichi"))));
EXPECT_THAT(kMultimap.EqualSpan(2), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(3),
UnorderedElementsAre(FieldsAre(Eq(3), Eq("three")),
FieldsAre(Eq(3), Eq("san"))));
EXPECT_THAT(kMultimap.EqualSpan(4), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(5),
UnorderedElementsAre(FieldsAre(Eq(5), Eq("five")),
FieldsAre(Eq(5), Eq("go"))));
EXPECT_THAT(kMultimap.EqualSpan(6), IsEmpty());
}
TEST(FlatMultimapTest, CustomerCompare) {
constexpr auto kMultimap =
CreateFlatMultimap<int, absl::string_view, std::greater<>>({
{1, "one"},
{3, "three"},
{5, "five"},
{1, "ichi"},
{3, "san"},
{5, "go"},
});
EXPECT_THAT(kMultimap.EqualSpan(0), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(1),
UnorderedElementsAre(FieldsAre(Eq(1), Eq("one")),
FieldsAre(Eq(1), Eq("ichi"))));
EXPECT_THAT(kMultimap.EqualSpan(2), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(3),
UnorderedElementsAre(FieldsAre(Eq(3), Eq("three")),
FieldsAre(Eq(3), Eq("san"))));
EXPECT_THAT(kMultimap.EqualSpan(4), IsEmpty());
EXPECT_THAT(kMultimap.EqualSpan(5),
UnorderedElementsAre(FieldsAre(Eq(5), Eq("five")),
FieldsAre(Eq(5), Eq("go"))));
EXPECT_THAT(kMultimap.EqualSpan(6), IsEmpty());
}
} // namespace
} // namespace mozc

View File

@ -0,0 +1,86 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MOZC_BASE_CONTAINER_FLAT_SET_H_
#define MOZC_BASE_CONTAINER_FLAT_SET_H_
#include <stddef.h>
#include <algorithm>
#include <array>
#include <functional>
#include <utility>
#include "absl/types/span.h"
#include "base/container/flat_internal.h"
namespace mozc {
// Read-only set that is backed by `constexpr`-sorted array.
template <class T, class Compare, size_t N>
class FlatSet {
public:
// Consider calling `CreateFlatSet` instead, so you don't have to manually
// specify the number of elements, `N`.
constexpr FlatSet(std::array<T, N> elements, const Compare &cmp = {})
: elements_(std::move(elements)), cmp_(cmp) {
internal::SortAndVerifyUnique(absl::MakeSpan(elements_), cmp_);
}
// Returns if the given element is in the set.
constexpr bool contains(const T &x) const {
auto lb = internal::FindFirst(absl::MakeSpan(elements_),
[&](const T &e) { return !cmp_(e, x); });
return lb != elements_.end() && !cmp_(x, *lb);
}
private:
std::array<T, N> elements_;
Compare cmp_;
};
// Creates a `FlatSet` from a C-style array of `Entry`s.
//
// Example:
//
// constexpr auto kSet = CreateFlatSet<absl::string_view>({
// "one",
// "two",
// "three",
// });
// Declare the variable as auto and use `CreateFlatSet`. The actual type is
// complex and explicitly declaring it would leak the number of elements, `N`.
template <class T, class Compare = std::less<>, size_t N>
constexpr auto CreateFlatSet(T (&&elements)[N], const Compare &cmp = {}) {
return FlatSet<T, Compare, N>(internal::ToArray(std::move(elements)), cmp);
}
} // namespace mozc
#endif // MOZC_BASE_CONTAINER_FLAT_SET_H_

View File

@ -0,0 +1,73 @@
// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/container/flat_set.h"
#include <functional>
#include "absl/strings/string_view.h"
#include "testing/gunit.h"
namespace mozc {
namespace {
TEST(FlatSetTest, Contains) {
constexpr auto kSet = CreateFlatSet<absl::string_view>({
"one",
"three",
"five",
});
EXPECT_FALSE(kSet.contains("zero"));
EXPECT_TRUE(kSet.contains("one"));
EXPECT_FALSE(kSet.contains("two"));
EXPECT_TRUE(kSet.contains("three"));
EXPECT_FALSE(kSet.contains("four"));
EXPECT_TRUE(kSet.contains("five"));
EXPECT_FALSE(kSet.contains("six"));
}
TEST(FlatSetTest, CustomerCompare) {
constexpr auto kSet = CreateFlatSet<absl::string_view, std::greater<>>({
"one",
"three",
"five",
});
EXPECT_FALSE(kSet.contains("zero"));
EXPECT_TRUE(kSet.contains("one"));
EXPECT_FALSE(kSet.contains("two"));
EXPECT_TRUE(kSet.contains("three"));
EXPECT_FALSE(kSet.contains("four"));
EXPECT_TRUE(kSet.contains("five"));
EXPECT_FALSE(kSet.contains("six"));
}
} // namespace
} // namespace mozc

View File

@ -28,6 +28,34 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A console utility to show progress.""" """A console utility to show progress."""
import os import os