mirror of
https://github.com/mii443/mozc.git
synced 2025-08-22 16:15:46 +00:00
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:
committed by
Hiroyuki Komatsu
parent
f215eaf71a
commit
992b1f49f1
@ -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(
|
||||
name = "freelist",
|
||||
hdrs = ["freelist.h"],
|
||||
|
46
src/base/container/entry.h
Normal file
46
src/base/container/entry.h
Normal 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_
|
128
src/base/container/flat_internal.h
Normal file
128
src/base/container/flat_internal.h
Normal 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_
|
98
src/base/container/flat_map.h
Normal file
98
src/base/container/flat_map.h
Normal 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_
|
78
src/base/container/flat_map_test.cc
Normal file
78
src/base/container/flat_map_test.cc
Normal 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
|
107
src/base/container/flat_multimap.h
Normal file
107
src/base/container/flat_multimap.h
Normal 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_
|
98
src/base/container/flat_multimap_test.cc
Normal file
98
src/base/container/flat_multimap_test.cc
Normal 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
|
86
src/base/container/flat_set.h
Normal file
86
src/base/container/flat_set.h
Normal 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_
|
73
src/base/container/flat_set_test.cc
Normal file
73
src/base/container/flat_set_test.cc
Normal 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
|
@ -28,6 +28,34 @@
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# 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."""
|
||||
|
||||
import os
|
||||
|
Reference in New Issue
Block a user