upgrade to Filament 1.21.0
This commit is contained in:
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_BINARYTREEARRAY_H
|
||||
#define TNT_UTILS_BINARYTREEARRAY_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class BinaryTreeArray {
|
||||
|
||||
// Simple fixed capacity stack
|
||||
template<typename TYPE, size_t CAPACITY,
|
||||
typename = typename std::enable_if<std::is_pod<TYPE>::value>::type>
|
||||
class stack {
|
||||
TYPE mElements[CAPACITY];
|
||||
size_t mSize = 0;
|
||||
public:
|
||||
bool empty() const noexcept { return mSize == 0; }
|
||||
void push(TYPE const& v) noexcept {
|
||||
assert(mSize < CAPACITY);
|
||||
mElements[mSize++] = v;
|
||||
}
|
||||
void pop() noexcept {
|
||||
assert(mSize > 0);
|
||||
--mSize;
|
||||
}
|
||||
const TYPE& back() const noexcept {
|
||||
return mElements[mSize - 1];
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static size_t count(size_t height) noexcept { return (1u << height) - 1; }
|
||||
static size_t left(size_t i, size_t height) noexcept { return i + 1; }
|
||||
static size_t right(size_t i, size_t height) noexcept { return i + (1u << (height - 1)); }
|
||||
|
||||
// this builds the depth-first binary tree array top down (post-order)
|
||||
template<typename Leaf, typename Node>
|
||||
static void traverse(size_t height, Leaf leaf, Node node) noexcept {
|
||||
|
||||
struct TNode {
|
||||
uint32_t index;
|
||||
uint32_t col;
|
||||
uint32_t height;
|
||||
uint32_t next;
|
||||
|
||||
bool isLeaf() const noexcept { return height == 1; }
|
||||
size_t left() const noexcept { return BinaryTreeArray::left(index, height); }
|
||||
size_t right() const noexcept { return BinaryTreeArray::right(index, height); }
|
||||
};
|
||||
|
||||
stack<TNode, 16> stack;
|
||||
stack.push(TNode{ 0, 0, (uint32_t)height, (uint32_t)count(height) });
|
||||
|
||||
uint32_t prevLeft = 0;
|
||||
uint32_t prevRight = 0;
|
||||
uint32_t prevIndex = 0;
|
||||
while (!stack.empty()) {
|
||||
TNode const* const UTILS_RESTRICT curr = &stack.back();
|
||||
const bool isLeaf = curr->isLeaf();
|
||||
const uint32_t index = curr->index;
|
||||
const uint32_t l = (uint32_t)curr->left();
|
||||
const uint32_t r = (uint32_t)curr->right();
|
||||
|
||||
if (prevLeft == index || prevRight == index) {
|
||||
if (!isLeaf) {
|
||||
// the 'next' node of our left node's right descendants is our right child
|
||||
stack.push({ l, 2 * curr->col, curr->height - 1, r });
|
||||
}
|
||||
} else if (l == prevIndex) {
|
||||
if (!isLeaf) {
|
||||
// the 'next' node of our right child is our own 'next' sibling
|
||||
stack.push({ r, 2 * curr->col + 1, curr->height - 1, curr->next });
|
||||
}
|
||||
} else {
|
||||
if (!isLeaf) {
|
||||
node(index, l, r, curr->next);
|
||||
} else {
|
||||
leaf(index, curr->col, curr->next);
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
prevLeft = l;
|
||||
prevRight = r;
|
||||
prevIndex = index;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif //TNT_UTILS_BINARYTREEARRAY_H
|
||||
@@ -86,7 +86,9 @@ public:
|
||||
constexpr StaticString(StringLiteral<N> const& other) noexcept // NOLINT(google-explicit-constructor)
|
||||
: mString(other),
|
||||
mLength(size_type(N - 1)),
|
||||
mHash(computeHash(other)) {
|
||||
mHash(computeHash(other, N - 1)) {
|
||||
// we rely on inlining for computeHash. It would be nice to do this with constexpr
|
||||
// instead, but unfortunately 'other' is not constexpr once a parameter.
|
||||
}
|
||||
|
||||
// assignment from a string literal
|
||||
@@ -94,7 +96,9 @@ public:
|
||||
StaticString& operator=(StringLiteral<N> const& other) noexcept {
|
||||
mString = other;
|
||||
mLength = size_type(N - 1);
|
||||
mHash = computeHash(other);
|
||||
// we rely on inlining for computeHash. It would be nice to do this with constexpr
|
||||
// instead, but unfortunately 'other' is not constexpr once a parameter.
|
||||
mHash = computeHash(other, N - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -103,11 +107,7 @@ public:
|
||||
StaticString r;
|
||||
r.mString = literal;
|
||||
r.mLength = size_type(length);
|
||||
size_type hash = 5381;
|
||||
while (int c = *literal++) {
|
||||
hash = (hash * 33u) ^ size_type(c);
|
||||
}
|
||||
r.mHash = hash;
|
||||
r.mHash = computeHash(literal, length);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -154,9 +154,9 @@ private:
|
||||
size_type mLength = 0;
|
||||
size_type mHash = 0;
|
||||
|
||||
template<size_t N>
|
||||
static constexpr size_type computeHash(StringLiteral<N> const& s) noexcept {
|
||||
static constexpr size_type computeHash(const char* s, const size_t N) noexcept {
|
||||
size_type hash = 5381;
|
||||
UTILS_NOUNROLL
|
||||
for (size_t i = 0; i < N - 1; i++) {
|
||||
hash = (hash * 33u) ^ size_type(s[i]);
|
||||
}
|
||||
@@ -206,12 +206,17 @@ public:
|
||||
// inside the string (i.e. it can contain nulls or non-ASCII encodings).
|
||||
CString(const char* cstr, size_t length);
|
||||
|
||||
// Allocates memory for a string of size length plus space for the null terminating character.
|
||||
// Also initializes the memory to 0. This constructor can be used to hold arbitrary data
|
||||
// inside the string.
|
||||
explicit CString(size_t length);
|
||||
|
||||
// Allocates memory and copies traditional C string content. Unlike the above constructor, this
|
||||
// does not alllow embedded nulls. This is explicit because this operation is costly.
|
||||
explicit CString(const char* cstr);
|
||||
|
||||
template<size_t N>
|
||||
explicit CString(StringLiteral<N> const& other) noexcept // NOLINT(google-explicit-constructor)
|
||||
CString(StringLiteral<N> const& other) noexcept // NOLINT(google-explicit-constructor)
|
||||
: CString(other, N - 1) {
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
/** Demangles a C++ type name */
|
||||
static utils::CString demangleTypeName(const char* mangled);
|
||||
|
||||
template <typename T>
|
||||
template<typename T>
|
||||
static utils::CString typeName() {
|
||||
#if UTILS_HAS_RTTI
|
||||
return demangleTypeName(typeid(T).name());
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_CONDITION_H
|
||||
#define TNT_UTILS_CONDITION_H
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <utils/linux/Condition.h>
|
||||
#else
|
||||
#include <utils/generic/Condition.h>
|
||||
#endif
|
||||
|
||||
#endif // TNT_UTILS_CONDITION_H
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_COUNTDOWNLATCH_H
|
||||
#define TNT_UTILS_COUNTDOWNLATCH_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// note: we use our version of mutex/condition to keep this public header STL free
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* A count down latch is used to block one or several threads until the latch is signaled
|
||||
* a certain number of times.
|
||||
*
|
||||
* Threads entering the latch are blocked until the latch is signaled enough times.
|
||||
*
|
||||
* @see CyclicBarrier
|
||||
*/
|
||||
class CountDownLatch {
|
||||
public:
|
||||
/**
|
||||
* Creates a count down latch with a specified count. The minimum useful value is 1.
|
||||
* @param count the latch counter initial value
|
||||
*/
|
||||
explicit CountDownLatch(size_t count) noexcept;
|
||||
~CountDownLatch() = default;
|
||||
|
||||
/**
|
||||
* Blocks until latch() is called \p count times.
|
||||
* @see CountDownLatch(size_t count)
|
||||
*/
|
||||
void await() noexcept;
|
||||
|
||||
/**
|
||||
* Releases threads blocked in await() when called \p count times. Calling latch() more than
|
||||
* \p count times has no effect.
|
||||
* @see reset()
|
||||
*/
|
||||
void latch() noexcept;
|
||||
|
||||
/**
|
||||
* Resets the count-down latch to the given value.
|
||||
*
|
||||
* @param new_count New latch count. A value of zero will immediately unblock all waiting
|
||||
* threads.
|
||||
*
|
||||
* @warning Use with caution. It's only safe to reset the latch count when you're sure
|
||||
* that no threads are waiting in await(). This can be guaranteed in various ways, for
|
||||
* instance, if you have a single thread calling await(), you could call reset() from that
|
||||
* thread, or you could use a CyclicBarrier to make sure all threads using the CountDownLatch
|
||||
* are at a known place (i.e.: not in await()) when reset() is called.
|
||||
*/
|
||||
void reset(size_t new_count) noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of times latch() has been called since construction or reset.
|
||||
* @see reset(), CountDownLatch(size_t count)
|
||||
*/
|
||||
size_t getCount() const noexcept;
|
||||
|
||||
CountDownLatch() = delete;
|
||||
CountDownLatch(const CountDownLatch&) = delete;
|
||||
CountDownLatch& operator=(const CountDownLatch&) = delete;
|
||||
|
||||
private:
|
||||
uint32_t m_initial_count;
|
||||
uint32_t m_remaining_count;
|
||||
mutable Mutex m_lock;
|
||||
mutable Condition m_cv;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_COUNTDOWNLATCH_H
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_CYCLIC_BARRIER_H
|
||||
#define TNT_UTILS_CYCLIC_BARRIER_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// note: we use our version of mutex/condition to keep this public header STL free
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* A cyclic barrier is used to synchronize several threads to a particular execution point.
|
||||
*
|
||||
* Threads entering the barrier are halted until all threads reach the barrier.
|
||||
*
|
||||
* @see CountDownLatch
|
||||
*/
|
||||
class CyclicBarrier {
|
||||
public:
|
||||
/**
|
||||
* Creates a cyclic barrier with a specified number of threads to synchronize. The minimum
|
||||
* useful value is 2. A value of 0 is invalid and is silently changed to 1.
|
||||
* @param num_threads Number of threads to synchronize.
|
||||
*/
|
||||
explicit CyclicBarrier(size_t num_threads) noexcept;
|
||||
|
||||
/**
|
||||
* @return The number of thread that are synchronized.
|
||||
*/
|
||||
size_t getThreadCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return Number of threads currently waiting on the barrier.
|
||||
*/
|
||||
size_t getWaitingThreadCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Blocks until getThreadCount()-1 other threads reach await().
|
||||
*/
|
||||
void await() noexcept;
|
||||
|
||||
/**
|
||||
* Resets the cyclic barrier to its original state and releases all waiting threads.
|
||||
*/
|
||||
void reset() noexcept;
|
||||
|
||||
CyclicBarrier() = delete;
|
||||
CyclicBarrier(const CyclicBarrier&) = delete;
|
||||
CyclicBarrier& operator=(const CyclicBarrier&) = delete;
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
TRAP, RELEASE
|
||||
};
|
||||
|
||||
const size_t m_num_threads;
|
||||
mutable Mutex m_lock;
|
||||
mutable Condition m_cv;
|
||||
|
||||
State m_state = State::TRAP;
|
||||
size_t m_trapped_threads = 0;
|
||||
size_t m_released_threads = 0;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_CYCLIC_BARRIER_H
|
||||
@@ -20,12 +20,11 @@
|
||||
#include <utils/compressed_pair.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <vector> // TODO: is this necessary?
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -397,7 +396,8 @@ private:
|
||||
SizeTypeWrapper() noexcept = default;
|
||||
SizeTypeWrapper(SizeTypeWrapper const& rhs) noexcept = default;
|
||||
explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { }
|
||||
SizeTypeWrapper operator=(TYPE rhs) noexcept { value = rhs; return *this; }
|
||||
SizeTypeWrapper& operator=(TYPE rhs) noexcept { value = rhs; return *this; }
|
||||
SizeTypeWrapper& operator=(SizeTypeWrapper& rhs) noexcept = delete;
|
||||
operator TYPE() const noexcept { return value; }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_HASH_H
|
||||
#define TNT_UTILS_HASH_H
|
||||
|
||||
#include <functional> // for std::hash
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
namespace hash {
|
||||
|
||||
inline uint32_t murmur3(const uint32_t* key, size_t wordCount, uint32_t seed) noexcept {
|
||||
uint32_t h = seed;
|
||||
size_t i = wordCount;
|
||||
do {
|
||||
uint32_t k = *key++;
|
||||
k *= 0xcc9e2d51u;
|
||||
k = (k << 15u) | (k >> 17u);
|
||||
k *= 0x1b873593u;
|
||||
h ^= k;
|
||||
h = (h << 13u) | (h >> 19u);
|
||||
h = (h * 5u) + 0xe6546b64u;
|
||||
} while (--i);
|
||||
h ^= wordCount;
|
||||
h ^= h >> 16u;
|
||||
h *= 0x85ebca6bu;
|
||||
h ^= h >> 13u;
|
||||
h *= 0xc2b2ae35u;
|
||||
h ^= h >> 16u;
|
||||
return h;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct MurmurHashFn {
|
||||
uint32_t operator()(const T& key) const noexcept {
|
||||
static_assert(0 == (sizeof(key) & 3u), "Hashing requires a size that is a multiple of 4.");
|
||||
return murmur3((const uint32_t*) &key, sizeof(key) / 4, 0);
|
||||
}
|
||||
};
|
||||
|
||||
// combines two hashes together
|
||||
template<class T>
|
||||
inline void combine(size_t& seed, const T& v) noexcept {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9u + (seed << 6u) + (seed >> 2u);
|
||||
}
|
||||
|
||||
// combines two hashes together, faster but less good
|
||||
template<class T>
|
||||
inline void combine_fast(size_t& seed, const T& v) noexcept {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) << 1u;
|
||||
}
|
||||
|
||||
} // namespace hash
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_HASH_H
|
||||
155
ios/include/utils/Invocable.h
Normal file
155
ios/include/utils/Invocable.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_INVOKABLE_H
|
||||
#define TNT_UTILS_INVOKABLE_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* Invocable is a move-only general purpose function wrapper. Instances can
|
||||
* store and invoke lambda expressions and other function objects.
|
||||
*
|
||||
* It is similar to std::function, with the following differences:
|
||||
* - Invocable is move only.
|
||||
* - Invocable can capture move only types.
|
||||
* - No conversion between 'compatible' functions.
|
||||
* - No small buffer optimization
|
||||
*/
|
||||
|
||||
// Helper for enabling methods if Fn matches the function signature
|
||||
// requirements of the Invocable type.
|
||||
#if __cplusplus >= 201703L
|
||||
// only available on C++17 and up
|
||||
template<typename Fn, typename R, typename... Args>
|
||||
using EnableIfFnMatchesInvocable =
|
||||
std::enable_if_t<std::is_invocable_v<Fn, Args...> &&
|
||||
std::is_same_v<R, std::invoke_result_t<Fn, Args...>>, int>;
|
||||
#else
|
||||
template<typename Fn, typename R, typename... Args>
|
||||
using EnableIfFnMatchesInvocable = std::enable_if_t<true, int>;
|
||||
#endif
|
||||
|
||||
template<typename Signature>
|
||||
class Invocable;
|
||||
|
||||
template<typename R, typename... Args>
|
||||
class Invocable<R(Args...)> {
|
||||
public:
|
||||
// Creates an Invocable that does not contain a functor.
|
||||
// Will evaluate to false.
|
||||
Invocable() = default;
|
||||
|
||||
~Invocable() noexcept;
|
||||
|
||||
// Creates an Invocable from the functor passed in.
|
||||
template<typename Fn, EnableIfFnMatchesInvocable<Fn, R, Args...> = 0>
|
||||
Invocable(Fn&& fn) noexcept;
|
||||
|
||||
Invocable(const Invocable&) = delete;
|
||||
Invocable(Invocable&& rhs) noexcept;
|
||||
|
||||
Invocable& operator=(const Invocable&) = delete;
|
||||
Invocable& operator=(Invocable&& rhs) noexcept;
|
||||
|
||||
// Invokes the invocable with the args passed in.
|
||||
// If the Invocable is empty, this will assert.
|
||||
template<typename... OperatorArgs>
|
||||
R operator()(OperatorArgs&& ... args);
|
||||
template<typename... OperatorArgs>
|
||||
R operator()(OperatorArgs&& ... args) const;
|
||||
|
||||
// Evaluates to true if Invocable contains a functor, false otherwise.
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
private:
|
||||
void* mInvocable = nullptr;
|
||||
void (*mDeleter)(void*) = nullptr;
|
||||
R (* mInvoker)(void*, Args...) = nullptr;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
template<typename Fn, EnableIfFnMatchesInvocable<Fn, R, Args...>>
|
||||
Invocable<R(Args...)>::Invocable(Fn&& fn) noexcept
|
||||
: mInvocable(new Fn(std::forward<std::decay_t<Fn>>(fn))),
|
||||
mDeleter(+[](void* erased_invocable) {
|
||||
auto typed_invocable = static_cast<Fn*>(erased_invocable);
|
||||
delete typed_invocable;
|
||||
}),
|
||||
mInvoker(+[](void* erased_invocable, Args... args) -> R {
|
||||
auto typed_invocable = static_cast<Fn*>(erased_invocable);
|
||||
return (*typed_invocable)(std::forward<Args>(args)...);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
Invocable<R(Args...)>::~Invocable() noexcept {
|
||||
if (mDeleter) {
|
||||
mDeleter(mInvocable);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
Invocable<R(Args...)>::Invocable(Invocable&& rhs) noexcept
|
||||
: mInvocable(rhs.mInvocable),
|
||||
mDeleter(rhs.mDeleter),
|
||||
mInvoker(rhs.mInvoker) {
|
||||
rhs.mInvocable = nullptr;
|
||||
rhs.mDeleter = nullptr;
|
||||
rhs.mInvoker = nullptr;
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
Invocable<R(Args...)>& Invocable<R(Args...)>::operator=(Invocable&& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
mInvocable = rhs.mInvocable;
|
||||
mDeleter = rhs.mDeleter;
|
||||
mInvoker = rhs.mInvoker;
|
||||
rhs.mInvocable = nullptr;
|
||||
rhs.mDeleter = nullptr;
|
||||
rhs.mInvoker = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
template<typename... OperatorArgs>
|
||||
R Invocable<R(Args...)>::operator()(OperatorArgs&& ... args) {
|
||||
assert(mInvoker && mInvocable);
|
||||
return mInvoker(mInvocable, std::forward<OperatorArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
template<typename... OperatorArgs>
|
||||
R Invocable<R(Args...)>::operator()(OperatorArgs&& ... args) const {
|
||||
assert(mInvoker && mInvocable);
|
||||
return mInvoker(mInvocable, std::forward<OperatorArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
Invocable<R(Args...)>::operator bool() const noexcept {
|
||||
return mInvoker != nullptr && mInvocable != nullptr;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_INVOKABLE_H
|
||||
@@ -1,545 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_JOBSYSTEM_H
|
||||
#define TNT_UTILS_JOBSYSTEM_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/architecture.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/memalign.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/WorkStealingDequeue.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class JobSystem {
|
||||
static constexpr size_t MAX_JOB_COUNT = 16384;
|
||||
static_assert(MAX_JOB_COUNT <= 0x7FFE, "MAX_JOB_COUNT must be <= 0x7FFE");
|
||||
using WorkQueue = WorkStealingDequeue<uint16_t, MAX_JOB_COUNT>;
|
||||
|
||||
public:
|
||||
class Job;
|
||||
|
||||
using JobFunc = void(*)(void*, JobSystem&, Job*);
|
||||
|
||||
class alignas(CACHELINE_SIZE) Job {
|
||||
public:
|
||||
Job() noexcept {} /* = default; */ /* clang bug */ // NOLINT(modernize-use-equals-default,cppcoreguidelines-pro-type-member-init)
|
||||
Job(const Job&) = delete;
|
||||
Job(Job&&) = delete;
|
||||
|
||||
private:
|
||||
friend class JobSystem;
|
||||
|
||||
// Size is chosen so that we can store at least std::function<>
|
||||
// the alignas() qualifier ensures we're multiple of a cache-line.
|
||||
static constexpr size_t JOB_STORAGE_SIZE_BYTES =
|
||||
sizeof(std::function<void()>) > 48 ? sizeof(std::function<void()>) : 48;
|
||||
static constexpr size_t JOB_STORAGE_SIZE_WORDS =
|
||||
(JOB_STORAGE_SIZE_BYTES + sizeof(void*) - 1) / sizeof(void*);
|
||||
|
||||
// keep it first, so it's correctly aligned with all architectures
|
||||
// this is were we store the job's data, typically a std::function<>
|
||||
// v7 | v8
|
||||
void* storage[JOB_STORAGE_SIZE_WORDS]; // 48 | 48
|
||||
JobFunc function; // 4 | 8
|
||||
uint16_t parent; // 2 | 2
|
||||
std::atomic<uint16_t> runningJobCount = { 1 }; // 2 | 2
|
||||
mutable std::atomic<uint16_t> refCount = { 1 }; // 2 | 2
|
||||
// 6 | 2 (padding)
|
||||
// 64 | 64
|
||||
};
|
||||
|
||||
explicit JobSystem(size_t threadCount = 0, size_t adoptableThreadsCount = 1) noexcept;
|
||||
|
||||
~JobSystem();
|
||||
|
||||
// Make the current thread part of the thread pool.
|
||||
void adopt();
|
||||
|
||||
// Remove this adopted thread from the parent. This is intended to be used for
|
||||
// shutting down a JobSystem. In particular, this doesn't allow the parent to
|
||||
// adopt more thread.
|
||||
void emancipate();
|
||||
|
||||
|
||||
// If a parent is not specified when creating a job, that job will automatically take the
|
||||
// root job as a parent.
|
||||
// The root job is reset when waited on.
|
||||
Job* setRootJob(Job* job) noexcept { return mRootJob = job; }
|
||||
|
||||
// use setRootJob() instead
|
||||
UTILS_DEPRECATED
|
||||
Job* setMasterJob(Job* job) noexcept { return setRootJob(job); }
|
||||
|
||||
|
||||
Job* create(Job* parent, JobFunc func) noexcept;
|
||||
|
||||
// NOTE: All methods below must be called from the same thread and that thread must be
|
||||
// owned by JobSystem's thread pool.
|
||||
|
||||
/*
|
||||
* Job creation examples:
|
||||
* ----------------------
|
||||
*
|
||||
* struct Functor {
|
||||
* uintptr_t storage[6];
|
||||
* void operator()(JobSystem&, Jobsystem::Job*);
|
||||
* } functor;
|
||||
*
|
||||
* struct Foo {
|
||||
* uintptr_t storage[6];
|
||||
* void method(JobSystem&, Jobsystem::Job*);
|
||||
* } foo;
|
||||
*
|
||||
* Functor and Foo size muse be <= uintptr_t[6]
|
||||
*
|
||||
* createJob()
|
||||
* createJob(parent)
|
||||
* createJob<Foo, &Foo::method>(parent, &foo)
|
||||
* createJob<Foo, &Foo::method>(parent, foo)
|
||||
* createJob<Foo, &Foo::method>(parent, std::ref(foo))
|
||||
* createJob(parent, functor)
|
||||
* createJob(parent, std::ref(functor))
|
||||
* createJob(parent, [ up-to 6 uintptr_t ](JobSystem*, Jobsystem::Job*){ })
|
||||
*
|
||||
* Utility functions:
|
||||
* ------------------
|
||||
* These are less efficient, but handle any size objects using the heap if needed.
|
||||
* (internally uses std::function<>), and don't require the callee to take
|
||||
* a (JobSystem&, Jobsystem::Job*) as parameter.
|
||||
*
|
||||
* struct BigFoo {
|
||||
* uintptr_t large[16];
|
||||
* void operator()();
|
||||
* void method(int answerToEverything);
|
||||
* static void exec(BigFoo&) { }
|
||||
* } bigFoo;
|
||||
*
|
||||
* jobs::createJob(js, parent, [ any-capture ](int answerToEverything){}, 42);
|
||||
* jobs::createJob(js, parent, &BigFoo::method, &bigFoo, 42);
|
||||
* jobs::createJob(js, parent, &BigFoo::exec, std::ref(bigFoo));
|
||||
* jobs::createJob(js, parent, bigFoo);
|
||||
* jobs::createJob(js, parent, std::ref(bigFoo));
|
||||
* etc...
|
||||
*
|
||||
* struct SmallFunctor {
|
||||
* uintptr_t storage[3];
|
||||
* void operator()(T* data, size_t count);
|
||||
* } smallFunctor;
|
||||
*
|
||||
* jobs::parallel_for(js, data, count, [ up-to 3 uintptr_t ](T* data, size_t count) { });
|
||||
* jobs::parallel_for(js, data, count, smallFunctor);
|
||||
* jobs::parallel_for(js, data, count, std::ref(smallFunctor));
|
||||
*
|
||||
*/
|
||||
|
||||
// creates an empty (no-op) job with an optional parent
|
||||
Job* createJob(Job* parent = nullptr) noexcept {
|
||||
return create(parent, nullptr);
|
||||
}
|
||||
|
||||
// creates a job from a KNOWN method pointer w/ object passed by pointer
|
||||
// the caller must ensure the object will outlive the Job
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T* data) noexcept {
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||
(*static_cast<T**>(user)->*method)(js, job);
|
||||
});
|
||||
if (job) {
|
||||
job->storage[0] = data;
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a KNOWN method pointer w/ object passed by value
|
||||
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||
Job* createJob(Job* parent, T data) noexcept {
|
||||
static_assert(sizeof(data) <= sizeof(Job::storage), "user data too large");
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||
T* that = static_cast<T*>(user);
|
||||
(that->*method)(js, job);
|
||||
that->~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::move(data));
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
// creates a job from a functor passed by value
|
||||
template<typename T>
|
||||
Job* createJob(Job* parent, T functor) noexcept {
|
||||
static_assert(sizeof(functor) <= sizeof(Job::storage), "functor too large");
|
||||
Job* job = create(parent, [](void* user, JobSystem& js, Job* job){
|
||||
T& that = *static_cast<T*>(user);
|
||||
that(js, job);
|
||||
that.~T();
|
||||
});
|
||||
if (job) {
|
||||
new(job->storage) T(std::move(functor));
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Jobs are normally finished automatically, this can be used to cancel a job before it is run.
|
||||
*
|
||||
* Never use this once a flavor of run() has been called.
|
||||
*/
|
||||
void cancel(Job*& job) noexcept;
|
||||
|
||||
/*
|
||||
* Adds a reference to a Job.
|
||||
*
|
||||
* This allows the caller to waitAndRelease() on this job from multiple threads.
|
||||
* Use runAndWait() if waiting from multiple threads is not needed.
|
||||
*
|
||||
* This job MUST BE waited on with waitAndRelease(), or released with release().
|
||||
*/
|
||||
Job* retain(Job* job) noexcept;
|
||||
|
||||
/*
|
||||
* Releases a reference from a Job obtained with runAndRetain() or a call to retain().
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void release(Job*& job) noexcept;
|
||||
void release(Job*&& job) noexcept {
|
||||
Job* p = job;
|
||||
release(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue. It's reference will drop automatically.
|
||||
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void run(Job*& job) noexcept;
|
||||
void run(Job*&& job) noexcept { // allows run(createJob(...));
|
||||
Job* p = job;
|
||||
run(p);
|
||||
}
|
||||
|
||||
void signal() noexcept;
|
||||
|
||||
/*
|
||||
* Add job to this thread's execution queue and and keep a reference to it.
|
||||
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* This job MUST BE waited on with wait(), or released with release().
|
||||
*/
|
||||
Job* runAndRetain(Job* job) noexcept;
|
||||
|
||||
/*
|
||||
* Wait on a job and destroys it.
|
||||
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||
*
|
||||
* The job must first be obtained from runAndRetain() or retain().
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void waitAndRelease(Job*& job) noexcept;
|
||||
|
||||
/*
|
||||
* Runs and wait for a job. This is equivalent to calling
|
||||
* runAndRetain(job);
|
||||
* wait(job);
|
||||
*
|
||||
* The job can't be used after this call.
|
||||
*/
|
||||
void runAndWait(Job*& job) noexcept;
|
||||
void runAndWait(Job*&& job) noexcept { // allows runAndWait(createJob(...));
|
||||
Job* p = job;
|
||||
runAndWait(p);
|
||||
}
|
||||
|
||||
// for debugging
|
||||
friend utils::io::ostream& operator << (utils::io::ostream& out, JobSystem const& js);
|
||||
|
||||
|
||||
// utility functions...
|
||||
|
||||
// set the name of the current thread (on OSes that support it)
|
||||
static void setThreadName(const char* threadName) noexcept;
|
||||
|
||||
enum class Priority {
|
||||
NORMAL,
|
||||
DISPLAY,
|
||||
URGENT_DISPLAY
|
||||
};
|
||||
|
||||
static void setThreadPriority(Priority priority) noexcept;
|
||||
static void setThreadAffinityById(size_t id) noexcept;
|
||||
|
||||
size_t getParallelSplitCount() const noexcept {
|
||||
return mParallelSplitCount;
|
||||
}
|
||||
|
||||
private:
|
||||
// this is just to avoid using std::default_random_engine, since we're in a public header.
|
||||
class default_random_engine {
|
||||
static constexpr uint32_t m = 0x7fffffffu;
|
||||
uint32_t mState; // must be 0 < seed < 0x7fffffff
|
||||
public:
|
||||
inline constexpr explicit default_random_engine(uint32_t seed = 1u) noexcept
|
||||
: mState(((seed % m) == 0u) ? 1u : seed % m) {
|
||||
}
|
||||
inline uint32_t operator()() noexcept {
|
||||
return mState = uint32_t((uint64_t(mState) * 48271u) % m);
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(CACHELINE_SIZE) ThreadState { // this causes 40-bytes padding
|
||||
// make sure storage is cache-line aligned
|
||||
WorkQueue workQueue;
|
||||
|
||||
// these are not accessed by the worker threads
|
||||
alignas(CACHELINE_SIZE) // this causes 56-bytes padding
|
||||
JobSystem* js;
|
||||
std::thread thread;
|
||||
default_random_engine rndGen;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
static_assert(sizeof(ThreadState) % CACHELINE_SIZE == 0,
|
||||
"ThreadState doesn't align to a cache line");
|
||||
|
||||
ThreadState& getState() noexcept;
|
||||
|
||||
void incRef(Job const* job) noexcept;
|
||||
void decRef(Job const* job) noexcept;
|
||||
|
||||
Job* allocateJob() noexcept;
|
||||
JobSystem::ThreadState* getStateToStealFrom(JobSystem::ThreadState& state) noexcept;
|
||||
bool hasJobCompleted(Job const* job) noexcept;
|
||||
|
||||
void requestExit() noexcept;
|
||||
bool exitRequested() const noexcept;
|
||||
bool hasActiveJobs() const noexcept;
|
||||
|
||||
void loop(ThreadState* state) noexcept;
|
||||
bool execute(JobSystem::ThreadState& state) noexcept;
|
||||
Job* steal(JobSystem::ThreadState& state) noexcept;
|
||||
void finish(Job* job) noexcept;
|
||||
|
||||
void put(WorkQueue& workQueue, Job* job) noexcept {
|
||||
assert(job);
|
||||
size_t index = job - mJobStorageBase;
|
||||
assert(index >= 0 && index < MAX_JOB_COUNT);
|
||||
workQueue.push(uint16_t(index + 1));
|
||||
}
|
||||
|
||||
Job* pop(WorkQueue& workQueue) noexcept {
|
||||
size_t index = workQueue.pop();
|
||||
assert(index <= MAX_JOB_COUNT);
|
||||
return !index ? nullptr : &mJobStorageBase[index - 1];
|
||||
}
|
||||
|
||||
Job* steal(WorkQueue& workQueue) noexcept {
|
||||
size_t index = workQueue.steal();
|
||||
assert(index <= MAX_JOB_COUNT);
|
||||
return !index ? nullptr : &mJobStorageBase[index - 1];
|
||||
}
|
||||
|
||||
void wait(std::unique_lock<Mutex>& lock, Job* job = nullptr) noexcept;
|
||||
void wakeAll() noexcept;
|
||||
void wakeOne() noexcept;
|
||||
|
||||
// these have thread contention, keep them together
|
||||
utils::Mutex mWaiterLock;
|
||||
utils::Condition mWaiterCondition;
|
||||
|
||||
std::atomic<uint32_t> mActiveJobs = { 0 };
|
||||
utils::Arena<utils::ThreadSafeObjectPoolAllocator<Job>, LockingPolicy::NoLock> mJobPool;
|
||||
|
||||
template <typename T>
|
||||
using aligned_vector = std::vector<T, utils::STLAlignedAllocator<T>>;
|
||||
|
||||
// these are essentially const, make sure they're on a different cache-lines than the
|
||||
// read-write atomics.
|
||||
// We can't use "alignas(CACHELINE_SIZE)" because the standard allocator can't make this
|
||||
// guarantee.
|
||||
char padding[CACHELINE_SIZE];
|
||||
|
||||
alignas(16) // at least we align to half (or quarter) cache-line
|
||||
aligned_vector<ThreadState> mThreadStates; // actual data is stored offline
|
||||
std::atomic<bool> mExitRequested = { false }; // this one is almost never written
|
||||
std::atomic<uint16_t> mAdoptedThreads = { 0 }; // this one is almost never written
|
||||
Job* const mJobStorageBase; // Base for conversion to indices
|
||||
uint16_t mThreadCount = 0; // total # of threads in the pool
|
||||
uint8_t mParallelSplitCount = 0; // # of split allowable in parallel_for
|
||||
Job* mRootJob = nullptr;
|
||||
|
||||
utils::SpinLock mThreadMapLock; // this should have very little contention
|
||||
tsl::robin_map<std::thread::id, ThreadState *> mThreadMap;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Utility functions built on top of JobSystem
|
||||
|
||||
namespace jobs {
|
||||
|
||||
// These are convenience C++11 style job creation methods that support lambdas
|
||||
//
|
||||
// IMPORTANT: these are less efficient to call and may perform heap allocation
|
||||
// depending on the capture and parameters
|
||||
//
|
||||
template<typename CALLABLE, typename ... ARGS>
|
||||
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||
CALLABLE&& func, ARGS&&... args) noexcept {
|
||||
struct Data {
|
||||
std::function<void()> f;
|
||||
// Renaming the method below could cause an Arrested Development.
|
||||
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||
} user{ std::bind(std::forward<CALLABLE>(func),
|
||||
std::forward<ARGS>(args)...) };
|
||||
return js.createJob<Data, &Data::gob>(parent, std::move(user));
|
||||
}
|
||||
|
||||
template<typename CALLABLE, typename T, typename ... ARGS,
|
||||
typename = typename std::enable_if<
|
||||
std::is_member_function_pointer<typename std::remove_reference<CALLABLE>::type>::value
|
||||
>::type
|
||||
>
|
||||
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||
CALLABLE&& func, T&& o, ARGS&&... args) noexcept {
|
||||
struct Data {
|
||||
std::function<void()> f;
|
||||
// Renaming the method below could cause an Arrested Development.
|
||||
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||
} user{ std::bind(std::forward<CALLABLE>(func), std::forward<T>(o),
|
||||
std::forward<ARGS>(args)...) };
|
||||
return js.createJob<Data, &Data::gob>(parent, std::move(user));
|
||||
}
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename S, typename F>
|
||||
struct ParallelForJobData {
|
||||
using SplitterType = S;
|
||||
using Functor = F;
|
||||
using JobData = ParallelForJobData;
|
||||
using size_type = uint32_t;
|
||||
|
||||
ParallelForJobData(size_type start, size_type count, uint8_t splits,
|
||||
Functor functor,
|
||||
const SplitterType& splitter) noexcept
|
||||
: start(start), count(count),
|
||||
functor(std::move(functor)),
|
||||
splits(splits),
|
||||
splitter(splitter) {
|
||||
}
|
||||
|
||||
void parallelWithJobs(JobSystem& js, JobSystem::Job* parent) noexcept {
|
||||
assert(parent);
|
||||
|
||||
// this branch is often miss-predicted (it both sides happen 50% of the calls)
|
||||
right_side:
|
||||
if (splitter.split(splits, count)) {
|
||||
const size_type lc = count / 2;
|
||||
JobData ld(start, lc, splits + uint8_t(1), functor, splitter);
|
||||
JobSystem::Job* l = js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(ld));
|
||||
if (UTILS_UNLIKELY(l == nullptr)) {
|
||||
// couldn't create a job, just pretend we're done splitting
|
||||
goto execute;
|
||||
}
|
||||
|
||||
// start the left side before attempting the right side, so we parallelize in case
|
||||
// of job creation failure -- rare, but still.
|
||||
js.run(l);
|
||||
|
||||
// don't spawn a job for the right side, just reuse us -- spawning jobs is more
|
||||
// costly than we'd like.
|
||||
start += lc;
|
||||
count -= lc;
|
||||
++splits;
|
||||
goto right_side;
|
||||
|
||||
} else {
|
||||
execute:
|
||||
// we're done splitting, do the real work here!
|
||||
functor(start, count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_type start; // 4
|
||||
size_type count; // 4
|
||||
Functor functor; // ?
|
||||
uint8_t splits; // 1
|
||||
SplitterType splitter; // 1
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
// parallel jobs with start/count indices
|
||||
template<typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
uint32_t start, uint32_t count, F functor, const S& splitter) noexcept {
|
||||
using JobData = details::ParallelForJobData<S, F>;
|
||||
JobData jobData(start, count, 0, std::move(functor), splitter);
|
||||
return js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(jobData));
|
||||
}
|
||||
|
||||
// parallel jobs with pointer/count
|
||||
template<typename T, typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
T* data, uint32_t count, F functor, const S& splitter) noexcept {
|
||||
auto user = [data, f = std::move(functor)](uint32_t s, uint32_t c) {
|
||||
f(data + s, c);
|
||||
};
|
||||
using JobData = details::ParallelForJobData<S, decltype(user)>;
|
||||
JobData jobData(0, count, 0, std::move(user), splitter);
|
||||
return js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(jobData));
|
||||
}
|
||||
|
||||
// parallel jobs on a Slice<>
|
||||
template<typename T, typename S, typename F>
|
||||
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||
utils::Slice<T> slice, F functor, const S& splitter) noexcept {
|
||||
return parallel_for(js, parent, slice.data(), slice.size(), functor, splitter);
|
||||
}
|
||||
|
||||
|
||||
template <size_t COUNT, size_t MAX_SPLITS = 12>
|
||||
class CountSplitter {
|
||||
public:
|
||||
bool split(size_t splits, size_t count) const noexcept {
|
||||
return (splits < MAX_SPLITS && count >= COUNT * 2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jobs
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_JOBSYSTEM_H
|
||||
@@ -424,8 +424,10 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define PANIC_FILE(F) (F)
|
||||
# define PANIC_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
# define PANIC_FILE(F) ""
|
||||
# define PANIC_FUNCTION __func__
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -433,7 +435,7 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
* @param format printf-style string describing the error in more details
|
||||
*/
|
||||
#define PANIC_PRECONDITION(format, ...) \
|
||||
::utils::PreconditionPanic::panic(__PRETTY_FUNCTION__, \
|
||||
::utils::PreconditionPanic::panic(PANIC_FUNCTION, \
|
||||
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
@@ -441,7 +443,7 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
* @param format printf-style string describing the error in more details
|
||||
*/
|
||||
#define PANIC_POSTCONDITION(format, ...) \
|
||||
::utils::PostconditionPanic::panic(__PRETTY_FUNCTION__, \
|
||||
::utils::PostconditionPanic::panic(PANIC_FUNCTION, \
|
||||
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
@@ -449,7 +451,7 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
* @param format printf-style string describing the error in more details
|
||||
*/
|
||||
#define PANIC_ARITHMETIC(format, ...) \
|
||||
::utils::ArithmeticPanic::panic(__PRETTY_FUNCTION__, \
|
||||
::utils::ArithmeticPanic::panic(PANIC_FUNCTION, \
|
||||
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
@@ -457,7 +459,7 @@ class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
* @param format printf-style string describing the error in more details
|
||||
*/
|
||||
#define PANIC_LOG(format, ...) \
|
||||
::utils::details::panicLog(__PRETTY_FUNCTION__, \
|
||||
::utils::details::panicLog(PANIC_FUNCTION, \
|
||||
PANIC_FILE(__FILE__), __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
|
||||
66
ios/include/utils/PrivateImplementation-impl.h
Normal file
66
ios/include/utils/PrivateImplementation-impl.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_PRIVATEIMPLEMENTATION_IMPL_H
|
||||
#define UTILS_PRIVATEIMPLEMENTATION_IMPL_H
|
||||
|
||||
/*
|
||||
* This looks like a header file, but really it acts as a .cpp, because it's used to
|
||||
* explicitly instantiate the methods of PrivateImplementation<>
|
||||
*/
|
||||
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
PrivateImplementation<T>::PrivateImplementation() noexcept
|
||||
: mImpl(new T) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename ... ARGS>
|
||||
PrivateImplementation<T>::PrivateImplementation(ARGS&& ... args) noexcept
|
||||
: mImpl(new T(std::forward<ARGS>(args)...)) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PrivateImplementation<T>::~PrivateImplementation() noexcept {
|
||||
delete mImpl;
|
||||
}
|
||||
|
||||
#ifndef UTILS_PRIVATE_IMPLEMENTATION_NON_COPYABLE
|
||||
|
||||
template<typename T>
|
||||
PrivateImplementation<T>::PrivateImplementation(PrivateImplementation const& rhs) noexcept
|
||||
: mImpl(new T(*rhs.mImpl)) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PrivateImplementation<T>& PrivateImplementation<T>::operator=(PrivateImplementation<T> const& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
*mImpl = *rhs.mImpl;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // UTILS_PRIVATEIMPLEMENTATION_IMPL_H
|
||||
61
ios/include/utils/PrivateImplementation.h
Normal file
61
ios/include/utils/PrivateImplementation.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_PRIVATEIMPLEMENTATION_H
|
||||
#define UTILS_PRIVATEIMPLEMENTATION_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* \privatesection
|
||||
* PrivateImplementation is used to hide the implementation details of a class and ensure a higher
|
||||
* level of backward binary compatibility.
|
||||
* The actual implementation is in src/PrivateImplementation-impl.h"
|
||||
*/
|
||||
template<typename T>
|
||||
class PrivateImplementation {
|
||||
public:
|
||||
// none of these methods must be implemented inline because it's important that their
|
||||
// implementation be hidden from the public headers.
|
||||
template<typename ... ARGS>
|
||||
explicit PrivateImplementation(ARGS&& ...) noexcept;
|
||||
PrivateImplementation() noexcept;
|
||||
~PrivateImplementation() noexcept;
|
||||
PrivateImplementation(PrivateImplementation const& rhs) noexcept;
|
||||
PrivateImplementation& operator = (PrivateImplementation const& rhs) noexcept;
|
||||
|
||||
// move ctor and copy operator can be implemented inline and don't need to be exported
|
||||
PrivateImplementation(PrivateImplementation&& rhs) noexcept : mImpl(rhs.mImpl) { rhs.mImpl = nullptr; }
|
||||
PrivateImplementation& operator = (PrivateImplementation&& rhs) noexcept {
|
||||
auto temp = mImpl;
|
||||
mImpl = rhs.mImpl;
|
||||
rhs.mImpl = temp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
T* mImpl = nullptr;
|
||||
inline T* operator->() noexcept { return mImpl; }
|
||||
inline T const* operator->() const noexcept { return mImpl; }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // UTILS_PRIVATEIMPLEMENTATION_H
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_PROFILER_H
|
||||
#define TNT_UTILS_PROFILER_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <chrono> // note: This is safe (only used inline)
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <unistd.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <linux/perf_event.h>
|
||||
#endif
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class Profiler {
|
||||
public:
|
||||
enum {
|
||||
INSTRUCTIONS = 0, // must be zero
|
||||
CPU_CYCLES = 1,
|
||||
DCACHE_REFS = 2,
|
||||
DCACHE_MISSES = 3,
|
||||
BRANCHES = 4,
|
||||
BRANCH_MISSES = 5,
|
||||
ICACHE_REFS = 6,
|
||||
ICACHE_MISSES = 7,
|
||||
|
||||
// Must be last one
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
EV_CPU_CYCLES = 1u << CPU_CYCLES,
|
||||
EV_L1D_REFS = 1u << DCACHE_REFS,
|
||||
EV_L1D_MISSES = 1u << DCACHE_MISSES,
|
||||
EV_BPU_REFS = 1u << BRANCHES,
|
||||
EV_BPU_MISSES = 1u << BRANCH_MISSES,
|
||||
EV_L1I_REFS = 1u << ICACHE_REFS,
|
||||
EV_L1I_MISSES = 1u << ICACHE_MISSES,
|
||||
// helpers
|
||||
EV_L1D_RATES = EV_L1D_REFS | EV_L1D_MISSES,
|
||||
EV_L1I_RATES = EV_L1I_REFS | EV_L1I_MISSES,
|
||||
EV_BPU_RATES = EV_BPU_REFS | EV_BPU_MISSES,
|
||||
};
|
||||
|
||||
Profiler() noexcept; // must call resetEvents()
|
||||
explicit Profiler(uint32_t eventMask) noexcept;
|
||||
~Profiler() noexcept;
|
||||
|
||||
Profiler(const Profiler& rhs) = delete;
|
||||
Profiler(Profiler&& rhs) = delete;
|
||||
Profiler& operator=(const Profiler& rhs) = delete;
|
||||
Profiler& operator=(Profiler&& rhs) = delete;
|
||||
|
||||
// selects which events are enabled.
|
||||
uint32_t resetEvents(uint32_t eventMask) noexcept;
|
||||
|
||||
uint32_t getEnabledEvents() const noexcept { return mEnabledEvents; }
|
||||
|
||||
// could return false if performance counters are not supported/enabled
|
||||
bool isValid() const { return mCountersFd[0] >= 0; }
|
||||
|
||||
class Counters {
|
||||
friend class Profiler;
|
||||
uint64_t nr;
|
||||
uint64_t time_enabled;
|
||||
uint64_t time_running;
|
||||
struct {
|
||||
uint64_t value;
|
||||
uint64_t id;
|
||||
} counters[Profiler::EVENT_COUNT];
|
||||
|
||||
friend Counters operator-(Counters lhs, const Counters& rhs) noexcept {
|
||||
lhs.nr -= rhs.nr;
|
||||
lhs.time_enabled -= rhs.time_enabled;
|
||||
lhs.time_running -= rhs.time_running;
|
||||
for (size_t i = 0; i < EVENT_COUNT; ++i) {
|
||||
lhs.counters[i].value -= rhs.counters[i].value;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
public:
|
||||
uint64_t getInstructions() const { return counters[INSTRUCTIONS].value; }
|
||||
uint64_t getCpuCycles() const { return counters[CPU_CYCLES].value; }
|
||||
uint64_t getL1DReferences() const { return counters[DCACHE_REFS].value; }
|
||||
uint64_t getL1DMisses() const { return counters[DCACHE_MISSES].value; }
|
||||
uint64_t getL1IReferences() const { return counters[ICACHE_REFS].value; }
|
||||
uint64_t getL1IMisses() const { return counters[ICACHE_MISSES].value; }
|
||||
uint64_t getBranchInstructions() const { return counters[BRANCHES].value; }
|
||||
uint64_t getBranchMisses() const { return counters[BRANCH_MISSES].value; }
|
||||
|
||||
std::chrono::duration<uint64_t, std::nano> getWallTime() const {
|
||||
return std::chrono::duration<uint64_t, std::nano>(time_enabled);
|
||||
}
|
||||
|
||||
std::chrono::duration<uint64_t, std::nano> getRunningTime() const {
|
||||
return std::chrono::duration<uint64_t, std::nano>(time_running);
|
||||
}
|
||||
|
||||
double getIPC() const noexcept {
|
||||
uint64_t cpuCycles = getCpuCycles();
|
||||
uint64_t instructions = getInstructions();
|
||||
return double(instructions) / double(cpuCycles);
|
||||
}
|
||||
|
||||
double getCPI() const noexcept {
|
||||
uint64_t cpuCycles = getCpuCycles();
|
||||
uint64_t instructions = getInstructions();
|
||||
return double(cpuCycles) / double(instructions);
|
||||
}
|
||||
|
||||
double getL1DMissRate() const noexcept {
|
||||
uint64_t cacheReferences = getL1DReferences();
|
||||
uint64_t cacheMisses = getL1DMisses();
|
||||
return double(cacheMisses) / double(cacheReferences);
|
||||
}
|
||||
|
||||
double getL1DHitRate() const noexcept {
|
||||
return 1.0 - getL1DMissRate();
|
||||
}
|
||||
|
||||
double getL1IMissRate() const noexcept {
|
||||
uint64_t cacheReferences = getL1IReferences();
|
||||
uint64_t cacheMisses = getL1IMisses();
|
||||
return double(cacheMisses) / double(cacheReferences);
|
||||
}
|
||||
|
||||
double getL1IHitRate() const noexcept {
|
||||
return 1.0 - getL1IMissRate();
|
||||
}
|
||||
|
||||
double getBranchMissRate() const noexcept {
|
||||
uint64_t branchReferences = getBranchInstructions();
|
||||
uint64_t branchMisses = getBranchMisses();
|
||||
return double(branchMisses) / double(branchReferences);
|
||||
}
|
||||
|
||||
double getBranchHitRate() const noexcept {
|
||||
return 1.0 - getBranchMissRate();
|
||||
}
|
||||
|
||||
double getMPKI(uint64_t misses) const noexcept {
|
||||
return (misses * 1000.0) / getInstructions();
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
void reset() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
void start() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
void stop() noexcept {
|
||||
int fd = mCountersFd[0];
|
||||
ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
|
||||
}
|
||||
|
||||
Counters readCounters() noexcept;
|
||||
|
||||
#else // !__linux__
|
||||
|
||||
void reset() noexcept { }
|
||||
void start() noexcept { }
|
||||
void stop() noexcept { }
|
||||
Counters readCounters() noexcept { return {}; }
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
bool hasBranchRates() const noexcept {
|
||||
return (mCountersFd[BRANCHES] >= 0) && (mCountersFd[BRANCH_MISSES] >= 0);
|
||||
}
|
||||
|
||||
bool hasICacheRates() const noexcept {
|
||||
return (mCountersFd[ICACHE_REFS] >= 0) && (mCountersFd[ICACHE_MISSES] >= 0);
|
||||
}
|
||||
|
||||
private:
|
||||
UTILS_UNUSED uint8_t mIds[EVENT_COUNT] = {};
|
||||
int mCountersFd[EVENT_COUNT];
|
||||
uint32_t mEnabledEvents = 0;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_PROFILER_H
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_RANGE_H
|
||||
#define TNT_UTILS_RANGE_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
struct Range {
|
||||
using value_type = T;
|
||||
T first = 0;
|
||||
T last = 0;
|
||||
|
||||
size_t size() const noexcept { return last - first; }
|
||||
bool empty() const noexcept { return !size(); }
|
||||
|
||||
class const_iterator {
|
||||
friend struct Range;
|
||||
T value = {};
|
||||
|
||||
public:
|
||||
const_iterator() noexcept = default;
|
||||
explicit const_iterator(T value) noexcept : value(value) {}
|
||||
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
|
||||
const value_type operator*() const { return value; }
|
||||
const value_type operator[](size_t n) const { return value + n; }
|
||||
|
||||
const_iterator& operator++() { ++value; return *this; }
|
||||
const_iterator& operator--() { --value; return *this; }
|
||||
|
||||
const const_iterator operator++(int) { const_iterator t(value); value++; return t; }
|
||||
const const_iterator operator--(int) { const_iterator t(value); value--; return t; }
|
||||
|
||||
const_iterator operator+(size_t rhs) const { return { value + rhs }; }
|
||||
const_iterator operator+(size_t rhs) { return { value + rhs }; }
|
||||
const_iterator operator-(size_t rhs) const { return { value - rhs }; }
|
||||
|
||||
difference_type operator-(const_iterator const& rhs) const { return value - rhs.value; }
|
||||
|
||||
bool operator==(const_iterator const& rhs) const { return (value == rhs.value); }
|
||||
bool operator!=(const_iterator const& rhs) const { return (value != rhs.value); }
|
||||
bool operator>=(const_iterator const& rhs) const { return (value >= rhs.value); }
|
||||
bool operator> (const_iterator const& rhs) const { return (value > rhs.value); }
|
||||
bool operator<=(const_iterator const& rhs) const { return (value <= rhs.value); }
|
||||
bool operator< (const_iterator const& rhs) const { return (value < rhs.value); }
|
||||
};
|
||||
|
||||
const_iterator begin() noexcept { return const_iterator{ first }; }
|
||||
const_iterator end() noexcept { return const_iterator{ last }; }
|
||||
const_iterator begin() const noexcept { return const_iterator{ first }; }
|
||||
const_iterator end() const noexcept { return const_iterator{ last }; }
|
||||
|
||||
const_iterator front() const noexcept { return const_iterator{ first }; }
|
||||
const_iterator back() const noexcept { return const_iterator{ last - 1 }; }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_RANGE_H
|
||||
@@ -237,7 +237,7 @@ protected:
|
||||
size_t count = getComponentCount();
|
||||
size_t aliveInARow = 0;
|
||||
default_random_engine& rng = mRng;
|
||||
#pragma nounroll
|
||||
UTILS_NOUNROLL
|
||||
while (count && aliveInARow < ratio) {
|
||||
// note: using the modulo favorizes lower number
|
||||
size_t i = rng() % count;
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#ifndef TNT_UTILS_SLICE_H
|
||||
#define TNT_UTILS_SLICE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_SYSTRACE_H
|
||||
#define TNT_UTILS_SYSTRACE_H
|
||||
|
||||
|
||||
#define SYSTRACE_TAG_NEVER (0)
|
||||
#define SYSTRACE_TAG_ALWAYS (1<<0)
|
||||
#define SYSTRACE_TAG_FILAMENT (1<<1) // don't change, used in makefiles
|
||||
#define SYSTRACE_TAG_JOBSYSTEM (1<<2)
|
||||
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
/*
|
||||
* The SYSTRACE_ macros use SYSTRACE_TAG as a the TAG, which should be defined
|
||||
* before this file is included. If not, the SYSTRACE_TAG_ALWAYS tag will be used.
|
||||
*/
|
||||
|
||||
#ifndef SYSTRACE_TAG
|
||||
#define SYSTRACE_TAG (SYSTRACE_TAG_ALWAYS)
|
||||
#endif
|
||||
|
||||
// enable tracing
|
||||
#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG)
|
||||
|
||||
// disable tracing
|
||||
#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG)
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Systrace context in the current scope. needed for calling all other systrace
|
||||
* commands below.
|
||||
*/
|
||||
#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___tracer(SYSTRACE_TAG)
|
||||
|
||||
|
||||
// SYSTRACE_NAME traces the beginning and end of the current scope. To trace
|
||||
// the correct start and end times this macro should be declared first in the
|
||||
// scope body.
|
||||
// It also automatically creates a Systrace context
|
||||
#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name)
|
||||
|
||||
// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name.
|
||||
#define SYSTRACE_CALL() SYSTRACE_NAME(__FUNCTION__)
|
||||
|
||||
#define SYSTRACE_NAME_BEGIN(name) \
|
||||
___tracer.traceBegin(SYSTRACE_TAG, name)
|
||||
|
||||
#define SYSTRACE_NAME_END() \
|
||||
___tracer.traceEnd(SYSTRACE_TAG)
|
||||
|
||||
|
||||
/**
|
||||
* Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
|
||||
* contexts, asynchronous events do not need to be nested. The name describes
|
||||
* the event, and the cookie provides a unique identifier for distinguishing
|
||||
* simultaneous events. The name and cookie used to begin an event must be
|
||||
* used to end it.
|
||||
*/
|
||||
#define SYSTRACE_ASYNC_BEGIN(name, cookie) \
|
||||
___tracer.asyncBegin(SYSTRACE_TAG, name, cookie)
|
||||
|
||||
/**
|
||||
* Trace the end of an asynchronous event.
|
||||
* This should have a corresponding SYSTRACE_ASYNC_BEGIN.
|
||||
*/
|
||||
#define SYSTRACE_ASYNC_END(name, cookie) \
|
||||
___tracer.asyncEnd(SYSTRACE_TAG, name, cookie)
|
||||
|
||||
/**
|
||||
* Traces an integer counter value. name is used to identify the counter.
|
||||
* This can be used to track how a value changes over time.
|
||||
*/
|
||||
#define SYSTRACE_VALUE32(name, val) \
|
||||
___tracer.value(SYSTRACE_TAG, name, int32_t(val))
|
||||
|
||||
#define SYSTRACE_VALUE64(name, val) \
|
||||
___tracer.value(SYSTRACE_TAG, name, int64_t(val))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// No user serviceable code below...
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace utils {
|
||||
namespace details {
|
||||
|
||||
class Systrace {
|
||||
public:
|
||||
|
||||
enum tags {
|
||||
NEVER = SYSTRACE_TAG_NEVER,
|
||||
ALWAYS = SYSTRACE_TAG_ALWAYS,
|
||||
FILAMENT = SYSTRACE_TAG_FILAMENT,
|
||||
JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM
|
||||
// we could define more TAGS here, as we need them.
|
||||
};
|
||||
|
||||
Systrace(uint32_t tag) noexcept {
|
||||
if (tag) init(tag);
|
||||
}
|
||||
|
||||
static void enable(uint32_t tags) noexcept;
|
||||
static void disable(uint32_t tags) noexcept;
|
||||
|
||||
|
||||
inline void traceBegin(uint32_t tag, const char* name) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
beginSection(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
inline void traceEnd(uint32_t tag) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
endSection(this);
|
||||
}
|
||||
}
|
||||
|
||||
inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
beginAsyncSection(this, name, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
endAsyncSection(this, name, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
inline void value(uint32_t tag, const char* name, int32_t value) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
setCounter(this, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void value(uint32_t tag, const char* name, int64_t value) noexcept {
|
||||
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||
setCounter(this, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ScopedTrace;
|
||||
|
||||
// whether tracing is supported at all by the platform
|
||||
|
||||
using ATrace_isEnabled_t = bool (*)(void);
|
||||
using ATrace_beginSection_t = void (*)(const char* sectionName);
|
||||
using ATrace_endSection_t = void (*)(void);
|
||||
using ATrace_beginAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
|
||||
using ATrace_endAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
|
||||
using ATrace_setCounter_t = void (*)(const char* counterName, int64_t counterValue);
|
||||
|
||||
struct GlobalState {
|
||||
bool isTracingAvailable;
|
||||
std::atomic<uint32_t> isTracingEnabled;
|
||||
int markerFd;
|
||||
|
||||
ATrace_isEnabled_t ATrace_isEnabled;
|
||||
ATrace_beginSection_t ATrace_beginSection;
|
||||
ATrace_endSection_t ATrace_endSection;
|
||||
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
|
||||
ATrace_endAsyncSection_t ATrace_endAsyncSection;
|
||||
ATrace_setCounter_t ATrace_setCounter;
|
||||
|
||||
void (*beginSection)(Systrace* that, const char* name);
|
||||
void (*endSection)(Systrace* that);
|
||||
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||
void (*setCounter)(Systrace* that, const char* name, int64_t value);
|
||||
};
|
||||
|
||||
static GlobalState sGlobalState;
|
||||
|
||||
|
||||
// per-instance versions for better performance
|
||||
ATrace_isEnabled_t ATrace_isEnabled;
|
||||
ATrace_beginSection_t ATrace_beginSection;
|
||||
ATrace_endSection_t ATrace_endSection;
|
||||
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
|
||||
ATrace_endAsyncSection_t ATrace_endAsyncSection;
|
||||
ATrace_setCounter_t ATrace_setCounter;
|
||||
|
||||
void (*beginSection)(Systrace* that, const char* name);
|
||||
void (*endSection)(Systrace* that);
|
||||
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||
void (*setCounter)(Systrace* that, const char* name, int64_t value);
|
||||
|
||||
void init(uint32_t tag) noexcept;
|
||||
|
||||
// cached values for faster access, no need to be initialized
|
||||
bool mIsTracingEnabled;
|
||||
int mMarkerFd = -1;
|
||||
pid_t mPid;
|
||||
|
||||
static void setup() noexcept;
|
||||
static void init_once() noexcept;
|
||||
static bool isTracingEnabled(uint32_t tag) noexcept;
|
||||
|
||||
static void begin_body(int fd, int pid, const char* name) noexcept;
|
||||
static void end_body(int fd, int pid) noexcept;
|
||||
static void async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
|
||||
static void async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
|
||||
static void int64_body(int fd, int pid, const char* name, int64_t value) noexcept;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
class ScopedTrace {
|
||||
public:
|
||||
// we don't inline this because it's relatively heavy due to a global check
|
||||
ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mTag(tag) {
|
||||
mTrace.traceBegin(tag, name);
|
||||
}
|
||||
|
||||
inline ~ScopedTrace() noexcept {
|
||||
mTrace.traceEnd(mTag);
|
||||
}
|
||||
|
||||
inline void value(uint32_t tag, const char* name, int32_t v) noexcept {
|
||||
mTrace.value(tag, name, v);
|
||||
}
|
||||
|
||||
inline void value(uint32_t tag, const char* name, int64_t v) noexcept {
|
||||
mTrace.value(tag, name, v);
|
||||
}
|
||||
|
||||
private:
|
||||
Systrace mTrace;
|
||||
const uint32_t mTag;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace utils
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#else // !ANDROID
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#define SYSTRACE_ENABLE()
|
||||
#define SYSTRACE_DISABLE()
|
||||
#define SYSTRACE_CONTEXT()
|
||||
#define SYSTRACE_NAME(name)
|
||||
#define SYSTRACE_NAME_BEGIN(name)
|
||||
#define SYSTRACE_NAME_END()
|
||||
#define SYSTRACE_CALL()
|
||||
#define SYSTRACE_ASYNC_BEGIN(name, cookie)
|
||||
#define SYSTRACE_ASYNC_END(name, cookie)
|
||||
#define SYSTRACE_VALUE32(name, val)
|
||||
#define SYSTRACE_VALUE64(name, val)
|
||||
|
||||
#endif // ANDROID
|
||||
|
||||
#endif // TNT_UTILS_SYSTRACE_H
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_THERMALMANAGER_H
|
||||
#define TNT_UTILS_THERMALMANAGER_H
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <utils/android/ThermalManager.h>
|
||||
#else
|
||||
#include <utils/generic/ThermalManager.h>
|
||||
#endif
|
||||
|
||||
#endif // TNT_UTILS_THERMALMANAGER_H
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||
#define TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A templated, lockless, fixed-size work-stealing dequeue
|
||||
*
|
||||
*
|
||||
* top bottom
|
||||
* v v
|
||||
* |----|----|----|----|----|----|
|
||||
* steal() push(), pop()
|
||||
* any thread main thread
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
class WorkStealingDequeue {
|
||||
static_assert(!(COUNT & (COUNT - 1)), "COUNT must be a power of two");
|
||||
static constexpr size_t MASK = COUNT - 1;
|
||||
|
||||
// mTop and mBottom must be signed integers. We use 64-bits atomics so we don't have
|
||||
// to worry about wrapping around.
|
||||
using index_t = int64_t;
|
||||
|
||||
std::atomic<index_t> mTop = { 0 }; // written/read in pop()/steal()
|
||||
std::atomic<index_t> mBottom = { 0 }; // written only in pop(), read in push(), steal()
|
||||
|
||||
TYPE mItems[COUNT];
|
||||
|
||||
// NOTE: it's not safe to return a reference because getItemAt() can be called
|
||||
// concurrently and the caller could std::move() the item unsafely.
|
||||
TYPE getItemAt(index_t index) noexcept { return mItems[index & MASK]; }
|
||||
|
||||
void setItemAt(index_t index, TYPE item) noexcept { mItems[index & MASK] = item; }
|
||||
|
||||
public:
|
||||
using value_type = TYPE;
|
||||
|
||||
inline void push(TYPE item) noexcept;
|
||||
inline TYPE pop() noexcept;
|
||||
inline TYPE steal() noexcept;
|
||||
|
||||
size_t getSize() const noexcept { return COUNT; }
|
||||
|
||||
// for debugging only...
|
||||
size_t getCount() const noexcept {
|
||||
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||
index_t top = mTop.load(std::memory_order_relaxed);
|
||||
return bottom - top;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds an item at the BOTTOM of the queue.
|
||||
*
|
||||
* Must be called from the main thread.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
void WorkStealingDequeue<TYPE, COUNT>::push(TYPE item) noexcept {
|
||||
// std::memory_order_relaxed is sufficient because this load doesn't acquire anything from
|
||||
// another thread. mBottom is only written in pop() which cannot be concurrent with push()
|
||||
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||
setItemAt(bottom, item);
|
||||
|
||||
// std::memory_order_release is used because we release the item we just pushed to other
|
||||
// threads which are calling steal().
|
||||
mBottom.store(bottom + 1, std::memory_order_release);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes an item from the BOTTOM of the queue.
|
||||
*
|
||||
* Must be called from the main thread.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
TYPE WorkStealingDequeue<TYPE, COUNT>::pop() noexcept {
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||
// Note however that this is not a typical acquire/release operation:
|
||||
// - not acquire because mBottom is only written in push() which is not concurrent
|
||||
// - not release because we're not publishing anything to steal() here
|
||||
//
|
||||
// QUESTION: does this prevent mTop load below to be reordered before the "store" part of
|
||||
// fetch_sub()? Hopefully it does. If not we'd need a full memory barrier.
|
||||
//
|
||||
index_t bottom = mBottom.fetch_sub(1, std::memory_order_seq_cst) - 1;
|
||||
|
||||
// bottom could be -1 if we tried to pop() from an empty queue. This will be corrected below.
|
||||
assert( bottom >= -1 );
|
||||
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||
// Note however that this is not a typical acquire operation
|
||||
// (i.e. other thread's writes of mTop don't publish data)
|
||||
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||
|
||||
if (top < bottom) {
|
||||
// Queue isn't empty and it's not the last item, just return it, this is the common case.
|
||||
return getItemAt(bottom);
|
||||
}
|
||||
|
||||
TYPE item{};
|
||||
if (top == bottom) {
|
||||
// we just took the last item
|
||||
item = getItemAt(bottom);
|
||||
|
||||
// Because we know we took the last item, we could be racing with steal() -- the last
|
||||
// item being both at the top and bottom of the queue.
|
||||
// We resolve this potential race by also stealing that item from ourselves.
|
||||
if (mTop.compare_exchange_strong(top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed)) {
|
||||
// success: we stole our last item from ourself, meaning that a concurrent steal()
|
||||
// would have failed.
|
||||
// mTop now equals top + 1, we adjust top to make the queue empty.
|
||||
top++;
|
||||
} else {
|
||||
// failure: mTop was not equal to top, which means the item was stolen under our feet.
|
||||
// top now equals to mTop. Simply discard the item we just popped.
|
||||
// The queue is now empty.
|
||||
item = TYPE();
|
||||
}
|
||||
} else {
|
||||
// We could be here if the item was stolen just before we read mTop, we'll adjust
|
||||
// mBottom below.
|
||||
assert(top - bottom == 1);
|
||||
}
|
||||
|
||||
// std::memory_order_relaxed used because we're not publishing any data.
|
||||
// no concurrent writes to mBottom possible, it's always safe to write mBottom.
|
||||
mBottom.store(top, std::memory_order_relaxed);
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Steals an item from the TOP of another thread's queue.
|
||||
*
|
||||
* This can be called concurrently with steal(), push() or pop()
|
||||
*
|
||||
* steal() never fails, either there is an item and it atomically takes it, or there isn't and
|
||||
* it returns an empty item.
|
||||
*/
|
||||
template <typename TYPE, size_t COUNT>
|
||||
TYPE WorkStealingDequeue<TYPE, COUNT>::steal() noexcept {
|
||||
while (true) {
|
||||
/*
|
||||
* Note: A Key component of this algorithm is that mTop is read before mBottom here
|
||||
* (and observed as such in other threads)
|
||||
*/
|
||||
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||
// Note however that this is not a typical acquire operation
|
||||
// (i.e. other thread's writes of mTop don't publish data)
|
||||
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||
|
||||
// std::memory_order_acquire is needed because we're acquiring items published in push().
|
||||
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||
index_t bottom = mBottom.load(std::memory_order_seq_cst);
|
||||
|
||||
if (top >= bottom) {
|
||||
// queue is empty
|
||||
return TYPE();
|
||||
}
|
||||
|
||||
// The queue isn't empty
|
||||
TYPE item(getItemAt(top));
|
||||
if (mTop.compare_exchange_strong(top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed)) {
|
||||
// success: we stole an item, just return it.
|
||||
return item;
|
||||
}
|
||||
// failure: the item we just tried to steal was pop()'ed under our feet,
|
||||
// simply discard it; nothing to do -- it's okay to try again.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_ZIP2ITERATOR_H
|
||||
#define TNT_UTILS_ZIP2ITERATOR_H
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A random access iterator that wraps two other random access iterators.
|
||||
* This mostly exists so that one can sort an array using values from another.
|
||||
*/
|
||||
|
||||
template<typename It1, typename It2>
|
||||
class Zip2Iterator {
|
||||
std::pair<It1, It2> mIt;
|
||||
using Ref1 = typename std::iterator_traits<It1>::reference;
|
||||
using Ref2 = typename std::iterator_traits<It2>::reference;
|
||||
using Val1 = typename std::iterator_traits<It1>::value_type;
|
||||
using Val2 = typename std::iterator_traits<It2>::value_type;
|
||||
|
||||
public:
|
||||
struct Ref : public std::pair<Ref1, Ref2> {
|
||||
using std::pair<Ref1, Ref2>::pair;
|
||||
using std::pair<Ref1, Ref2>::operator=;
|
||||
private:
|
||||
friend void swap(Ref lhs, Ref rhs) {
|
||||
using std::swap;
|
||||
swap(lhs.first, rhs.first);
|
||||
swap(lhs.second, rhs.second);
|
||||
}
|
||||
};
|
||||
|
||||
using value_type = std::pair<Val1, Val2>;
|
||||
using reference = Ref;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
Zip2Iterator() = default;
|
||||
Zip2Iterator(It1 first, It2 second) : mIt({first, second}) {}
|
||||
Zip2Iterator(Zip2Iterator const& rhs) noexcept = default;
|
||||
Zip2Iterator& operator=(Zip2Iterator const& rhs) = default;
|
||||
|
||||
reference operator*() const { return { *mIt.first, *mIt.second }; }
|
||||
|
||||
reference operator[](size_t n) const { return *(*this + n); }
|
||||
|
||||
Zip2Iterator& operator++() {
|
||||
++mIt.first;
|
||||
++mIt.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator--() {
|
||||
--mIt.first;
|
||||
--mIt.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix operator needed by Microsoft C++
|
||||
const Zip2Iterator operator++(int) {
|
||||
Zip2Iterator t(*this);
|
||||
mIt.first++;
|
||||
mIt.second++;
|
||||
return t;
|
||||
}
|
||||
|
||||
const Zip2Iterator operator--(int) {
|
||||
Zip2Iterator t(*this);
|
||||
mIt.first--;
|
||||
mIt.second--;
|
||||
return t;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator+=(size_t v) {
|
||||
mIt.first += v;
|
||||
mIt.second += v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator& operator-=(size_t v) {
|
||||
mIt.first -= v;
|
||||
mIt.second -= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Zip2Iterator operator+(size_t rhs) const { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||
Zip2Iterator operator+(size_t rhs) { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||
Zip2Iterator operator-(size_t rhs) const { return { mIt.first - rhs, mIt.second - rhs }; }
|
||||
|
||||
difference_type operator-(Zip2Iterator const& rhs) const { return mIt.first - rhs.mIt.first; }
|
||||
|
||||
bool operator==(Zip2Iterator const& rhs) const { return (mIt.first == rhs.mIt.first); }
|
||||
bool operator!=(Zip2Iterator const& rhs) const { return (mIt.first != rhs.mIt.first); }
|
||||
bool operator>=(Zip2Iterator const& rhs) const { return (mIt.first >= rhs.mIt.first); }
|
||||
bool operator> (Zip2Iterator const& rhs) const { return (mIt.first > rhs.mIt.first); }
|
||||
bool operator<=(Zip2Iterator const& rhs) const { return (mIt.first <= rhs.mIt.first); }
|
||||
bool operator< (Zip2Iterator const& rhs) const { return (mIt.first < rhs.mIt.first); }
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ZIP2ITERATOR_H
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||
#define TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct AThermalManager;
|
||||
|
||||
namespace utils {
|
||||
|
||||
class ThermalManager {
|
||||
public:
|
||||
enum class ThermalStatus : int8_t {
|
||||
ERROR = -1,
|
||||
NONE,
|
||||
LIGHT,
|
||||
MODERATE,
|
||||
SEVERE,
|
||||
CRITICAL,
|
||||
EMERGENCY,
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
ThermalManager();
|
||||
~ThermalManager();
|
||||
|
||||
// Movable
|
||||
ThermalManager(ThermalManager&& rhs) noexcept;
|
||||
ThermalManager& operator=(ThermalManager&& rhs) noexcept;
|
||||
|
||||
// not copiable
|
||||
ThermalManager(ThermalManager const& rhs) = delete;
|
||||
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||
|
||||
ThermalStatus getCurrentThermalStatus() const noexcept;
|
||||
|
||||
private:
|
||||
AThermalManager* mThermalManager = nullptr;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_APILEVEL_H
|
||||
#define TNT_UTILS_APILEVEL_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* Returns this platform's API level. On Android this function will return
|
||||
* the API level as defined by the SDK API level version. If a platform does
|
||||
* not have an API level, this function returns 0.
|
||||
*/
|
||||
UTILS_PUBLIC
|
||||
int api_level();
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_APILEVEL_H
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_ARCHITECTURE_H
|
||||
#define TNT_UTILS_ARCHITECTURE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
constexpr size_t CACHELINE_SIZE = 64;
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ARCHITECTURE_H
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_ASHMEM_H
|
||||
#define TNT_UTILS_ASHMEM_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
int ashmem_create_region(const char *name, size_t size);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_ASHMEM_H
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <algorithm> // for std::fill
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(__ARM_NEON)
|
||||
@@ -314,10 +314,12 @@ private:
|
||||
|
||||
using bitset8 = bitset<uint8_t>;
|
||||
using bitset32 = bitset<uint32_t>;
|
||||
using bitset64 = bitset<uint64_t>;
|
||||
using bitset256 = bitset<uint64_t, 4>;
|
||||
|
||||
static_assert(sizeof(bitset8) == sizeof(uint8_t), "bitset8 isn't 8 bits!");
|
||||
static_assert(sizeof(bitset32) == sizeof(uint32_t), "bitset32 isn't 32 bits!");
|
||||
static_assert(sizeof(bitset64) == sizeof(uint64_t), "bitset64 isn't 64 bits!");
|
||||
|
||||
} // namespace utils
|
||||
|
||||
|
||||
@@ -167,6 +167,14 @@
|
||||
# define UTILS_HAS_FEATURE_CXX_THREAD_LOCAL 0
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// MSVC does not support loop unrolling hints
|
||||
# define UTILS_NOUNROLL
|
||||
#else
|
||||
// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax.
|
||||
# define UTILS_NOUNROLL _Pragma("nounroll")
|
||||
#endif
|
||||
|
||||
#if __has_feature(cxx_rtti) || defined(_CPPRTTI)
|
||||
# define UTILS_HAS_RTTI 1
|
||||
#else
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_GENERIC_CONDITION_H
|
||||
#define TNT_UTILS_GENERIC_CONDITION_H
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class Condition : public std::condition_variable {
|
||||
public:
|
||||
using std::condition_variable::condition_variable;
|
||||
|
||||
inline void notify_n(size_t n) noexcept {
|
||||
if (n == 1) {
|
||||
notify_one();
|
||||
} else if (n > 1) {
|
||||
notify_all();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_GENERIC_CONDITION_H
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||
#define TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class ThermalManager {
|
||||
public:
|
||||
enum class ThermalStatus : int8_t {
|
||||
ERROR = -1,
|
||||
NONE,
|
||||
LIGHT,
|
||||
MODERATE,
|
||||
SEVERE,
|
||||
CRITICAL,
|
||||
EMERGENCY,
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
ThermalManager() = default;
|
||||
|
||||
// Movable
|
||||
ThermalManager(ThermalManager&& rhs) noexcept = default;
|
||||
ThermalManager& operator=(ThermalManager&& rhs) noexcept = default;
|
||||
|
||||
// not copiable
|
||||
ThermalManager(ThermalManager const& rhs) = delete;
|
||||
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||
|
||||
ThermalStatus getCurrentThermalStatus() const noexcept {
|
||||
return ThermalStatus::NONE;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_LINUX_CONDITION_H
|
||||
#define TNT_UTILS_LINUX_CONDITION_H
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable> // for cv_status
|
||||
#include <limits>
|
||||
#include <mutex> // for unique_lock
|
||||
|
||||
#include <utils/linux/Mutex.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A very simple condition variable class that can be used as an (almost) drop-in replacement
|
||||
* for std::condition_variable (doesn't have the timed wait() though).
|
||||
* It is very low overhead as most of it is inlined.
|
||||
*/
|
||||
|
||||
class Condition {
|
||||
public:
|
||||
Condition() noexcept = default;
|
||||
Condition(const Condition&) = delete;
|
||||
Condition& operator=(const Condition&) = delete;
|
||||
|
||||
void notify_all() noexcept {
|
||||
pulse(std::numeric_limits<int>::max());
|
||||
}
|
||||
|
||||
void notify_one() noexcept {
|
||||
pulse(1);
|
||||
}
|
||||
|
||||
void notify_n(size_t n) noexcept {
|
||||
if (n > 0) pulse(n);
|
||||
}
|
||||
|
||||
void wait(std::unique_lock<Mutex>& lock) noexcept {
|
||||
wait_until(lock.mutex(), false, nullptr);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void wait(std::unique_lock<Mutex>& lock, P predicate) {
|
||||
while (!predicate()) {
|
||||
wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
|
||||
const std::chrono::time_point<std::chrono::steady_clock, D>& timeout_time) noexcept {
|
||||
// convert to nanoseconds
|
||||
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
|
||||
using sec_t = decltype(timespec::tv_sec);
|
||||
using nsec_t = decltype(timespec::tv_nsec);
|
||||
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
|
||||
return wait_until(lock.mutex(), false, &ts);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
|
||||
const std::chrono::time_point<std::chrono::system_clock, D>& timeout_time) noexcept {
|
||||
// convert to nanoseconds
|
||||
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
|
||||
using sec_t = decltype(timespec::tv_sec);
|
||||
using nsec_t = decltype(timespec::tv_nsec);
|
||||
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
|
||||
return wait_until(lock.mutex(), true, &ts);
|
||||
}
|
||||
|
||||
template<typename C, typename D, typename P>
|
||||
bool wait_until(std::unique_lock<Mutex>& lock,
|
||||
const std::chrono::time_point<C, D>& timeout_time, P predicate) noexcept {
|
||||
while (!predicate()) {
|
||||
if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
|
||||
return predicate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename R, typename Period>
|
||||
std::cv_status wait_for(std::unique_lock<Mutex>& lock,
|
||||
const std::chrono::duration<R, Period>& rel_time) noexcept {
|
||||
return wait_until(lock, std::chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
|
||||
template<typename R, typename Period, typename P>
|
||||
bool wait_for(std::unique_lock<Mutex>& lock,
|
||||
const std::chrono::duration<R, Period>& rel_time, P pred) noexcept {
|
||||
return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<uint32_t> mState = { 0 };
|
||||
|
||||
void pulse(int threadCount) noexcept;
|
||||
|
||||
std::cv_status wait_until(Mutex* lock,
|
||||
bool realtimeClock, timespec* ts) noexcept;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_LINUX_CONDITION_H
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_LINUX_MUTEX_H
|
||||
#define TNT_UTILS_LINUX_MUTEX_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* A very simple mutex class that can be used as an (almost) drop-in replacement
|
||||
* for std::mutex.
|
||||
* It is very low overhead as most of it is inlined.
|
||||
*/
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
constexpr Mutex() noexcept = default;
|
||||
Mutex(const Mutex&) = delete;
|
||||
Mutex& operator=(const Mutex&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
uint32_t old_state = UNLOCKED;
|
||||
if (UTILS_UNLIKELY(!mState.compare_exchange_strong(old_state,
|
||||
LOCKED, std::memory_order_acquire, std::memory_order_relaxed))) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
if (UTILS_UNLIKELY(mState.exchange(UNLOCKED, std::memory_order_release) == LOCKED_CONTENDED)) {
|
||||
wake();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
UNLOCKED = 0, LOCKED = 1, LOCKED_CONTENDED = 2
|
||||
};
|
||||
std::atomic<uint32_t> mState = { UNLOCKED };
|
||||
|
||||
void wait() noexcept;
|
||||
void wake() noexcept;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_LINUX_MUTEX_H
|
||||
@@ -17,18 +17,21 @@
|
||||
#ifndef TNT_UTILS_OSTREAM_H
|
||||
#define TNT_UTILS_OSTREAM_H
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/compiler.h> // ssize_t is a POSIX type.
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
namespace utils::io {
|
||||
|
||||
class UTILS_PUBLIC ostream {
|
||||
public:
|
||||
struct ostream_;
|
||||
|
||||
class UTILS_PUBLIC ostream : protected utils::PrivateImplementation<ostream_> {
|
||||
friend struct ostream_;
|
||||
|
||||
public:
|
||||
virtual ~ostream();
|
||||
|
||||
ostream& operator<<(short value) noexcept;
|
||||
@@ -63,6 +66,8 @@ public:
|
||||
ostream& hex() noexcept;
|
||||
|
||||
protected:
|
||||
ostream& print(const char* format, ...) noexcept;
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer() noexcept;
|
||||
@@ -86,11 +91,8 @@ protected:
|
||||
size_t capacity = 0; // total capacity of the buffer
|
||||
};
|
||||
|
||||
std::mutex mLock;
|
||||
Buffer mData;
|
||||
Buffer& getBuffer() noexcept { return mData; }
|
||||
|
||||
ostream& print(const char* format, ...) noexcept;
|
||||
Buffer& getBuffer() noexcept;
|
||||
Buffer const& getBuffer() const noexcept;
|
||||
|
||||
private:
|
||||
virtual ostream& flush() noexcept = 0;
|
||||
@@ -105,9 +107,7 @@ private:
|
||||
LONG_DOUBLE
|
||||
};
|
||||
|
||||
inline const char* getFormat(type t) const noexcept;
|
||||
|
||||
bool mShowHex = false;
|
||||
const char* getFormat(type t) const noexcept;
|
||||
};
|
||||
|
||||
// handles std::string
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_SSTREAM_H
|
||||
#define TNT_UTILS_SSTREAM_H
|
||||
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace utils {
|
||||
namespace io {
|
||||
|
||||
class sstream : public ostream {
|
||||
public:
|
||||
|
||||
ostream &flush() noexcept override;
|
||||
|
||||
const char* c_str() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_SSTREAM_H
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_STRING_H
|
||||
#define TNT_UTILS_STRING_H
|
||||
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
float strtof_c(const char* start, char** end);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_STRING_H
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_TRAP_H
|
||||
#define TNT_UTILS_TRAP_H
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <Windows.h>
|
||||
#include <utils/unwindows.h>
|
||||
#endif
|
||||
|
||||
namespace utils {
|
||||
|
||||
// This can be used as a programmatic breakpoint.
|
||||
inline void debug_trap() noexcept {
|
||||
#if defined(WIN32)
|
||||
DebugBreak();
|
||||
#else
|
||||
std::raise(SIGINT);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_TRAP_H
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_VECTOR_H
|
||||
#define TNT_UTILS_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* Inserts the specified item in the vector at its sorted position.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void insert_sorted(std::vector<T>& v, T item) {
|
||||
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||
v.insert(pos, std::move(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified item in the vector at its sorted position.
|
||||
* The item type must implement the < operator. If the specified
|
||||
* item is already present in the vector, this method returns without
|
||||
* inserting the item again.
|
||||
*
|
||||
* @return True if the item was inserted at is sorted position, false
|
||||
* if the item already exists in the vector.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool insert_sorted_unique(std::vector<T>& v, T item) {
|
||||
if (UTILS_LIKELY(v.size() == 0 || v.back() < item)) {
|
||||
v.push_back(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||
if (UTILS_LIKELY(pos == v.end() || item < *pos)) {
|
||||
v.insert(pos, std::move(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end utils namespace
|
||||
|
||||
#endif // TNT_UTILS_VECTOR_H
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_WIN32_STDTYPES_H
|
||||
#define TNT_UTILS_WIN32_STDTYPES_H
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
// Copied from linux libc sys/stat.h:
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define PATH_MAX (MAX_PATH)
|
||||
|
||||
// For getcwd
|
||||
#include <direct.h>
|
||||
#define getcwd _getcwd
|
||||
|
||||
#endif
|
||||
#endif // TNT_UTILS_WIN32_STDTYPES_H
|
||||
Reference in New Issue
Block a user