3#include <engine/engine_export.h>
4#include <hpp/filesystem.hpp>
47 auto load(std::memory_order order = std::memory_order_seq_cst)
const -> std::shared_ptr<T>
49#if defined(__cpp_lib_atomic_shared_ptr) && (__cpp_lib_atomic_shared_ptr >= 201711L)
50 return ptr_.load(order);
52 return std::atomic_load_explicit(&ptr_, order);
56 void store(std::shared_ptr<T> desired, std::memory_order order = std::memory_order_seq_cst)
58#if defined(__cpp_lib_atomic_shared_ptr) && (__cpp_lib_atomic_shared_ptr >= 201711L)
59 ptr_.store(std::move(desired), order);
61 std::atomic_store_explicit(&ptr_, std::move(desired), order);
66#if defined(__cpp_lib_atomic_shared_ptr) && (__cpp_lib_atomic_shared_ptr >= 201711L)
67 std::atomic<std::shared_ptr<T>> ptr_{};
69 std::shared_ptr<T> ptr_{};
156 return uid() == rhs.uid() &&
id() == rhs.id() &&
is_valid() == rhs.is_valid();
161 update_last_access();
162 return uintptr_t(
peek().
get());
169 operator bool()
const
183 if(
auto s = load_state())
197 auto uid() const -> hpp::uuid
199 if(
auto s = load_state())
211 return fs::path(
id()).stem().string();
216 return fs::path(
id()).extension().string();
227 auto get(
bool wait =
true) const ->
std::shared_ptr<T>
229 update_last_access();
231 if(
auto cached_asset =
peek())
238 auto s = load_state();
239 if(!s || !s->task.valid())
241 return empty_asset();
244 if(!s->task.is_submitted())
249 const bool ready = s->task.is_ready();
250 const bool should_get = ready || wait;
253 return empty_asset();
261 task.change_priority(tpp::priority::high());
264 auto value = task.get();
267 std::lock_guard<std::mutex> lock(link_->weak_asset_mtx);
268 link_->weak_asset = value;
271 return empty_asset();
279 auto s = load_state();
280 return s && s->task.valid();
288 auto s = load_state();
289 return s && s->task.valid() && s->task.is_ready();
297 auto s = load_state();
298 return s && s->task.valid() && !s->task.is_submitted();
306 auto s = load_state();
307 return s && s->task.valid() && s->task.is_submitted() && !s->task.is_ready();
316 auto s = load_state();
317 if(s && s->task.valid() && !s->task.is_submitted())
337 auto old = load_state();
338 auto fresh = std::make_shared<state_t>();
341 fresh->uid = old->uid;
344 link_->state.store(std::move(fresh), std::memory_order_release);
346 std::lock_guard<std::mutex> lock(link_->weak_asset_mtx);
347 link_->weak_asset.reset();
359 const auto ns = link_->last_access_ns.load(std::memory_order_relaxed);
360 return std::chrono::steady_clock::time_point(std::chrono::nanoseconds(ns));
368 if(
auto s = load_state(); s && s->task.valid())
372 return tpp::job_id{};
390 std::lock_guard<std::mutex> lock(link_->weak_asset_mtx);
391 link_->weak_asset.reset();
405 fresh.uid = internal_uid;
406 fresh.id = internal_id;
421 fresh.id = internal_id;
433 if(
auto s = load_state(); s && s->task.valid())
435 const auto task_count = s->task.use_count();
438 APPLOG_TRACE(
"{} - task leak use_count {}", s->id, task_count);
446 link_->state.store(std::make_shared<state_t>(), std::memory_order_release);
448 std::lock_guard<std::mutex> lock(link_->weak_asset_mtx);
449 link_->weak_asset.reset();
471 static const std::string empty{
"None"};
491 std::lock_guard<std::mutex> lock(link_->weak_asset_mtx);
492 return link_->weak_asset.lock();
500 static_assert(
sizeof(
asset_link_t) >= 1,
"Type must be fully defined");
503 link_ = std::make_shared<asset_link_t>();
517 return link_->state.load(std::memory_order_acquire);
527 void publish_state(F&& mutator)
529 auto old = load_state();
530 auto fresh = std::make_shared<state_t>();
535 std::forward<F>(mutator)(*fresh);
536 link_->state.store(std::move(fresh), std::memory_order_release);
543 static auto empty_asset() -> std::shared_ptr<T>
545 static const std::shared_ptr<T> empty = std::make_shared<T>();
549 void update_last_access()
const
555 const auto now = std::chrono::steady_clock::now().time_since_epoch();
556 const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
557 link_->last_access_ns.store(ns, std::memory_order_relaxed);
561 std::shared_ptr<asset_link_t> link_;
tpp::job_shared_future< T > task_future
atomic_shared_ptr()=default
auto load(std::memory_order order=std::memory_order_seq_cst) const -> std::shared_ptr< T >
atomic_shared_ptr(std::shared_ptr< T > initial)
void store(std::shared_ptr< T > desired, std::memory_order order=std::memory_order_seq_cst)
#define APPLOG_TRACE(...)
Hash specialization for batch_key to enable use in std::unordered_map.
Thread-safe handle to an asset.
static auto get_empty_id() -> const std::string &
Gets the conventional empty string identifier ("None").
auto is_valid() const -> bool
Checks if the handle references a task.
typename asset_link_t::state_t state_t
auto id() const -> std::string
Gets the string identifier of the asset.
void demote_to_deferred()
Demotes a fully loaded asset back to deferred state.
auto operator==(const asset_handle &rhs) const -> bool
Equality operator for asset handles.
void invalidate()
Invalidates the handle, resetting its state.
std::shared_ptr< state_t > state_ptr
static auto get_empty() -> const asset_handle &
Gets an empty asset handle.
void set_internal_ids(const hpp::uuid &internal_uid, const std::string &internal_id=get_empty_id())
Sets the internal IDs (uid + string identifier).
typename asset_link_t::task_future_t task_future_t
auto last_access() const -> std::chrono::steady_clock::time_point
Gets the last access timestamp.
void set_internal_job(const task_future_t &future)
Sets the internal job future.
auto peek() const -> std::shared_ptr< T >
Returns the loaded asset if it is currently in memory, or nullptr otherwise.
auto get(bool wait=true) const -> std::shared_ptr< T >
Gets the shared pointer to the asset.
asset_link< T > asset_link_t
auto extension() const -> std::string
auto name() const -> std::string
Gets the name of the asset derived from its path.
auto is_ready() const -> bool
Checks if the task is ready.
auto task_id() const
Gets the task ID (may be empty if there's no task).
auto is_deferred() const -> bool
Checks if the handle has a deferred job not yet submitted to workers.
void submit()
Submits a deferred task to the thread pool for execution. Does nothing if the task is already submitt...
void ensure()
Ensures the asset link is initialized.
auto is_loading() const -> bool
Checks if the asset is currently loading.
auto version() const -> uintptr_t
void set_internal_id(const std::string &internal_id=get_empty_id())
Sets the internal string identifier.
auto uid() const -> hpp::uuid
Gets the unique identifier of the asset.
Immutable snapshot of the link's logical state.
hpp::uuid uid
Unique identifier for the asset.
task_future_t task
Task future for the asset (valid for both scheduled and deferred jobs).
std::string id
String identifier for the asset.
Thread-safe link to an asset.
asset_detail::atomic_shared_ptr< state_t > state
std::mutex weak_asset_mtx
std::atomic< int64_t > last_access_ns
task_future< std::shared_ptr< T > > task_future_t
std::weak_ptr< T > weak_asset_t