| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #pragma once | 
| 2 |  |  |  |  |  |  | #include | 
| 3 |  |  |  |  |  |  | #include | 
| 4 |  |  |  |  |  |  | #include | 
| 5 |  |  |  |  |  |  | #include | 
| 6 |  |  |  |  |  |  | #include | 
| 7 |  |  |  |  |  |  | #include | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | namespace xs { | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 142 |  |  |  |  |  | struct Hash : Sv { | 
| 12 | 6 |  |  |  |  |  | static Hash create () { return Hash(newHV(), NONE); } | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | static Hash create (size_t cap) { | 
| 15 |  |  |  |  |  |  | auto ret = create(); | 
| 16 |  |  |  |  |  |  | ret.reserve(cap); | 
| 17 |  |  |  |  |  |  | return ret; | 
| 18 |  |  |  |  |  |  | } | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | static Hash create (const std::initializer_list>& l) { return Hash(l); } | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | static Hash noinc  (SV* val) { return Hash(val, NONE); } | 
| 23 |  |  |  |  |  |  | static Hash noinc  (HV* val) { return Hash(val, NONE); } | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 12 |  |  |  |  |  | Hash (std::nullptr_t = nullptr) {} | 
| 26 |  |  |  |  |  |  | Hash (SV* sv, bool policy = INCREMENT) : Sv(sv, policy) { _validate(); } | 
| 27 | 50 |  |  |  |  |  | Hash (HV* sv, bool policy = INCREMENT) : Sv(sv, policy) {} | 
| 28 |  |  |  |  |  |  |  | 
| 29 | 86 |  |  |  |  |  | Hash (const Hash& oth) : Sv(oth)            {} | 
| 30 |  |  |  |  |  |  | Hash (Hash&&      oth) : Sv(std::move(oth)) {} | 
| 31 |  |  |  |  |  |  | Hash (const Sv&   oth) : Hash(oth.get())    {} | 
| 32 |  |  |  |  |  |  | Hash (Sv&&        oth) : Sv(std::move(oth)) { _validate(); } | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | Hash (const Simple&) = delete; | 
| 35 |  |  |  |  |  |  | Hash (const Array&)  = delete; | 
| 36 |  |  |  |  |  |  | Hash (const Sub&)    = delete; | 
| 37 |  |  |  |  |  |  | Hash (const Glob&)   = delete; | 
| 38 |  |  |  |  |  |  | Hash (const Io&)     = delete; | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | Hash (const std::initializer_list>&); | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | Hash& operator= (SV* val)         { Sv::operator=(val); _validate(); return *this; } | 
| 43 | 6 |  |  |  |  |  | Hash& operator= (HV* val)         { Sv::operator=(val); return *this; } | 
| 44 | 12 |  |  |  |  |  | Hash& operator= (std::nullptr_t)  { Sv::operator=(nullptr); return *this; } | 
| 45 |  |  |  |  |  |  | Hash& operator= (const Hash& oth) { Sv::operator=(oth); return *this; } | 
| 46 | 6 |  |  |  |  |  | Hash& operator= (Hash&& oth)      { Sv::operator=(std::move(oth)); return *this; } | 
| 47 |  |  |  |  |  |  | Hash& operator= (const Sv& oth)   { return operator=(oth.get()); } | 
| 48 |  |  |  |  |  |  | Hash& operator= (Sv&& oth)        { Sv::operator=(std::move(oth)); _validate(); return *this; } | 
| 49 |  |  |  |  |  |  | Hash& operator= (const Simple&)   = delete; | 
| 50 |  |  |  |  |  |  | Hash& operator= (const Array&)    = delete; | 
| 51 |  |  |  |  |  |  | Hash& operator= (const Sub&)      = delete; | 
| 52 |  |  |  |  |  |  | Hash& operator= (const Glob&)     = delete; | 
| 53 |  |  |  |  |  |  | Hash& operator= (const Io&)       = delete; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | void set (SV* val) { Sv::operator=(val); } | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | operator AV* () const = delete; | 
| 58 |  |  |  |  |  |  | operator HV* () const { return (HV*)sv; } | 
| 59 |  |  |  |  |  |  | operator CV* () const = delete; | 
| 60 |  |  |  |  |  |  | operator GV* () const = delete; | 
| 61 |  |  |  |  |  |  | operator IO* () const = delete; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | HV* operator-> () const { return (HV*)sv; } | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | template  panda::enable_if_one_of_t* get () const { return (T*)sv; } | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 51 |  |  |  |  |  | Scalar fetch (const panda::string_view& key) const { | 
| 68 | 51 | 50 |  |  |  |  | if (!sv) return Scalar(); | 
| 69 | 51 | 50 |  |  |  |  | SV** ref = hv_fetch((HV*)sv, key.data(), key.length(), 0); | 
| 70 | 102 |  |  |  |  |  | Scalar ret; | 
| 71 | 51 | 100 |  |  |  |  | if (ref) ret.set(*ref); | 
|  |  | 50 |  |  |  |  |  | 
| 72 | 51 |  |  |  |  |  | return ret; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | Scalar at (const panda::string_view& key) const { | 
| 76 |  |  |  |  |  |  | Scalar ret = fetch(key); | 
| 77 |  |  |  |  |  |  | if (!ret) throw std::out_of_range("at: no key"); | 
| 78 |  |  |  |  |  |  | return ret; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | Scalar operator[] (const panda::string_view& key) const { return fetch(key); } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | void store (const panda::string_view& key, const Scalar& val, U32 hash = 0); | 
| 84 |  |  |  |  |  |  | void store (const panda::string_view& key, std::nullptr_t,    U32 hash = 0) { store(key, Scalar(), hash); } | 
| 85 |  |  |  |  |  |  | void store (const panda::string_view& key, SV* v,             U32 hash = 0) { store(key, Scalar(v), hash); } | 
| 86 |  |  |  |  |  |  | void store (const panda::string_view& key, const Sv& v,       U32 hash = 0) { store(key, Scalar(v), hash); } | 
| 87 |  |  |  |  |  |  | void store (const panda::string_view& key, const Array&,      U32 hash = 0) = delete; | 
| 88 |  |  |  |  |  |  | void store (const panda::string_view& key, const Hash&,       U32 hash = 0) = delete; | 
| 89 |  |  |  |  |  |  | void store (const panda::string_view& key, const Sub&,        U32 hash = 0) = delete; | 
| 90 |  |  |  |  |  |  | void store (const panda::string_view& key, const Io&,         U32 hash = 0) = delete; | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 20 |  |  |  |  |  | KeyProxy operator[] (const panda::string_view& key) { return KeyProxy(hv_fetch((HV*)sv, key.data(), key.length(), 1), false); } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | Scalar erase (const panda::string_view& key) { | 
| 95 |  |  |  |  |  |  | Scalar ret; | 
| 96 |  |  |  |  |  |  | ret.set(hv_delete((HV*)sv, key.data(), key.length(), 0)); | 
| 97 |  |  |  |  |  |  | return ret; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | bool contains (const panda::string_view& key) const { return exists(key); } | 
| 101 |  |  |  |  |  |  | bool exists   (const panda::string_view& key) const { | 
| 102 |  |  |  |  |  |  | if (!sv) return false; | 
| 103 |  |  |  |  |  |  | return hv_exists((HV*)sv, key.data(), key.length()); | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | size_t size     () const { return sv ? HvUSEDKEYS(sv) : 0; } | 
| 107 |  |  |  |  |  |  | size_t capacity () const { return sv ? HvMAX(sv)+1 : 0; } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | void reserve (size_t newcap) { hv_ksplit((HV*)sv, newcap); } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | void undef () { if (sv) hv_undef((HV*)sv); } | 
| 112 |  |  |  |  |  |  | void clear () { if (sv) hv_clear((HV*)sv); } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | struct const_iterator : private std::iterator { | 
| 115 | 6 |  |  |  |  |  | const_iterator () : arr(NULL), end(NULL), cur(HashEntry()) {} | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 6 |  |  |  |  |  | const_iterator (HV* hv) : arr(HvARRAY(hv)), end(arr + HvMAX(hv) + 1), cur(HashEntry()) { | 
| 118 | 3 | 50 |  |  |  |  | if (HvUSEDKEYS(hv)) operator++(); | 
|  |  | 50 |  |  |  |  |  | 
| 119 | 3 |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | const_iterator (const const_iterator& oth) : arr(oth.arr), end(oth.end), cur(oth.cur) {} | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 15 |  |  |  |  |  | const_iterator& operator++ () { | 
| 124 | 15 | 100 |  |  |  |  | if (cur) { | 
| 125 | 12 |  |  |  |  |  | cur = HeNEXT(cur); | 
| 126 | 12 | 100 |  |  |  |  | if (cur) return *this; | 
| 127 |  |  |  |  |  |  | } | 
| 128 | 42 | 100 |  |  |  |  | while (!cur && arr != end) cur = *arr++; | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 129 | 11 |  |  |  |  |  | return *this; | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | const_iterator operator++ (int) { | 
| 133 |  |  |  |  |  |  | const_iterator ret = *this; | 
| 134 |  |  |  |  |  |  | operator++(); | 
| 135 |  |  |  |  |  |  | return ret; | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | bool operator== (const const_iterator& oth) const { return cur == oth.cur; } | 
| 139 | 30 |  |  |  |  |  | bool operator!= (const const_iterator& oth) const { return cur != oth.cur; } | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | const HashEntry* operator-> () { return &cur; } | 
| 142 | 26 |  |  |  |  |  | const HashEntry& operator*  () { return cur; } | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | const_iterator& operator= (const const_iterator& oth) { | 
| 145 |  |  |  |  |  |  | arr = oth.arr; | 
| 146 |  |  |  |  |  |  | end = oth.end; | 
| 147 |  |  |  |  |  |  | cur = oth.cur; | 
| 148 |  |  |  |  |  |  | return *this; | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | protected: | 
| 152 |  |  |  |  |  |  | HE**      arr; | 
| 153 |  |  |  |  |  |  | HE**      end; | 
| 154 |  |  |  |  |  |  | HashEntry cur; | 
| 155 |  |  |  |  |  |  | }; | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | struct iterator : private std::iterator, const_iterator { | 
| 158 |  |  |  |  |  |  | using const_iterator::const_iterator; | 
| 159 |  |  |  |  |  |  | HashEntry* operator-> () { return &cur; } | 
| 160 |  |  |  |  |  |  | HashEntry& operator*  () { return cur; } | 
| 161 |  |  |  |  |  |  | }; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 6 | 50 |  |  |  |  | const_iterator cbegin () const { return sv ? const_iterator((HV*)sv) : const_iterator(); } | 
| 164 | 6 |  |  |  |  |  | const_iterator cend   () const { return const_iterator(); } | 
| 165 | 6 |  |  |  |  |  | const_iterator begin  () const { return cbegin(); } | 
| 166 | 6 |  |  |  |  |  | const_iterator end    () const { return cend(); } | 
| 167 |  |  |  |  |  |  | iterator       begin  ()       { return sv ? iterator((HV*)sv) : iterator(); } | 
| 168 |  |  |  |  |  |  | iterator       end    ()       { return iterator(); } | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | U32 push_on_stack (SV** sp) const; | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | private: | 
| 173 |  |  |  |  |  |  | void _validate () { | 
| 174 |  |  |  |  |  |  | if (!sv) return; | 
| 175 |  |  |  |  |  |  | if (SvTYPE(sv) == SVt_PVHV) return; | 
| 176 |  |  |  |  |  |  | if (SvROK(sv)) {           // reference to hash? | 
| 177 |  |  |  |  |  |  | SV* val = SvRV(sv); | 
| 178 |  |  |  |  |  |  | if (SvTYPE(val) == SVt_PVHV) { | 
| 179 |  |  |  |  |  |  | Sv::operator=(val); | 
| 180 |  |  |  |  |  |  | return; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  | if (is_undef()) return reset(); | 
| 184 |  |  |  |  |  |  | reset(); | 
| 185 |  |  |  |  |  |  | throw std::invalid_argument("SV is not a Hash or Hash reference"); | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | }; | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | // DEPRECATED, will be removed, use Hash.begin()/end() instead | 
| 192 |  |  |  |  |  |  | #define XS_HV_ITER(hv,code) {                                                       \ | 
| 193 |  |  |  |  |  |  | STRLEN hvmax = HvMAX(hv);                                                       \ | 
| 194 |  |  |  |  |  |  | HE** hvarr = HvARRAY(hv);                                                       \ | 
| 195 |  |  |  |  |  |  | if (HvUSEDKEYS(hv))                                                             \ | 
| 196 |  |  |  |  |  |  | for (STRLEN bucket_num = 0; bucket_num <= hvmax; ++bucket_num)              \ | 
| 197 |  |  |  |  |  |  | for (const HE* he = hvarr[bucket_num]; he; he = HeNEXT(he)) { code }    \ | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  | #define XS_HV_ITER_NU(hv,code) XS_HV_ITER(hv,{if(!SvOK(HeVAL(he))) continue; code}) |