GPT-5 到底有多强?
我这里不说废话,这是我和它协作40分钟的结果。
代码应当在 GPLv3.0 下发布,但是我不方便建立 GitHub 仓库提供副本,所以许可证的文件请见:https://www.gnu.org/licenses/
提示词如下:
让我们来写一个 Stack 类,用 C++ 23!
1. 使用 template <typename... Types> 配合 std::variant 和 std::visit 解决对齐和类型安全的问题
2. 支持标准库风格的迭代器
3. 使用 std::construct_at 和 std::destroy_at 手动管理对象存在周期,避免不必要的开销
4. 兼容 pmr 和 allocator,支持修改分配策略
5. 使用 concept 明确地定义相关的需求,避免模板天书
做得非常棒,我们现在进行迭代:
1. 检查展开模板参数包的问题
[compiler log ...]
2. 除非必要,使用`and`、`or`等风格的逻辑运算符,不要使用老式C风格的逻辑运算符
3. 使用 Doxygen 风格的注释,可以详细地说明;注释信息中英双语
4. 考虑到日常使用,应该在合适的位置设置好默认参数,并且尽可能地让模板参数能够自行推导
别急,来修 bug!
[compiler log ...]
这次更新,我们迭代这几个:
1. 引入 noexcept(move) 颗粒度的更细异常保证
2. 提供 small_buffer 小对象优化版本
3. 加强可行范围内的 static reflection,对基础类型和对齐可解决的小类型进行优化
维持设计需求不变(也就是已有的设计语义约束),我们来修 Bug:
[compiler log ...]
嗯,我觉得很不错,你很棒!
接下来的任务:生成一份测试代码,饱和性质地测试一遍我们的 stack;只写在 main 函数中。
嗯,你的测试代码有问题,修复一下bug:
[compiler log ...]
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 azureveil <azureveil4295@yeah.net>
//
// This file is part of azureveil stack demo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <variant>
#include <memory>
#include <memory_resource>
#include <type_traits>
#include <concepts>
#include <iterator>
#include <utility>
#include <new>
#include <cstddef>
#include <stdexcept>
#include <algorithm>
#include <initializer_list>
#include <array>
#include <cstring> // memcpy
#include <cassert>
namespace tools
{
/**
* @brief A type-list for meta programming. / 用于元编程的类型列表
*/
template <class... Ts>
struct type_list
{
};
/* ========================= Concepts(概念)========================= */
/**
* @brief Check T is in pack Ts... / 判断类型 T 是否在 Ts... 中
*/
template <class T, class... Ts>
concept InPack = (std::same_as<std::remove_cvref_t<T>, Ts> or ...);
/**
* @brief Element pack requirements for stack. / 栈的候选类型包需求
* - every type is destructible and move-constructible
* - pack size > 0
*
* 重要:折叠表达式必须写成 ((A and B) and ...),避免编译器报
* "binary expression in operand of fold-expression"。
*/
template <class... Ts>
concept StackElementPack =
((std::destructible<Ts> and std::move_constructible<Ts>) and ...) and (sizeof...(Ts) > 0);
/**
* @brief Allocator can be rebound to T. / 分配器可重绑定到 T
*/
template <class Alloc, class T>
concept RebindableAllocator = requires {
typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
};
/**
* @brief f is a valid visitor for std::variant<Ts...>. / 访问器概念
*/
template <class F, class... Ts>
concept VariantVisitor =
requires(F f, std::variant<Ts...> &v) { std::visit(f, v); } and
requires(F f, const std::variant<Ts...> &cv) { std::visit(f, cv); };
/* ========================= meta: unique types ===================== */
namespace detail
{
/**
* @brief contains<List, T> -> bool_constant / 判断 T 是否在 type_list 中
*/
template <class List, class T>
struct contains;
template <class T>
struct contains<type_list<>, T> : std::false_type
{
};
template <class Head, class... Tail, class T>
struct contains<type_list<Head, Tail...>, T>
: std::conditional_t<std::same_as<Head, T>, std::true_type, contains<type_list<Tail...>, T>>
{
};
/**
* @brief prepend<List, T> / 在列表前部插入
*/
template <class List, class T>
struct prepend;
template <class... Ts, class T>
struct prepend<type_list<Ts...>, T>
{
using type = type_list<T, Ts...>;
};
/**
* @brief unique_types<Ts...> 去重并保持首次出现顺序 / make unique, keep first-appearance order
*/
template <class... Ts>
struct unique_types;
template <>
struct unique_types<>
{
using type = type_list<>;
};
template <class T, class... Rest>
struct unique_types<T, Rest...>
{
using rest = typename unique_types<Rest...>::type;
static constexpr bool in = contains<rest, T>::value;
using type = std::conditional_t<in, rest, typename prepend<rest, T>::type>;
};
/**
* @brief forward decl: to_basic_stack<Alloc, type_list<...>>
* 仅声明,不定义,避免重定义冲突!
*/
template <class Alloc, class List>
struct to_basic_stack;
} // namespace detail
/* ========================= basic_stack with SBO =================== */
/**
* @class basic_stack
* @brief A type-safe, allocator-aware multi-type stack based on std::variant,
* with optional Small Buffer Optimization (SBO).
* 使用 std::variant 的类型安全、分配器友好、可选小对象优化(SBO)的多类型栈。
*
* @tparam Allocator allocator type (defaults to std::allocator<std::byte>)
* 分配器类型(默认 std::allocator<std::byte>)
* @tparam SBO inline capacity in elements for small-buffer optimization
* 小对象优化的内联容量(按元素个数)
* @tparam Types... element alternative types (non-empty pack)
* 备选元素类型(非空包)
*
* # Design highlights / 设计要点
* - Storage is `std::variant<Types...>` for type-safety & alignment.(对齐与类型安全由 variant 保证)
* - Manual lifetime with `std::construct_at` / `std::destroy_at`.(手动控制对象生命周期)
* - Standard-style iterators (contiguous).(标准库风格迭代器,连续存储)
* - Supports PMR 和常规分配器。/ Supports PMR and regular allocators.
* - `noexcept(move)` granular policy: relocation chooses move-or-copy by traits. /
* 基于类型性质(traits)选择“移动或拷贝”,提供细粒度异常保证。
* - SBO: small sizes live on-stack; larger spill to heap. / 小容量走栈上内联,大容量溢出到堆。
*
* @note 对“静态反射(static reflection)”的可行优化:
* - 若 `storage_type`(即 `std::variant<Ts...>`)满足
* `std::is_trivially_copyable_v`,则迁移使用 `memcpy` 快路径;
* - 否则若 `std::is_nothrow_move_constructible_v<storage_type>`,则采用移动构造;
* - 否则退化为拷贝构造,保持强异常保证(strong exception safety)。
*/
template <
class Allocator = std::allocator<std::byte>,
std::size_t SBO = 0,
class... Types>
requires StackElementPack<Types...> and RebindableAllocator<Allocator, std::variant<Types...>>
class basic_stack
{
public:
using storage_type = std::variant<Types...>;
using value_type = storage_type;
using allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<storage_type>;
using allocator_traits = std::allocator_traits<allocator_type>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = storage_type &;
using const_reference = const storage_type &;
using pointer = storage_type *;
using const_pointer = const storage_type *;
using iterator = storage_type *;
using const_iterator = const storage_type *;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
// ---- Static reflection knobs / 静态性质开关 ----
static constexpr bool triv_copyable = std::is_trivially_copyable_v<storage_type>;
static constexpr bool triv_destruct = std::is_trivially_destructible_v<storage_type>;
static constexpr bool nothrow_move = std::is_nothrow_move_constructible_v<storage_type>;
static constexpr std::size_t TSize = sizeof(storage_type);
static constexpr std::size_t TAlign = alignof(storage_type);
static constexpr bool has_sbo = (SBO > 0);
/// @brief SBO 内联块(仅在 has_sbo 为真时作为候选)/ inline storage when SBO enabled
struct alignas(TAlign) sbo_block
{
std::array<std::byte, SBO * TSize> buf{};
};
/// @brief 无 SBO 时的占位类型(空壳)/ empty placeholder when SBO disabled
struct no_sbo_block
{
};
/// @brief 依据 has_sbo 选择实际的 sbo_ 成员类型
using sbo_storage_t = std::conditional_t<has_sbo, sbo_block, no_sbo_block>;
public:
/* ------------- constructors / 构造与析构 ------------- */
/**
* @brief Default ctor (uses SBO if available, otherwise no allocation).
* 默认构造(若启用 SBO 则指向内联缓冲,否则不分配)
*/
basic_stack() noexcept(noexcept(allocator_type{}))
: alloc_{}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()} {}
/**
* @brief Construct with allocator. / 指定分配器构造
*/
explicit basic_stack(const Allocator &a)
: alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()} {}
/**
* @brief PMR resource ctor (enabled only for PMR allocator). /
* PMR 资源构造(仅当分配器为 PMR 时启用)
*/
basic_stack(std::pmr::memory_resource *r)
requires std::same_as<std::remove_cvref_t<Allocator>, std::pmr::polymorphic_allocator<std::byte>>
: alloc_{allocator_type{r}}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
{
}
/**
* @brief Reserve capacity upfront. / 预留容量的构造
* @param reserve_cap initial capacity / 初始容量
* @param a allocator (optional) / 可选分配器
*/
explicit basic_stack(size_type reserve_cap, const Allocator &a = Allocator{})
: alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
{
if (reserve_cap > cap_)
reserve(reserve_cap);
}
/**
* @brief Construct from initializer_list of variants. / 从 variant 列表构造
*/
basic_stack(std::initializer_list<storage_type> init, const Allocator &a = Allocator{})
: alloc_{rebind_alloc_(a)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
{
reserve(init.size());
for (auto const &v : init)
push(v);
}
basic_stack(const basic_stack &other)
: alloc_{allocator_traits::select_on_container_copy_construction(other.alloc_)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
{
reserve(other.size_);
try
{
uninit_copy_n_(other.data_, other.size_, data_);
size_ = other.size_;
}
catch (...)
{
destroy_n_(data_, size_);
deallocate_if_heap_();
throw;
}
}
basic_stack(basic_stack &&other) noexcept
: alloc_{std::move(other.alloc_)}, data_{init_data_ptr_()}, size_{0}, cap_{init_cap_()}
{
// 优先:若分配器“总是相等”,可直接窃取缓冲
if constexpr (allocator_traits::is_always_equal::value)
{
if (other.using_heap_())
{
data_ = other.data_;
cap_ = other.cap_;
size_ = other.size_;
other.data_ = other.inline_ptr_();
other.cap_ = other.init_cap_();
other.size_ = 0;
return;
}
}
// PMR 特例:同一 resource 也可安全窃取
else if constexpr (std::same_as<std::remove_cvref_t<Allocator>, std::pmr::polymorphic_allocator<std::byte>>)
{
if (other.using_heap_() and alloc_.resource() == other.alloc_.resource())
{
data_ = other.data_;
cap_ = other.cap_;
size_ = other.size_;
other.data_ = other.inline_ptr_();
other.cap_ = other.init_cap_();
other.size_ = 0;
return;
}
}
}
basic_stack &operator=(const basic_stack &other)
{
if (this == &other)
return *this;
if constexpr (allocator_traits::propagate_on_container_copy_assignment::value)
{
if (alloc_ != other.alloc_)
{
clear();
deallocate_if_heap_();
}
alloc_ = other.alloc_;
}
if (other.size_ > cap_)
{
reallocate_to_(other.size_);
}
// 赋值已有元素并填充/销毁多余
const size_type common = std::min(size_, other.size_);
for (size_type i = 0; i < common; ++i)
data_[i] = other.data_[i];
if (size_ < other.size_)
{
uninit_copy_n_(other.data_ + size_, other.size_ - size_, data_ + size_);
}
else
{
destroy_n_(data_ + other.size_, size_ - other.size_);
}
size_ = other.size_;
return *this;
}
basic_stack &operator=(basic_stack &&other) noexcept(
allocator_traits::propagate_on_container_move_assignment::value or
std::is_nothrow_move_assignable_v<allocator_type>)
{
if (this == &other)
return *this;
if constexpr (allocator_traits::propagate_on_container_move_assignment::value)
{
clear();
deallocate_if_heap_();
alloc_ = std::move(other.alloc_);
if (other.using_heap_())
{
data_ = other.data_;
size_ = other.size_;
cap_ = other.cap_;
other.data_ = other.inline_ptr_();
other.size_ = 0;
other.cap_ = other.init_cap_();
}
else
{
data_ = inline_ptr_();
cap_ = init_cap_();
size_ = 0;
reserve(other.size_);
uninit_move_or_copy_n_(other.data_, other.size_, data_);
size_ = other.size_;
other.clear();
}
}
else
{
if (alloc_ == other.alloc_)
{
clear();
deallocate_if_heap_();
if (other.using_heap_())
{
data_ = other.data_;
size_ = other.size_;
cap_ = other.cap_;
other.data_ = other.inline_ptr_();
other.size_ = 0;
other.cap_ = other.init_cap_();
}
else
{
data_ = inline_ptr_();
cap_ = init_cap_();
size_ = 0;
reserve(other.size_);
uninit_move_or_copy_n_(other.data_, other.size_, data_);
size_ = other.size_;
other.clear();
}
}
else
{
assign_move_from_(other);
}
}
return *this;
}
~basic_stack()
{
destroy_n_(data_, size_);
deallocate_if_heap_();
}
/* ------------- iterators / 迭代器 ------------- */
/// @brief begin / 起始迭代器
iterator begin() noexcept { return data_; }
const_iterator begin() const noexcept { return data_; }
const_iterator cbegin() const noexcept { return data_; }
/// @brief end / 末尾迭代器
iterator end() noexcept { return data_ + size_; }
const_iterator end() const noexcept { return data_ + size_; }
const_iterator cend() const noexcept { return data_ + size_; }
/// @brief reverse begin / 反向起始
reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{end()}; }
/// @brief reverse end / 反向末尾
reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
const_reverse_iterator crend() const noexcept { return const_reverse_iterator{begin()}; }
/* ------------- capacity / 容量 ------------- */
/// @brief empty? / 是否为空
[[nodiscard]] bool empty() const noexcept { return size_ == 0; }
/// @brief size / 当前大小
[[nodiscard]] size_type size() const noexcept { return size_; }
/// @brief capacity / 当前容量
[[nodiscard]] size_type capacity() const noexcept { return cap_; }
/// @brief reserve capacity / 预留容量
void reserve(size_type new_cap)
{
if (new_cap <= cap_)
return;
reallocate_to_(new_cap);
}
/// @brief shrink to fit (may move back into SBO) / 收缩容量(可能回迁至 SBO)
void shrink_to_fit()
{
if (size_ == cap_)
return;
const size_type target = size_;
// 若启用 SBO 且可容纳,则回迁内联
if constexpr (has_sbo)
{
if (target <= SBO)
{
reallocate_to_(SBO);
return;
}
}
reallocate_to_(target);
}
/// @brief clear (destroy all elements) / 清空(析构所有元素)
void clear() noexcept
{
destroy_n_(data_, size_);
size_ = 0;
}
/* ------------- element access / 访问 ------------- */
/// @brief top (mutable) / 顶部元素(可变)
reference top()
{
if (empty())
throw std::out_of_range("stack is empty");
return data_[size_ - 1];
}
/// @brief top (const) / 顶部元素(常量)
const_reference top() const
{
if (empty())
throw std::out_of_range("stack is empty");
return data_[size_ - 1];
}
/**
* @brief Visit top via visitor. / 使用访问器访问顶部元素
*/
template <VariantVisitor<Types...> F>
decltype(auto) visit_top(F &&f)
{
return std::visit(std::forward<F>(f), top());
}
template <VariantVisitor<Types...> F>
decltype(auto) visit_top(F &&f) const
{
return std::visit(std::forward<F>(f), top());
}
/**
* @brief Visit all elements. / 访问所有元素
*/
template <VariantVisitor<Types...> F>
void visit_all(F &&f)
{
for (auto &e : *this)
std::visit(f, e);
}
template <VariantVisitor<Types...> F>
void visit_all(F &&f) const
{
for (auto &e : *this)
std::visit(f, e);
}
/* ------------- modifiers / 修改器 ------------- */
/**
* @brief Push a variant value. / 压入一个 variant 值
*/
void push(value_type v)
{
ensure_growth_();
std::construct_at(data_ + size_, std::move(v));
++size_;
}
/**
* @brief Push a concrete alternative in Types... / 压入具体候选类型的值
*/
template <class T>
requires InPack<T, Types...>
void push(T &&x)
{
ensure_growth_();
std::construct_at(
data_ + size_,
std::in_place_type<std::remove_cvref_t<T>>,
std::forward<T>(x));
++size_;
}
/**
* @brief Emplace the top element as alternative T. / 原地构造指定候选类型 T 的顶部元素
*/
template <class T, class... Args>
requires InPack<T, Types...> and std::constructible_from<T, Args...>
reference emplace(Args &&...args)
{
ensure_growth_();
std::construct_at(data_ + size_, std::in_place_type<T>, std::forward<Args>(args)...);
++size_;
return data_[size_ - 1];
}
/**
* @brief Pop the top element (destroy). / 弹出顶部元素(析构)
*/
void pop()
{
if (empty())
throw std::out_of_range("stack is empty");
std::destroy_at(data_ + (size_ - 1));
--size_;
}
/* ------------- allocator / 分配器 ------------- */
/// @brief get allocator / 获取分配器
allocator_type get_allocator() const noexcept { return alloc_; }
/**
* @brief Rebind to another allocator type. / 迁移到另一种分配器策略
* @note Copy/move variant elements as needed. / 根据异常安全选择拷贝或移动
*/
template <class NewAlloc>
requires RebindableAllocator<NewAlloc, storage_type>
basic_stack<NewAlloc, SBO, Types...> rebind_allocator(const NewAlloc &na = NewAlloc{}) const
{
basic_stack<NewAlloc, SBO, Types...> dst(na);
dst.reserve(size_);
for (size_type i = 0; i < size_; ++i)
{
dst.push(data_[i]);
}
return dst;
}
private:
/* ------------- internal helpers / 内部工具 ------------- */
// —— SBO helpers / SBO 辅助 —— //
pointer inline_ptr_() noexcept
{
if constexpr (has_sbo)
{
// std::launder: 避免潜在的严格别名与生命周期问题
return std::launder(reinterpret_cast<pointer>(sbo_.buf.data()));
}
else
{
return nullptr;
}
}
const_pointer inline_ptr_() const noexcept
{
if constexpr (has_sbo)
{
return std::launder(reinterpret_cast<const_pointer>(sbo_.buf.data()));
}
else
{
return nullptr;
}
}
bool using_heap_() const noexcept
{
if constexpr (has_sbo)
return data_ != inline_ptr_();
else
return data_ != nullptr;
}
pointer init_data_ptr_() noexcept
{
if constexpr (has_sbo)
return inline_ptr_();
else
return nullptr;
}
size_type init_cap_() const noexcept
{
if constexpr (has_sbo)
return SBO;
else
return 0;
}
static allocator_type rebind_alloc_(const Allocator &a)
{
using rebound = typename std::allocator_traits<Allocator>::template rebind_alloc<storage_type>;
return rebound{a};
}
pointer allocate_(size_type n) { return allocator_traits::allocate(alloc_, n); }
void deallocate_if_heap_() noexcept
{
if (using_heap_() and data_)
allocator_traits::deallocate(alloc_, data_, cap_);
data_ = init_data_ptr_();
cap_ = init_cap_();
}
static void destroy_n_(pointer p, size_type n) noexcept
{
for (size_type i = 0; i < n; ++i)
{
std::destroy_at(p + i);
}
}
static void uninit_copy_n_(const_pointer src, size_type n, pointer dst)
{
size_type i = 0;
try
{
for (; i < n; ++i)
std::construct_at(dst + i, src[i]);
}
catch (...)
{
destroy_n_(dst, i);
throw;
}
}
// —— granular move/copy by traits / 基于性质的精细迁移 —— //
static void uninit_move_or_copy_n_(pointer src, size_type n, pointer dst)
{
// Fast path: trivially copyable → memcpy
if constexpr (triv_copyable)
{
std::memcpy(static_cast<void *>(dst), static_cast<void const *>(src), n * TSize);
return;
}
size_type i = 0;
try
{
if constexpr (nothrow_move)
{
for (; i < n; ++i)
std::construct_at(dst + i, std::move(src[i]));
}
else
{
for (; i < n; ++i)
std::construct_at(dst + i, src[i]); // fallback copy
}
}
catch (...)
{
destroy_n_(dst, i);
throw;
}
}
void reallocate_to_(size_type new_cap)
{
// 选择目标缓冲区:优先使用 SBO(若可容纳)
pointer new_buf = nullptr;
if constexpr (has_sbo)
{
new_buf = (new_cap <= SBO) ? inline_ptr_() : allocate_(new_cap);
}
else
{
new_buf = allocate_(new_cap);
}
if (new_buf == data_)
{ // 仍在同一缓冲,无需动作
cap_ = (new_buf == inline_ptr_()) ? init_cap_() : new_cap;
return;
}
size_type moved = 0;
try
{
uninit_move_or_copy_n_(data_, size_, new_buf);
moved = size_;
}
catch (...)
{
if (new_buf != inline_ptr_())
{
destroy_n_(new_buf, moved); // 对于 memcpy 情况,trivial dtor 则无副作用
allocator_traits::deallocate(alloc_, new_buf, new_cap);
}
throw;
}
// 旧缓冲区清理
destroy_n_(data_, size_);
if (using_heap_())
allocator_traits::deallocate(alloc_, data_, cap_);
data_ = new_buf;
cap_ = (data_ == inline_ptr_()) ? init_cap_() : new_cap;
}
void ensure_growth_()
{
if (size_ == cap_)
{
const size_type base = (cap_ == 0) ? (has_sbo ? SBO : 0) : cap_;
const size_type new_cap = (base == 0) ? 4 : (base * 2);
reallocate_to_(new_cap);
}
}
void assign_move_from_(basic_stack &other)
{
clear();
reserve(other.size_);
uninit_move_or_copy_n_(other.data_, other.size_, data_);
size_ = other.size_;
other.clear();
}
private:
allocator_type alloc_{};
pointer data_{nullptr};
size_type size_{0};
size_type cap_{0};
// SBO storage (exists only if SBO>0) / 仅当 SBO>0 才有意义
sbo_storage_t sbo_{};
};
/* ========================= Aliases / 别名 ========================= */
template <class... Types>
using Stack = basic_stack<std::allocator<std::byte>, 0, Types...>;
template <std::size_t SBO, class... Types>
using SmallStack = basic_stack<std::allocator<std::byte>, SBO, Types...>;
template <class... Types>
using PmrStack = basic_stack<std::pmr::polymorphic_allocator<std::byte>, 0, Types...>;
template <std::size_t SBO, class... Types>
using PmrSmallStack = basic_stack<std::pmr::polymorphic_allocator<std::byte>, SBO, Types...>;
/* === meta glue: materialize to_basic_stack (after basic_stack exists) === */
/* !!!修复重定义:只在此处做唯一的偏特化定义,之前仅声明不定义。 */
namespace detail
{
template <class Alloc, class... Ts>
struct to_basic_stack<Alloc, type_list<Ts...>>
{
using type = basic_stack<Alloc, 0, Ts...>;
};
} // namespace detail
/* ========================= Factory helpers / 工厂辅助 ==================== */
/**
* @brief Make a stack with deduced unique types from arguments (default allocator).
* 通过实参类型推导并去重,构造使用默认分配器的栈。
*
* @return stack with Types... = unique(remove_cvref_t<Args>...) / 去重后的类型包
*
* 使用示例:
* auto s = tools::stack_of(1, std::string{"x"}, 3.14); // Stack<int, std::string, double>
*/
template <class... Args>
auto stack_of(Args &&...)
{
using uniq_list = typename detail::unique_types<std::remove_cvref_t<Args>...>::type;
using stack_t = typename detail::to_basic_stack<std::allocator<std::byte>, uniq_list>::type;
return stack_t{};
}
/**
* @brief Make a stack with a given allocator. / 使用给定分配器的工厂
*/
template <class Alloc, class... Args>
requires RebindableAllocator<Alloc, std::variant<std::remove_cvref_t<Args>...>>
auto stack_of_with_alloc(const Alloc &a, Args &&...)
{
using uniq_list = typename detail::unique_types<std::remove_cvref_t<Args>...>::type;
using stack_t = typename detail::to_basic_stack<Alloc, uniq_list>::type;
return stack_t{a};
}
/**
* @brief PMR convenience factory. / PMR 快捷工厂
*/
template <class... Args>
auto stack_of_pmr(std::pmr::memory_resource *r, Args &&...)
{
using uniq_list = typename detail::unique_types<std::remove_cvref_t<Args>...>::type;
using stack_t = typename detail::to_basic_stack<std::pmr::polymorphic_allocator<std::byte>, uniq_list>::type;
return stack_t{r};
}
/* ========================= CTAD guides / 推导指引 ======================== */
/**
* @brief Deduce Ts... from initializer_list<variant<Ts...>> (default allocator).
* 从 initializer_list<variant<Ts...>> 推导元素类型(默认分配器)
*/
template <class... Ts>
basic_stack(std::initializer_list<std::variant<Ts...>>, std::allocator<std::byte>)
-> basic_stack<std::allocator<std::byte>, 0, Ts...>;
template <class... Ts>
basic_stack(std::initializer_list<std::variant<Ts...>>)
-> basic_stack<std::allocator<std::byte>, 0, Ts...>;
/**
* @brief Deduce Ts... + PMR allocator from initializer_list. / 从初始化列表推导 Ts... 与 PMR 分配器
*/
template <class... Ts>
basic_stack(std::initializer_list<std::variant<Ts...>>, std::pmr::polymorphic_allocator<std::byte>)
-> basic_stack<std::pmr::polymorphic_allocator<std::byte>, 0, Ts...>;
} // namespace tools
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 azureveil <azureveil4295@yeah.net>
//
// This file is part of azureveil stack demo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "stack.hpp"
#include <cassert>
#include <string>
#include <iostream>
#include <variant>
#include <vector>
#include <array>
#include <memory_resource>
#include <algorithm>
#include <stdexcept>
#include <cctype>
#include <type_traits>
#include <climits>
// —— 两个测试类型必须放在函数外:标准禁止局部类含静态数据成员 ——
// 计数型:用于验证生命周期(构造/析构数量)
struct Counted
{
static int live;
int id = -1;
Counted() : id(-1) { ++live; }
explicit Counted(int i) : id(i) { ++live; }
Counted(const Counted &o) : id(o.id) { ++live; }
Counted(Counted &&o) noexcept : id(o.id) { ++live; }
Counted &operator=(const Counted &) = default;
Counted &operator=(Counted &&) = default;
~Counted() { --live; }
};
int Counted::live = 0;
// 用于异常路径:拷贝到第 N 次时抛异常;移动构造非 noexcept,促使“回退拷贝路径”
struct ThrowOnCopy
{
static int copy_count;
static int throw_after;
int v = 0;
ThrowOnCopy() = default;
explicit ThrowOnCopy(int x) : v(x) {}
ThrowOnCopy(const ThrowOnCopy &o) : v(o.v)
{
if (++copy_count == throw_after)
throw std::runtime_error("copy boom");
}
ThrowOnCopy(ThrowOnCopy &&o) noexcept(false) : v(o.v) {}
ThrowOnCopy &operator=(const ThrowOnCopy &) = default;
ThrowOnCopy &operator=(ThrowOnCopy &&) = default;
~ThrowOnCopy() = default;
};
int ThrowOnCopy::copy_count = 0;
int ThrowOnCopy::throw_after = INT_MAX;
int main()
{
using namespace tools;
// ========== 1) 基础功能:SmallStack + 多类型 push/emplace/visit ==========
{
SmallStack<4, int, std::string, double, Counted> s; // SBO=4
assert(s.empty());
s.emplace<int>(42);
s.push(std::string{"alpha"});
s.push(3.14);
s.emplace<Counted>(7);
assert(s.size() == 4);
assert(s.capacity() >= 4);
s.visit_top([](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, Counted>) assert(x.id == 7); });
int cnt_int = 0;
int cnt_str = 0;
int cnt_dbl = 0;
int cnt_cnt = 0;
long long sum_int = 0;
double sum_dbl = 0.0;
s.visit_all([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) { ++cnt_int; sum_int += x; }
else if constexpr (std::is_same_v<T, std::string>) { ++cnt_str; }
else if constexpr (std::is_same_v<T, double>) { ++cnt_dbl; sum_dbl += x; }
else if constexpr (std::is_same_v<T, Counted>) { ++cnt_cnt; } });
assert(cnt_int == 1 and cnt_str == 1 and cnt_dbl == 1 and cnt_cnt == 1);
assert(sum_int == 42);
assert(sum_dbl > 3.0 and sum_dbl < 3.2);
int live_before = Counted::live;
s.pop(); // 弹出 Counted{7}
assert(Counted::live == live_before - 1);
assert(s.size() == 3);
s.clear();
assert(s.empty());
}
// ========== 2) 容量行为:SBO 命中、溢出堆、shrink 回迁 ==========
{
SmallStack<4, int, std::string> s;
for (int i = 0; i < 4; ++i)
s.push(i); // SBO 内
assert(s.capacity() == 4);
s.push(100); // 触发溢出
assert(s.capacity() >= 5);
while (s.size() > 4)
s.pop(); // 回到 SBO 大小
s.shrink_to_fit();
assert(s.capacity() == 4); // 回迁成功
}
// ========== 3) reserve/growth:多次重分配不丢数据 ==========
{
Stack<int, std::string> s;
for (int i = 0; i < 100; ++i)
{
if (i % 10 == 0)
s.push(std::string{"s-" + std::to_string(i)});
else
s.push(i);
}
int ints = 0, strs = 0, sum = 0;
s.visit_all([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) { ++ints; sum += x; }
else if constexpr (std::is_same_v<T, std::string>) { ++strs; } });
assert(ints == 90 and strs == 10);
assert(s.size() == 100);
const auto sz = s.size();
s.shrink_to_fit();
assert(s.size() == sz);
}
// ========== 4) PMR:单调缓冲资源 + PmrSmallStack ==========
{
std::array<std::byte, 4096> buf{};
std::pmr::monotonic_buffer_resource mbr(buf.data(), buf.size());
PmrSmallStack<4, int, std::string> ps(&mbr);
ps.emplace<int>(1);
ps.emplace<std::string>("pmr");
ps.emplace<int>(2);
ps.emplace<int>(3); // 填满 SBO
ps.emplace<int>(4); // 溢出到堆(仍由 mbr 管)
assert(ps.size() == 5);
int sum = 0, strings = 0;
ps.visit_all([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) sum += x;
else if constexpr (std::is_same_v<T, std::string>) ++strings; });
assert(sum == (1 + 2 + 3 + 4) and strings == 1);
}
// ========== 5) 工厂函数与 CTAD(不再用严格顺序的 static_assert) ==========
{
auto s1 = stack_of(1, std::string{"x"}, 2.5, 3, 4.0);
using stor1 = typename decltype(s1)::storage_type;
static_assert(std::variant_size_v<stor1> == 3);
// 运行期验证三种类型都能正常压入/访问
s1.push(123);
s1.push(std::string{"ok"});
s1.push(3.14);
bool saw_int = false, saw_str = false, saw_dbl = false;
s1.visit_all([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T,int>) saw_int = true;
if constexpr (std::is_same_v<T,std::string>) saw_str = true;
if constexpr (std::is_same_v<T,double>) saw_dbl = true; });
assert(saw_int and saw_str and saw_dbl);
// PMR 工厂 & initializer_list + CTAD
std::pmr::monotonic_buffer_resource mbr;
auto s2 = stack_of_pmr(&mbr, 1, std::string{"y"}, 3.0);
using stor2 = typename decltype(s2)::storage_type;
static_assert(std::variant_size_v<stor2> == 3);
using V = std::variant<int, std::string>;
basic_stack lst = {V{1}, V{std::string{"ctad"}}}; // Ts... 推导为 <int, std::string>
assert(lst.size() == 2);
}
// ========== 6) rebind_allocator:迁移到 PMR ==========
{
auto s = stack_of(1, std::string{"reb"}, 2.0);
s.push(7);
s.push(std::string{"z"});
std::array<std::byte, 2048> buf{};
std::pmr::monotonic_buffer_resource mbr(buf.data(), buf.size());
auto sp = s.rebind_allocator(std::pmr::polymorphic_allocator<std::byte>{&mbr});
assert(sp.size() == s.size());
auto stringify = [](auto const &v) -> std::string
{
return std::visit([](auto const &x) -> std::string
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, std::string>) return x;
else return std::to_string(x); }, v);
};
std::vector<std::string> a, b;
a.reserve(s.size());
b.reserve(sp.size());
for (auto const &e : s)
a.push_back(stringify(e));
for (auto const &e : sp)
b.push_back(stringify(e));
assert(a == b);
}
// ========== 7) 变更访问:就地变换字符串 ==========
{
SmallStack<4, int, std::string> s;
s.push(1);
s.push(std::string{"MiXed"});
s.push(2);
for (auto &v : s)
{
std::visit([](auto &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, std::string>) {
for (auto& c : x) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
} }, v);
}
bool seen_upper = false;
s.visit_all([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, std::string>) seen_upper = (x == "MIXED"); });
assert(seen_upper);
}
// ========== 8) 异常安全(强保证):拷贝途中抛异常,栈保持不变 ==========
{
using S = Stack<ThrowOnCopy, int>;
S s;
for (int i = 0; i < 8; ++i)
{
if (i % 2 == 0)
s.push(ThrowOnCopy{i});
else
s.push(i);
}
const std::vector<int> snapshot = [&]
{
std::vector<int> vv;
vv.reserve(s.size());
for (auto const &e : s)
{
std::visit([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) vv.push_back(x);
else vv.push_back(x.v); }, e);
}
return vv;
}();
ThrowOnCopy::copy_count = 0;
ThrowOnCopy::throw_after = 3;
const auto old_size = s.size();
const auto old_cap = s.capacity();
bool threw = false;
try
{
s.reserve(old_cap + 8); // 触发重分配 → 拷贝途中抛异常
}
catch (std::runtime_error const &)
{
threw = true;
}
ThrowOnCopy::throw_after = INT_MAX;
assert(threw);
assert(s.size() == old_size); // 强保证:大小不变
std::vector<int> after;
after.reserve(s.size());
for (auto const &e : s)
{
std::visit([&](auto const &x)
{
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) after.push_back(x);
else after.push_back(x.v); }, e);
}
assert(after == snapshot);
}
// ========== 9) 生命周期泄漏检查 ==========
{
int before = Counted::live;
{
SmallStack<4, Counted> s;
for (int i = 0; i < 16; ++i)
s.emplace<Counted>(i);
assert(Counted::live >= before + 16);
s.clear();
assert(s.empty());
}
assert(Counted::live == before);
}
// ========== 10) 顶部访问与异常边界 ==========
{
Stack<int> s;
bool threw = false;
try
{
(void)s.top();
}
catch (std::out_of_range const &)
{
threw = true;
}
assert(threw);
s.push(7);
assert(std::get<int>(s.top()) == 7);
s.pop();
assert(s.empty());
}
std::cout << "[OK] all saturated tests passed.\n";
return 0;
}