//
// File: hzTmplMapS.h
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
// Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#ifndef hzTmplMapS_h
#define hzTmplMapS_h
#include <sys/stat.h>
#include "hzProcess.h"
#include "hzString.h"
#include "hzLock.h"
#include "hzIsamT.h"
/*
** The formal hzMapS template
*/
template<class KEY, class OBJ> class hzMapS
{
// Category: Object Collection
//
// The hzMapS template provides a memory resident one to one map of keys to objects. The keys are required to be unique and there may only be one
// object per key. Both the keys and the objects can be of any C++, HadronZoo or application specific type.
_hz_tmpl_ISAM base ; // _hz_set_isam_Value ordered list by value
KEY m_NullKey ; // Null key
mutable KEY m_DefaultKey ; // Default key (effectively NULL)
OBJ m_NullObj ; // Null key
mutable OBJ m_DefaultObj ; // Default key (effectively NULL)
// Prevent copies
hzMapS<KEY,OBJ> (const hzMapS<KEY,OBJ>&) ;
hzMapS<KEY,OBJ>& operator= (const hzMapS<KEY,OBJ>&) ;
public:
hzMapS (void)
{
base.Start(sizeof(KEY), sizeof(OBJ)) ;
base.SetLock(HZ_NOLOCK) ;
base.m_compare = _tmpl_map_compare<KEY,OBJ> ;
memset(&m_NullKey, 0, sizeof(KEY)) ;
memset(&m_NullObj, 0, sizeof(OBJ)) ;
_hzGlobal_Memstats.m_numSmaps++ ;
}
hzMapS (hzLockOpt eLock)
{
base.Start(sizeof(KEY), sizeof(OBJ)) ;
base.SetLock(eLock) ;
base.m_compare = _tmpl_map_compare<KEY,OBJ> ;
memset(&m_NullKey, 0, sizeof(KEY)) ;
memset(&m_NullObj, 0, sizeof(OBJ)) ;
_hzGlobal_Memstats.m_numSmaps++ ;
}
hzMapS (const hzString& name)
{
base.Start(sizeof(KEY), sizeof(OBJ)) ;
base.SetLock(HZ_NOLOCK) ;
base.SetName(name) ;
base.m_compare = _tmpl_map_compare<KEY,OBJ> ;
memset(&m_NullKey, 0, sizeof(KEY)) ;
memset(&m_NullObj, 0, sizeof(OBJ)) ;
_hzGlobal_Memstats.m_numSmaps++ ;
}
hzMapS (hzLockOpt eLock, const hzString& name)
{
base.Start(sizeof(KEY), sizeof(OBJ)) ;
base.SetLock(eLock) ;
base.SetName(name) ;
base.m_compare = _tmpl_map_compare<KEY,OBJ> ;
memset(&m_NullKey, 0, sizeof(KEY)) ;
memset(&m_NullObj, 0, sizeof(OBJ)) ;
_hzGlobal_Memstats.m_numSmaps++ ;
}
~hzMapS (void) { _hzGlobal_Memstats.m_numSmaps-- ; }
// Init functions
void SetLock (hzLockOpt eLock) { base.SetLock(eLock) ; }
void SetName (const hzString& name) { base.SetName(name) ; }
void Clear (void) { base.Clear() ; }
// Insert and delete by key
hzEcode Insert (const KEY& key, const OBJ& obj)
{
// _hzfunc("hzMapS::Insert") ;
_hz_map_bkt<KEY,OBJ>* pBuck ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base.InsertKeyU(nSlot, &key) ;
if (pDN)
{
pBuck = (_hz_map_bkt<KEY,OBJ>*) pDN->m_pElements ;
pBuck->m_Keys[nSlot] = key ;
pBuck->m_Objs[nSlot] = obj ;
return E_OK ;
}
return hzerr(E_CORRUPT, "Failed to Insert") ;
}
hzEcode Delete (const KEY& key)
{
// _hzfunc("hzMapS::Delete") ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
if (!pDN)
return E_NOTFOUND ;
pDN = base.DeleteKey(nSlot, &key) ;
return E_OK ;
}
// Locate keys or objects by position
OBJ& GetObj (uint32_t nIndex) const
{
// _hzfunc("hzMapS::GetObj") ;
_hz_map_bkt<KEY,OBJ>* pBuck ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base._findDnodeByPos(nSlot, nIndex, false) ;
if (!pDN)
{
m_DefaultObj = m_NullObj ;
return m_DefaultObj ;
}
pBuck = (_hz_map_bkt<KEY,OBJ>*) pDN->m_pElements ;
return pBuck->m_Objs[nSlot] ;
}
KEY& GetKey (uint32_t nIndex) const
{
// _hzfunc("hzMapS::GetKey") ;
_hz_map_bkt<KEY,OBJ>* pBuck ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base._findDnodeByPos(nSlot, nIndex, false) ;
if (!pDN)
{
m_DefaultKey = m_NullKey ;
return m_DefaultKey ;
}
pBuck = (_hz_map_bkt<KEY,OBJ>*) pDN->m_pElements ;
return pBuck->m_Keys[nSlot] ;
}
// Locate elements by value
bool Exists (const KEY& key) const
{
// _hzfunc("hzMapS::Exists") ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
if (!pDN)
return false ;
return true ;
}
OBJ& operator[] (const KEY& key) const
{
//_hzfunc("hzMapS::operator[]") ;
_hz_map_bkt<KEY,OBJ>* pBuck ;
_hz_vn_Dat* pDN ;
int32_t nSlot ;
pDN = base._findDnodeByKey(nSlot, &key, HZ_ISAMSRCH_LO) ;
if (!pDN)
{
m_DefaultObj = m_NullObj ;
return m_DefaultObj ;
}
pBuck = (_hz_map_bkt<KEY,OBJ>*) pDN->m_pElements ;
return pBuck->m_Objs[nSlot] ;
}
int32_t First (const KEY key) const
{
// _hzfunc("hzMapS::First") ;
uint32_t nPosn ;
int32_t nSlot ;
if (base._findAllByKey(nSlot, nPosn, key, HZ_ISAMSRCH_LO))
return 0x7fffffff & nPosn ;
return -1 ;
}
int32_t Last (const KEY key) const
{
// _hzfunc("hzMapS::Last") ;
uint32_t nPosn ;
int32_t nSlot ;
if (base._findAllByKey(nSlot, nPosn, key, HZ_ISAMSRCH_HI))
return 0x7fffffff & nPosn ;
return -1 ;
}
int32_t Target (const KEY key) const
{
// _hzfunc("hzMapS::Target") ;
uint32_t nPosn ;
int32_t nSlot ;
if (base._findAllByKey(nSlot, nPosn, key, HZ_ISAMSRCH_END))
return 0x7fffffff & nPosn ;
return -1 ;
}
// Diagnostics
uint32_t Nodes (void) const { return base.Nodes() ; }
uint32_t Count (void) const { return base.Count() ; }
hzEcode NodeErrors (void) const { return base.NodeReport(true) ; }
hzEcode NodeReport (void) const { return base.NodeReport(false) ; }
} ;
template<class KEY, class OBJ> class hzPMapS
{
// Category: Object Collection
//
// Persistent 1:1 map. This is a Serial Datacron implimented as a memory resident 1:1 map, plus delta file.
//
// Note that classes represented by KEY and OBJ must have serialization functions. Specifically they must have a >> ifstream operator, and either a << ostream operator or an
// operator const char*.
//
// Note that unlike hzMapS, the classes represented by KEY and OBJ must have serialization functions.
hzMapS<KEY,OBJ> m_map ; // The map
std::ofstream m_os ; // Delta file
hzString m_path ; // Delta file path
bool m_bOpen ; // Is delta file open for writing
// Prevent copies
hzPMapS<KEY,OBJ> (const hzPMapS<KEY,OBJ>&) ;
hzPMapS<KEY,OBJ>& operator= (const hzPMapS<KEY,OBJ>&) ;
public:
hzPMapS (void)
{
m_map.SetLock(HZ_NOLOCK) ;
m_bOpen = false ;
}
hzPMapS (hzLockOpt eLock)
{
m_map.SetLock(eLock) ;
m_bOpen = false ;
}
hzPMapS (const hzString& name)
{
m_map.SetLock(HZ_NOLOCK) ;
m_map.SetName(name) ;
m_bOpen = false ;
}
hzPMapS (hzLockOpt eLock, const hzString& name)
{
m_map.SetLock(eLock) ;
m_map.SetName(name) ;
m_bOpen = false ;
}
~hzPMapS (void) { _hzGlobal_Memstats.m_numSmaps-- ; }
// Init functions
void SetName (const hzString& name) { m_map.SetName(name) ; }
void DeltaSet (const hzString& path) { m_path = path ; }
void DeltaOpen (void)
{
std::ifstream is ; // Delta file for input
struct stat fs ; // File status
KEY key ; // Key
OBJ obj ; // Object
//rc = OpenInputStrm(is, *m_path) ;
if (lstat(*m_path, &fs) == 0)
{
if (fs.st_size)
{
is.open(*m_path) ;
for (; is.tellg() < fs.st_size ;)
{
is >> key ;
if (is.fail())
is.clear() ;
if (is.tellg() == fs.st_size)
break ;
is >> obj ;
if (is.fail())
is.clear() ;
if (is.tellg() == fs.st_size)
threadLog("B: At EOF\n") ;
if (!key) continue ;
if (!obj) continue ;
m_map.Insert(key, obj) ;
}
is.close() ;
}
}
m_bOpen = true ;
m_os.open(*m_path, std::ios::app) ;
}
void DeltaClose (void) { m_os.close() ; }
void Clear (void) { m_map.Clear() ; }
// Insert and delete by key
hzEcode Insert (const KEY& key, const OBJ& obj)
{
hzEcode rc ; // Return code
if (!m_bOpen)
return E_WRITEFAIL ;
rc = m_map.Insert(key, obj) ;
if (rc == E_OK)
{
m_os << key << "\n" ;
m_os << obj << "\n" ;
m_os.flush() ;
}
return rc ;
}
hzEcode Delete (const KEY& key)
{
hzEcode rc ; // Return code
if (!m_bOpen)
return E_WRITEFAIL ;
rc = m_map.Delete(key) ;
m_os << key << "\n" ;
m_os << "0\n" ;
m_os.flush() ;
return rc ;
}
// Locate keys or objects by position
OBJ& GetObj (uint32_t nIndex) const { return m_map.GetObj(nIndex) ; }
KEY& GetKey (uint32_t nIndex) const { return m_map.GetKey(nIndex) ; }
// Locate elements by value
bool Exists (const KEY& key) const { return m_map.Exists(key) ; }
OBJ& operator[] (const KEY& key) const { return m_map.operator[](key) ; }
int32_t First (const KEY key) const { return m_map.First(key) ; }
int32_t Last (const KEY key) const { return m_map.Last(key) ; }
int32_t Target (const KEY key) const { return m_map.Target(key) ; }
// Diagnostics
uint32_t Nodes (void) const { return m_map.Nodes() ; }
uint32_t Count (void) const { return m_map.Count() ; }
hzEcode NodeErrors (void) const { return m_map.NodeReport(true) ; }
hzEcode NodeReport (void) const { return m_map.NodeReport(false) ; }
} ;
#endif // hzTmplMapS_h