Skip to content

Commit

Permalink
dictionary: use hash/equal function operators for case sensitivity
Browse files Browse the repository at this point in the history
added key hash function operator structure (calls standard hash)
added key equal function operator structure
(both structures support case sensitivity option)
added key hash and equal structures to key map alias
added key iterator alias

changed constructor to pass case sensitive option to the key hash and
equal structures, and removed case sensitive member (not needed)

replaced key list vector since unmodified names are now put into the
key map (so names are now obtained from here) with iterators vector so
that entries can still be looked up by index
  • Loading branch information
thunder422 committed Oct 7, 2014
1 parent e79c179 commit 1f2483e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 44 deletions.
51 changes: 14 additions & 37 deletions dictionary.cpp
Expand Up @@ -36,7 +36,7 @@
void Dictionary::clear(void)
{
m_freeStack = {};
m_keyList.clear();
m_iterator.clear();
m_keyMap.clear();
}

Expand All @@ -49,28 +49,23 @@ uint16_t Dictionary::add(const TokenPtr &token,
// if requested, store upper case of key in hash to make search case
// insensitive (actual string will be stored in key list)
std::string key {token->string().toStdString()};
if (m_caseSensitive == CaseSensitive::No)
{
std::transform(key.begin(), key.end(), key.begin(), toupper);
}
auto iterator = m_keyMap.find(key);
int index;
if (iterator == m_keyMap.end()) // string not present?
{
if (m_freeStack.empty()) // no free indexes available?
{
index = m_keyList.size();
m_keyList.emplace_back(token->string().toStdString());
index = m_iterator.size();
newEntry = EntryType::New;
m_iterator.emplace_back(m_keyMap.emplace(key, index).first);
}
else // use a previously freed index
{
index = m_freeStack.top();
m_freeStack.pop();
m_keyList[index] = token->string().toStdString();
newEntry = EntryType::Reused;
m_iterator[index] = m_keyMap.emplace(key, index).first;
}
m_keyMap.emplace(key, index);
}
else // string already present, update use count
{
Expand All @@ -88,17 +83,12 @@ uint16_t Dictionary::add(const TokenPtr &token,

int Dictionary::remove(uint16_t index)
{
std::string key {m_keyList[index]};
if (m_caseSensitive == CaseSensitive::No)
{
std::transform(key.begin(), key.end(), key.begin(), toupper);
}
auto iterator = m_keyMap.find(key);
auto iterator = m_iterator[index];
if (iterator != m_keyMap.end() && --iterator->second.m_useCount == 0)
{
m_keyList[iterator->second.m_index].clear();
m_freeStack.emplace(iterator->second.m_index);
m_keyMap.erase(iterator);
m_iterator[index] = m_keyMap.end();
return true;
}
return false;
Expand All @@ -108,27 +98,14 @@ int Dictionary::remove(uint16_t index)
QString Dictionary::debugText(const QString header)
{
QString string {QString("\n%1:\n").arg(header)};
for (size_t i {}; i < m_keyList.size(); i++)
for (size_t i {}; i < m_iterator.size(); i++)
{
if (!m_keyList[i].empty())
if (m_iterator[i] != m_keyMap.end())
{
std::string key {m_keyList[i]};
if (m_caseSensitive == CaseSensitive::No)
{
std::transform(key.begin(), key.end(), key.begin(), toupper);
}
auto iterator = m_keyMap.find(key);
if (iterator == m_keyMap.end())
{
string.append(QString("%1: |%2| key not found\n").arg(i)
.arg(QString::fromStdString(m_keyList[i])));
}
else
{
string.append(QString("%1: %2 |%3|\n").arg(i)
.arg(iterator->second.m_useCount)
.arg(QString::fromStdString(m_keyList[i])));
}
auto iterator = m_iterator[i];
string.append(QString("%1: %2 |%3|\n").arg(i)
.arg(iterator->second.m_useCount)
.arg(QString::fromStdString(iterator->first)));
}
}
string.append("Free:");
Expand All @@ -144,10 +121,10 @@ QString Dictionary::debugText(const QString header)
int index {tempStack.top()};
tempStack.pop();
string.append(QString(" %1").arg(index));
if (!m_keyList[index].empty())
if (m_iterator[index] != m_keyMap.end())
{
string.append(QString("|%1|")
.arg(QString::fromStdString(m_keyList[index])));
.arg(QString::fromStdString(m_iterator[index]->first)));
}
}
}
Expand Down
58 changes: 51 additions & 7 deletions dictionary.h
Expand Up @@ -49,14 +49,14 @@ class Dictionary
};

Dictionary(CaseSensitive caseSensitive = CaseSensitive::No) :
m_caseSensitive {caseSensitive} {}
m_keyMap {10, KeyHash {caseSensitive}, KeyEqual {caseSensitive}} {}

void clear(void);
uint16_t add(const TokenPtr &token, EntryType *returnNewEntry = nullptr);
int remove(uint16_t index);
std::string string(int index) const
{
return m_keyList[index];
return m_iterator[index]->first;
}
QString debugText(const QString header);

Expand All @@ -69,12 +69,56 @@ class Dictionary
uint16_t m_useCount; // use count of entry
};

using KeyMap = std::unordered_map<std::string, EntryValue>;
// case sensitive optional key hash function operator
struct KeyHash
{
CaseSensitive caseSensitive;

size_t operator()(const std::string &s) const
{
if (caseSensitive != CaseSensitive::No)
{
return std::hash<std::string>{}(s);
}
std::string s2;
std::transform(s.begin(), s.end(), std::back_inserter(s2), toupper);
return std::hash<std::string>{}(s2);
}
};

// case sensitive optional key equal function operator
struct KeyEqual
{
CaseSensitive caseSensitive;

bool operator()(const std::string &s1, const std::string &s2) const
{
if (caseSensitive != CaseSensitive::No)
{
return s1 == s2;
}
if (s1.size() != s2.size())
{
return false;
}
for (size_t i = 0; i < s1.size(); ++i)
{
if (toupper(s1[i]) != toupper(s2[i]))
{
return false;
}
}
return true;
}
};

using KeyMap = std::unordered_map<std::string, EntryValue, KeyHash,
KeyEqual>;
using KeyIterator = KeyMap::iterator;

CaseSensitive m_caseSensitive; // case sensitive keys
std::stack<uint16_t> m_freeStack; // stack of free items
std::vector<std::string> m_keyList; // list of keys
KeyMap m_keyMap; // hash map of keys to indexes
std::stack<uint16_t> m_freeStack; // stack of free entries
std::vector<KeyIterator> m_iterator; // iterators to entries (by index)
KeyMap m_keyMap; // map of key entries
};


Expand Down

0 comments on commit 1f2483e

Please sign in to comment.