Bug Summary

File:root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp
Warning:line 247, column 60
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name kimi-linear.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +avx -target-feature +avx2 -target-feature +bmi2 -target-feature +f16c -target-feature +fma -target-feature +sse4.2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/llama.cpp -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/llama.cpp -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D _GNU_SOURCE=1 -D GGML_USE_CPU=1 -D GGML_VERSION="GGML_VERSION" -D GGML_COMMIT="GGML_COMMIT" -D GGML_SHARED=1 -D LLAMA_SHARED=1 -D GGML_BUILD=1 -D LLAMA_BUILD=1 -D GGML_BACKEND_SHARED=1 -D GGML_BACKEND_BUILD=1 -D MOZ_HAS_MOZGLUE -I /root/firefox-clang/third_party/llama.cpp -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/llama.cpp -I /root/firefox-clang/third_party/llama.cpp/ggml -I /root/firefox-clang/third_party/llama.cpp/ggml/include -I /root/firefox-clang/third_party/llama.cpp/ggml/src -I /root/firefox-clang/third_party/llama.cpp/ggml/src/ggml-cpu -I /root/firefox-clang/third_party/llama.cpp/include -I /root/firefox-clang/third_party/llama.cpp/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-sign-compare -Wno-unused-function -Wno-tautological-unsigned-enum-zero-compare -Wno-implicit-fallthrough -Wno-unreachable-code -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp

/root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp

1#include "llama-memory-recurrent.h"
2#include "models.h"
3
4void llama_model_kimi_linear::load_arch_hparams(llama_model_loader & ml) {
5 ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
6 ml.get_key(LLM_KV_ATTENTION_KEY_LENGTH_MLA, hparams.n_embd_head_k_mla_impl);
7 ml.get_key(LLM_KV_ATTENTION_VALUE_LENGTH_MLA, hparams.n_embd_head_v_mla_impl);
8 ml.get_key(LLM_KV_ATTENTION_KV_LORA_RANK, hparams.n_lora_kv);
9 ml.get_key(LLM_KV_SSM_CONV_KERNEL, hparams.ssm_d_conv);
10 ml.get_key(LLM_KV_KDA_HEAD_DIM, hparams.n_embd_head_kda);
11
12 // MLA qk_rope_head_dim (for reference)
13 // qk_rope_head_dim = 64, qk_nope_head_dim = 128, qk_head_dim = 192
14
15 // Mark KDA layers as recurrent using n_head_kv pattern (like Jamba)
16 // Set n_head_kv = 0 for KDA layers (recurrent), n_head_kv = n_head for MLA layers (attention)
17 for (uint32_t i = 0; i < hparams.n_layer(); ++i) {
18 hparams.is_recr_impl[i] = hparams.n_head_kv(i) == 0; // KDA layers are recurrent
19 }
20
21 // MoE parameters - Kimi uses moe_intermediate_size = 1024
22 ml.get_key(LLM_KV_EXPERT_FEED_FORWARD_LENGTH, hparams.n_ff_exp);
23 ml.get_key(LLM_KV_EXPERT_SHARED_COUNT, hparams.n_expert_shared);
24 ml.get_key(LLM_KV_LEADING_DENSE_BLOCK_COUNT, hparams.n_layer_dense_lead, false);
25 ml.get_key(LLM_KV_EXPERT_WEIGHTS_SCALE, hparams.expert_weights_scale, false);
26 ml.get_key(LLM_KV_EXPERT_GATING_FUNC, hparams.expert_gating_func);
27
28 switch (hparams.n_layer()) {
29 case 27: type = LLM_TYPE_48B_A3B; break; // Kimi-Linear-48B-A3B
30 default: type = LLM_TYPE_UNKNOWN;
31 }
32}
33
34void llama_model_kimi_linear::load_arch_tensors(llama_model_loader &) {
35 LLAMA_LOAD_LOCALSconst int n_layer = hparams.n_layer(); (void)(n_layer); const
int n_layer_all = hparams.n_layer_all; (void)(n_layer_all); const
int n_layer_nextn = hparams.n_layer_nextn; (void)(n_layer_nextn
); const int64_t n_head = hparams.n_head(); (void)(n_head); const
int64_t n_head_kv = hparams.n_head_kv(); (void)(n_head_kv); const
int64_t n_embd = hparams.n_embd; (void)(n_embd); const int64_t
n_embd_k_gqa = hparams.n_embd_k_gqa(); (void)(n_embd_k_gqa);
const int64_t n_embd_v_gqa = hparams.n_embd_v_gqa(); (void)(
n_embd_v_gqa); const int64_t n_embd_head_k = hparams.n_embd_head_k
(); (void)(n_embd_head_k); const int64_t n_embd_head_v = hparams
.n_embd_head_v(); (void)(n_embd_head_v); const int64_t n_ff =
hparams.n_ff(); (void)(n_ff); const int64_t n_embd_gqa = n_embd_v_gqa
; (void)(n_embd_gqa); const int64_t n_vocab = vocab.n_tokens(
); (void)(n_vocab); const int64_t n_token_types = vocab.n_token_types
(); (void)(n_token_types); const int64_t n_rot = hparams.n_rot
(); (void)(n_rot); const int64_t n_expert = hparams.n_expert;
(void)(n_expert); const int64_t n_expert_used = hparams.n_expert_used
; (void)(n_expert_used); const int64_t n_ctx_train = hparams.
n_ctx_train; (void)(n_ctx_train);
;
36
37 tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
38
39 // output
40 output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
41 output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, 0);
42
43 for (int i = 0; i < n_layer; ++i) {
44 auto & layer = layers[i];
45
46 layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
47
48 // Check for KDA specific tensors to determine layer type or if it's a mixed model
49 // Assuming KDA layer if KDA tensors are present
50
51 // KDA uses head_dim = 128 (from linear_attn_config.head_dim)
52 const int64_t n_embd_head_k_kda = hparams.n_embd_head_kda;
53 const int64_t n_embd_head_v_kda = hparams.n_embd_head_kda;
54 const int64_t ssm_d_conv = hparams.ssm_d_conv;
55
56 if (hparams.is_recr(i)) {
57 // Conv1d weights: try 4D first, then 3D (quantization may remove trailing 1)
58 // 4D: [d_conv, 1, d_inner, 1], 3D: [d_conv, 1, d_inner]
59 layer.ssm_q_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_Q, "weight", i), {ssm_d_conv, 1, n_embd_head_k_kda * n_head, 1}, TENSOR_NOT_REQUIRED);
60 if (!layer.ssm_q_conv) {
61 layer.ssm_q_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_Q, "weight", i), {ssm_d_conv, 1, n_embd_head_k_kda * n_head}, 0);
62 }
63
64 // KDA Layer - Conv1d weights may be 3D or 4D
65 layer.ssm_k_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_K, "weight", i), {ssm_d_conv, 1, n_embd_head_k_kda * n_head, 1}, TENSOR_NOT_REQUIRED);
66 if (!layer.ssm_k_conv) {
67 layer.ssm_k_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_K, "weight", i), {ssm_d_conv, 1, n_embd_head_k_kda * n_head}, 0);
68 }
69 layer.ssm_v_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_V, "weight", i), {ssm_d_conv, 1, n_embd_head_v_kda * n_head, 1}, TENSOR_NOT_REQUIRED);
70 if (!layer.ssm_v_conv) {
71 layer.ssm_v_conv = create_tensor(tn(LLM_TENSOR_SSM_CONV1D_V, "weight", i), {ssm_d_conv, 1, n_embd_head_v_kda * n_head}, 0);
72 }
73
74 // q, k, v projections
75 // Python: q_proj, k_proj, v_proj
76 create_tensor_qkv(layer, i, n_embd, n_embd_head_k_kda * n_head, n_embd_head_k_kda * n_head, n_embd_head_v_kda * n_head, 0);
77
78 // KDA specific projections
79 // f_a_proj, f_b_proj
80 layer.ssm_f_a = create_tensor(tn(LLM_TENSOR_SSM_F_A, "weight", i), {n_embd, n_embd_head_k_kda}, 0); // head_dim
81 layer.ssm_f_b = create_tensor(tn(LLM_TENSOR_SSM_F_B, "weight", i), {n_embd_head_k_kda, n_embd_head_k_kda * n_head}, 0); // projection_size
82
83 // b_proj (beta mixing coefficient)
84 layer.ssm_beta = create_tensor(tn(LLM_TENSOR_SSM_BETA, "weight", i), {n_embd, n_head}, 0);
85
86 // A_log - Shape in GGUF: [1, num_heads, 1, 1] (4D) or [1, num_heads] (2D after quantization) Note: -exp(A_log) is applied in convert_hf_to_gguf.py
87 layer.ssm_a = create_tensor(tn(LLM_TENSOR_SSM_A, i), {1, n_head, 1, 1}, TENSOR_NOT_REQUIRED);
88 if (!layer.ssm_a) {
89 layer.ssm_a = create_tensor(tn(LLM_TENSOR_SSM_A, i), {1, n_head}, 0);
90 }
91
92 // dt_bias - shape [n_embd_head_k_kda * n_head] = [4096]
93 layer.ssm_dt_b = create_tensor(tn(LLM_TENSOR_SSM_DT, "bias", i), {n_embd_head_k_kda * n_head}, 0);
94
95 // g_a_proj, g_b_proj (output gate)
96 layer.ssm_g_a = create_tensor(tn(LLM_TENSOR_SSM_G_A, "weight", i), {n_embd, n_embd_head_k_kda}, 0);
97 layer.ssm_g_b = create_tensor(tn(LLM_TENSOR_SSM_G_B, "weight", i), {n_embd_head_k_kda, n_embd_head_k_kda * n_head}, 0);
98
99 // o_norm (reusing SSM_NORM)
100 layer.ssm_o_norm = create_tensor(tn(LLM_TENSOR_SSM_NORM, "weight", i), {n_embd_head_k_kda}, 0); // FusedRMSNormGated
101
102 // o_proj
103 layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_head_v_kda * n_head, n_embd}, 0);
104
105 } else {
106 // MLA Layer - use MLA-specific head dimensions
107 const int64_t q_lora_rank = hparams.n_lora_q;
108 const int64_t kv_lora_rank = hparams.n_lora_kv;
109 const int64_t n_embd_head_k_mla = hparams.n_embd_head_k_mla();
110 const int64_t n_embd_head_v_mla = hparams.n_embd_head_v_mla();
111
112 layer.attn_q_a_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_A_NORM, "weight", i), {q_lora_rank}, TENSOR_NOT_REQUIRED);
113 layer.attn_kv_a_norm = create_tensor(tn(LLM_TENSOR_ATTN_KV_A_NORM, "weight", i), {kv_lora_rank}, 0);
114
115 if (layer.attn_q_a_norm) {
116 layer.wq_a = create_tensor(tn(LLM_TENSOR_ATTN_Q_A, "weight", i), {n_embd, q_lora_rank}, 0);
117 layer.wq_b = create_tensor(tn(LLM_TENSOR_ATTN_Q_B, "weight", i), {q_lora_rank, n_head * n_embd_head_k_mla}, 0);
118 } else {
119 // Kimi MLA without Q compression: wq = [n_embd, n_head * n_embd_head_k_mla]
120 layer.wq = create_tensor(tn(LLM_TENSOR_ATTN_Q, "weight", i), {n_embd, n_head * n_embd_head_k_mla}, 0);
121 }
122
123 // Kimi: qk_rope_head_dim = 64 (actual RoPE dimension for MLA)
124 // Note: hparams.n_rot may be 72 (from conversion) but actual is 64
125 const int64_t qk_rope_head_dim = hparams.n_rot(); // From config: qk_rope_head_dim
126 layer.wkv_a_mqa = create_tensor(tn(LLM_TENSOR_ATTN_KV_A_MQA, "weight", i), {n_embd, kv_lora_rank + qk_rope_head_dim}, 0);
127 // Support Legacy GGUFs that don't split wkv_b (MLA KV cache disabled)
128 layer.wkv_b = create_tensor(tn(LLM_TENSOR_ATTN_KV_B, "weight", i),
129 {kv_lora_rank, n_head * (n_embd_head_k_mla - qk_rope_head_dim + n_embd_head_v_mla)}, TENSOR_NOT_REQUIRED | TENSOR_SKIP_IF_VIRTUAL);
130 if (!layer.wkv_b) { // MLA KV cache enabled
131 layer.wk_b = create_tensor(tn(LLM_TENSOR_ATTN_K_B, "weight", i), {n_embd_head_k_mla - qk_rope_head_dim, kv_lora_rank, n_head}, 0);
132 layer.wv_b = create_tensor(tn(LLM_TENSOR_ATTN_V_B, "weight", i), {kv_lora_rank, n_embd_head_v_mla, n_head}, 0);
133 }
134 layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_head * n_embd_head_v_mla, n_embd}, 0);
135 }
136
137 layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
138
139 // MoE intermediate size (different from dense FFN)
140 const int64_t n_ff_exp = hparams.n_ff_exp;
141
142 // Kimi uses n_layer_dense_lead to determine which layers use dense FFN vs MoE
143 // first_k_dense_replace = 1 means layer 0 uses dense FFN, layers 1+ use MoE
144 if (i < (int) hparams.n_layer_dense_lead) {
145 // Dense FFN layer - use normal n_ff
146 layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
147 layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}, 0);
148 layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
149 } else {
150 // MoE layer - use n_ff_exp (1024) instead of n_ff (9216)
151 layer.ffn_gate_inp = create_tensor(tn(LLM_TENSOR_FFN_GATE_INP, "weight", i), {n_embd, n_expert}, 0);
152 layer.ffn_gate_exps = create_tensor(tn(LLM_TENSOR_FFN_GATE_EXPS, "weight", i), {n_embd, n_ff_exp, n_expert}, 0);
153 layer.ffn_down_exps = create_tensor(tn(LLM_TENSOR_FFN_DOWN_EXPS, "weight", i), {n_ff_exp, n_embd, n_expert}, 0);
154 layer.ffn_up_exps = create_tensor(tn(LLM_TENSOR_FFN_UP_EXPS, "weight", i), {n_embd, n_ff_exp, n_expert}, 0);
155
156 // Shared experts use moe_intermediate_size * num_shared_experts
157 // Kimi: shared_expert_intermediate_size = 1024 * 1 = 1024
158 // Tensors are 2D: [n_embd, n_ff_shexp] or [n_ff_shexp, n_embd]
159 const int64_t n_ff_shexp_actual = n_ff_exp * (hparams.n_expert_shared > 0 ? hparams.n_expert_shared : 1);
160 layer.ffn_gate_shexp = create_tensor(tn(LLM_TENSOR_FFN_GATE_SHEXP, "weight", i), {n_embd, n_ff_shexp_actual}, TENSOR_NOT_REQUIRED);
161 layer.ffn_down_shexp = create_tensor(tn(LLM_TENSOR_FFN_DOWN_SHEXP, "weight", i), {n_ff_shexp_actual, n_embd}, TENSOR_NOT_REQUIRED);
162 layer.ffn_up_shexp = create_tensor(tn(LLM_TENSOR_FFN_UP_SHEXP, "weight", i), {n_embd, n_ff_shexp_actual}, TENSOR_NOT_REQUIRED);
163
164 layer.ffn_exp_probs_b = create_tensor(tn(LLM_TENSOR_FFN_EXP_PROBS_B, "bias", i), {n_expert}, 0);
165 }
166 }
167}
168
169std::unique_ptr<llm_graph_context> llama_model_kimi_linear::build_arch_graph(const llm_graph_params & params) const {
170 return std::make_unique<graph>(*this, params);
1
Calling 'make_unique<llama_model_kimi_linear::graph, const llama_model_kimi_linear &, const llm_graph_params &>'
171}
172
173// Causal Conv1d function for Q,K,V
174// When qkv is 0, it is Q, 1 is K, 2 is V
175static ggml_tensor * causal_conv1d(ggml_cgraph * gf, ggml_context * ctx0, ggml_tensor * conv_states_all, ggml_tensor * conv_state_all, int64_t qkv, ggml_tensor * x, ggml_tensor * proj_w, ggml_tensor * conv_w, int64_t d_conv, int64_t head_dim, int64_t n_head, int64_t n_seq_tokens, int64_t n_seqs, int64_t n_tokens, int64_t kv_head) {
176 const int64_t d_inner = head_dim * n_head;
177 const int64_t conv_state_size = (d_conv - 1) * d_inner;
178 const int64_t n_embd_r_total = 3 * conv_state_size; // Q + K + V
179
180 // conv_state_all is [n_embd_r_total, n_seqs], split into Q, K, V
181 // Each conv state is [(d_conv-1) * d_inner] per sequence, need to reshape to [d_conv-1, d_inner, n_seqs]
182 // Memory layout: for each seq, Q state is first conv_state_size elements, then K, then V
183 // conv_state_all has stride: nb[0] = element_size, nb[1] = n_embd_r_total * element_size
184 // View Q conv state: offset 0, size conv_state_size per seq
185 // conv_state_all is [n_embd_r_total, n_seqs] with memory layout:
186 // state[i + seq * n_embd_r_total] where i = conv_step + channel * (d_conv-1) + {0, conv_state_size, 2*conv_state_size} for Q/K/V
187 // We want [d_conv-1, d_inner, n_seqs] view:
188 // nb1 = (d_conv-1) * element_size (stride between channels)
189 // nb2 = n_embd_r_total * element_size (stride between seqs)
190 ggml_tensor * conv_state_x = ggml_view_3d(ctx0, conv_state_all, d_conv - 1, d_inner, n_seqs,
191 (d_conv - 1) * ggml_element_size(conv_state_all), // nb1: stride between channels
192 n_embd_r_total * ggml_element_size(conv_state_all), // nb2: stride between seqs
193 qkv * conv_state_size * ggml_element_size(conv_state_all));
194
195// Causal Conv1d function for Q,K,V
196// When qkv is 0, it is Q, 1 is K, 2 is V
197 // Step 1: Q, K, V projections -> [d_inner, n_tokens]
198 ggml_tensor * x_proj = ggml_mul_mat(ctx0, proj_w, x);
199
200 // Reshape input: {d_inner, n_tokens} -> {d_inner, n_seq_tokens, n_seqs}
201 ggml_tensor * x_3d = ggml_reshape_3d(ctx0, x_proj, d_inner, n_seq_tokens, n_seqs);
202
203 // Concat Q conv state and current input: {d_conv-1 + n_seq_tokens, d_inner, n_seqs}
204 ggml_tensor * conv_x = ggml_concat(ctx0, conv_state_x, ggml_transpose(ctx0, x_3d), 0);
205
206 // Save last (d_conv-1) columns back to Q conv state
207 ggml_tensor * last_conv_x = ggml_view_3d(ctx0, conv_x, d_conv - 1, d_inner, n_seqs,
208 conv_x->nb[1], conv_x->nb[2], n_seq_tokens * conv_x->nb[0]);
209 ggml_build_forward_expand(gf,
210 ggml_cpy(ctx0, last_conv_x,
211 ggml_view_3d(ctx0, conv_states_all,
212 d_conv - 1, d_inner, n_seqs,
213 (d_conv - 1) * ggml_element_size(conv_states_all), // nb1: contiguous within one channel's conv taps
214 n_embd_r_total * ggml_element_size(conv_states_all), // nb2: stride between sequences (skip over K,V states)
215 (kv_head * n_embd_r_total + qkv * conv_state_size) * ggml_element_size(conv_states_all)))); // offset to first seq's Q/K/V state
216 // Reshape conv weight: GGUF [d_conv, 1, d_inner, 1] -> ggml_ssm_conv expects [d_conv, d_inner]
217 // GGUF stores as [d_conv, 1, d_inner, 1] with memory layout w[conv_step + channel * d_conv]
218 // vLLM stores as [d_inner, d_conv] with memory layout w[channel * d_conv + conv_step]
219 // ggml_ssm_conv computes: c[conv_step + channel * d_conv]
220 // GGUF layout: [d_conv, 1, d_inner] or [d_conv, 1, d_inner, 1] -> reshape to [d_conv, d_inner]
221 // Reshape conv weight from [d_conv, 1, d_inner, 1] to [d_conv, d_inner] for ggml_ssm_conv
222 ggml_tensor * conv_weight = ggml_reshape_2d(ctx0, conv_w, d_conv, d_inner);
223
224 // Apply conv1d
225 // ggml_ssm_conv output: {d_inner, n_seq_tokens, n_seqs}
226 ggml_tensor * Xcur = ggml_ssm_conv(ctx0, conv_x, conv_weight);
227 // Reshape to 2D for bias add: {d_inner, n_tokens}
228 Xcur = ggml_reshape_2d(ctx0, Xcur, d_inner, n_tokens);
229 Xcur = ggml_silu(ctx0, Xcur);
230
231 return ggml_reshape_4d(ctx0, Xcur, head_dim, n_head, n_seq_tokens, n_seqs);
232}
233
234llama_model_kimi_linear::graph::graph(const llama_model & model, const llm_graph_params & params) :
235 llm_build_delta_net_base(params), model(model) {
236 ggml_tensor * cur;
237 ggml_tensor * inpL;
238
239 inpL = build_inp_embd(model.tok_embd);
240 cb(inpL, "model.embed_tokens", -1);
241
242 // Note: Kimi MLA does NOT use RoPE (rotary_emb=None in vLLM)
243 // So we don't need inp_pos
244
245 auto * inp_kv = !hparams.is_mla() ? build_inp_mem_hybrid() : nullptr;
3
Assuming the condition is false
4
'?' condition is false
5
'inp_kv' initialized to a null pointer value
246 auto * inp_k = hparams.is_mla() ? build_inp_mem_hybrid_k() : nullptr;
6
Assuming the condition is false
7
'?' condition is false
247 auto * inp_rs = hparams.is_mla() ? inp_k->get_recr() : inp_kv->get_recr();
8
Assuming the condition is false
9
'?' condition is false
10
Called C++ object pointer is null
248 auto * inp_attn_kv = !hparams.is_mla() ? inp_kv->get_attn() : nullptr;
249 auto * inp_attn_k = hparams.is_mla() ? inp_k->get_attn() : nullptr;
250
251 // Output ids for selecting which tokens to output
252 ggml_tensor * inp_out_ids = build_inp_out_ids();
253
254 // Kimi dimension constants
255 const int64_t n_head = hparams.n_head();
256 const int64_t head_dim = hparams.n_embd_head_kda;
257 const int64_t d_conv = hparams.ssm_d_conv;
258 const int64_t d_inner = n_head * head_dim; // 32 * 128 = 4096
259 const int64_t n_seqs = ubatch.n_seqs;
260 const int64_t n_seq_tokens = ubatch.n_seq_tokens;
261
262 // Verify batch consistency for recurrent layers
263 GGML_ASSERT(n_seqs != 0)if (!(n_seqs != 0)) ggml_abort("/root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp"
, 263, "GGML_ASSERT(%s) failed", "n_seqs != 0")
;
264 GGML_ASSERT(ubatch.equal_seqs())if (!(ubatch.equal_seqs())) ggml_abort("/root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp"
, 264, "GGML_ASSERT(%s) failed", "ubatch.equal_seqs()")
;
265 GGML_ASSERT(ubatch.n_tokens == n_seq_tokens * n_seqs)if (!(ubatch.n_tokens == n_seq_tokens * n_seqs)) ggml_abort("/root/firefox-clang/third_party/llama.cpp/src/models/kimi-linear.cpp"
, 265, "GGML_ASSERT(%s) failed", "ubatch.n_tokens == n_seq_tokens * n_seqs"
)
;
266
267 // MLA params
268 const int64_t n_embd_head_k_mla = hparams.n_embd_head_k_mla();
269 const int64_t n_embd_head_v_mla = hparams.n_embd_head_v_mla();
270 const int64_t kv_lora_rank = hparams.n_lora_kv;
271 // qk_rope_head_dim = 64 (from Kimi config) which is hparams.n_rot
272 // Confirmed from tensor shape: wkv_a_mqa [2304, 576] = [n_embd, kv_lora_rank + qk_rope_head_dim]
273 const int64_t n_embd_head_qk_rope = hparams.n_rot(); // config.qk_rope_head_dim
274 const int64_t n_embd_head_qk_nope = n_embd_head_k_mla - n_embd_head_qk_rope; // 192 - 64 = 128
275 // Attention scale for MLA
276 const float kq_scale_mla = 1.0f / sqrtf((float)n_embd_head_k_mla);
277
278 for (int il = 0; il < n_layer; ++il) {
279 const auto & layer = model.layers[il];
280 ggml_tensor * inpSA = inpL;
281
282 // Attention Norm
283 cur = build_norm(inpL, layer.attn_norm, NULL__null, LLM_NORM_RMS, il);
284 cb(cur, "attn_norm", il);
285
286 ggml_build_forward_expand(gf, cur);
287
288 if (hparams.is_recr(il)) {
289 // === KDA Layer (Kimi Delta Attention) with Recurrent State ===
290 // Reference: vLLM kda.py
291 const auto * mctx_cur = inp_rs->mctx;
292 const auto kv_head = mctx_cur->get_head();
293
294 // Get conv states from r_l tensor (Q, K, V each have separate state)
295 ggml_tensor * conv_states_all = mctx_cur->get_r_l(il);
296 cb(conv_states_all, "conv_states_all", il);
297 ggml_tensor * conv_state_all = build_rs(inp_rs, conv_states_all, hparams.n_embd_r(), n_seqs);
298 ggml_tensor * Qcur = causal_conv1d(gf, ctx0, conv_states_all, conv_state_all, 0, cur, layer.wq, layer.ssm_q_conv, d_conv, head_dim, n_head, n_seq_tokens, n_seqs, n_tokens, kv_head);
299 ggml_tensor * Kcur = causal_conv1d(gf, ctx0, conv_states_all, conv_state_all, 1, cur, layer.wk, layer.ssm_k_conv, d_conv, head_dim, n_head, n_seq_tokens, n_seqs, n_tokens, kv_head);
300 ggml_tensor * Vcur = causal_conv1d(gf, ctx0, conv_states_all, conv_state_all, 2, cur, layer.wv, layer.ssm_v_conv, d_conv, head_dim, n_head, n_seq_tokens, n_seqs, n_tokens, kv_head);
301
302 // g1 = -exp(A_log) * softplus(f_b(f_a(x)) + dt_bias)
303 ggml_tensor * f_a = ggml_mul_mat(ctx0, layer.ssm_f_a, cur);
304 ggml_tensor * g1 = ggml_mul_mat(ctx0, layer.ssm_f_b, f_a);
305 cb(g1, "g1 f_b(f_a(cur))", il);
306 g1 = ggml_add(ctx0, g1, layer.ssm_dt_b);
307 g1 = ggml_softplus(ctx0, g1);
308 g1 = ggml_reshape_3d(ctx0, g1, head_dim, n_head, n_tokens);
309
310 // A_log shape is [1, n_head] or [1, n_head, 1, 1], need to broadcast to [head_dim, n_head, n_tokens]. No need to -exp(a_log) because it was done in convert_hf_to_gguf.py
311 // Reshape to [1, n_head, 1] for broadcasting with g1 [head_dim, n_head, n_tokens]
312 ggml_tensor * A = ggml_reshape_3d(ctx0, layer.ssm_a, 1, n_head, 1);
313 g1 = ggml_mul(ctx0, g1, A);
314 cb(g1, "kda_g1", il);
315
316 g1 = ggml_reshape_4d(ctx0, g1, head_dim, n_head, n_seq_tokens, n_seqs);
317
318 // Compute beta (mixing coefficient)
319 ggml_tensor * beta = ggml_mul_mat(ctx0, layer.ssm_beta, cur);
320 beta = ggml_reshape_4d(ctx0, beta, 1, n_head, n_seq_tokens, n_seqs);
321 cb(beta, "kda_beta", il);
322
323 beta = ggml_sigmoid(ctx0, beta);
324
325 // Reshape for KDA recurrence
326 // {n_embd, n_tokens} -> {n_embd, n_seq_tokens, n_seqs}
327 cur = ggml_reshape_3d(ctx0, cur, cur->ne[0], n_seq_tokens, n_seqs);
328
329 // Get SSM state and compute KDA recurrence using ggml_kda_scan
330 ggml_tensor * ssm_states_all = mctx_cur->get_s_l(il);
331 ggml_tensor * state = build_rs(inp_rs, ssm_states_all, hparams.n_embd_s(), n_seqs);
332 state = ggml_reshape_4d(ctx0, state, head_dim, head_dim, n_head, n_seqs);
333
334 const float eps_norm = hparams.f_norm_rms_eps;
335
336 Qcur = ggml_l2_norm(ctx0, Qcur, eps_norm);
337 Kcur = ggml_l2_norm(ctx0, Kcur, eps_norm);
338
339 // Choose between build_delta_net_chunking and build_delta_net_recurrent based on n_tokens
340 auto attn_out = build_delta_net(Qcur, Kcur, Vcur, g1, beta, state, il);
341
342 ggml_tensor * output = ggml_cont(ctx0, attn_out.first);
343 ggml_tensor * new_state = attn_out.second;
344 cb(output, "attn_output", il);
345 cb(new_state, "new_state", il);
346
347 // Update the recurrent states
348 ggml_build_forward_expand(gf,
349 ggml_cpy(ctx0, new_state,
350 ggml_view_1d(ctx0, ssm_states_all, hparams.n_embd_s() * n_seqs,
351 kv_head * hparams.n_embd_s() * ggml_element_size(ssm_states_all))));
352
353 // Output gating g2 = g_b(g_a(x))
354 ggml_tensor * cur_2d = ggml_reshape_2d(ctx0, cur, cur->ne[0], n_seq_tokens * n_seqs);
355 ggml_tensor * g_a = ggml_mul_mat(ctx0, layer.ssm_g_a, cur_2d);
356 ggml_tensor * g2 = ggml_mul_mat(ctx0, layer.ssm_g_b, g_a);
357 cb(g2, "g2 g_b(g_a(cur_2d))", il);
358 g2 = ggml_reshape_3d(ctx0, g2, head_dim, n_head, n_seq_tokens * n_seqs);
359
360 // Apply o_norm with sigmoid gating
361 // Note: Kimi model uses sigmoid gating, not SiLU (despite FusedRMSNormGated default being swish)
362 // Formula: output = RMSNorm(x) * sigmoid(g)
363 ggml_tensor * attn_out_final = ggml_reshape_3d(ctx0, output, head_dim, n_head, n_seq_tokens * n_seqs);
364 ggml_tensor * normed = build_norm(attn_out_final, layer.ssm_o_norm, nullptr, LLM_NORM_RMS, il);
365 cb(normed, "kda_normed", il);
366 ggml_tensor * gate = ggml_sigmoid(ctx0, g2);
367 ggml_tensor * gated = ggml_mul(ctx0, normed, gate);
368
369 // Output projection
370 gated = ggml_cont_2d(ctx0, gated, d_inner, n_tokens);
371 cur = ggml_mul_mat(ctx0, layer.wo, gated);
372 cb(cur, "kda_out", il);
373
374 } else {
375 // === MLA Layer (Multi-head Latent Attention) without KV Cache ===
376 // Reference: vLLM mla.py
377 // Step 1: Q projection and reshape
378 // vLLM Kimi: q = q_proj(hidden_states), then view as [n_tokens, n_head, qk_head_dim]
379 // Note: Kimi MLA does NOT use RoPE (rotary_emb=None in vLLM)
380 ggml_tensor * Qcur = ggml_mul_mat(ctx0, layer.wq, cur);
381
382 // Step 2: KV compression
383 // kv_cmpr_pe = kv_a_proj_with_mqa(hidden_states) -> [kv_lora_rank + qk_rope_head_dim, n_tokens]
384 ggml_tensor * kv_cmpr_pe = ggml_mul_mat(ctx0, layer.wkv_a_mqa, cur);
385
386 // Split: kv_cmpr = kv_lora[:kv_lora_rank], k_pe = kv_lora[kv_lora_rank:]
387 ggml_tensor * kv_cmpr = ggml_view_2d(ctx0, kv_cmpr_pe, kv_lora_rank, n_tokens,
388 ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope), 0);
389 ggml_tensor * k_pe = ggml_view_3d(ctx0, kv_cmpr_pe, n_embd_head_qk_rope, 1, n_tokens,
390 ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope),
391 ggml_row_size(kv_cmpr_pe->type, kv_lora_rank + n_embd_head_qk_rope),
392 ggml_row_size(kv_cmpr_pe->type, kv_lora_rank));
393 // Note: Kimi MLA does NOT apply RoPE (rotary_emb=None in vLLM)
394 // k_pe is used directly without RoPE
395 // Normalize kv_c
396 kv_cmpr = build_norm(kv_cmpr, layer.attn_kv_a_norm, nullptr, LLM_NORM_RMS, il);
397
398 if (layer.wk_b && layer.wv_b) { // MLA KV cache enabled
399 // extract q_nope
400 ggml_tensor * q_nope =
401 ggml_view_3d(ctx0, Qcur, n_embd_head_qk_nope, n_head, n_tokens, ggml_row_size(Qcur->type, n_embd_head_k_mla),
402 ggml_row_size(Qcur->type, n_embd_head_k_mla) * n_head, 0);
403 cb(q_nope, "q_nope", il);
404
405 // and {n_embd_head_qk_rope, n_head, n_tokens}
406 ggml_tensor * q_pe = ggml_view_3d(
407 ctx0, Qcur, n_embd_head_qk_rope, n_head, n_tokens, ggml_row_size(Qcur->type, n_embd_head_k_mla),
408 ggml_row_size(Qcur->type, n_embd_head_k_mla) * n_head, ggml_row_size(Qcur->type, n_embd_head_qk_nope));
409 cb(q_pe, "q_pe", il);
410
411 // {n_embd_head_qk_nope, n_tokens, n_head}
412 q_nope = ggml_permute(ctx0, q_nope, 0, 2, 1, 3);
413 cb(q_nope, "q_nope_perm", il);
414
415 // {n_embd_head_qk_nope, kv_lora_rank, n_head} x {n_embd_head_qk_nope, n_tokens, n_head}
416 ggml_tensor * q_nope_absorbed = ggml_mul_mat(ctx0, layer.wk_b, q_nope);
417 cb(q_nope_absorbed, "q_nope_absorbed", il);
418
419 // {kv_lora_rank, n_head, n_tokens}
420 q_nope_absorbed = ggml_permute(ctx0, q_nope_absorbed, 0, 2, 1, 3);
421 cb(q_nope_absorbed, "q_nope_absorbed_perm", il);
422
423 // {n_embd_head_qk_rope + kv_lora_rank, n_head, n_tokens}
424 // note: rope must go first for in-place context shifting in build_rope_shift()
425 Qcur = ggml_concat(ctx0, q_nope_absorbed, q_pe, 0);
426 cb(Qcur, "Qcur", il);
427
428 kv_cmpr = ggml_reshape_3d(ctx0, kv_cmpr, kv_lora_rank, 1, n_tokens);
429 cb(kv_cmpr, "kv_cmpr_reshape", il);
430
431 // {n_embd_head_qk_rope + kv_lora_rank, 1, n_tokens}
432 ggml_tensor * Kcur = ggml_concat(ctx0, kv_cmpr, k_pe, 0);
433 cb(Kcur, "Kcur", il);
434
435 // {kv_lora_rank, 1, n_tokens}
436 ggml_tensor * Vcur = kv_cmpr;
437 cb(Vcur, "Vcur", il);
438
439 cur = build_attn(inp_attn_k, layer.wo, NULL__null, layer.wo_s, Qcur, Kcur, Vcur, nullptr, nullptr, layer.wv_b, kq_scale_mla, il);
440 cb(cur, "mla_out", il);
441 } else { // MLA KV cache disabled. Fall back to MHA KV cache.
442 Qcur = ggml_reshape_3d(ctx0, Qcur, n_embd_head_k_mla, n_head, n_tokens);
443 cb(Qcur, "mla_Q", il);
444 // KV decompression: kv = kv_b_proj(kv_c_normed)
445 ggml_tensor * kv = ggml_mul_mat(ctx0, layer.wkv_b, kv_cmpr);
446 const int64_t kv_per_head = n_embd_head_qk_nope + n_embd_head_v_mla;
447
448 // Split kv into k_nope and v
449 ggml_tensor * k_nope = ggml_view_3d(ctx0, kv, n_embd_head_qk_nope, n_head, n_tokens,
450 ggml_row_size(kv->type, kv_per_head),
451 ggml_row_size(kv->type, kv_per_head * n_head), 0);
452 ggml_tensor * Vcur = ggml_view_3d(ctx0, kv, n_embd_head_v_mla, n_head, n_tokens,
453 ggml_row_size(kv->type, kv_per_head),
454 ggml_row_size(kv->type, kv_per_head * n_head),
455 ggml_row_size(kv->type, n_embd_head_qk_nope));
456 Vcur = ggml_cont(ctx0, Vcur);
457 cb(Vcur, "mla_V", il);
458
459 // Concatenate k_nope + k_pe (broadcast k_pe to all heads)
460 // K = [k_nope, k_pe] where k_nope is [qk_nope_head_dim, n_head, n_tokens]
461 // and k_pe is [qk_rope_head_dim, 1, n_tokens] broadcast to all heads
462 // Need to broadcast k_pe from [qk_rope, 1, n_tokens] to [qk_rope, n_head, n_tokens]
463 ggml_tensor * k_pe_target = ggml_new_tensor_3d(ctx0, k_pe->type, n_embd_head_qk_rope, n_head, n_tokens);
464 ggml_tensor * k_pe_repeated = ggml_repeat(ctx0, k_pe, k_pe_target);
465 ggml_tensor * Kcur = ggml_concat(ctx0, k_pe_repeated, k_nope, 0);
466 cb(Kcur, "mla_K", il);
467
468 // Direct softmax attention (with MHA KV cache)
469 // Use build_attn with inp_attn for proper mask handling
470 cur = build_attn(inp_attn_kv, layer.wo, NULL__null, layer.wo_s, Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, kq_scale_mla, il);
471 cb(cur, "mla_out", il);
472 }
473 }
474
475 // On last layer, select only the output tokens
476 if (il == n_layer - 1 && inp_out_ids) {
477 cur = ggml_get_rows(ctx0, cur, inp_out_ids);
478 inpSA = ggml_get_rows(ctx0, inpSA, inp_out_ids);
479 }
480
481 // Residual
482 ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
483 cb(ffn_inp, "ffn_inp", il);
484
485 // FFN Norm
486 cur = build_norm(ffn_inp, layer.ffn_norm, NULL__null, LLM_NORM_RMS, il);
487 cb(cur, "ffn_norm", il);
488
489 if ((uint32_t) il < hparams.n_layer_dense_lead) {
490 // Dense FFN layer
491 cur = build_ffn(cur,
492 layer.ffn_up, NULL__null, NULL__null,
493 layer.ffn_gate, NULL__null, NULL__null,
494 layer.ffn_down, NULL__null, NULL__null,
495 NULL__null, LLM_FFN_SILU, LLM_FFN_PAR, il);
496 cb(cur, "ffn_out", il);
497 } else {
498 // MoE layer
499 // Kimi uses moe_renormalize=True and routed_scaling_factor (stored as expert_weights_scale) = 2.446
500 ggml_tensor * moe_out = build_moe_ffn(cur,
501 layer.ffn_gate_inp,
502 layer.ffn_up_exps,
503 layer.ffn_gate_exps,
504 layer.ffn_down_exps,
505 layer.ffn_exp_probs_b,
506 hparams.n_expert,
507 hparams.n_expert_used,
508 LLM_FFN_SILU, true,
509 hparams.expert_weights_scale,
510 (llama_expert_gating_func_type) hparams.expert_gating_func,
511 il);
512 cb(moe_out, "ffn_moe_out", il);
513
514 // Shared expert
515 {
516 ggml_tensor * ffn_shexp = build_ffn(cur,
517 layer.ffn_up_shexp, NULL__null, NULL__null,
518 layer.ffn_gate_shexp, NULL__null, NULL__null,
519 layer.ffn_down_shexp, NULL__null, NULL__null,
520 NULL__null, LLM_FFN_SILU, LLM_FFN_PAR, il);
521 cb(ffn_shexp, "ffn_shexp", il);
522
523 cur = ggml_add(ctx0, moe_out, ffn_shexp);
524 cb(cur, "ffn_out", il);
525 }
526 }
527 // Residual
528 cur = ggml_add(ctx0, cur, ffn_inp);
529
530 cur = build_cvec(cur, il);
531 cb(cur, "l_out", il);
532
533 // input for next layer
534 inpL = cur;
535 }
536 cur = inpL;
537
538 // Final Norm
539 cur = build_norm(cur, model.output_norm, NULL__null, LLM_NORM_RMS, -1);
540
541 cb(cur, "result_norm", -1);
542 res->t_embd = cur;
543
544 // Output
545 cur = ggml_mul_mat(ctx0, model.output, cur);
546 cb(cur, "result_output", -1);
547 res->t_logits = cur;
548
549 ggml_build_forward_expand(gf, cur);
550}

/usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/bits/unique_ptr.h

1// unique_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2008-2026 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/unique_ptr.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _UNIQUE_PTR_H1
31#define _UNIQUE_PTR_H1 1
32
33#include <bits/c++config.h>
34#include <debug/assertions.h>
35#include <type_traits>
36#include <tuple>
37#include <bits/stl_function.h>
38#include <bits/functional_hash.h>
39#if __cplusplus202002L >= 202002L
40# include <compare>
41# if _GLIBCXX_HOSTED1
42# include <bits/ostream.h>
43# endif
44#endif
45
46namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
47{
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
49
50 /**
51 * @addtogroup pointer_abstractions
52 * @{
53 */
54
55#if _GLIBCXX_USE_DEPRECATED1
56#pragma GCC diagnostic push
57#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
58 template<typename> class auto_ptr;
59#pragma GCC diagnostic pop
60#endif
61
62 /** Primary template of default_delete, used by unique_ptr for single objects
63 *
64 * @headerfile memory
65 * @since C++11
66 */
67 template<typename _Tp>
68 struct default_delete
69 {
70 /// Default constructor
71 constexpr default_delete() noexcept = default;
72
73 /** @brief Converting constructor.
74 *
75 * Allows conversion from a deleter for objects of another type, `_Up`,
76 * only if `_Up*` is convertible to `_Tp*`.
77 */
78 template<typename _Up,
79 typename = _Require<is_convertible<_Up*, _Tp*>>>
80 _GLIBCXX23_CONSTEXPR
81 default_delete(const default_delete<_Up>&) noexcept { }
82
83 /// Calls `delete __ptr`
84 _GLIBCXX23_CONSTEXPR
85 void
86 operator()(_Tp* __ptr) const
87 {
88 static_assert(!is_void<_Tp>::value,
89 "can't delete pointer to incomplete type");
90 static_assert(sizeof(_Tp)>0,
91 "can't delete pointer to incomplete type");
92 delete __ptr;
93 }
94 };
95
96 // _GLIBCXX_RESOLVE_LIB_DEFECTS
97 // DR 740 - omit specialization for array objects with a compile time length
98
99 /** Specialization of default_delete for arrays, used by `unique_ptr<T[]>`
100 *
101 * @headerfile memory
102 * @since C++11
103 */
104 template<typename _Tp>
105 struct default_delete<_Tp[]>
106 {
107 public:
108 /// Default constructor
109 constexpr default_delete() noexcept = default;
110
111 /** @brief Converting constructor.
112 *
113 * Allows conversion from a deleter for arrays of another type, such as
114 * a const-qualified version of `_Tp`.
115 *
116 * Conversions from types derived from `_Tp` are not allowed because
117 * it is undefined to `delete[]` an array of derived types through a
118 * pointer to the base type.
119 */
120 template<typename _Up,
121 typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
122 _GLIBCXX23_CONSTEXPR
123 default_delete(const default_delete<_Up[]>&) noexcept { }
124
125 /// Calls `delete[] __ptr`
126 template<typename _Up>
127 _GLIBCXX23_CONSTEXPR
128 typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
129 operator()(_Up* __ptr) const
130 {
131 static_assert(sizeof(_Tp)>0,
132 "can't delete pointer to incomplete type");
133 delete [] __ptr;
134 }
135 };
136
137 /// @cond undocumented
138
139 // Manages the pointer and deleter of a unique_ptr
140 template <typename _Tp, typename _Dp>
141 class __uniq_ptr_impl
142 {
143 template <typename _Up, typename _Ep, typename = void>
144 struct _Ptr
145 {
146 using type = _Up*;
147 };
148
149 template <typename _Up, typename _Ep>
150 struct
151 _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
152 {
153 using type = typename remove_reference<_Ep>::type::pointer;
154 };
155
156 public:
157 using _DeleterConstraint = enable_if<
158 __and_<__not_<is_pointer<_Dp>>,
159 is_default_constructible<_Dp>>::value>;
160
161 using pointer = typename _Ptr<_Tp, _Dp>::type;
162
163 static_assert( !is_rvalue_reference<_Dp>::value,
164 "unique_ptr's deleter type must be a function object type"
165 " or an lvalue reference type" );
166
167 __uniq_ptr_impl() = default;
168 _GLIBCXX23_CONSTEXPR
169 __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
170
171 template<typename _Del>
172 _GLIBCXX23_CONSTEXPR
173 __uniq_ptr_impl(pointer __p, _Del&& __d)
174 : _M_t(__p, std::forward<_Del>(__d)) { }
175
176 _GLIBCXX23_CONSTEXPR
177 __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
178 : _M_t(std::move(__u._M_t))
179 { __u._M_ptr() = nullptr; }
180
181 _GLIBCXX23_CONSTEXPR
182 __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
183 {
184 reset(__u.release());
185 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
186 return *this;
187 }
188
189 _GLIBCXX23_CONSTEXPR
190 pointer& _M_ptr() noexcept { return std::get<0>(_M_t); }
191 _GLIBCXX23_CONSTEXPR
192 pointer _M_ptr() const noexcept { return std::get<0>(_M_t); }
193 _GLIBCXX23_CONSTEXPR
194 _Dp& _M_deleter() noexcept { return std::get<1>(_M_t); }
195 _GLIBCXX23_CONSTEXPR
196 const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); }
197
198 _GLIBCXX23_CONSTEXPR
199 void reset(pointer __p) noexcept
200 {
201 const pointer __old_p = _M_ptr();
202 _M_ptr() = __p;
203 if (__old_p)
204 _M_deleter()(__old_p);
205 }
206
207 _GLIBCXX23_CONSTEXPR
208 pointer release() noexcept
209 {
210 pointer __p = _M_ptr();
211 _M_ptr() = nullptr;
212 return __p;
213 }
214
215 _GLIBCXX23_CONSTEXPR
216 void
217 swap(__uniq_ptr_impl& __rhs) noexcept
218 {
219 using std::swap;
220 swap(this->_M_ptr(), __rhs._M_ptr());
221 swap(this->_M_deleter(), __rhs._M_deleter());
222 }
223
224 private:
225 tuple<pointer, _Dp> _M_t;
226 };
227
228 // Defines move construction + assignment as either defaulted or deleted.
229 template <typename _Tp, typename _Dp,
230 bool = is_move_constructible<_Dp>::value,
231 bool = is_move_assignable<_Dp>::value>
232 struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>
233 {
234 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
235 __uniq_ptr_data(__uniq_ptr_data&&) = default;
236 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
237 };
238
239 template <typename _Tp, typename _Dp>
240 struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp>
241 {
242 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
243 __uniq_ptr_data(__uniq_ptr_data&&) = default;
244 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
245 };
246
247 template <typename _Tp, typename _Dp>
248 struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp>
249 {
250 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
251 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
252 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
253 };
254
255 template <typename _Tp, typename _Dp>
256 struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp>
257 {
258 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
259 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
260 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
261 };
262 /// @endcond
263
264 // 20.7.1.2 unique_ptr for single objects.
265
266 /// A move-only smart pointer that manages unique ownership of a resource.
267 /// @headerfile memory
268 /// @since C++11
269 template <typename _Tp, typename _Dp = default_delete<_Tp>>
270 class unique_ptr
271 {
272 template <typename _Up>
273 using _DeleterConstraint =
274 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
275
276 __uniq_ptr_data<_Tp, _Dp> _M_t;
277
278 public:
279 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
280 using element_type = _Tp;
281 using deleter_type = _Dp;
282
283 private:
284 // helper template for detecting a safe conversion from another
285 // unique_ptr
286 template<typename _Up, typename _Ep>
287 using __safe_conversion_up = __and_<
288 is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
289 __not_<is_array<_Up>>
290 >;
291
292#if ! __cpp_concepts202002
293 template<typename _Ptr, typename = void>
294 struct _Nothrow_deref
295 : false_type { };
296
297 template<typename _Ptr>
298 struct _Nothrow_deref<_Ptr, __void_t<decltype(*std::declval<_Ptr>())>>
299 : __bool_constant<noexcept(*std::declval<_Ptr>())> { };
300#endif
301
302 public:
303 // Constructors.
304
305 /// Default constructor, creates a unique_ptr that owns nothing.
306 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
307 constexpr unique_ptr() noexcept
308 : _M_t()
309 { }
310
311 /** Takes ownership of a pointer.
312 *
313 * @param __p A pointer to an object of @c element_type
314 *
315 * The deleter will be value-initialized.
316 */
317 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
318 _GLIBCXX23_CONSTEXPR
319 explicit
320 unique_ptr(pointer __p) noexcept
321 : _M_t(__p)
322 { }
323
324 /** Takes ownership of a pointer.
325 *
326 * @param __p A pointer to an object of @c element_type
327 * @param __d A reference to a deleter.
328 *
329 * The deleter will be initialized with @p __d
330 */
331 template<typename _Del = deleter_type,
332 typename = _Require<is_copy_constructible<_Del>>>
333 _GLIBCXX23_CONSTEXPR
334 unique_ptr(pointer __p, const deleter_type& __d) noexcept
335 : _M_t(__p, __d) { }
336
337 /** Takes ownership of a pointer.
338 *
339 * @param __p A pointer to an object of @c element_type
340 * @param __d An rvalue reference to a (non-reference) deleter.
341 *
342 * The deleter will be initialized with @p std::move(__d)
343 */
344 template<typename _Del = deleter_type,
345 typename = _Require<is_move_constructible<_Del>>>
346 _GLIBCXX23_CONSTEXPR
347 unique_ptr(pointer __p,
348 __enable_if_t<!is_lvalue_reference<_Del>::value,
349 _Del&&> __d) noexcept
350 : _M_t(__p, std::move(__d))
351 { }
352
353 template<typename _Del = deleter_type,
354 typename _DelUnref = typename remove_reference<_Del>::type>
355 _GLIBCXX23_CONSTEXPR
356 unique_ptr(pointer,
357 __enable_if_t<is_lvalue_reference<_Del>::value,
358 _DelUnref&&>) = delete;
359
360 /// Creates a unique_ptr that owns nothing.
361 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
362 constexpr unique_ptr(nullptr_t) noexcept
363 : _M_t()
364 { }
365
366 // Move constructors.
367
368 /// Move constructor.
369 unique_ptr(unique_ptr&&) = default;
370
371 /** @brief Converting constructor from another type
372 *
373 * Requires that the pointer owned by @p __u is convertible to the
374 * type of pointer owned by this object, @p __u does not own an array,
375 * and @p __u has a compatible deleter type.
376 */
377 template<typename _Up, typename _Ep, typename = _Require<
378 __safe_conversion_up<_Up, _Ep>,
379 __conditional_t<is_reference<_Dp>::value,
380 is_same<_Ep, _Dp>,
381 is_convertible<_Ep, _Dp>>>>
382 _GLIBCXX23_CONSTEXPR
383 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
384 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
385 { }
386
387#if _GLIBCXX_USE_DEPRECATED1
388#pragma GCC diagnostic push
389#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
390 /// Converting constructor from @c auto_ptr
391 template<typename _Up,
392 typename = _Require<is_convertible<_Up*, pointer>,
393 is_same<_Dp, default_delete<_Tp>>>>
394 unique_ptr(auto_ptr<_Up>&& __u) noexcept;
395#pragma GCC diagnostic pop
396#endif
397
398 /// Destructor, invokes the deleter if the stored pointer is not null.
399#if __cplusplus202002L > 202002L && __cpp_constexpr_dynamic_alloc201907L
400 constexpr
401#endif
402 ~unique_ptr() noexcept
403 {
404 static_assert(__is_invocable<deleter_type&, pointer>::value,
405 "unique_ptr's deleter must be invocable with a pointer");
406 auto& __ptr = _M_t._M_ptr();
407 if (__ptr != nullptr)
408 get_deleter()(std::move(__ptr));
409 __ptr = pointer();
410 }
411
412 // Assignment.
413
414 /** @brief Move assignment operator.
415 *
416 * Invokes the deleter if this object owns a pointer.
417 */
418 unique_ptr& operator=(unique_ptr&&) = default;
419
420 /** @brief Assignment from another type.
421 *
422 * @param __u The object to transfer ownership from, which owns a
423 * convertible pointer to a non-array object.
424 *
425 * Invokes the deleter if this object owns a pointer.
426 */
427 template<typename _Up, typename _Ep>
428 _GLIBCXX23_CONSTEXPR
429 typename enable_if< __and_<
430 __safe_conversion_up<_Up, _Ep>,
431 is_assignable<deleter_type&, _Ep&&>
432 >::value,
433 unique_ptr&>::type
434 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
435 {
436 reset(__u.release());
437 get_deleter() = std::forward<_Ep>(__u.get_deleter());
438 return *this;
439 }
440
441 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
442 _GLIBCXX23_CONSTEXPR
443 unique_ptr&
444 operator=(nullptr_t) noexcept
445 {
446 reset();
447 return *this;
448 }
449
450 // Observers.
451
452 /// Dereference the stored pointer.
453 _GLIBCXX23_CONSTEXPR
454 typename add_lvalue_reference<element_type>::type
455 operator*() const
456 // _GLIBCXX_RESOLVE_LIB_DEFECTS
457 // 2762. unique_ptr operator*() should be noexcept
458 // 4324. unique_ptr<void>::operator* is not SFINAE-friendly
459#if __cpp_concepts202002
460 noexcept(noexcept(*std::declval<pointer>()))
461 requires requires { *std::declval<pointer>(); }
462#else
463 noexcept(_Nothrow_deref<pointer>::value)
464#endif
465 {
466#if _GLIBCXX_USE_BUILTIN_TRAIT(__reference_converts_from_temporary)(1 || ! 0)
467 // _GLIBCXX_RESOLVE_LIB_DEFECTS
468 // 4148. unique_ptr::operator* should not allow dangling references
469 using _ResT = typename add_lvalue_reference<element_type>::type;
470 using _DerefT = decltype(*get());
471 static_assert(!__reference_converts_from_temporary(_ResT, _DerefT),
472 "operator* must not return a dangling reference");
473#endif
474 __glibcxx_assert(get() != pointer())do { if (__builtin_expect(!bool(get() != pointer()), false)) std
::__glibcxx_assert_fail("/usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/bits/unique_ptr.h"
, 474, __PRETTY_FUNCTION__, "get() != pointer()"); } while (false
)
;
475 return *get();
476 }
477
478 /// Return the stored pointer.
479 _GLIBCXX23_CONSTEXPR
480 pointer
481 operator->() const noexcept
482 {
483 _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
484 return get();
485 }
486
487 /// Return the stored pointer.
488 _GLIBCXX23_CONSTEXPR
489 pointer
490 get() const noexcept
491 { return _M_t._M_ptr(); }
492
493 /// Return a reference to the stored deleter.
494 _GLIBCXX23_CONSTEXPR
495 deleter_type&
496 get_deleter() noexcept
497 { return _M_t._M_deleter(); }
498
499 /// Return a reference to the stored deleter.
500 _GLIBCXX23_CONSTEXPR
501 const deleter_type&
502 get_deleter() const noexcept
503 { return _M_t._M_deleter(); }
504
505 /// Return @c true if the stored pointer is not null.
506 _GLIBCXX23_CONSTEXPR
507 explicit operator bool() const noexcept
508 { return get() == pointer() ? false : true; }
509
510 // Modifiers.
511
512 /// Release ownership of any stored pointer.
513 _GLIBCXX23_CONSTEXPR
514 pointer
515 release() noexcept
516 { return _M_t.release(); }
517
518 /** @brief Replace the stored pointer.
519 *
520 * @param __p The new pointer to store.
521 *
522 * The deleter will be invoked if a pointer is already owned.
523 */
524 _GLIBCXX23_CONSTEXPR
525 void
526 reset(pointer __p = pointer()) noexcept
527 {
528 static_assert(__is_invocable<deleter_type&, pointer>::value,
529 "unique_ptr's deleter must be invocable with a pointer");
530 _M_t.reset(std::move(__p));
531 }
532
533 /// Exchange the pointer and deleter with another object.
534 _GLIBCXX23_CONSTEXPR
535 void
536 swap(unique_ptr& __u) noexcept
537 {
538 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
539 _M_t.swap(__u._M_t);
540 }
541
542 // Disable copy from lvalue.
543 unique_ptr(const unique_ptr&) = delete;
544 unique_ptr& operator=(const unique_ptr&) = delete;
545
546 private:
547#ifdef __glibcxx_out_ptr
548 template<typename, typename, typename...>
549 friend class out_ptr_t;
550 template<typename, typename, typename...>
551 friend class inout_ptr_t;
552#endif
553 };
554
555 // 20.7.1.3 unique_ptr for array objects with a runtime length
556 // [unique.ptr.runtime]
557 // _GLIBCXX_RESOLVE_LIB_DEFECTS
558 // DR 740 - omit specialization for array objects with a compile time length
559
560 /// A move-only smart pointer that manages unique ownership of an array.
561 /// @headerfile memory
562 /// @since C++11
563 template<typename _Tp, typename _Dp>
564 class unique_ptr<_Tp[], _Dp>
565 {
566 template <typename _Up>
567 using _DeleterConstraint =
568 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
569
570 __uniq_ptr_data<_Tp, _Dp> _M_t;
571
572 // like is_base_of<_Tp, _Up> but false if unqualified types are the same
573 template<typename _Up>
574 using __is_derived_Tp
575 = __and_< is_base_of<_Tp, _Up>,
576 __not_<is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up>>> >;
577
578 public:
579 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
580 using element_type = _Tp;
581 using deleter_type = _Dp;
582
583 // helper template for detecting a safe conversion from another
584 // unique_ptr
585 template<typename _Up, typename _Ep,
586 typename _UPtr = unique_ptr<_Up, _Ep>,
587 typename _UP_pointer = typename _UPtr::pointer,
588 typename _UP_element_type = typename _UPtr::element_type>
589 using __safe_conversion_up = __and_<
590 is_array<_Up>,
591 is_same<pointer, element_type*>,
592 is_same<_UP_pointer, _UP_element_type*>,
593 is_convertible<_UP_element_type(*)[], element_type(*)[]>
594 >;
595
596 // helper template for detecting a safe conversion from a raw pointer
597 template<typename _Up>
598 using __safe_conversion_raw = __and_<
599 __or_<__or_<is_same<_Up, pointer>,
600 is_same<_Up, nullptr_t>>,
601 __and_<is_pointer<_Up>,
602 is_same<pointer, element_type*>,
603 is_convertible<
604 typename remove_pointer<_Up>::type(*)[],
605 element_type(*)[]>
606 >
607 >
608 >;
609
610 // Constructors.
611
612 /// Default constructor, creates a unique_ptr that owns nothing.
613 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
614 constexpr unique_ptr() noexcept
615 : _M_t()
616 { }
617
618 /** Takes ownership of a pointer.
619 *
620 * @param __p A pointer to an array of a type safely convertible
621 * to an array of @c element_type
622 *
623 * The deleter will be value-initialized.
624 */
625 template<typename _Up,
626 typename _Vp = _Dp,
627 typename = _DeleterConstraint<_Vp>,
628 typename = typename enable_if<
629 __safe_conversion_raw<_Up>::value, bool>::type>
630 _GLIBCXX23_CONSTEXPR
631 explicit
632 unique_ptr(_Up __p) noexcept
633 : _M_t(__p)
634 { }
635
636 /** Takes ownership of a pointer.
637 *
638 * @param __p A pointer to an array of a type safely convertible
639 * to an array of @c element_type
640 * @param __d A reference to a deleter.
641 *
642 * The deleter will be initialized with @p __d
643 */
644 template<typename _Up, typename _Del = deleter_type,
645 typename = _Require<__safe_conversion_raw<_Up>,
646 is_copy_constructible<_Del>>>
647 _GLIBCXX23_CONSTEXPR
648 unique_ptr(_Up __p, const deleter_type& __d) noexcept
649 : _M_t(__p, __d) { }
650
651 /** Takes ownership of a pointer.
652 *
653 * @param __p A pointer to an array of a type safely convertible
654 * to an array of @c element_type
655 * @param __d A reference to a deleter.
656 *
657 * The deleter will be initialized with @p std::move(__d)
658 */
659 template<typename _Up, typename _Del = deleter_type,
660 typename = _Require<__safe_conversion_raw<_Up>,
661 is_move_constructible<_Del>>>
662 _GLIBCXX23_CONSTEXPR
663 unique_ptr(_Up __p,
664 __enable_if_t<!is_lvalue_reference<_Del>::value,
665 _Del&&> __d) noexcept
666 : _M_t(std::move(__p), std::move(__d))
667 { }
668
669 template<typename _Up, typename _Del = deleter_type,
670 typename _DelUnref = typename remove_reference<_Del>::type,
671 typename = _Require<__safe_conversion_raw<_Up>>>
672 unique_ptr(_Up,
673 __enable_if_t<is_lvalue_reference<_Del>::value,
674 _DelUnref&&>) = delete;
675
676 /// Move constructor.
677 unique_ptr(unique_ptr&&) = default;
678
679 /// Creates a unique_ptr that owns nothing.
680 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
681 constexpr unique_ptr(nullptr_t) noexcept
682 : _M_t()
683 { }
684
685 template<typename _Up, typename _Ep, typename = _Require<
686 __safe_conversion_up<_Up, _Ep>,
687 __conditional_t<is_reference<_Dp>::value,
688 is_same<_Ep, _Dp>,
689 is_convertible<_Ep, _Dp>>>>
690 _GLIBCXX23_CONSTEXPR
691 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
692 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
693 { }
694
695 /// Destructor, invokes the deleter if the stored pointer is not null.
696#if __cplusplus202002L > 202002L && __cpp_constexpr_dynamic_alloc201907L
697 constexpr
698#endif
699 ~unique_ptr()
700 {
701 auto& __ptr = _M_t._M_ptr();
702 if (__ptr != nullptr)
703 get_deleter()(__ptr);
704 __ptr = pointer();
705 }
706
707 // Assignment.
708
709 /** @brief Move assignment operator.
710 *
711 * Invokes the deleter if this object owns a pointer.
712 */
713 unique_ptr&
714 operator=(unique_ptr&&) = default;
715
716 /** @brief Assignment from another type.
717 *
718 * @param __u The object to transfer ownership from, which owns a
719 * convertible pointer to an array object.
720 *
721 * Invokes the deleter if this object owns a pointer.
722 */
723 template<typename _Up, typename _Ep>
724 _GLIBCXX23_CONSTEXPR
725 typename
726 enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
727 is_assignable<deleter_type&, _Ep&&>
728 >::value,
729 unique_ptr&>::type
730 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
731 {
732 reset(__u.release());
733 get_deleter() = std::forward<_Ep>(__u.get_deleter());
734 return *this;
735 }
736
737 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
738 _GLIBCXX23_CONSTEXPR
739 unique_ptr&
740 operator=(nullptr_t) noexcept
741 {
742 reset();
743 return *this;
744 }
745
746 // Observers.
747
748 /// Access an element of owned array.
749 _GLIBCXX23_CONSTEXPR
750 typename std::add_lvalue_reference<element_type>::type
751 operator[](size_t __i) const
752 {
753 __glibcxx_assert(get() != pointer())do { if (__builtin_expect(!bool(get() != pointer()), false)) std
::__glibcxx_assert_fail("/usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/bits/unique_ptr.h"
, 753, __PRETTY_FUNCTION__, "get() != pointer()"); } while (false
)
;
754 return get()[__i];
755 }
756
757 /// Return the stored pointer.
758 _GLIBCXX23_CONSTEXPR
759 pointer
760 get() const noexcept
761 { return _M_t._M_ptr(); }
762
763 /// Return a reference to the stored deleter.
764 _GLIBCXX23_CONSTEXPR
765 deleter_type&
766 get_deleter() noexcept
767 { return _M_t._M_deleter(); }
768
769 /// Return a reference to the stored deleter.
770 _GLIBCXX23_CONSTEXPR
771 const deleter_type&
772 get_deleter() const noexcept
773 { return _M_t._M_deleter(); }
774
775 /// Return @c true if the stored pointer is not null.
776 _GLIBCXX23_CONSTEXPR
777 explicit operator bool() const noexcept
778 { return get() == pointer() ? false : true; }
779
780 // Modifiers.
781
782 /// Release ownership of any stored pointer.
783 _GLIBCXX23_CONSTEXPR
784 pointer
785 release() noexcept
786 { return _M_t.release(); }
787
788 /** @brief Replace the stored pointer.
789 *
790 * @param __p The new pointer to store.
791 *
792 * The deleter will be invoked if a pointer is already owned.
793 */
794 template <typename _Up,
795 typename = _Require<
796 __or_<is_same<_Up, pointer>,
797 __and_<is_same<pointer, element_type*>,
798 is_pointer<_Up>,
799 is_convertible<
800 typename remove_pointer<_Up>::type(*)[],
801 element_type(*)[]
802 >
803 >
804 >
805 >>
806 _GLIBCXX23_CONSTEXPR
807 void
808 reset(_Up __p) noexcept
809 { _M_t.reset(std::move(__p)); }
810
811 _GLIBCXX23_CONSTEXPR
812 void reset(nullptr_t = nullptr) noexcept
813 { reset(pointer()); }
814
815 /// Exchange the pointer and deleter with another object.
816 _GLIBCXX23_CONSTEXPR
817 void
818 swap(unique_ptr& __u) noexcept
819 {
820 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
821 _M_t.swap(__u._M_t);
822 }
823
824 // Disable copy from lvalue.
825 unique_ptr(const unique_ptr&) = delete;
826 unique_ptr& operator=(const unique_ptr&) = delete;
827
828 private:
829#ifdef __glibcxx_out_ptr
830 template<typename, typename, typename...> friend class out_ptr_t;
831 template<typename, typename, typename...> friend class inout_ptr_t;
832#endif
833 };
834
835 /// @{
836 /// @relates unique_ptr
837
838 /// Swap overload for unique_ptr
839 template<typename _Tp, typename _Dp>
840 inline
841#if __cplusplus202002L > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
842 // Constrained free swap overload, see p0185r1
843 _GLIBCXX23_CONSTEXPR
844 typename enable_if<__is_swappable<_Dp>::value>::type
845#else
846 void
847#endif
848 swap(unique_ptr<_Tp, _Dp>& __x,
849 unique_ptr<_Tp, _Dp>& __y) noexcept
850 { __x.swap(__y); }
851
852#if __cplusplus202002L > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
853 // _GLIBCXX_RESOLVE_LIB_DEFECTS
854 // 2766. Swapping non-swappable types
855 template<typename _Tp, typename _Dp>
856 typename enable_if<!__is_swappable<_Dp>::value>::type
857 swap(unique_ptr<_Tp, _Dp>&,
858 unique_ptr<_Tp, _Dp>&) = delete;
859#endif
860
861 /// Equality operator for unique_ptr objects, compares the owned pointers
862 template<typename _Tp, typename _Dp,
863 typename _Up, typename _Ep>
864 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
865 inline bool
866 operator==(const unique_ptr<_Tp, _Dp>& __x,
867 const unique_ptr<_Up, _Ep>& __y)
868 { return __x.get() == __y.get(); }
869
870 /// unique_ptr comparison with nullptr
871 template<typename _Tp, typename _Dp>
872 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
873 inline bool
874 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
875 { return !__x; }
876
877#ifndef __cpp_lib_three_way_comparison201907L
878 /// unique_ptr comparison with nullptr
879 template<typename _Tp, typename _Dp>
880 _GLIBCXX_NODISCARD[[__nodiscard__]]
881 inline bool
882 operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
883 { return !__x; }
884
885 /// Inequality operator for unique_ptr objects, compares the owned pointers
886 template<typename _Tp, typename _Dp,
887 typename _Up, typename _Ep>
888 _GLIBCXX_NODISCARD[[__nodiscard__]]
889 inline bool
890 operator!=(const unique_ptr<_Tp, _Dp>& __x,
891 const unique_ptr<_Up, _Ep>& __y)
892 { return __x.get() != __y.get(); }
893
894 /// unique_ptr comparison with nullptr
895 template<typename _Tp, typename _Dp>
896 _GLIBCXX_NODISCARD[[__nodiscard__]]
897 inline bool
898 operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
899 { return (bool)__x; }
900
901 /// unique_ptr comparison with nullptr
902 template<typename _Tp, typename _Dp>
903 _GLIBCXX_NODISCARD[[__nodiscard__]]
904 inline bool
905 operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
906 { return (bool)__x; }
907#endif // three way comparison
908
909 /// Relational operator for unique_ptr objects, compares the owned pointers
910 template<typename _Tp, typename _Dp,
911 typename _Up, typename _Ep>
912 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
913 inline bool
914 operator<(const unique_ptr<_Tp, _Dp>& __x,
915 const unique_ptr<_Up, _Ep>& __y)
916 {
917 typedef typename
918 std::common_type<typename unique_ptr<_Tp, _Dp>::pointer,
919 typename unique_ptr<_Up, _Ep>::pointer>::type _CT;
920 return std::less<_CT>()(__x.get(), __y.get());
921 }
922
923 /// unique_ptr comparison with nullptr
924 template<typename _Tp, typename _Dp>
925 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
926 inline bool
927 operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
928 {
929 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
930 nullptr);
931 }
932
933 /// unique_ptr comparison with nullptr
934 template<typename _Tp, typename _Dp>
935 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
936 inline bool
937 operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
938 {
939 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
940 __x.get());
941 }
942
943 /// Relational operator for unique_ptr objects, compares the owned pointers
944 template<typename _Tp, typename _Dp,
945 typename _Up, typename _Ep>
946 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
947 inline bool
948 operator<=(const unique_ptr<_Tp, _Dp>& __x,
949 const unique_ptr<_Up, _Ep>& __y)
950 { return !(__y < __x); }
951
952 /// unique_ptr comparison with nullptr
953 template<typename _Tp, typename _Dp>
954 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
955 inline bool
956 operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
957 { return !(nullptr < __x); }
958
959 /// unique_ptr comparison with nullptr
960 template<typename _Tp, typename _Dp>
961 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
962 inline bool
963 operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
964 { return !(__x < nullptr); }
965
966 /// Relational operator for unique_ptr objects, compares the owned pointers
967 template<typename _Tp, typename _Dp,
968 typename _Up, typename _Ep>
969 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
970 inline bool
971 operator>(const unique_ptr<_Tp, _Dp>& __x,
972 const unique_ptr<_Up, _Ep>& __y)
973 { return (__y < __x); }
974
975 /// unique_ptr comparison with nullptr
976 template<typename _Tp, typename _Dp>
977 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
978 inline bool
979 operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
980 {
981 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
982 __x.get());
983 }
984
985 /// unique_ptr comparison with nullptr
986 template<typename _Tp, typename _Dp>
987 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
988 inline bool
989 operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
990 {
991 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
992 nullptr);
993 }
994
995 /// Relational operator for unique_ptr objects, compares the owned pointers
996 template<typename _Tp, typename _Dp,
997 typename _Up, typename _Ep>
998 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
999 inline bool
1000 operator>=(const unique_ptr<_Tp, _Dp>& __x,
1001 const unique_ptr<_Up, _Ep>& __y)
1002 { return !(__x < __y); }
1003
1004 /// unique_ptr comparison with nullptr
1005 template<typename _Tp, typename _Dp>
1006 _GLIBCXX_NODISCARD[[__nodiscard__]] _GLIBCXX23_CONSTEXPR
1007 inline bool
1008 operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
1009 { return !(__x < nullptr); }
1010
1011 /// unique_ptr comparison with nullptr
1012 template<typename _Tp, typename _Dp>
1013 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
1014 operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
1015 { return !(nullptr < __x); }
1016
1017#ifdef __cpp_lib_three_way_comparison201907L
1018 template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
1019 requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
1020 typename unique_ptr<_Up, _Ep>::pointer>
1021 _GLIBCXX23_CONSTEXPR
1022 inline
1023 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
1024 typename unique_ptr<_Up, _Ep>::pointer>
1025 operator<=>(const unique_ptr<_Tp, _Dp>& __x,
1026 const unique_ptr<_Up, _Ep>& __y)
1027 { return compare_three_way()(__x.get(), __y.get()); }
1028
1029 template<typename _Tp, typename _Dp>
1030 requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
1031 _GLIBCXX23_CONSTEXPR
1032 inline
1033 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
1034 operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
1035 {
1036 using pointer = typename unique_ptr<_Tp, _Dp>::pointer;
1037 return compare_three_way()(__x.get(), static_cast<pointer>(nullptr));
1038 }
1039#endif
1040 /// @} relates unique_ptr
1041
1042 /// @cond undocumented
1043 template<typename _Up, typename _Ptr = typename _Up::pointer>
1044 struct __uniq_ptr_hash
1045 : public __hash_base<size_t, _Up>
1046#if ! _GLIBCXX_INLINE_VERSION0
1047 , private __hash_empty_base<_Ptr>
1048#endif
1049 {
1050 size_t
1051 operator()(const _Up& __u) const
1052 noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>())))
1053 { return hash<_Ptr>()(__u.get()); }
1054 };
1055
1056 template<typename _Up>
1057 using __uniq_ptr_hash_base
1058 = __conditional_t<__is_hash_enabled_for<typename _Up::pointer>,
1059 __uniq_ptr_hash<_Up>,
1060 __hash_not_enabled<typename _Up::pointer>>;
1061 /// @endcond
1062
1063 /// std::hash specialization for unique_ptr.
1064 template<typename _Tp, typename _Dp>
1065 struct hash<unique_ptr<_Tp, _Dp>>
1066 : public __uniq_ptr_hash_base<unique_ptr<_Tp, _Dp>>
1067 { };
1068
1069#ifdef __glibcxx_make_unique201304L // C++ >= 14 && HOSTED
1070 /// @cond undocumented
1071namespace __detail
1072{
1073 template<typename _Tp>
1074 struct _MakeUniq
1075 { typedef unique_ptr<_Tp> __single_object; };
1076
1077 template<typename _Tp>
1078 struct _MakeUniq<_Tp[]>
1079 { typedef unique_ptr<_Tp[]> __array; };
1080
1081 template<typename _Tp, size_t _Bound>
1082 struct _MakeUniq<_Tp[_Bound]>
1083 { struct __invalid_type { }; };
1084
1085 template<typename _Tp>
1086 using __unique_ptr_t = typename _MakeUniq<_Tp>::__single_object;
1087 template<typename _Tp>
1088 using __unique_ptr_array_t = typename _MakeUniq<_Tp>::__array;
1089 template<typename _Tp>
1090 using __invalid_make_unique_t = typename _MakeUniq<_Tp>::__invalid_type;
1091}
1092 /// @endcond
1093
1094 /** Create an object owned by a `unique_ptr`.
1095 * @tparam _Tp A non-array object type.
1096 * @param __args Constructor arguments for the new object.
1097 * @returns A `unique_ptr<_Tp>` that owns the new object.
1098 * @since C++14
1099 * @relates unique_ptr
1100 */
1101 template<typename _Tp, typename... _Args>
1102 _GLIBCXX23_CONSTEXPR
1103 inline __detail::__unique_ptr_t<_Tp>
1104 make_unique(_Args&&... __args)
1105 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
2
Calling constructor for 'graph'
1106
1107 /** Create an array owned by a `unique_ptr`.
1108 * @tparam _Tp An array type of unknown bound, such as `U[]`.
1109 * @param __num The number of elements of type `U` in the new array.
1110 * @returns A `unique_ptr<U[]>` that owns the new array.
1111 * @since C++14
1112 * @relates unique_ptr
1113 *
1114 * The array elements are value-initialized.
1115 */
1116 template<typename _Tp>
1117 _GLIBCXX23_CONSTEXPR
1118 inline __detail::__unique_ptr_array_t<_Tp>
1119 make_unique(size_t __num)
1120 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
1121
1122 /** Disable std::make_unique for arrays of known bound.
1123 * @tparam _Tp An array type of known bound, such as `U[N]`.
1124 * @since C++14
1125 * @relates unique_ptr
1126 */
1127 template<typename _Tp, typename... _Args>
1128 __detail::__invalid_make_unique_t<_Tp>
1129 make_unique(_Args&&...) = delete;
1130
1131#if __cplusplus202002L > 201703L
1132 /** Create a default-initialied object owned by a `unique_ptr`.
1133 * @tparam _Tp A non-array object type.
1134 * @returns A `unique_ptr<_Tp>` that owns the new object.
1135 * @since C++20
1136 * @relates unique_ptr
1137 */
1138 template<typename _Tp>
1139 _GLIBCXX23_CONSTEXPR
1140 inline __detail::__unique_ptr_t<_Tp>
1141 make_unique_for_overwrite()
1142 { return unique_ptr<_Tp>(new _Tp); }
1143
1144 /** Create a default-initialized array owned by a `unique_ptr`.
1145 * @tparam _Tp An array type of unknown bound, such as `U[]`.
1146 * @param __num The number of elements of type `U` in the new array.
1147 * @returns A `unique_ptr<U[]>` that owns the new array.
1148 * @since C++20
1149 * @relates unique_ptr
1150 */
1151 template<typename _Tp>
1152 _GLIBCXX23_CONSTEXPR
1153 inline __detail::__unique_ptr_array_t<_Tp>
1154 make_unique_for_overwrite(size_t __num)
1155 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]); }
1156
1157 /** Disable std::make_unique_for_overwrite for arrays of known bound.
1158 * @tparam _Tp An array type of known bound, such as `U[N]`.
1159 * @since C++20
1160 * @relates unique_ptr
1161 */
1162 template<typename _Tp, typename... _Args>
1163 __detail::__invalid_make_unique_t<_Tp>
1164 make_unique_for_overwrite(_Args&&...) = delete;
1165#endif // C++20
1166
1167#endif // C++14 && HOSTED
1168
1169#if __cplusplus202002L > 201703L && __cpp_concepts202002 && _GLIBCXX_HOSTED1
1170 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1171 // 2948. unique_ptr does not define operator<< for stream output
1172 /// Stream output operator for unique_ptr
1173 /// @relates unique_ptr
1174 /// @since C++20
1175 template<typename _CharT, typename _Traits, typename _Tp, typename _Dp>
1176 inline basic_ostream<_CharT, _Traits>&
1177 operator<<(basic_ostream<_CharT, _Traits>& __os,
1178 const unique_ptr<_Tp, _Dp>& __p)
1179 requires requires { __os << __p.get(); }
1180 {
1181 __os << __p.get();
1182 return __os;
1183 }
1184#endif // C++20 && HOSTED
1185
1186#if __cpp_variable_templates201304L
1187 template<typename _Tp>
1188 constexpr bool __is_unique_ptr = false;
1189 template<typename _Tp, typename _Del>
1190 constexpr bool __is_unique_ptr<unique_ptr<_Tp, _Del>> = true;
1191#endif
1192
1193 /// @} group pointer_abstractions
1194
1195#if __cplusplus202002L >= 201703L
1196 namespace __detail::__variant
1197 {
1198 template<typename> struct _Never_valueless_alt; // see <variant>
1199
1200 // Provide the strong exception-safety guarantee when emplacing a
1201 // unique_ptr into a variant.
1202 template<typename _Tp, typename _Del>
1203 struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>>
1204 : std::true_type
1205 { };
1206 } // namespace __detail::__variant
1207#endif // C++17
1208
1209_GLIBCXX_END_NAMESPACE_VERSION
1210} // namespace
1211
1212#endif /* _UNIQUE_PTR_H */