File Coverage

Base.xs
Criterion Covered Total %
statement 140 210 66.6
branch 64 132 48.4
condition n/a
subroutine n/a
pod n/a
total 204 342 59.6


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include
6             #include
7              
8             #ifdef _WIN32
9             #include
10             #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
11             static SRWLOCK rwlock;
12             #define INIT_LOCK() InitializeSRWLock(&rwlock)
13             #define RLOCK() AcquireSRWLockShared(&rwlock)
14             #define RUNLOCK() ReleaseSRWLockShared(&rwlock)
15             #define WLOCK() AcquireSRWLockExclusive(&rwlock)
16             #define WUNLOCK() ReleaseSRWLockExclusive(&rwlock)
17             #else
18             static CRITICAL_SECTION cs_lock;
19             #define INIT_LOCK() InitializeCriticalSection(&cs_lock)
20             #define RLOCK() EnterCriticalSection(&cs_lock)
21             #define RUNLOCK() LeaveCriticalSection(&cs_lock)
22             #define WLOCK() EnterCriticalSection(&cs_lock)
23             #define WUNLOCK() LeaveCriticalSection(&cs_lock)
24             #endif
25             #else
26             #include
27             static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
28             #define INIT_LOCK() /* pthread rwlock is statically inited */
29             #define RLOCK() pthread_rwlock_rdlock(&rwlock)
30             #define RUNLOCK() pthread_rwlock_unlock(&rwlock)
31             #define WLOCK() pthread_rwlock_wrlock(&rwlock)
32             #define WUNLOCK() pthread_rwlock_unlock(&rwlock)
33             #endif
34              
35             /* 全局 root */
36             static SV *global_root = NULL;
37             static int strict_mode = 1;
38              
39             /* 懒初始化全局 root(hashref) */
40 39           static void ensure_global_root(void) {
41 39 100         if (!global_root) {
42 1           HV *h = newHV();
43 1           SV *rv = newRV_noinc((SV*)h); /* rv refcount = 1 */
44 1           global_root = rv; /* 保存为全局 */
45             /* 不需要额外 inc;global_root 本身持有该 RV 的唯一引用 */
46             }
47 39           }
48              
49 12           static char **split_path(const char *path, I32 *count) {
50 12 50         if (!path || !*path) { *count = 0; return NULL; }
    50          
51 12           char *s = strdup(path);
52 12 50         if (!s) { *count = 0; return NULL; }
53 12           I32 n = 1;
54 12           const char *p = path;
55 24 100         while ((p = strstr(p, "->"))) { n++; p += 2; }
56 12           char **parts = (char**)malloc(sizeof(char*) * n);
57 12 50         if (!parts) { free(s); *count = 0; return NULL; }
58 12           I32 idx = 0;
59 12           char *cur = s;
60             char *sep;
61 24 100         while ((sep = strstr(cur, "->"))) {
62 12           *sep = '\0';
63 12           parts[idx++] = strdup(cur);
64 12           cur = sep + 2;
65             }
66 12           parts[idx++] = strdup(cur);
67 12           *count = idx;
68 12           free(s);
69 12           return parts;
70             }
71              
72 12           static void free_parts(char **parts, I32 count) {
73 12 50         if (!parts) return;
74 36 50         for (I32 i = 0; i < count; i++) if (parts[i]) free(parts[i]);
    100          
75 12           free(parts);
76             }
77              
78 3           static int hv_is_empty(HV *hv) {
79             HE *he;
80 3           hv_iterinit(hv);
81 3           he = hv_iternext(hv);
82 3           return he == NULL;
83             }
84              
85 13           static HV *get_root_hv(void) {
86 13           ensure_global_root();
87 13           return (HV*)SvRV(global_root);
88             }
89              
90             /* 写入:严格/宽松路径处理,返回值的“拷贝”(newSVsv),方便直接作为返回值 */
91 3           static SV *xsbase_set_by_path(const char *path, SV *val) {
92 3           ensure_global_root();
93 3 50         if (!path) croak("XS::Base::has: key required");
94              
95 3           I32 parts_n = 0;
96 3           char **parts = split_path(path, &parts_n);
97 3 50         if (!parts || parts_n == 0) { free_parts(parts, parts_n); croak("invalid key"); }
    50          
98              
99 3           HV *hv = get_root_hv();
100              
101 6 50         for (I32 i = 0; i < parts_n; i++) {
102 6           const char *k = parts[i];
103 6           I32 klen = (I32)strlen(k);
104              
105 6 100         if (i == parts_n - 1) {
106 3           SV *to_store = newSVsv(val); /* 拷贝写入 */
107 3           (void)hv_store(hv, k, klen, to_store, 0); /* hv_store 不会自动 inc,传的 SV 应是我们要交给 HV 管理的“所有权” */
108 3           SV *ret = newSVsv(to_store); /* 再拷贝一份作为返回值,避免外面改动影响内部存储 */
109 3           free_parts(parts, parts_n);
110 3           return ret;
111             } else {
112 3           SV **psv = hv_fetch(hv, k, klen, 0);
113 3 50         if (psv && *psv) {
    0          
114 0           SV *sv = *psv;
115 0 0         if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV) {
    0          
116 0           hv = (HV*)SvRV(sv);
117             } else {
118 0 0         if (strict_mode) {
119 0           free_parts(parts, parts_n);
120 0           croak("XS::Base::has: path collision at intermediate node '%s' (not a hashref) - strict mode", k);
121             } else {
122             /* 宽松模式:覆盖非 hashref 中间节点为新 hashref */
123 0           SV *old = hv_delete(hv, k, klen, G_DISCARD);
124 0 0         if (old) SvREFCNT_dec(old);
125 0           HV *newhv = newHV();
126 0           SV *r = newRV_noinc((SV*)newhv); /* r refcount=1 交给 HV */
127 0           (void)hv_store(hv, k, klen, r, 0);
128 0           hv = newhv;
129             }
130             }
131             } else {
132             /* 不存在:创建中间 hashref */
133 3           HV *newhv = newHV();
134 3           SV *r = newRV_noinc((SV*)newhv);
135 3           (void)hv_store(hv, k, klen, r, 0);
136 3           hv = newhv;
137             }
138             }
139             }
140              
141 0           free_parts(parts, parts_n);
142 0           return NULL; /* 不会走到这 */
143             }
144              
145             /* 读取:返回“拷贝”(newSVsv),避免把 HV 里的 SV 直接 inc 返回导致生命周期复杂 */
146 8           static SV *xsbase_get_by_path(const char *path) {
147 8           ensure_global_root();
148 8 50         if (!path || !*path) return NULL;
    50          
149              
150 8           HV *hv = get_root_hv();
151 8           I32 parts_n = 0;
152 8           char **parts = split_path(path, &parts_n);
153 8 50         if (!parts || parts_n == 0) { free_parts(parts, parts_n); return NULL; }
    50          
154              
155 8           SV *val = NULL;
156              
157 12 50         for (I32 i = 0; i < parts_n; i++) {
158 12           STRLEN klen = (STRLEN)strlen(parts[i]);
159 12           SV **svp = hv_fetch(hv, parts[i], (I32)klen, 0);
160 12 100         if (!svp || !*svp) { val = NULL; break; }
    50          
161              
162 9           SV *sv = *svp;
163 9 100         if (i == parts_n - 1) {
164 5           val = newSVsv(sv); /* 返回拷贝 */
165 5           break;
166             }
167 4 50         if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV) {
    50          
168 4           hv = (HV*)SvRV(sv);
169             } else {
170 0           val = NULL;
171 0           break;
172             }
173             }
174              
175 8           free_parts(parts, parts_n);
176 8           return val; /* 可能为 NULL */
177             }
178              
179             /* def: 不存在才写,返回值的拷贝 */
180 0           static SV *xsbase_def_by_path(const char *path, SV *val) {
181 0           ensure_global_root();
182 0           SV *existing = xsbase_get_by_path(path);
183 0 0         if (existing) return existing; /* 已是“拷贝” */
184 0           return xsbase_set_by_path(path, val); /* 返回“拷贝” */
185             }
186              
187             /* del: 删除叶子并回溯清理空父节点 */
188 1           static int xsbase_del_by_path(const char *path) {
189 1           ensure_global_root();
190 1 50         if (!path || !*path) croak("XS::Base::del: key required");
    50          
191              
192 1           I32 parts_n = 0;
193 1           char **parts = split_path(path, &parts_n);
194 1 50         if (!parts || parts_n == 0) { free_parts(parts, parts_n); croak("invalid key"); }
    50          
195              
196 1           HV *hv = get_root_hv();
197 1           HV **parents = (HV**)malloc(sizeof(HV*) * parts_n);
198 1           char **pkeys = (char**)malloc(sizeof(char*) * parts_n);
199 1 50         if (!parents || !pkeys) {
    50          
200 0           free(parents); free(pkeys); free_parts(parts, parts_n);
201 0           croak("malloc failed");
202             }
203              
204 1           int ok = 0;
205 3 50         for (I32 i = 0; i < parts_n; i++) {
206 3           parents[i] = hv;
207 3           pkeys[i] = strdup(parts[i]);
208              
209 3           STRLEN klen = (STRLEN)strlen(parts[i]);
210 3           SV **svp = hv_fetch(hv, parts[i], (I32)klen, 0);
211 3 50         if (!svp || !*svp) { ok = 0; break; }
    50          
212              
213 3           SV *sv = *svp;
214 3 100         if (i < parts_n - 1) {
215 2 50         if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV) {
    50          
216 2           hv = (HV*)SvRV(sv);
217             } else {
218 0           ok = 0; break;
219             }
220             } else {
221 1           SV *removed = hv_delete(parents[i], pkeys[i], (I32)strlen(pkeys[i]), G_DISCARD);
222 1 50         if (removed) SvREFCNT_dec(removed);
223              
224 3 50         for (I32 j = parts_n - 1; j >= 0; j--) {
225 3 100         if (hv_is_empty(parents[j]) && j > 0) {
    50          
226 2           SV *rem = hv_delete(parents[j-1], pkeys[j-1], (I32)strlen(pkeys[j-1]), G_DISCARD);
227 2 50         if (rem) SvREFCNT_dec(rem);
228             } else break;
229             }
230 1           ok = 1; break;
231             }
232             }
233              
234 4 50         for (I32 i = 0; i < parts_n; i++) if (pkeys[i]) free(pkeys[i]);
    100          
235 1           free(parents);
236 1           free(pkeys);
237 1           free_parts(parts, parts_n);
238 1           return ok;
239             }
240              
241 1           static void xsbase_clr_all(void) {
242 1           ensure_global_root();
243 1           hv_clear(get_root_hv());
244 1           }
245              
246             /* 返回同一个 RV(global_root),并 inc;Perl 端可配合 _dec_sv 释放 */
247 0           static SV *xsbase_get_root_ref(void) {
248 0           ensure_global_root();
249 0           SvREFCNT_inc(global_root);
250 0           return global_root;
251             }
252              
253 0           static void xsbase_replace_root(SV *newroot) {
254 0           ensure_global_root();
255 0 0         if (!newroot || !SvROK(newroot) || SvTYPE(SvRV(newroot)) != SVt_PVHV) {
    0          
    0          
256 0           croak("XS::Base::replace_root requires a hashref");
257             }
258 0           HV *src = (HV*)SvRV(newroot);
259 0           HV *dst = get_root_hv();
260              
261 0           hv_clear(dst);
262 0           hv_iterinit(src);
263             HE *he;
264 0 0         while ((he = hv_iternext(src)) != NULL) {
265 0           SV *keysv = hv_iterkeysv(he);
266             STRLEN klen;
267 0           char *k = (char*)SvPV(keysv, klen);
268 0           SV *val = HeVAL(he);
269 0           SV *copy = newSVsv(val); /* 拷贝 */
270 0           (void)hv_store(dst, k, (I32)klen, copy, 0);
271             }
272 0           }
273              
274 0           static void xsbase_dec_sv(SV *sv) {
275 0 0         if (sv) SvREFCNT_dec(sv);
276 0           }
277              
278             /* ---------- XS 绑定 ---------- */
279              
280             MODULE = XS::Base PACKAGE = XS::Base
281              
282             BOOT:
283             INIT_LOCK();
284            
285              
286             PROTOTYPES: DISABLED
287              
288             SV *
289             has(key, ...)
290             SV *key
291             PPCODE:
292             {
293             //dXSARGS;
294 11           ensure_global_root();
295 11 100         if (items != 1 && items != 2) croak("Usage: XS::Base::has(KEY) or XS::Base::has(KEY, VAL)");
    50          
296             STRLEN klen;
297 11           char *k = (char*)SvPV(key, klen);
298              
299 11 100         if (items == 2) {
300             /* 写操作:独占写锁 */
301 3           SV *val = ST(1);
302 3           WLOCK();
303 3           SV *ret = xsbase_set_by_path(k, val);
304 3           WUNLOCK();
305 3 50         if (ret) ST(0) = ret;
306 0           else ST(0) = &PL_sv_undef;
307             } else {
308             /* 读操作:共享读锁 */
309 8           RLOCK();
310 8           SV *ret = xsbase_get_by_path(k);
311 8           RUNLOCK();
312 8 100         if (ret) ST(0) = ret;
313 3           else ST(0) = &PL_sv_undef;
314             }
315 11           XSRETURN(1);
316             }
317              
318             int
319             del(key)
320             SV *key
321             CODE:
322             {
323 1           ensure_global_root();
324             STRLEN klen;
325 1           char *k = (char*)SvPV(key, klen);
326 1           WLOCK();
327 1           int r = xsbase_del_by_path(k);
328 1           WUNLOCK();
329 1 50         RETVAL = r;
330             }
331             OUTPUT:
332             RETVAL
333              
334             SV *
335             def(key, val)
336             SV *key
337             SV *val
338             PPCODE:
339             {
340 0           dXSARGS;
341 0           ensure_global_root();
342              
343 0 0         if (items != 2) croak("Usage: XS::Base::def(KEY, VAL)");
344              
345             STRLEN klen;
346 0           char *k = (char*)SvPV(key, klen);
347              
348 0           WLOCK();
349 0           SV *ret = xsbase_def_by_path(k, val); /* 拷贝 */
350 0           WUNLOCK();
351              
352 0 0         EXTEND(SP, 1);
353 0 0         if (ret) { PUSHs(sv_2mortal(ret)); } else { PUSHs(&PL_sv_undef); }
354 0           XSRETURN(1);
355             }
356              
357             void
358             clr()
359             CODE:
360             {
361 1           ensure_global_root();
362 1           WLOCK();
363 1           xsbase_clr_all();
364 1           WUNLOCK();
365             }
366              
367             SV *
368             get_root_ref()
369             CODE:
370             {
371 0           ensure_global_root();
372 0           RLOCK();
373 0           SV *r = xsbase_get_root_ref(); /* inc 后返回同一 RV */
374 0           RUNLOCK();
375              
376             /* 返回的 r 不能 mortal;让上层决定是否调用 _dec_sv 释放 */
377 0           ST(0) = r;
378 0           XSRETURN(1);
379             }
380              
381             void
382             replace_root(newroot)
383             SV *newroot
384             CODE:
385             {
386 0           ensure_global_root();
387 0           WLOCK();
388 0           xsbase_replace_root(newroot);
389 0           WUNLOCK();
390             }
391              
392             void
393             _dec_sv(sv)
394             SV *sv
395             CODE:
396             {
397 0           xsbase_dec_sv(sv);
398             }
399              
400             void
401             set_strict_mode(onoff)
402             int onoff
403             CODE:
404             {
405 0           strict_mode = onoff ? 1 : 0;
406             }
407              
408             int
409             get_strict_mode()
410             CODE:
411             {
412 0 0         RETVAL = strict_mode;
413             }
414             OUTPUT:
415             RETVAL