* Copyright (c) 2025 Huawei Device Co., Ltd.
* 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 COMMON_COMPONENTS_COMMON_WORK_STACK_H
#define COMMON_COMPONENTS_COMMON_WORK_STACK_H
#include <mutex>
#include <type_traits>
#include "base/common.h"
#include "common_components/log/log.h"
namespace common {
template <typename T, size_t capacity>
class StackBase {
public:
StackBase() = default;
~StackBase()
{
DCHECK_CC(IsEmpty());
}
NO_COPY_SEMANTIC_CC(StackBase);
NO_MOVE_SEMANTIC_CC(StackBase);
bool IsEmpty() const;
bool IsFull() const;
void Push(T *e);
void Pop(T **e);
StackBase *GetNext() const;
void SetNext(StackBase *next);
private:
size_t top_ {0};
StackBase *next_ {nullptr};
T *data_[capacity];
};
namespace __work_stack_internal_impl {
template <typename T, size_t capacity, typename PushToGlobalNotify>
class LocalStackImpl;
}
template <typename T, size_t capacity>
class StackList {
public:
using InternalStack = StackBase<T, capacity>;
StackList() = default;
~StackList()
{
DCHECK_CC(head_ == nullptr);
}
NO_COPY_SEMANTIC_CC(StackList);
NO_MOVE_SEMANTIC_CC(StackList);
size_t Count();
private:
void Push(InternalStack *stack);
void Pop(InternalStack **stack);
InternalStack *head_ {nullptr};
std::mutex mutex_;
template <typename, size_t, typename>
friend class __work_stack_internal_impl::LocalStackImpl;
};
namespace __work_stack_internal_impl {
class LocalStackBaseWithoutNotify {
protected:
LocalStackBaseWithoutNotify() = default;
~LocalStackBaseWithoutNotify() = default;
NO_COPY_SEMANTIC_CC(LocalStackBaseWithoutNotify);
NO_MOVE_SEMANTIC_CC(LocalStackBaseWithoutNotify);
};
template <typename PushToGlobalNotify>
class LocalStackBaseWithNotify {
protected:
explicit LocalStackBaseWithNotify(PushToGlobalNotify *pushToGlobalNotify)
: pushToGlobalNotify_(pushToGlobalNotify)
{
DCHECK_CC(pushToGlobalNotify_ != nullptr);
}
~LocalStackBaseWithNotify()
{
pushToGlobalNotify_ = nullptr;
}
NO_COPY_SEMANTIC_CC(LocalStackBaseWithNotify);
NO_MOVE_SEMANTIC_CC(LocalStackBaseWithNotify);
void NotifyPushToGlobal()
{
DCHECK_CC(pushToGlobalNotify_ != nullptr);
(*pushToGlobalNotify_)();
}
private:
PushToGlobalNotify *pushToGlobalNotify_ {nullptr};
};
struct DummyNoPushToGlobalNotify {};
template <typename T, size_t capacity, typename PushToGlobalNotify>
class LocalStackImpl final : public std::conditional_t<std::is_same_v<DummyNoPushToGlobalNotify, PushToGlobalNotify>,
LocalStackBaseWithoutNotify,
LocalStackBaseWithNotify<PushToGlobalNotify>> {
using InternalStack = StackBase<T, capacity>;
using GlobalStack = StackList<T, capacity>;
private:
static constexpr bool HAS_PUSH_TO_GLOBAL_NOTIFY = !std::is_same_v<DummyNoPushToGlobalNotify, PushToGlobalNotify>;
public:
template <typename U = PushToGlobalNotify,
typename = std::enable_if<!std::is_same_v<DummyNoPushToGlobalNotify, U>>>
LocalStackImpl(GlobalStack *globalStack, PushToGlobalNotify *pushToGlobalNotify)
: LocalStackBaseWithNotify<PushToGlobalNotify>(pushToGlobalNotify), globalStack_(globalStack)
{
inStack_ = new InternalStack();
outStack_ = new InternalStack();
}
template <typename U = PushToGlobalNotify,
typename = std::enable_if<std::is_same_v<DummyNoPushToGlobalNotify, U>>>
explicit LocalStackImpl(GlobalStack *globalStack) : globalStack_(globalStack)
{
inStack_ = new InternalStack();
outStack_ = new InternalStack();
}
~LocalStackImpl()
{
DCHECK_CC(IsEmpty());
delete inStack_;
delete outStack_;
inStack_ = nullptr;
outStack_ = nullptr;
}
NO_COPY_SEMANTIC_CC(LocalStackImpl);
NO_MOVE_SEMANTIC_CC(LocalStackImpl);
void Push(T *e);
bool Pop(T **e);
bool IsEmpty() const;
void Publish();
private:
void PushInStackToGlobal();
bool PopOutStackFromGlobal();
GlobalStack *globalStack_ {nullptr};
InternalStack *inStack_ {nullptr};
InternalStack *outStack_ {nullptr};
};
}
template <typename T, size_t capacity,
typename PushToGlobalNotify = __work_stack_internal_impl::DummyNoPushToGlobalNotify>
using LocalStack = __work_stack_internal_impl::LocalStackImpl<T, capacity, PushToGlobalNotify>;
}
#endif