Files
klubhaus-doorbell/libraries/FastLED/src/fl/thread_local.h
2026-02-12 00:45:31 -08:00

212 lines
5.9 KiB
C++

#pragma once
#include "fl/thread.h"
#if FASTLED_USE_THREAD_LOCAL
#include "fl/hash_map.h"
#include <pthread.h> // ok include
#include <memory> // ok include
#endif
#if FASTLED_USE_THREAD_LOCAL
// Real thread-local implementation using POSIX threading
#else
// Fake thread-local implementation (globally shared data)
#if FASTLED_MULTITHREADED
#warning \
"ThreadLocal is not implemented, using the fake version with globally shared data"
#endif
#endif
namespace fl {
#if FASTLED_USE_THREAD_LOCAL
template <typename T> class ThreadLocalReal;
template <typename T> using ThreadLocal = ThreadLocalReal<T>;
#else
template <typename T> class ThreadLocalFake;
template <typename T> using ThreadLocal = ThreadLocalFake<T>;
#endif
///////////////////// REAL IMPLEMENTATION //////////////////////////////////////
#if FASTLED_USE_THREAD_LOCAL
template <typename T> class ThreadLocalReal {
public:
// Default: each thread's object is default-constructed
ThreadLocalReal() : mDefaultValue(), mHasDefault(false) {
initializeKey();
}
// With default: each thread's object is copy-constructed from defaultVal
template <typename U>
explicit ThreadLocalReal(const U &defaultVal) : mDefaultValue(defaultVal), mHasDefault(true) {
initializeKey();
}
// Destructor - cleanup pthread key
~ThreadLocalReal() {
if (mKeyInitialized) {
pthread_key_delete(mKey);
}
}
// Copy constructor
ThreadLocalReal(const ThreadLocalReal& other) : mDefaultValue(other.mDefaultValue), mHasDefault(other.mHasDefault) {
initializeKey();
}
// Assignment operator
ThreadLocalReal& operator=(const ThreadLocalReal& other) {
if (this != &other) {
mDefaultValue = other.mDefaultValue;
mHasDefault = other.mHasDefault;
// Key remains the same for this instance
}
return *this;
}
// Access the thread-local instance
T &access() {
ThreadStorage* storage = getStorage();
if (!storage) {
storage = createStorage();
}
if (mHasDefault && !storage->initialized) {
copyValue(storage->value, mDefaultValue);
storage->initialized = true;
}
return storage->value;
}
const T &access() const {
ThreadStorage* storage = getStorage();
if (!storage) {
storage = createStorage();
}
if (mHasDefault && !storage->initialized) {
copyValue(storage->value, mDefaultValue);
storage->initialized = true;
}
return storage->value;
}
// Set the value for this thread
void set(const T& value) {
copyValue(access(), value);
}
// Convenience operators
operator T &() { return access(); }
operator const T &() const { return access(); }
ThreadLocalReal &operator=(const T &v) {
set(v);
return *this;
}
private:
// Helper function to copy values, specialized for arrays
template<typename U>
static void copyValue(U& dest, const U& src) {
dest = src; // Default behavior for non-array types
}
// Specialization for array types
template<typename U, size_t N>
static void copyValue(U (&dest)[N], const U (&src)[N]) {
for (size_t i = 0; i < N; ++i) {
copyValue(dest[i], src[i]); // Recursively handle nested arrays
}
}
// Storage for thread-local data
struct ThreadStorage {
T value{};
bool initialized = false;
};
// POSIX thread key for this instance
pthread_key_t mKey;
bool mKeyInitialized = false;
T mDefaultValue{};
bool mHasDefault = false;
// Initialize the pthread key
void initializeKey() {
int result = pthread_key_create(&mKey, cleanupThreadStorage);
if (result == 0) {
mKeyInitialized = true;
} else {
// Handle error - for now just mark as not initialized
mKeyInitialized = false;
}
}
// Get thread-specific storage
ThreadStorage* getStorage() const {
if (!mKeyInitialized) {
return nullptr;
}
return static_cast<ThreadStorage*>(pthread_getspecific(mKey));
}
// Create thread-specific storage
ThreadStorage* createStorage() const {
if (!mKeyInitialized) {
return nullptr;
}
ThreadStorage* storage = new ThreadStorage();
int result = pthread_setspecific(mKey, storage);
if (result != 0) {
delete storage;
return nullptr;
}
return storage;
}
// Cleanup function called when thread exits
static void cleanupThreadStorage(void* data) {
if (data) {
delete static_cast<ThreadStorage*>(data);
}
}
};
#endif // FASTLED_USE_THREAD_LOCAL
///////////////////// FAKE IMPLEMENTATION //////////////////////////////////////
template <typename T> class ThreadLocalFake {
public:
// Default: each thread's object is default-constructed
ThreadLocalFake() : mValue() {}
// With default: each thread's object is copy-constructed from defaultVal
template <typename U>
explicit ThreadLocalFake(const U &defaultVal) : mValue(defaultVal) {}
// Access the thread-local instance (not actually thread-local in fake version)
T &access() { return mValue; }
const T &access() const { return mValue; }
// Set the value (globally shared in fake version)
void set(const T& value) {
mValue = value;
}
// Convenience operators for "ThreadLocal<T> = x;"
operator T &() { return access(); }
operator const T &() const { return access(); }
ThreadLocalFake &operator=(const T &v) {
set(v);
return *this;
}
private:
T mValue;
};
} // namespace fl