32 #ifndef _QORE_QOREHASHNODEINTERN_H
34 #define _QORE_QOREHASHNODEINTERN_H
44 DLLLOCAL HashMember(
const char* n_key) : key(n_key) {
47 DLLLOCAL ~HashMember() {
51 typedef std::list<HashMember*> qhlist_t;
53 #ifdef HAVE_QORE_HASH_MAP
55 #include <qore/hash_map_include.h>
56 #include "qore/intern/xxhash.h"
58 typedef HASH_MAP<const char*, qhlist_t::iterator, qore_hash_str, eqstr> hm_hm_t;
60 typedef std::map<const char*, qhlist_t::iterator, ltstr> hm_hm_t;
69 DLLLOCAL qhi_priv() : val(false) {
72 DLLLOCAL qhi_priv(
const qhi_priv& old) : i(old.i), val(old.val) {
75 DLLLOCAL
bool valid()
const {
79 DLLLOCAL
bool next(qhlist_t& ml) {
82 if (ml.begin() != ml.end()) {
95 DLLLOCAL
bool prev(qhlist_t& ml) {
97 if (ml.begin() != ml.end()) {
112 DLLLOCAL
void reset() {
121 class qore_hash_private {
123 qhlist_t member_list;
127 const QoreTypeInfo* complexTypeInfo =
nullptr;
128 unsigned obj_count = 0;
133 DLLLOCAL qore_hash_private() {
138 DLLLOCAL ~qore_hash_private() {
139 assert(member_list.empty());
142 DLLLOCAL
QoreValue getKeyValueIntern(
const char* key)
const;
146 DLLLOCAL
QoreValue getKeyValueExistenceIntern(
const char* key,
bool& exists)
const;
148 DLLLOCAL
int checkKey(
const char* key,
ExceptionSink* xsink)
const;
150 DLLLOCAL
QoreValue getReferencedKeyValueIntern(
const char* key)
const {
152 return getReferencedKeyValueIntern(key, exists);
155 DLLLOCAL
QoreValue getReferencedKeyValueIntern(
const char* key,
bool& exists)
const {
158 hm_hm_t::const_iterator i = hm.find(key);
161 return (*(i->second))->val.refSelf();
168 DLLLOCAL
int64 getKeyAsBigInt(
const char* key,
bool &found)
const {
170 hm_hm_t::const_iterator i = hm.find(key);
174 return (*(i->second))->val.getAsBigInt();
181 DLLLOCAL
bool getKeyAsBool(
const char* key,
bool& found)
const {
183 hm_hm_t::const_iterator i = hm.find(key);
187 return (*(i->second))->val.getAsBool();
194 DLLLOCAL
bool existsKey(
const char* key)
const {
196 return hm.find(key) != hm.end();
199 DLLLOCAL
bool existsKeyValue(
const char* key)
const {
201 hm_hm_t::const_iterator i = hm.find(key);
204 return !(*(i->second))->val.isNothing();
207 DLLLOCAL HashMember* findMember(
const char* key) {
209 hm_hm_t::iterator i = hm.find(key);
210 return i != hm.end() ? (*(i->second)) :
nullptr;
213 DLLLOCAL HashMember* findCreateMember(
const char* key) {
215 HashMember* om = findMember(key);
219 om =
new HashMember(key);
220 assert(om->val.isNothing());
221 member_list.push_back(om);
224 qhlist_t::iterator i = member_list.end();
226 hm[om->key.c_str()] = i;
232 DLLLOCAL
QoreValue& getValueRef(
const char* key) {
233 return findCreateMember(key)->val;
238 DLLLOCAL
void internDeleteKey(qhlist_t::iterator i) {
241 member_list.erase(i);
247 DLLLOCAL
void deleteKey(
const char* key,
ExceptionSink *xsink) {
250 hm_hm_t::iterator i = hm.find(key);
255 qhlist_t::iterator li = i->second;
265 reinterpret_cast<QoreObject*
>(n)->doDelete(xsink);
273 DLLLOCAL
void removeKey(
const char* key,
ExceptionSink *xsink) {
274 takeKeyValueIntern(key).discard(xsink);
277 DLLLOCAL
QoreValue takeKeyValueIntern(
const char* key) {
280 hm_hm_t::iterator i = hm.find(key);
285 qhlist_t::iterator li = i->second;
297 DLLLOCAL
QoreValue takeKeyValueIntern(
const char* key,
bool& exists) {
300 hm_hm_t::iterator i = hm.find(key);
308 qhlist_t::iterator li = i->second;
320 DLLLOCAL
const char* getFirstKey()
const {
321 return member_list.empty() ? nullptr : member_list.front()->key.c_str();
324 DLLLOCAL
const char* getLastKey()
const {
325 return member_list.empty() ? nullptr : member_list.back()->key.c_str();
330 DLLLOCAL
void merge(
const qore_hash_private& h0,
ExceptionSink* xsink);
335 DLLLOCAL
int getLValue(
const char* key, LValueHelper& lvh,
bool for_remove,
ExceptionSink* xsink);
337 DLLLOCAL
void getTypeName(
QoreString& str)
const {
340 else if (complexTypeInfo)
341 str.
concat(QoreTypeInfo::getName(complexTypeInfo));
352 h->
priv->hashdecl = hashdecl;
354 h->
priv->complexTypeInfo = complexTypeInfo;
358 DLLLOCAL
QoreHashNode* getEmptyCopy(
bool is_value)
const {
361 h->
priv->hashdecl = hashdecl;
363 h->
priv->complexTypeInfo = complexTypeInfo;
367 DLLLOCAL
QoreHashNode* copyCheckNewType(
const qore_hash_private& other)
const {
369 if (hashdecl || other.hashdecl) {
370 if (!hashdecl || !other.hashdecl || !hashdecl->
equal(other.hashdecl)) {
371 rv->
priv->hashdecl =
nullptr;
372 rv->
priv->complexTypeInfo = autoHashTypeInfo;
375 const QoreTypeInfo* orig_ctype, * ctype;
376 orig_ctype = ctype = QoreTypeInfo::getUniqueReturnComplexHash(complexTypeInfo);
377 const QoreTypeInfo* newElementType = QoreTypeInfo::getUniqueReturnComplexHash(other.complexTypeInfo);
378 if ((!ctype || ctype == anyTypeInfo) && (!newElementType || newElementType == anyTypeInfo)) {
379 rv->
priv->complexTypeInfo =
nullptr;
380 }
else if (QoreTypeInfo::matchCommonType(ctype, newElementType)) {
381 rv->
priv->complexTypeInfo = ctype == orig_ctype ? complexTypeInfo : qore_get_complex_hash_type(ctype);
383 rv->
priv->complexTypeInfo = autoHashTypeInfo;
389 DLLLOCAL
QoreHashNode* copy(
const QoreTypeInfo* newComplexTypeInfo)
const {
391 h->
priv->complexTypeInfo = newComplexTypeInfo;
392 copyIntern(*h->
priv);
399 if (!strip || (!complexTypeInfo && !hashdecl)) {
401 copyIntern(*h->
priv);
406 for (
auto& i : member_list) {
407 hash_assignment_priv ha(*h, i->key.c_str());
408 QoreValue v = copy_strip_complex_types(i->val);
410 assert(ha.swap(v).isNothing());
419 DLLLOCAL
void copyIntern(qore_hash_private& h)
const {
421 for (
auto& i : member_list) {
422 hash_assignment_priv ha(h, i->key.c_str());
424 assert(ha.swap(i->val.refSelf()).isNothing());
426 ha.swap(i->val.refSelf());
436 return *xsink ? nullptr : rv.release();
442 for (qhlist_t::const_iterator i = member_list.begin(), e = member_list.end(); i != e; ++i) {
443 h->
priv->setKeyValue((*i)->key, (*i)->val.refSelf(), xsink);
452 hash_assignment_priv ha(*
this, key);
454 ha.assign(val, sdh, xsink);
458 hash_assignment_priv ha(*
this, key.c_str());
460 ha.assign(val, sdh, xsink);
463 DLLLOCAL
void setKeyValueIntern(
const char* key,
QoreValue v) {
464 hash_assignment_priv ha(*
this, key);
471 hash_assignment_priv ha(*
this, key);
472 ha.assign(val, xsink);
476 hash_assignment_priv ha(*
this, key.c_str());
477 ha.assign(val, xsink);
481 hash_assignment_priv ha(*
this, key,
false, o);
482 ha.assign(val, xsink);
485 DLLLOCAL
bool derefImpl(
ExceptionSink* xsink,
bool reverse =
false) {
487 for (qhlist_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
488 (*i)->val.discard(xsink);
492 for (qhlist_t::iterator i = member_list.begin(), e = member_list.end(); i != e; ++i) {
493 (*i)->val.discard(xsink);
504 DLLLOCAL
QoreValue swapKeyValueIfExists(
const char* key,
QoreValue val, qore_object_private* o,
bool& exists) {
505 hash_assignment_priv ha(*
this, key,
true, o);
514 DLLLOCAL
QoreValue swapKeyValue(
const char* key,
QoreValue val, qore_object_private* o) {
517 hash_assignment_priv ha(*
this, key,
false, o);
522 derefImpl(xsink, reverse);
525 DLLLOCAL
size_t size()
const {
526 return member_list.size();
529 DLLLOCAL
bool empty()
const {
530 return member_list.empty();
533 DLLLOCAL
void incScanCount(
int dt) {
536 assert(obj_count || dt > 0);
541 DLLLOCAL
const QoreTypeInfo* getValueTypeInfo()
const {
542 return complexTypeInfo ? QoreTypeInfo::getComplexHashValueType(complexTypeInfo) : nullptr;
545 DLLLOCAL
const QoreTypeInfo* getTypeInfo()
const {
549 return complexTypeInfo;
558 if (!h->
priv->hashdecl && !h->
priv->complexTypeInfo)
562 return h->
priv->copy(
true);
567 rv->
priv->hashdecl = hd;
571 DLLLOCAL
static qore_hash_private* get(
QoreHashNode& h) {
575 DLLLOCAL
static const qore_hash_private* get(
const QoreHashNode& h) {
580 DLLLOCAL
static int parseInitHashInitialization(
const QoreProgramLocation* loc, LocalVar *oflag,
int pflag,
int& lvids, QoreParseListNode* args,
const QoreTypeInfo*& argTypeInfo,
QoreValue& arg);
582 DLLLOCAL
static int parseInitComplexHashInitialization(
const QoreProgramLocation* loc, LocalVar *oflag,
int pflag, QoreParseListNode* args,
const QoreTypeInfo* vti);
584 DLLLOCAL
static void parseCheckComplexHashInitialization(
const QoreProgramLocation* loc,
const QoreTypeInfo* typeInfo,
const QoreTypeInfo* expTypeInfo,
QoreValue exp,
const char* context_action,
bool strict_check =
true);
586 DLLLOCAL
static void parseCheckTypedAssignment(
const QoreProgramLocation* loc,
QoreValue arg,
const QoreTypeInfo* vti,
const char* context_action,
bool strict_check =
true);
588 DLLLOCAL
static QoreHashNode* newComplexHash(
const QoreTypeInfo* typeInfo,
const QoreParseListNode* args,
ExceptionSink* xsink);
592 DLLLOCAL
static unsigned getScanCount(
const QoreHashNode& h) {
593 assert(!h.
priv->is_obj);
594 return h.
priv->obj_count;
597 DLLLOCAL
static void incScanCount(
const QoreHashNode& h,
int dt) {
598 assert(!h.
priv->is_obj);
599 h.
priv->incScanCount(dt);
603 return h->
priv->member_list.empty() ?
QoreValue() : h->priv->member_list.front()->val;
607 return h->
priv->member_list.empty() ?
QoreValue() : h->priv->member_list.back()->val;