diff --git a/Jupiter/DLList.h b/Jupiter/DLList.h index be9c096..8ca999e 100644 --- a/Jupiter/DLList.h +++ b/Jupiter/DLList.h @@ -46,13 +46,27 @@ namespace Jupiter T *data; }; + /* + * @brief Returns the head of the list + * + * @return Head of the list + */ + Node *getHead() const; + + /* + * @brief Returns the tail of the list + * + * @return Tail of the list + */ + Node *getTail() const; + /** - * @brief Returns the n'th Node in the list. + * @brief Returns the Node at the specified index in the list. * - * @param n Index of the node to return. - * @return n'th Node in the list. + * @param index Index of the node to return. + * @return Node at specified index in the list. */ - Node *getNode(size_t n) const; + Node *getNode(size_t index) const; /** * @brief Gets the data at a specified index. @@ -87,7 +101,7 @@ namespace Jupiter void add(T *data, size_t index); /** - * @brief Adds data to the end of the list. + * @brief Adds data to the tail of the list. * * @param data Data to add to the list. */ @@ -96,7 +110,7 @@ namespace Jupiter /** * @brief Default constructor for the DLList class. */ - DLList(); + DLList() = default; /** * @brief Copy constructor for the DLList class. @@ -111,42 +125,35 @@ namespace Jupiter /** Private members */ private: - Node *head; - Node *end; + Node *m_head = nullptr; + Node *m_tail = nullptr; }; } // Implementation -template Jupiter::DLList::DLList() -{ - Jupiter::DLList::head = nullptr; - Jupiter::DLList::end = nullptr; - Jupiter::List::length = 0; -} - template Jupiter::DLList::DLList(const Jupiter::DLList &source) { Jupiter::List::length = source.length; if (Jupiter::List::length == 0) { - Jupiter::DLList::head = nullptr; - Jupiter::DLList::end = nullptr; + m_head = nullptr; + m_tail = nullptr; } else if (Jupiter::List::length == 1) { Jupiter::DLList::Node *n = new Jupiter::DLList::Node; n->data = source.getNode(0)->data; - Jupiter::DLList::head = n; - Jupiter::DLList::end = n; + m_head = n; + m_tail = n; } else { Jupiter::DLList::Node *sourceNode = source.getNode(0); Jupiter::DLList::Node *n = new Jupiter::DLList::Node; n->data = sourceNode->data; - Jupiter::DLList::head = n; + m_head = n; sourceNode = sourceNode->next; while (sourceNode->next != nullptr) @@ -161,14 +168,14 @@ template Jupiter::DLList::DLList(const Jupiter::DLList &source n = n->next; n->data = sourceNode->data; - Jupiter::DLList::end = n; + m_tail = n; } } template Jupiter::DLList::~DLList() { Jupiter::DLList::Node *p; - Jupiter::DLList::Node *c = Jupiter::DLList::head; + Jupiter::DLList::Node *c = m_head; while (c != nullptr) { p = c; @@ -177,16 +184,26 @@ template Jupiter::DLList::~DLList() } } +template typename Jupiter::DLList::Node *Jupiter::DLList::getHead() const +{ + return m_head; +} + +template typename Jupiter::DLList::Node *Jupiter::DLList::getTail() const +{ + return m_tail; +} + template typename Jupiter::DLList::Node *Jupiter::DLList::getNode(size_t index) const { Jupiter::DLList::Node *r; if (index * 2 < Jupiter::List::length) { - r = Jupiter::DLList::head; + r = m_head; for (size_t i = 0; i < index; i++) r = r->next; return r; } - r = Jupiter::DLList::end; + r = m_tail; for (size_t i = Jupiter::List::length - 1; i > index; i--) r = r->previous; return r; } @@ -203,16 +220,16 @@ template T *Jupiter::DLList::remove(size_t index) template T *Jupiter::DLList::remove(Node *data) { - if (Jupiter::DLList::head == data) + if (m_head == data) { - Jupiter::DLList::head = data->next; + m_head = data->next; if (data->next != nullptr) data->next->previous = data->previous; - else Jupiter::DLList::end = nullptr; + else m_tail = nullptr; } - else if (Jupiter::DLList::end == data) + else if (m_tail == data) { - Jupiter::DLList::end = data->previous; - Jupiter::DLList::end->next = nullptr; + m_tail = data->previous; + m_tail->next = nullptr; } else { @@ -231,16 +248,16 @@ template void Jupiter::DLList::add(T *data, size_t index) node->data = data; if (index == 0) { - node->next = Jupiter::DLList::head; - Jupiter::DLList::head->previous = node; - Jupiter::DLList::head = node; + node->next = m_head; + m_head->previous = node; + m_head = node; node->previous = nullptr; } else if (index == Jupiter::List::length) { - node->previous = Jupiter::DLList::end; - Jupiter::DLList::end->next = node; - Jupiter::DLList::end = node; + node->previous = m_tail; + m_tail->next = node; + m_tail = node; node->next = nullptr; } else @@ -261,15 +278,15 @@ template void Jupiter::DLList::add(T *data) n->next = nullptr; if (Jupiter::List::length == 0) { - Jupiter::DLList::head = n; - Jupiter::DLList::end = n; + m_head = n; + m_tail = n; n->previous = nullptr; } else { - n->previous = Jupiter::DLList::end; - Jupiter::DLList::end->next = n; - Jupiter::DLList::end = n; + n->previous = m_tail; + m_tail->next = n; + m_tail = n; } Jupiter::List::length++; } diff --git a/Jupiter/Hash.c b/Jupiter/Hash.c deleted file mode 100644 index c8358f2..0000000 --- a/Jupiter/Hash.c +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (C) 2015 Jessica James. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Written by Jessica James - */ - -#include "Hash.h" -#include - -const uint32_t JUPITER_FNV_1_32_OFFSET_BASIS = 2166136261UL; -const uint64_t JUPITER_FNV_1_64_OFFSET_BASIS = 14695981039346656037ULL; -const uint32_t JUPITER_FNV_1_32_PRIME = 16777619UL; -const uint64_t JUPITER_FNV_1_64_PRIME = 1099511628211ULL; - -uint64_t Jupiter_fnv1(void *data, size_t length) -{ - uint8_t *ptr = (uint8_t *)data; - uint64_t hash = JUPITER_FNV_1_64_OFFSET_BASIS; - while (length-- != 0) - { - hash = hash * JUPITER_FNV_1_64_PRIME; - hash = hash ^ *ptr++; - } - return hash; -} - -uint64_t Jupiter_fnv1a(void *data, size_t length) -{ - uint8_t *ptr = (uint8_t *)data; - uint64_t hash = JUPITER_FNV_1_64_OFFSET_BASIS; - while (length-- != 0) - { - hash = hash ^ *ptr++; - hash = hash * JUPITER_FNV_1_64_PRIME; - } - return hash; -} \ No newline at end of file diff --git a/Jupiter/Hash.cpp b/Jupiter/Hash.cpp new file mode 100644 index 0000000..11e2e10 --- /dev/null +++ b/Jupiter/Hash.cpp @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2015-2016 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#include "Hash.h" + +/** Constants */ +constexpr uint32_t JUPITER_FNV_1_32_OFFSET_BASIS = 2166136261UL; +constexpr uint64_t JUPITER_FNV_1_64_OFFSET_BASIS = 14695981039346656037ULL; +constexpr uint32_t JUPITER_FNV_1_32_PRIME = 16777619UL; +constexpr uint64_t JUPITER_FNV_1_64_PRIME = 1099511628211ULL; + +/** Fowler-Noll-Vo */ + +uint64_t Jupiter::fnv1(const uint8_t *data, const uint8_t *end) +{ + uint64_t hash = JUPITER_FNV_1_64_OFFSET_BASIS; + + while (data != end) + { + hash = hash * JUPITER_FNV_1_64_PRIME; + hash = hash ^ *data; + ++data; + } + + return hash; +} + +uint64_t Jupiter::fnv1a(const uint8_t *data, const uint8_t *end) +{ + uint64_t hash = JUPITER_FNV_1_64_OFFSET_BASIS; + + while (data != end) + { + hash = hash ^ *data; + hash = hash * JUPITER_FNV_1_64_PRIME; + ++data; + } + + return hash; +} + +uint32_t Jupiter::fnv1_32(const uint8_t *data, const uint8_t *end) +{ + uint32_t hash = JUPITER_FNV_1_32_OFFSET_BASIS; + + while (data != end) + { + hash = hash * JUPITER_FNV_1_32_PRIME; + hash = hash ^ *data; + ++data; + } + + return hash; +} + +uint32_t Jupiter::fnv1a_32(const uint8_t *data, const uint8_t *end) +{ + uint32_t hash = JUPITER_FNV_1_32_OFFSET_BASIS; + + while (data != end) + { + hash = hash ^ *data; + hash = hash * JUPITER_FNV_1_32_PRIME; + ++data; + } + + return hash; +} \ No newline at end of file diff --git a/Jupiter/Hash.h b/Jupiter/Hash.h index 0b616b2..baefd0f 100644 --- a/Jupiter/Hash.h +++ b/Jupiter/Hash.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Jessica James. + * Copyright (C) 2015-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,53 +24,121 @@ * @brief Defines some hashing algorithms. */ -#include "Jupiter.h" -#if defined __cplusplus #include +#include "Jupiter.h" +#include "Readable_String.h" namespace Jupiter { + /** Sums */ + template inline R calcsum(const T *in_data, size_t in_length); + template inline R calcsum(const Jupiter::Readable_String &str); + /** Fowler-Noll-Vo hash algorithms */ + template inline uint64_t fnv1(const T &data); template inline uint64_t fnv1(const T *str, size_t length); template inline uint64_t fnv1(const Jupiter::Readable_String &str); + template inline uint32_t fnv1_32(const T &data); + template inline uint32_t fnv1_32(const T *str, size_t length); + template inline uint32_t fnv1_32(const Jupiter::Readable_String &str); + + template inline uint64_t fnv1a(const T &data); template inline uint64_t fnv1a(const T *str, size_t length); template inline uint64_t fnv1a(const Jupiter::Readable_String &str); + + template inline uint32_t fnv1a_32(const T &data); + template inline uint32_t fnv1a_32(const T *str, size_t length); + template inline uint32_t fnv1a_32(const Jupiter::Readable_String &str); + + JUPITER_API uint64_t fnv1(const uint8_t *data, const uint8_t *end); + JUPITER_API uint64_t fnv1a(const uint8_t *data, const uint8_t *end); + + JUPITER_API uint32_t fnv1_32(const uint8_t *data, const uint8_t *end); + JUPITER_API uint32_t fnv1a_32(const uint8_t *data, const uint8_t *end); } -extern "C" +/** Calcsum implementation */ + +template inline R Jupiter::calcsum(const T *in_data, size_t in_length) { -#else -#include -#endif // __cplusplus + const uint8_t *itr = reinterpret_cast(in_data); + const uint8_t *end = reinterpret_cast(in_data + in_length); + R sum = 0; -JUPITER_API uint64_t Jupiter_fnv1(void *data, size_t length); -JUPITER_API uint64_t Jupiter_fnv1a(void *data, size_t length); + while (itr != end) + { + sum += *itr; + ++itr; + } -#if defined __cplusplus + return sum; +} + +template inline R Jupiter::calcsum(const Jupiter::Readable_String &str) +{ + return Jupiter::calcsum(str.ptr(), str.size()); } /** fnv1 implementation */ +template inline uint64_t Jupiter::fnv1(const T &data) +{ + return Jupiter::fnv1(&data, &data + 1); +} + template inline uint64_t Jupiter::fnv1(const T *data, size_t length) { - return Jupiter_fnv1(data, length * sizeof(T)); + return Jupiter::fnv1(reinterpret_cast(data), reinterpret_cast(data + length)); } template inline uint64_t Jupiter::fnv1(const Jupiter::Readable_String &data) { - return Jupiter_fnv1(data.ptr(), data.size() * sizeof(T)); + return Jupiter::fnv1(reinterpret_cast(data.ptr()), reinterpret_cast(data.ptr() + data.size())); +} + +template inline uint32_t Jupiter::fnv1_32(const T &data) +{ + return Jupiter::fnv1_32(&data, &data + 1); +} + +template inline uint32_t Jupiter::fnv1_32(const T *data, size_t length) +{ + return Jupiter::fnv1_32(reinterpret_cast(data), reinterpret_cast(data + length)); +} + +template inline uint32_t Jupiter::fnv1_32(const Jupiter::Readable_String &data) +{ + return Jupiter::fnv1_32(reinterpret_cast(data.ptr()), reinterpret_cast(data.ptr() + data.size())); +} + +template inline uint64_t Jupiter::fnv1a(const T &data) +{ + return Jupiter::fnv1a(reinterpret_cast(&data), reinterpret_cast(&data + 1)); } template inline uint64_t Jupiter::fnv1a(const T *data, size_t length) { - return Jupiter_fnv1a(data, length * sizeof(T)); + return Jupiter::fnv1a(reinterpret_cast(data), reinterpret_cast(data + length)); } template inline uint64_t Jupiter::fnv1a(const Jupiter::Readable_String &data) { - return Jupiter_fnv1a(data.ptr(), data.size() * sizeof(T)); + return Jupiter::fnv1a(data.ptr(), data.size()); } -#endif // __cplusplus +template inline uint32_t Jupiter::fnv1a_32(const T &data) +{ + return Jupiter::fnv1a_32(reinterpret_cast(&data), reinterpret_cast(&data + 1)); +} + +template inline uint32_t Jupiter::fnv1a_32(const T *data, size_t length) +{ + return Jupiter::fnv1a_32(reinterpret_cast(data), reinterpret_cast(data + length)); +} + +template inline uint32_t Jupiter::fnv1a_32(const Jupiter::Readable_String &data) +{ + return Jupiter::fnv1a_32(data.ptr(), data.size()); +} #endif // _HASH_H_HEADER \ No newline at end of file diff --git a/Jupiter/Hash_Table.h b/Jupiter/Hash_Table.h new file mode 100644 index 0000000..c307d1f --- /dev/null +++ b/Jupiter/Hash_Table.h @@ -0,0 +1,242 @@ +/** + * Copyright (C) 2016 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#if !defined _HASH_TABLE_H_HEADER +#define _HASH_TABLE_H_HEADER + +/** + * @file Hash_Table.h + * @brief Defines a generic hash table structure + */ + +#include "String.h" +#include "SLList.h" + +namespace Jupiter +{ + template inline size_t default_hash_function(const T &in); + + /** + * @brief Provides a generic hash table structure + * + * @param KeyT Type the table will use for keys; must implement following: operator==, move constructor + * @param ValueT Type the table will use for values + * @param InKeyT Type the table will accept for keys (Default: KeyT) + * @param InValueT Type the table will accept for values (Default: KeyT) + * @param HashF Function to be used for generating hashes (Default: Fowler-Noll-Vo 1a) + */ + template> class Hash_Table + { + public: + /** Initial number of buckets to allocate; m_buckets_size is never less than INIT_SIZE. */ + static constexpr const size_t INIT_SIZE = 8; + + /** + * @brief Container for table entries + */ + struct Bucket + { + /** + * @brief An individual entry within the table, including its normal key and value. + */ + struct Entry + { + KeyT key; + ValueT value; + + Entry(const InKeyT &in_key, const InValueT &in_value); + }; + + /** + * @brief Searches for an entry in the bucket and returns its value if it exists. + * + * @param in_key Key of the entry to search for + * @return Pointer to the value of the entry if it exists, nullptr otherwise + */ + ValueT *get(const InKeyT &in_key) const; + + /** + * @brief Sets the value for an entry in the bucket + * + * @param in_key Key of the entry to set + * @param in_value Value to set in the entry + * @return True if a new entry was added, false if an entry was overwritten + */ + bool set(const InKeyT &in_key, const InValueT &in_value); + + /** + * @brief Removes an entry from the bucket + * + * @param in_key Key of the entry to search for + * @return Value of the entry which was removed on success, nullptr otherwise + */ + ValueT *remove(const InKeyT &in_key); + + /** + * @brief Copy assignment operator + * + * @param in_bucket Bucket to copy entries from + * @return Reference to this bucket + */ + Bucket &operator=(const Bucket &in_bucket); + + /** + * @brief Move assignment operator + * + * @param in_bucket Bucket to move entries from + * @return Reference to this bucket + */ + Bucket &operator=(Bucket &&in_bucket); + + /** + * @brief Default constructor for the Bucket class + */ + Bucket() = default; + + /** + * @brief Copy constructor for the Bucket class + */ + Bucket(const Bucket &in_bucket); + + /** + * @brief Move constructor for the Bucket class + */ + Bucket(Bucket &&in_bucket); + + /** + * @brief Destructor for the Bucket class + */ + ~Bucket(); + + /** List of entries in the bucket */ + Jupiter::SLList m_pairs; + }; + + /** + * @brief Fetches the value of an entry based on its key + * + * @param in_key Key of the entry to search for + * @return Value of the entry if it exists, nullptr otherwise + */ + ValueT *get(const InKeyT &in_key) const; + + /** + * @brief Sets the value for an entry in the table + * + * @param in_key Key of the entry to set + * @param in_value Value of the entry to set + */ + void set(const InKeyT &in_key, const InValueT &in_value); + + /** + * @brief Removes an entry from the table and returns its value + * + * @param in_key Key of the entry to remove + * @return Value of the entry that was removed if it exists, nullptr otherwise + */ + ValueT *remove(const InKeyT &in_key); + + /** + * @brief Returns the number of entries in the table + * + * @return Number of entries in the table + */ + size_t size() const; + + /** + * @brief Erases the table's contents + */ + void erase(); + + /** + * @brief Shrinks the table's internal bucket pool to the current number of entries, not to be less than INIT_SIZE. + */ + void shrink(); + + /** + * @brief Copy assignment operator + * + * @param in_table Table to copy entries from + * @return Reference to this table + */ + Hash_Table &operator=(const Hash_Table &in_table); + + /** + * @brief Move assignment operator + * + * @param in_table Table to move entries from + * @return Reference to this table + */ + Hash_Table &operator=(Hash_Table &&in_table); + + /** + * @brief Default constructor for the Hash_Table class + */ + Hash_Table(); + + /** + * @brief Allocation constructor for the Hash_Table class + * + * @param in_buckets_size Number of buckets to initialize to + */ + Hash_Table(size_t in_buckets_size); + + /** + * @brief Copy constructor for the Hash_Table class + * + * @param in_table Table to copy entries from + */ + Hash_Table(const Hash_Table &in_table); + + /** + * @brief Move constructor for the Hash_Table class + * + * @param in_table Table to move entries from + */ + Hash_Table(Hash_Table &&in_table); + + /** + * @brief Destructor for the Hash_Table class + */ + ~Hash_Table(); + + private: + /** + * @brief Doubles the size of m_buckets + */ + void expand(); + + /** + * @brief Copies entries from m_buckets to in_buckets; used when expanding or shrinking m_buckets. + * + * @param in_buckets Array of buckets to copy entries into + * @param in_buckets_size Number of buckets in in_buckets + */ + void copy_to_buckets(Bucket *in_buckets, size_t in_buckets_size); + + Bucket *m_buckets; /** Array of Buckets */ + size_t m_buckets_size; /** Number of buckets */ + size_t m_length = 0; /** Number of entries */ + }; + + typedef Hash_Table> HashTable; +} + +#include "Hash_Table_Imp.h" + +#endif // _HASH_TABLE_H_HEADER \ No newline at end of file diff --git a/Jupiter/Hash_Table_Imp.h b/Jupiter/Hash_Table_Imp.h new file mode 100644 index 0000000..8b49045 --- /dev/null +++ b/Jupiter/Hash_Table_Imp.h @@ -0,0 +1,317 @@ +/** + * Copyright (C) 2016 Jessica James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Jessica James + */ + +#if !defined _HASH_TABLE_IMP_H_HEADER +#define _HASH_TABLE_IMP_H_HEADER + +/** +* @file Hash_Table_Imp.h +* @brief Provides the implementation for Hash_Table. +*/ + +#include "Hash_Table.h" +#include "Hash.h" + +/** +* IMPLEMENTATION: +* Hash_Table +*/ + +template inline size_t Jupiter::default_hash_function(const T &in) +{ + if (sizeof(size_t) >= sizeof(uint64_t)) + return static_cast(Jupiter::fnv1a(in)); + + return static_cast(Jupiter::fnv1a_32(in)); +} + +/** Hash_Table::Bucket::Entry */ + +template +Jupiter::Hash_Table::Bucket::Entry::Entry(const InKeyT &in_key, const InValueT &in_value) +{ + key = in_key; + value = in_value; +} + +/** Hash_Table::Bucket */ + +template +ValueT *Jupiter::Hash_Table::Bucket::get(const InKeyT &in_key) const +{ + for (Jupiter::SLList::Node *node = m_pairs.getHead(); node != nullptr; node = node->next) + if (node->data->key == in_key) + return &node->data->value; + + return nullptr; +} + +template +bool Jupiter::Hash_Table::Bucket::set(const InKeyT &in_key, const InValueT &in_value) +{ + for (Jupiter::SLList::Node *node = m_pairs.getHead(); node != nullptr; node = node->next) + if (node->data->key == in_key) + { + node->data->value = in_value; + return false; + } + + m_pairs.add(new Entry(in_key, in_value)); + return true; +} + +template +ValueT *Jupiter::Hash_Table::Bucket::remove(const InKeyT &in_key) +{ + Jupiter::SLList::Node *node = m_pairs.getHead(); + Entry *pair; + ValueT *result; + + // No nodes in the bucket + if (node == nullptr) + return nullptr; + + // Check if the head is the desired node + if (node->data->key == in_key) + { + pair = m_pairs.removeHead(); + result = new ValueT(std::move(pair->value)); + delete pair; + + return result; + } + + // iterate through list + while (node->next != nullptr) + { + if (node->next->data->key == in_key) + { + // The next node is the desired node + pair = m_pairs.removeNext(node); + result = new ValueT(std::move(pair->value)); + delete pair; + + return result; + } + node = node->next; + } + + return nullptr; +} + +template +typename Jupiter::Hash_Table::Bucket &Jupiter::Hash_Table::Bucket::operator=(const Bucket &in_bucket) +{ + m_pairs.eraseAndDelete(); + for (Jupiter::SLList::Node *node = in_bucket.m_pairs.getHead(); node != nullptr; node = node->next) + m_pairs.add(new Entry(node->data->key, node->data->value)); + + return *this; +} + +template +typename Jupiter::Hash_Table::Bucket &Jupiter::Hash_Table::Bucket::operator=(Bucket &&in_bucket) +{ + m_pairs = std::move(in_bucket.m_pairs); + return *this; +} + +template +Jupiter::Hash_Table::Bucket::Bucket(const Bucket &in_bucket) +{ + for (Jupiter::SLList::Node *node = in_bucket.m_pairs.getHead(); node != nullptr; node = node->next) + m_pairs.add(new Entry(node->data->key, node->data->value)); +} + +template +Jupiter::Hash_Table::Bucket::Bucket(Bucket &&in_bucket) +{ + m_pairs = std::move(in_bucket.m_pairs); +} + +template +Jupiter::Hash_Table::Bucket::~Bucket() +{ + m_pairs.eraseAndDelete(); +} + +/** Hash_Table */ + +template +ValueT *Jupiter::Hash_Table::get(const InKeyT &in_key) const +{ + return m_buckets[HashF(in_key) % m_buckets_size].get(in_key); +} + +template +void Jupiter::Hash_Table::set(const InKeyT &in_key, const InValueT &in_value) +{ + if (m_buckets[HashF(in_key) % m_buckets_size].set(in_key, in_value)) + if (++m_length == m_buckets_size) + expand(); +} + +template +ValueT *Jupiter::Hash_Table::remove(const InKeyT &in_key) +{ + ValueT *value = m_buckets[HashF(in_key) % m_buckets_size].remove(in_key); + + if (value != nullptr) + --m_length; + + return value; +} + +template +size_t Jupiter::Hash_Table::size() const +{ + return m_length; +} + +template +void Jupiter::Hash_Table::erase() +{ + m_length = 0; + delete[] m_buckets; + + m_buckets_size = INIT_SIZE; + m_buckets = new Bucket[m_buckets_size]; +} + +template +void Jupiter::Hash_Table::shrink() +{ + size_t buckets_size = m_length < INIT_SIZE ? INIT_SIZE : m_length; + Bucket *buckets = new Bucket[buckets_size]; + + copy_to_buckets(buckets, buckets_size); + + delete[] m_buckets; + m_buckets = buckets; + m_buckets_size = buckets_size; +} + +template +typename Jupiter::Hash_Table &Jupiter::Hash_Table::operator=(const Hash_Table &in_table) +{ + // TODO: Optimize; can overwrite data instead of deleting and allocationg again if m_buckets_size > in.m_buckets_size + delete[] m_buckets; + + m_length = in_table.m_length; + m_buckets_size = in_table.m_buckets_size; + m_buckets = new Bucket[m_buckets_size]; + + for (size_t index = 0; index != m_buckets_size; ++index) + m_buckets[index] = in_table.m_buckets[index]; + + return *this; +} + +template +typename Jupiter::Hash_Table &Jupiter::Hash_Table::operator=(Hash_Table &&in_table) +{ + // TODO: Optimize; can swap empty array instead of always deleting + delete[] m_buckets; + + m_buckets = in_table.m_buckets; + m_buckets_size = in_table.m_buckets_size; + m_length = in_table.m_length; + + in_table.m_buckets = new Bucket[1]; + in_table.m_buckets_size = 1; + in_table.m_length = 0; + return *this; +} + +/** Constructors */ + +template +Jupiter::Hash_Table::Hash_Table() +{ + m_buckets_size = INIT_SIZE; + m_buckets = new Bucket[m_buckets_size]; +} + +template +Jupiter::Hash_Table::Hash_Table(size_t in_buckets_size) +{ + m_buckets_size = in_buckets_size; + m_buckets = new Bucket[m_buckets_size]; +} + +template +Jupiter::Hash_Table::Hash_Table(const Hash_Table &in_table) +{ + m_length = in_table.m_length; + m_buckets_size = in_table.m_buckets_size; + m_buckets = new Bucket[m_buckets_size]; + + for (size_t index = 0; index != m_buckets_size; ++index) + m_buckets[index] = in_table.m_buckets[index]; +} + +template +Jupiter::Hash_Table::Hash_Table(Hash_Table &&in_table) +{ + m_buckets = in_table.m_buckets; + m_buckets_size = in_table.m_buckets_size; + m_length = in_table.m_length; + + in_table.m_buckets = new Bucket[1]; + in_table.m_buckets_size = 1; + in_table.m_length = 0; +} + +template +Jupiter::Hash_Table::~Hash_Table() +{ + delete[] m_buckets; +} + +/** Hash_Table/private */ + +template +void Jupiter::Hash_Table::expand() +{ + size_t buckets_size = m_buckets_size * 2; + Bucket *buckets = new Bucket[buckets_size]; + + copy_to_buckets(buckets, buckets_size); + + delete[] m_buckets; + m_buckets = buckets; + m_buckets_size = buckets_size; +} + +template +void Jupiter::Hash_Table::copy_to_buckets(Bucket *in_buckets, size_t in_buckets_size) +{ + Jupiter::SLList::Node *node; + for (size_t index = 0; index != m_buckets_size; ++index) + { + for (node = m_buckets[index].m_pairs.getHead(); node != nullptr; node = node->next) + in_buckets[HashF(node->data->key) % in_buckets_size].set(node->data->key, node->data->value); + } +} + +/* +template +Jupiter::Hash_Table +*/ + +#endif // _HASH_TABLE_IMP_H_HEADER \ No newline at end of file diff --git a/Jupiter/Jupiter.vcxproj b/Jupiter/Jupiter.vcxproj index 34ccf47..9acbe91 100644 --- a/Jupiter/Jupiter.vcxproj +++ b/Jupiter/Jupiter.vcxproj @@ -182,7 +182,7 @@ - + @@ -210,6 +210,8 @@ + + diff --git a/Jupiter/Jupiter.vcxproj.filters b/Jupiter/Jupiter.vcxproj.filters index aea77b0..bb40027 100644 --- a/Jupiter/Jupiter.vcxproj.filters +++ b/Jupiter/Jupiter.vcxproj.filters @@ -55,6 +55,9 @@ {7a4d818a-481e-467c-a3e3-d6d0e7dde244} + + {7db21243-8b23-4dd2-9888-0bdd3c5a1edd} + @@ -105,9 +108,6 @@ Source Files\IRC - - Source Files - Source Files @@ -123,6 +123,9 @@ Source Files\Object Extensions + + Source Files + @@ -233,9 +236,6 @@ Header Files\Strings - - Header Files - Header Files\Files @@ -260,6 +260,15 @@ Header Files\Object Extensions + + Header Files\Hash + + + Header Files\Hash + + + Header Files\Hash + diff --git a/Jupiter/SLList.h b/Jupiter/SLList.h index a18bf6d..231918c 100644 --- a/Jupiter/SLList.h +++ b/Jupiter/SLList.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013-2015 Jessica James. + * Copyright (C) 2013-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -45,13 +45,27 @@ namespace Jupiter T *data = nullptr; }; + /* + * @brief Returns the head of the list + * + * @return Head of the list + */ + Node *getHead() const; + + /* + * @brief Returns the tail of the list + * + * @return Tail of the list + */ + Node *getTail() const; + /** - * @brief Returns the n'th Node in the list. + * @brief Returns the Node at the specified index in the list. * - * @param n Index of the node to return. - * @return n'th Node in the list. + * @param index Index of the node to return. + * @return Node at specified index in the list. */ - Node *getNode(size_t n) const; + Node *getNode(size_t index) const; /** * @brief Gets the data at a specified index. @@ -61,6 +75,13 @@ namespace Jupiter */ T *get(size_t index) const; + /** + * @brief Removes the head of the list + * + * @return Value that was stored in the head of the list + */ + T *removeHead(); + /** * @brief Removes the n'th Node in the list, and returns its contents. * @@ -78,29 +99,58 @@ namespace Jupiter T *removeNext(Node *data); /** - * @brief Adds data to the list at a specified index. + * @brief Adds data to the end of the list. * * @param data Data to add to the list. - * @param index Position in the list to add the data to. + */ + void add(T *data); + + /** + * @brief Inserts data to the specified index in the list. + * + * @param data Data to insert into the list. + * @param index Position in the list to insert data to. */ void add(T *data, size_t index); /** - * @brief Adds data to the front of the list. + * @brief Inserts data to the head of the list. * - * @param data Data to add to the list. + * @param data Data to insert into the list. */ - void add(T *data); + void addHead(T *data); + + /** + * @breif Erases all entries in the list + */ + void erase(); + + /** + * @breif Erases and deletes all entries in the list + */ + void eraseAndDelete(); + + SLList &operator=(const SLList &in_list); + SLList &operator=(SLList &&in_list); /** * @brief Default constructor for the SLList class. */ - SLList(); + SLList() = default; /** * @brief Copy constructor for the SLList class. + * + * @param in_list List to copy data from */ - SLList(const SLList &); + SLList(const SLList &in_list); + + /** + * @brief Move constructor for the SLList class + * + * @param in_list List to move data from + */ + SLList(SLList &&in_list); /** * @brief Destructor for the SLList class. @@ -110,105 +160,200 @@ namespace Jupiter /** Private members */ private: - Node *head; + void copy_from_internal(const SLList &in_list); + + Node *m_head = nullptr; + Node *m_tail = nullptr; }; } // Implementation -template Jupiter::SLList::SLList() +template typename Jupiter::SLList::Node *Jupiter::SLList::getHead() const { - Jupiter::SLList::head = new Jupiter::SLList::Node(); - Jupiter::List::length = 0; + return m_head; } -template Jupiter::SLList::SLList(const Jupiter::SLList &source) +template typename Jupiter::SLList::Node *Jupiter::SLList::getTail() const { - Jupiter::SLList::head = new Jupiter::SLList::Node(); - Jupiter::SLList::Node *sourceNode = source.head; - - head->data = sourceNode->data; - sourceNode = sourceNode->next; + return m_tail; +} + +template typename Jupiter::SLList::Node *Jupiter::SLList::getNode(size_t in_index) const +{ + if (in_index == Jupiter::SLList::length) + return m_tail; - Jupiter::SLList::Node *n = Jupiter::SLList::head; + Jupiter::SLList::Node *node = m_head; - while (sourceNode != nullptr) + while (in_index != 0) { - n->next = new Jupiter::SLList::Node(); - n = n->next; - n->data = sourceNode->data; - sourceNode = sourceNode->next; + node = node->next; + --in_index; } - Jupiter::List::length = source.length; + + return node; } -template Jupiter::SLList::~SLList() +template T *Jupiter::SLList::get(size_t in_index) const { - Jupiter::SLList::Node *p; - Jupiter::SLList::Node *c = head; - do - { - p = c; - c = c->next; - delete p; - } while (c != nullptr); + return Jupiter::SLList::getNode(in_index)->data; } -template typename Jupiter::SLList::Node *Jupiter::SLList::getNode(size_t index) const +template T *Jupiter::SLList::removeHead() { - Jupiter::SLList::Node *t = head->next; - for (size_t i = 0; i != index; i++) t = t->next; - return t; + if (m_head == nullptr) + return nullptr; + + T *result = m_head->data; + + Jupiter::SLList::Node *node = m_head; + m_head = m_head->next; + delete node; + --Jupiter::List::length; + + return result; } -template T *Jupiter::SLList::get(size_t index) const +template T *Jupiter::SLList::remove(size_t in_index) { - return Jupiter::SLList::getNode(index)->data; + if (in_index == 0) + return Jupiter::SLList::removeHead(); + + Jupiter::SLList::Node *node = m_head; + + while (in_index != 1) + { + node = node->next; + --in_index; + } + + Jupiter::SLList::Node *tmp = node->next; + T *result = tmp->data; + + node->next = tmp->next; + delete tmp; + --Jupiter::List::length; + + return result; } -template T *Jupiter::SLList::remove(size_t index) +template T *Jupiter::SLList::removeNext(Node *in_data) { - Jupiter::SLList::Node *t = head; - for (size_t i = 0; i != index; i++) - t = t->next; - Jupiter::SLList::Node *t2 = t->next; - t->next = t2->next; - T *r = t2->data; - delete t2; + Jupiter::SLList::Node *node = in_data->next; + + if (node == nullptr) + return nullptr; + + T *result = node->data; + + in_data->next = node->next; + delete node; --Jupiter::List::length; - return r; + + return result; +} + +template void Jupiter::SLList::add(T *data) +{ + Jupiter::SLList::Node *node = new Jupiter::SLList::Node(); + node->data = data; + + if (m_head == nullptr) + m_head = node; + else + m_tail->next = node; + + m_tail = node; + ++Jupiter::List::length; +} + +template void Jupiter::SLList::add(T *in_data, size_t in_index) +{ + if (in_index == 0) + { + Jupiter::SLList::addHead(in_data); + return; + } + + if (in_index >= Jupiter::List::length) + { + Jupiter::SLList::add(in_data); + return; + } + + Jupiter::SLList::Node *node = new Jupiter::SLList::Node(); + node->data = in_data; + + Jupiter::SLList::Node *itr = m_head; + + while (in_index != 1) + { + itr = itr->next; + --in_index; + } + + node->next = itr->next; + itr->next = node; + + ++Jupiter::List::length; } -template T *Jupiter::SLList::removeNext(Node *data) +template void Jupiter::SLList::addHead(T *data) { - Jupiter::SLList::Node *t = data->next; - if (t == nullptr) return nullptr; - T *r = t->data; - data->next = t->next; - delete t; - Jupiter::List::length--; - return r; + Jupiter::SLList::Node *node = new Jupiter::SLList::Node(); + node->data = data; + node->next = m_head; + m_head = node; + + if (m_tail == nullptr) + m_tail = node; + + ++Jupiter::List::length; } -template void Jupiter::SLList::add(T *data, size_t index) +template void Jupiter::SLList::erase() { - Jupiter::SLList::Node *n = new Jupiter::SLList::Node(); - n->data = data; - Jupiter::SLList::Node *t = Jupiter::SLList::head; - for (size_t i = 0; i < index; i++) t = t->next; - n->next = t->next; - t->next = n; - Jupiter::List::length++; + Jupiter::SLList::Node *node = m_head; + + if (node == nullptr) + return; + + Jupiter::SLList::Node *tmp; + + do + { + tmp = node; + node = node->next; + delete tmp; + } while (node != nullptr); + + m_head = nullptr; + m_tail = nullptr; + Jupiter::List::length = 0; } -template void Jupiter::SLList::add(T *data) +template void Jupiter::SLList::eraseAndDelete() { - Jupiter::SLList::Node *n = new Jupiter::SLList::Node(); - n->data = data; - n->next = Jupiter::SLList::head->next; - Jupiter::SLList::head->next = n; - Jupiter::List::length++; + Jupiter::SLList::Node *node = m_head; + + if (node == nullptr) + return; + + Jupiter::SLList::Node *tmp; + + do + { + tmp = node; + node = node->next; + delete tmp->data; + delete tmp; + } while (node != nullptr); + + m_head = nullptr; + m_tail = nullptr; + Jupiter::List::length = 0; } template<> struct _Jupiter_DataBuffer_partial_specialization_impl @@ -216,7 +361,7 @@ template<> struct _Jupiter_DataBuffer_partial_specialization_impl static void push(Jupiter::DataBuffer *buffer, const Jupiter::SLList *data) { buffer->push(data->size()); - Jupiter::SLList::Node *head = data->getNode(0); + Jupiter::SLList::Node *head = data->getHead(); while (head != nullptr) buffer->push(*head++->data); }; @@ -232,4 +377,65 @@ template<> struct _Jupiter_DataBuffer_partial_specialization_impl Jupiter::SLList &Jupiter::SLList::operator=(const SLList &in_list) +{ + Jupiter::SLList::erase(); + + Jupiter::SLList::copy_from_internal(in_list); + + return *this; +} + +template Jupiter::SLList &Jupiter::SLList::operator=(SLList &&in_list) +{ + m_head = in_list.m_head; + m_tail = in_list.m_tail; + + return *this; +} + +template Jupiter::SLList::SLList(const Jupiter::SLList &in_list) +{ + Jupiter::SLList::copy_from_internal(in_list); +} + +template Jupiter::SLList::SLList(Jupiter::SLList &&in_list) +{ + m_head = in_list.m_head; + m_tail = in_list.m_tail; + + in_list.m_head = nullptr; + in_list.m_tail = nullptr; +} + +template Jupiter::SLList::~SLList() +{ + Jupiter::SLList::erase(); +} + +/** Internal */ + +template void Jupiter::SLList::copy_from_internal(const SLList &in_list) +{ + Jupiter::SLList::Node *source_node = in_list.m_head; + + if (source_node == nullptr) + return; + + Jupiter::SLList::Node *node = new Jupiter::SLList::Node(); + node->data = source_node->data; + source_node = source_node->next; + + while (source_node != nullptr) + { + node->next = new Jupiter::SLList::Node(); + node = node->next; + node->data = source_node->data; + source_node = source_node->next; + } + + m_tail = node; + Jupiter::List::length = in_list.length; +} + #endif // _SLLIST_H_HEADER \ No newline at end of file diff --git a/Jupiter/String_Imp.h b/Jupiter/String_Imp.h index 8fdfd31..f1614d1 100644 --- a/Jupiter/String_Imp.h +++ b/Jupiter/String_Imp.h @@ -22,7 +22,6 @@ /** * @file String_Imp.h * @brief Provides the implementations for String_Strict and String_Loose. -* Note: Modification of this file is not supported in any way. */ #include "String.h" diff --git a/Release/Jupiter.lib b/Release/Jupiter.lib deleted file mode 100644 index 53117fd..0000000 Binary files a/Release/Jupiter.lib and /dev/null differ diff --git a/Tester/Test.cpp b/Tester/Test.cpp index 8633875..023ea9c 100644 --- a/Tester/Test.cpp +++ b/Tester/Test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Jupiter/Functions.h" #include "Jupiter/CString.h" #include "Jupiter/String.h" @@ -9,6 +10,11 @@ #include "Jupiter/InvalidIndex.h" #include "Jupiter/Reference_String.h" #include "Jupiter/DataBuffer.h" +#include "Jupiter/HTTP.h" +#include "Jupiter/HTTP_Server.h" +#include "Jupiter/HTTP_QueryString.h" +#include "Jupiter/Hash.h" +#include "Jupiter/Hash_Table.h" using namespace Jupiter; using namespace Jupiter::literals; @@ -18,16 +24,35 @@ unsigned int totalTests = 0; void test(bool expr) { - totalTests++; - if (expr) goodTests++; - else printf("Test number %u failed!" ENDL, totalTests); + ++totalTests; + if (expr) + ++goodTests; + else + printf("Test number %u failed!" ENDL, totalTests); +} + +Jupiter::StringS randstr(size_t length) +{ + StringS str; + + while (length != 0) + { + str += ' ' + rand() % ('z' - ' '); + --length; + } + + return str; } int main() { - if (goodTests == totalTests) printf("All %u tests succeeded." ENDL, totalTests); - else printf("ERROR: Only %u/%u tests succeeded. %u tests failed." ENDL, goodTests, totalTests, totalTests - goodTests); + if (goodTests == totalTests) + printf("All %u tests succeeded." ENDL, totalTests); + else + printf("ERROR: Only %u/%u tests succeeded. %u tests failed." ENDL, goodTests, totalTests, totalTests - goodTests); + puts("Press any key to continue..."); fgetc(stdin); + return 0; -} \ No newline at end of file +}