blob: 1a50e59c937fc867a3a70fe89fb395de58a3b16f [file] [edit]
// Copyright 2026 Google LLC
//
// 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
//
// https://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 THIRD_PARTY_CREDENTIO_ASYNC_CANCELLATION_TOKEN_H_
#define THIRD_PARTY_CREDENTIO_ASYNC_CANCELLATION_TOKEN_H_
#include <cstdint>
#include <memory>
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
namespace credentio {
class CancellationToken;
// Internal shared state for cancellation.
class CancellationState {
public:
CancellationState() = default;
bool IsCancelled() const {
absl::MutexLock lock(mutex_);
return cancelled_;
}
void Cancel();
// Returns >0 registration ID if successfully registered.
// Returns 0 if already cancelled (and executes callback immediately inline).
uint64_t RegisterCallback(absl::AnyInvocable<void()> cb);
void DeregisterCallback(uint64_t id);
private:
mutable absl::Mutex mutex_;
bool cancelled_ ABSL_GUARDED_BY(mutex_) = false;
uint64_t next_id_ ABSL_GUARDED_BY(mutex_) = 1;
absl::flat_hash_map<uint64_t, absl::AnyInvocable<void()>> callbacks_
ABSL_GUARDED_BY(mutex_);
};
// Represents a read-only view of a cancellation state.
class CancellationToken {
public:
CancellationToken() = default;
bool IsCancelled() const {
if (!state_) return false;
return state_->IsCancelled();
}
// Copyable and movable.
CancellationToken(const CancellationToken&) = default;
CancellationToken& operator=(const CancellationToken&) = default;
CancellationToken(CancellationToken&&) = default;
CancellationToken& operator=(CancellationToken&&) = default;
private:
friend class CancellationSource;
friend class CancellationCallback;
explicit CancellationToken(std::shared_ptr<CancellationState> state)
: state_(std::move(state)) {}
std::shared_ptr<CancellationState> state_;
};
// The source of cancellation.
class CancellationSource {
public:
CancellationSource() : state_(std::make_shared<CancellationState>()) {}
void Cancel() {
if (state_) {
state_->Cancel();
}
}
CancellationToken GetToken() const { return CancellationToken(state_); }
private:
std::shared_ptr<CancellationState> state_;
};
// Represents a registration of a callback against a CancellationToken.
// When this object falls out of scope, the callback is automatically
// deregistered.
class CancellationCallback {
public:
CancellationCallback(CancellationToken token, absl::AnyInvocable<void()> cb)
: state_(std::move(token.state_)) {
if (state_) {
id_ = state_->RegisterCallback(std::move(cb));
}
}
~CancellationCallback() {
if (state_ && id_ != 0) {
state_->DeregisterCallback(id_);
}
}
// Non-copyable, non-movable.
CancellationCallback(const CancellationCallback&) = delete;
CancellationCallback& operator=(const CancellationCallback&) = delete;
private:
std::shared_ptr<CancellationState> state_;
uint64_t id_ = 0;
};
} // namespace credentio
#endif // THIRD_PARTY_CREDENTIO_ASYNC_CANCELLATION_TOKEN_H_