-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial reference stability unit tests
Summary: Adding a few initial unit tests for the future map reference stability checker. `F14ValueMap` and `F14VectorMap` do not provide reference stability guarantees. Reviewed By: skcho Differential Revision: D49535916 fbshipit-source-id: 2ae470cf71ae3aebe287002101a39eff9a3e856d
- Loading branch information
1 parent
22cc4b7
commit ca4c3b4
Showing
1 changed file
with
258 additions
and
0 deletions.
There are no files selected for viewing
258 changes: 258 additions & 0 deletions
258
infer/tests/codetoanalyze/cpp/pulse/reference_stability.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
/* | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#include <initializer_list> | ||
#include <unordered_map> | ||
#include <utility> | ||
|
||
// Keep a simplified skeleton of F14 maps for testing. | ||
namespace folly { | ||
struct F14HashToken; | ||
|
||
template <typename Key, typename Mapped> | ||
struct F14BasicMap { | ||
using key_type = Key; | ||
using mapped_type = Mapped; | ||
using value_type = std::pair<const Key, Mapped>; | ||
using size_type = std::size_t; | ||
using iterator = value_type*; | ||
using const_iterator = value_type const*; | ||
|
||
F14BasicMap() noexcept; | ||
|
||
explicit F14BasicMap(std::size_t initialCapacity); | ||
|
||
template <typename InputIt> | ||
F14BasicMap(InputIt first, InputIt last, std::size_t initialCapacity = 0); | ||
|
||
F14BasicMap(F14BasicMap const& rhs); | ||
|
||
F14BasicMap(F14BasicMap&& rhs); | ||
|
||
F14BasicMap(std::initializer_list<value_type> init, | ||
std::size_t initialCapacity = 0); | ||
|
||
F14BasicMap& operator=(F14BasicMap const&); | ||
|
||
F14BasicMap& operator=(F14BasicMap&&); | ||
|
||
F14BasicMap& operator=(std::initializer_list<value_type> ilist); | ||
|
||
iterator begin() noexcept; | ||
const_iterator begin() const noexcept; | ||
const_iterator cbegin() const noexcept; | ||
iterator end() noexcept; | ||
const_iterator end() const noexcept; | ||
const_iterator cend() const noexcept; | ||
|
||
void clear() noexcept; | ||
|
||
std::pair<iterator, bool> insert(value_type const& value); | ||
std::pair<iterator, bool> insert(value_type&& value); | ||
iterator insert(const_iterator /*hint*/, value_type const& value); | ||
iterator insert(const_iterator /*hint*/, value_type&& value); | ||
|
||
template <class... Args> | ||
iterator emplace_hint(const_iterator /*hint*/, Args&&... args); | ||
|
||
template <class InputIt> | ||
void insert(InputIt first, InputIt last); | ||
void insert(std::initializer_list<value_type> ilist); | ||
|
||
template <typename M> | ||
std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj); | ||
|
||
template <typename M> | ||
std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj); | ||
|
||
template <typename M> | ||
std::pair<iterator, bool> insert_or_assign(F14HashToken const& token, | ||
key_type const& key, | ||
M&& obj); | ||
|
||
template <typename M> | ||
std::pair<iterator, bool> insert_or_assign(F14HashToken const& token, | ||
key_type&& key, | ||
M&& obj); | ||
|
||
template <typename M> | ||
iterator insert_or_assign(const_iterator /*hint*/, | ||
key_type const& key, | ||
M&& obj); | ||
|
||
template <typename M> | ||
iterator insert_or_assign(const_iterator /*hint*/, key_type&& key, M&& obj); | ||
|
||
template <typename... Args> | ||
std::pair<iterator, bool> emplace(Args&&... args); | ||
|
||
template <typename... Args> | ||
std::pair<iterator, bool> try_emplace(key_type const& key, Args&&... args); | ||
|
||
template <typename... Args> | ||
std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args); | ||
|
||
template <typename... Args> | ||
std::pair<iterator, bool> try_emplace_token(F14HashToken const& token, | ||
key_type const& key, | ||
Args&&... args); | ||
|
||
template <typename... Args> | ||
std::pair<iterator, bool> try_emplace_token(F14HashToken const& token, | ||
key_type&& key, | ||
Args&&... args); | ||
|
||
template <typename... Args> | ||
iterator try_emplace(const_iterator /*hint*/, | ||
key_type const& key, | ||
Args&&... args); | ||
|
||
template <typename... Args> | ||
iterator try_emplace(const_iterator /*hint*/, key_type&& key, Args&&... args); | ||
|
||
iterator erase(const_iterator pos); | ||
|
||
iterator erase(iterator pos); | ||
|
||
iterator erase(const_iterator first, const_iterator last); | ||
|
||
size_type erase(key_type const& key); | ||
|
||
template <typename BeforeDestroy> | ||
iterator eraseInto(const_iterator pos, BeforeDestroy&& beforeDestroy); | ||
|
||
template <typename BeforeDestroy> | ||
iterator eraseInto(iterator pos, BeforeDestroy&& beforeDestroy); | ||
|
||
template <typename BeforeDestroy> | ||
iterator eraseInto(const_iterator first, | ||
const_iterator last, | ||
BeforeDestroy&& beforeDestroy); | ||
|
||
template <typename BeforeDestroy> | ||
size_type eraseInto(key_type const& key, BeforeDestroy&& beforeDestroy); | ||
|
||
mapped_type& at(key_type const& key); | ||
|
||
mapped_type const& at(key_type const& key) const; | ||
|
||
mapped_type& operator[](key_type const& key); | ||
|
||
mapped_type& operator[](key_type&& key); | ||
|
||
F14HashToken prehash(key_type const& key) const; | ||
|
||
iterator find(key_type const& key); | ||
|
||
const_iterator find(key_type const& key) const; | ||
|
||
iterator find(F14HashToken const& token, key_type const& key); | ||
|
||
const_iterator find(F14HashToken const& token, key_type const& key) const; | ||
|
||
std::pair<iterator, iterator> equal_range(key_type const& key); | ||
|
||
std::pair<const_iterator, const_iterator> equal_range( | ||
key_type const& key) const; | ||
|
||
void rehash(std::size_t bucketCapacity); | ||
|
||
void reserve(std::size_t capacity); | ||
}; | ||
|
||
template <typename K, typename V> | ||
using F14ValueMap = F14BasicMap<K, V>; | ||
template <typename K, typename V> | ||
using F14VectorMap = F14BasicMap<K, V>; | ||
template <typename K, typename V> | ||
using F14FastMap = F14BasicMap<K, V>; | ||
} // namespace folly | ||
|
||
void unordered_map_ok() { | ||
std::unordered_map<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
|
||
// Obtain long-lived references to keys and values. | ||
const auto& keyRef = map.begin()->first; | ||
const auto& valueRef = map.begin()->second; | ||
|
||
// Possible rehash, but std::unordered_map guarantees reference stability. | ||
map[4] = 16; | ||
const auto keyCopy = keyRef; | ||
} | ||
|
||
void folly_fastmap_bad_FN() { | ||
folly::F14FastMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
|
||
// Obtain long-lived references to keys and values. | ||
const auto& keyRef = map.begin()->first; | ||
const auto& valueRef = map.begin()->second; | ||
|
||
// Possible rehash, references invalidated. | ||
map.emplace(4, 16); | ||
const auto keyCopy = keyRef; | ||
} | ||
|
||
void folly_fastmap_short_lived_ok() { | ||
folly::F14FastMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
|
||
{ | ||
// Use short-lived references in a limited scope. | ||
const auto& keyRef = map.begin()->first; | ||
const auto& valueRef = map.begin()->second; | ||
|
||
const auto keyCopy = keyRef; | ||
const auto valueCopy = valueRef; | ||
|
||
// No need to access keyRef and valueRef outside this block. | ||
// Short-lived references are still valid here. | ||
} | ||
|
||
// Modify the map (no potential issues with short-lived references). | ||
map[4] = 16; | ||
|
||
// Access elements using iterators (no long-lived references). | ||
for (const auto& pair : map) { | ||
const auto keyCopy = pair.first; | ||
const auto valueCopy = pair.second; | ||
} | ||
} | ||
|
||
void long_lived_but_unused_ref_ok() { | ||
folly::F14FastMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
|
||
const auto& value = map.at(1); | ||
|
||
map.reserve(100); | ||
|
||
// value should be marked as invalidated here, but no error reported. | ||
} | ||
|
||
// We know there is no growth, so iterators/references wouldn't be invalidated. | ||
void no_growth_ok() { | ||
folly::F14FastMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
|
||
const auto& keyRef = map.at(1); | ||
|
||
// We know that 1 is already a key in the map, so there won't be a rehash. | ||
map[1] = 1; | ||
|
||
const auto valueCopy = keyRef; | ||
} | ||
|
||
void folly_valuemap_bad_FN() { | ||
folly::F14ValueMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
const auto& valueRef = map.at(1); | ||
map.clear(); | ||
const auto valueCopy = valueRef; | ||
} | ||
|
||
void folly_vectormap_bad_FN() { | ||
folly::F14VectorMap<int, int> map = {{1, 1}, {2, 4}, {3, 9}}; | ||
const auto& valueRef = map.at(1); | ||
map.clear(); | ||
const auto valueCopy = valueRef; | ||
} |