From b851808a5dd6c647a8ad0f382d55b240300ca93d Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Sun, 5 Nov 2017 10:05:03 -0800 Subject: [PATCH 001/102] Added repo token to coveralls.yml (#34) --- .coveralls.yml | 1 + .travis.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .coveralls.yml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 00000000..2f41ac1f --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +repo_token: 3Te84vayRwnQuCXcPP8iYI1m55iKZl2yL diff --git a/.travis.yml b/.travis.yml index 551cd875..0027b3d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,4 +49,4 @@ after_success: - lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info 'tests/*' '/include/*' 'examples/*' --output-file coverage.info - lcov --list coverage.info - - coveralls-lcov --repo-token=${Coveralls} coverage.info + - coveralls-lcov coverage.info From f0bbe054290d7ae089021db3d1d99feee7de5e6a Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 5 Nov 2017 14:52:35 -0500 Subject: [PATCH 002/102] CMakeLists-configuration (#35) * CMakeLists updated to make each individual CMakeList have its own compiler configuration * conflicts and coverage issues resolved --- .travis.yml | 16 ++++++++-------- CMakeLists.txt | 1 - README.md | 6 ++---- lib/wlib/strings/StaticString.h | 1 - tests/CMakeLists.txt | 4 ++++ tests/strings/static_string_check.cpp | 1 + 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0027b3d2..b3956ed1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,15 +16,15 @@ addons: - cppcheck install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-5" CC="gcc-5"; fi + - if [ "$CXX" = "g++" ]; then export CXX="g++-5" CC="gcc-5"; fi - - cd ${TRAVIS_BUILD_DIR} - - wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz - - tar xf lcov_1.11.orig.tar.gz - - sudo make -C lcov-1.11/ install - - gem install coveralls-lcov - - lcov --version - - g++ --version + - cd ${TRAVIS_BUILD_DIR} + - wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz + - tar xf lcov_1.11.orig.tar.gz + - sudo make -C lcov-1.11/ install + - gem install coveralls-lcov + - lcov --version + - g++ --version before_script: - cd ${TRAVIS_BUILD_DIR} diff --git a/CMakeLists.txt b/CMakeLists.txt index 07d8b8ca..79fc07f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,6 @@ enable_testing() SET(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") diff --git a/README.md b/README.md index 7a712439..d86b58fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -[![Build Status](https://travis-ci.org/teamwaterloop/embedded-cplusplus.svg?branch=master)](https://travis-ci.org/teamwaterloop/embedded-cplusplus) [![Coverage Status](https://coveralls.io/repos/github/teamwaterloop/embedded-cplusplus/badge.svg?branch=master)](https://coveralls.io/github/teamwaterloop/embedded-cplusplus?branch=master) +[![Build Status](https://travis-ci.org/teamwaterloop/embedded-cplusplus.svg?branch=master)](https://travis-ci.org/teamwaterloop/embedded-cplusplus) +[![Coverage Status](https://coveralls.io/repos/github/teamwaterloop/embedded-cplusplus/badge.svg?branch=master)](https://coveralls.io/github/teamwaterloop/embedded-cplusplus?branch=master) # Waterloop Embedded C++ C++ version of libraries used by Waterloop for embedded systems - - - diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index 4dd2cf0a..4e90dcb6 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -1,7 +1,6 @@ #ifndef WLIB_STATICSTRING_H #define WLIB_STATICSTRING_H - #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e1bc21eb..7c0cfa64 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,7 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Waddress -Warray-bounds -Wbuiltin-macro-redefined -Wconversion") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self -Wnon-virtual-dtor -Woverloaded-virtual -Wsuggest-attribute=const") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wswitch -Wunreachable-code") + set(GTEST_INCLUDE_DIR ${gtest_SOURCE_DIR}/include) set(WLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/lib/wlib) diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 7a7e1922..1abd8367 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -9,6 +9,7 @@ TEST(static_string_tests, constructor_tests){ StaticString<8> string3{string1}; // string object given auto *ptr = memory_alloc(75); + ptr = memory_realloc(ptr, 35); memory_free(ptr); string3.empty(); From 5136ee18584a6a456a8fcacad01abdd92078574f Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Sun, 5 Nov 2017 20:00:33 -0800 Subject: [PATCH 003/102] Fixed up Bitset (#36) * Fixed up Bitset * code review changes * cast changed from int to uint32_t --- lib/wlib/CMakeLists.txt | 10 +- lib/wlib/Wlib.h | 9 +- lib/wlib/stl/Bitset.h | 190 +++++++++++++++++--------- tests/CMakeLists.txt | 1 + tests/stl/bitset_check.cpp | 126 +++++++++++++++++ tests/strings/static_string_check.cpp | 18 +-- tests/test.cpp | 4 +- wmake | 0 8 files changed, 275 insertions(+), 83 deletions(-) create mode 100644 tests/stl/bitset_check.cpp mode change 100644 => 100755 wmake diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index db5a3f5d..a34d133b 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,13 +1,13 @@ project(wlib) file (GLOB header_files - "Wlib.h" - "strings/*.h" - "stl/*.h" - "memory/*.h") + "Wlib.h" + "strings/*.h" + "stl/*.h" + "memory/*.h") file (GLOB source_files - "memory/*.cpp") + "memory/*.cpp") set(HEADER_FILES ${header_files} ) set(SOURCE_FILES ${source_files}) diff --git a/lib/wlib/Wlib.h b/lib/wlib/Wlib.h index 1d35ca0d..48983b50 100644 --- a/lib/wlib/Wlib.h +++ b/lib/wlib/Wlib.h @@ -1,11 +1,10 @@ #ifndef EMBEDDEDTESTS_WLIB_H #define EMBEDDEDTESTS_WLIB_H -#define max(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) - +#define max(x, y) (((x) > (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y)) +#define BYTE_SIZE 8 +#define INT_SIZE (BYTE_SIZE * sizeof(uint32_t)) + #endif //EMBEDDEDTESTS_WLIB_H diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index ace3ad6a..3625675c 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -17,77 +17,134 @@ #include #include +#include "Wlib.h" + namespace wlp { -#define NO_OF_BITS (8 * sizeof(unsigned int)) - template + /** + * Computes the mask corresponding to the number of bits + * or the exponent in the from 2^n - 1. + * @tparam exp the number of bits, 32 or less + */ + template + struct pow_mask { + static const uint32_t value = (uint32_t) ((1 << exp) - 1); + }; + + /** + * Template specialization for 32 bits to + * prevent overflow. + */ + template<> struct pow_mask<32> { + static const uint32_t value = 0xffffffff; + }; + + /** + * Compute the minimum number of integers + * needed to store a certain number of bits. + * @tparam nBits the bits to store + */ + template + struct ceil_bits { + static const uint32_t value = (nBits + INT_SIZE - 1) / INT_SIZE; + }; + + template class Bitset { public: /** - * Default Constructor creates an empty bitset + * Default Constructor creates an empty bitset. */ Bitset() { memset(m_array, 0, sizeof(m_array)); } /** - * Constructor creates a bitset from a number that can be of max - * 64 bit in size + * Constructor creates a bitset from a number that + * can be of max 64 bit in size. * - * @param number the number to create bitset from + * @param n the number to create bitset from */ - explicit Bitset(uint64_t number){ - memset(m_array, 0, sizeof(m_array)); - - uint16_t size = sizeof(number) * 8; + explicit Bitset(uint64_t n) { + setFromNumber(n); + } - if (size > bits) size = bits; + /** + * Copy constructor. + * @param b Bitset to copy + */ + Bitset(Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + } - for (uint16_t index = 0; index < size; ++index) { - uint8_t remainder = (uint8_t) (number % 2); - number /= 2; + /** + * Copy constructor for const. + * @param b Bitset to copy + */ + Bitset(const Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + } - if (remainder) set(index); - else reset(index); + /** + * Set the value of the Bitset from a number + * of maximum 64 bit size. + * @param n the number to set from + */ + void setFromNumber(uint64_t n) { + memset(m_array, 0, sizeof(m_array)); + constexpr uint32_t end = nBits / INT_SIZE; + constexpr uint32_t extra = nBits - end * INT_SIZE; + for (uint16_t i = 0; i < end; ++i) { + m_array[i] = (uint32_t) n; + n >>= INT_SIZE; + } + if (extra) { + m_array[end] = ((uint32_t) n) & pow_mask::value; } } /** - * Sets the bit at @code index to be true + * Sets the bit at @code index to be true. * * @param index the index of the bit */ void set(uint16_t index) { - m_array[index / NO_OF_BITS] |= (1U << (index % NO_OF_BITS)); + m_array[index / INT_SIZE] |= (1U << (index % INT_SIZE)); } /** - * Sets the bit at @code index to be false + * Sets the bit at @code index to be false. * * @param index the index of the bit */ void reset(uint16_t index) { - m_array[index / NO_OF_BITS] &= ~(1U << (index % NO_OF_BITS)); + m_array[index / INT_SIZE] &= ~(1U << (index % INT_SIZE)); } /** - * Toggles the but at @code index + * Toggles the but at @code index. * * @param index the index of the bit */ void flip(uint16_t index) { - m_array[index / NO_OF_BITS] ^= (1U << (index % NO_OF_BITS)); + m_array[index / INT_SIZE] ^= (1U << (index % INT_SIZE)); } /** - * Returns the value of bit at @code index + * Returns the value of bit at @code index. * * @param index the index of the bit * @return the bit value */ - bool test(uint16_t index) { - return (m_array[index / NO_OF_BITS] & (1U << (index % NO_OF_BITS))) != 0; + bool test(uint16_t index) const { + return (m_array[index / INT_SIZE] & (1U << (index % INT_SIZE))) != 0; } /** @@ -95,16 +152,11 @@ namespace wlp { * * @return unsigned 64 bit integer */ - uint64_t to_uint64_t() { - uint64_t number = 0; - - for (uint8_t i = 0; i < 64; ++i) { - uint64_t powerVal = (uint64_t) ceil(pow(2, i)); - uint8_t bitVal = (uint8_t) test(i); - number += bitVal * powerVal; + uint64_t to_uint64_t() const { + if (nBits <= 32) { + return to_uint32_t(); } - - return number; + return (((uint64_t) m_array[1]) << INT_SIZE) | ((uint32_t) m_array[0]); } /** @@ -112,16 +164,8 @@ namespace wlp { * * @return unsigned 32 bit integer */ - uint32_t to_uint32_t() { - uint32_t number = 0; - - for (uint8_t i = 0; i < 32; ++i) { - uint32_t powerVal = (uint32_t) ceil(pow(2, i)); - uint8_t bitVal = (uint8_t) test(i); - number += bitVal * powerVal; - } - - return number; + uint32_t to_uint32_t() const { + return (uint32_t) m_array[0]; } /** @@ -129,16 +173,8 @@ namespace wlp { * * @return unsigned 16 bit integer */ - uint16_t to_uint16_t() { - uint16_t number = 0; - - for (uint8_t i = 0; i < 16; ++i) { - uint16_t powerVal = (uint16_t) ceil(pow(2, i)); - uint8_t bitVal = (uint8_t) test(i); - number += bitVal * powerVal; - } - - return number; + uint16_t to_uint16_t() const { + return (uint16_t) (m_array[0] & pow_mask<16>::value); } /** @@ -146,20 +182,50 @@ namespace wlp { * * @return unsigned 8 bit integer */ - uint8_t to_uint8_t() { - uint8_t number = 0; + uint8_t to_uint8_t() const { + return (uint8_t) (m_array[0] & pow_mask<8>::value); + } - for (uint8_t i = 0; i < 8; ++i) { - uint8_t powerVal = (uint8_t) ceil(pow(2, i)); - uint8_t bitVal = (uint8_t) test(i); - number += bitVal * powerVal; + /** + * Access operator returns the bit at the given position. + * @param i the position of the bit to test + * @return the value of the bit + */ + bool operator[](const uint16_t i) const { + return test(i); + } + + /** + * Assignment operator copies the contents of the bitset. + * @param b Bitset to assign + */ + Bitset& operator=(Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; } + return *this; + } - return number; + /** + * Assignment operator copies the contents of the bitset. + * @param b Bitset to assign + */ + Bitset& operator=(const Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + return *this; } private: - int m_array[bits/ NO_OF_BITS]; + /** + * Backing array of integers that contain the bites. + * Integer type arrays generally have the fastest access + * times in C++. + */ + uint32_t m_array[ceil_bits::value]; }; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7c0cfa64..f9d04ecc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,7 @@ include_directories(${WLIB_INCLUDE_DIR}) file(GLOB files "test.cpp" + "stl/*.cpp" "strings/*.cpp") add_executable(tests ${files}) diff --git a/tests/stl/bitset_check.cpp b/tests/stl/bitset_check.cpp new file mode 100644 index 00000000..8627c922 --- /dev/null +++ b/tests/stl/bitset_check.cpp @@ -0,0 +1,126 @@ +#include "gtest/gtest.h" +#include "stl/Bitset.h" + +namespace wlp { + + template + class Bitset<64>; + + template + class Bitset<46>; + + template + class Bitset<27>; + + template + class Bitset<176>; + +} + +using namespace wlp; + +typedef uint16_t ui16; + +TEST(bitset_test, test_constructor_64) { + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 + }; + Bitset<64> b(n); + for (ui16 i = 0; i < 64; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n, b.to_uint64_t()); + ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); +} + +TEST(bitset_test, test_constructor_underflow) { + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + Bitset<46> b(n); + for (ui16 i = 0; i < 64; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n & 0x3fffffffffff, b.to_uint64_t()); + ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); +} + +TEST(bitset_test, test_constructor_overflow) { + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 + }; + Bitset<27> b(n); + for (ui16 i = 0; i < 32; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n & 0x7ffffff, b.to_uint64_t()); + ASSERT_EQ(n & 0x7ffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); +} + +TEST(bitset_test, test_set_reset_flip_get) { + bool sequence[] = { + 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 + }; + Bitset<176> b1; + Bitset<176> b2; + for (ui16 i = 0; i < 176; i++) { + b2.set(i); + ASSERT_EQ(1, b2[i]); + ASSERT_EQ(0, b1[i]); + if (sequence[i]) { + b1.set(i); + } else { + b2.reset(i); + } + } + for (ui16 i = 0; i < 176; i++) { + ASSERT_EQ(sequence[i], b1[i]); + ASSERT_EQ(sequence[i], b2[i]); + } + for (ui16 i = 0; i < 176; i++) { + b1.flip(i); + } + for (ui16 i = 0; i < 176; i++) { + ASSERT_NE(b1[i], b2[i]); + } +} + +TEST(bitset_test, test_copy_constructors) { + Bitset<42> source1(17316249074701521315); + Bitset<42> source2(6426756347354645451); + const Bitset<42> copy1_1 = source1; + const Bitset<42> copy1_2 = copy1_1; + ASSERT_EQ(source1.to_uint64_t(), copy1_1.to_uint64_t()); + ASSERT_EQ(source1.to_uint64_t(), copy1_2.to_uint64_t()); + Bitset<42> copy2; + copy2 = source2; + ASSERT_EQ(copy2.to_uint64_t(), source2.to_uint64_t()); + copy2 = copy1_1; + ASSERT_EQ(copy2.to_uint64_t(), source1.to_uint64_t()); +} diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 1abd8367..abbe38cd 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -4,17 +4,17 @@ #include "memory/Memory.h" TEST(static_string_tests, constructor_tests){ - StaticString<8> string1{"helloooo"}; // text given - StaticString<8> string2; // no text - StaticString<8> string3{string1}; // string object given + StaticString<8> string1{"helloooo"}; // text given + StaticString<8> string2; // no text + StaticString<8> string3{string1}; // string object given - auto *ptr = memory_alloc(75); - ptr = memory_realloc(ptr, 35); - memory_free(ptr); + auto *ptr = memory_alloc(75); + ptr = memory_realloc(ptr, 35); + memory_free(ptr); - string3.empty(); + string3.empty(); - string2.clear(); + string2.clear(); - ASSERT_EQ("helloooo", "helloooo"); + ASSERT_EQ("helloooo", "helloooo"); } \ No newline at end of file diff --git a/tests/test.cpp b/tests/test.cpp index d213081c..385b8964 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -12,6 +12,6 @@ #include int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/wmake b/wmake old mode 100644 new mode 100755 From 9da5ad62a3afd6364661a2dd7e095e7ca78395d7 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 6 Nov 2017 12:39:16 -0800 Subject: [PATCH 004/102] Converted tabs to spaces (#37) --- examples/CMakeLists.txt | 2 +- lib/wlib/CMakeLists.txt | 10 +- lib/wlib/stl/Bitset.h | 412 +++++++-------- lib/wlib/strings/StaticString.h | 694 +++++++++++++------------- tests/stl/bitset_check.cpp | 194 +++---- tests/strings/static_string_check.cpp | 18 +- tests/test.cpp | 4 +- 7 files changed, 667 insertions(+), 667 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5acc01d2..b62845f6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,4 +6,4 @@ file(GLOB files add_executable(examples ${files}) target_link_libraries(examples wlib) -ADD_DEPENDENCIES(examples wlib) +add_dependencies(examples wlib) diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index a34d133b..db5a3f5d 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,13 +1,13 @@ project(wlib) file (GLOB header_files - "Wlib.h" - "strings/*.h" - "stl/*.h" - "memory/*.h") + "Wlib.h" + "strings/*.h" + "stl/*.h" + "memory/*.h") file (GLOB source_files - "memory/*.cpp") + "memory/*.cpp") set(HEADER_FILES ${header_files} ) set(SOURCE_FILES ${source_files}) diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index 3625675c..a9983671 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -21,212 +21,212 @@ namespace wlp { - /** - * Computes the mask corresponding to the number of bits - * or the exponent in the from 2^n - 1. - * @tparam exp the number of bits, 32 or less - */ - template - struct pow_mask { - static const uint32_t value = (uint32_t) ((1 << exp) - 1); - }; - - /** - * Template specialization for 32 bits to - * prevent overflow. - */ - template<> struct pow_mask<32> { - static const uint32_t value = 0xffffffff; - }; - - /** - * Compute the minimum number of integers - * needed to store a certain number of bits. - * @tparam nBits the bits to store - */ - template - struct ceil_bits { - static const uint32_t value = (nBits + INT_SIZE - 1) / INT_SIZE; - }; - - template - class Bitset { - public: - /** - * Default Constructor creates an empty bitset. - */ - Bitset() { - memset(m_array, 0, sizeof(m_array)); - } - - /** - * Constructor creates a bitset from a number that - * can be of max 64 bit in size. - * - * @param n the number to create bitset from - */ - explicit Bitset(uint64_t n) { - setFromNumber(n); - } - - /** - * Copy constructor. - * @param b Bitset to copy - */ - Bitset(Bitset& b) { - uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { - m_array[i] = (m_array[i] & 0) | b.m_array[i]; - } - } - - /** - * Copy constructor for const. - * @param b Bitset to copy - */ - Bitset(const Bitset& b) { - uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { - m_array[i] = (m_array[i] & 0) | b.m_array[i]; - } - } - - /** - * Set the value of the Bitset from a number - * of maximum 64 bit size. - * @param n the number to set from - */ - void setFromNumber(uint64_t n) { - memset(m_array, 0, sizeof(m_array)); - constexpr uint32_t end = nBits / INT_SIZE; - constexpr uint32_t extra = nBits - end * INT_SIZE; - for (uint16_t i = 0; i < end; ++i) { - m_array[i] = (uint32_t) n; - n >>= INT_SIZE; - } - if (extra) { - m_array[end] = ((uint32_t) n) & pow_mask::value; - } - } - - - /** - * Sets the bit at @code index to be true. - * - * @param index the index of the bit - */ - void set(uint16_t index) { - m_array[index / INT_SIZE] |= (1U << (index % INT_SIZE)); - } - - /** - * Sets the bit at @code index to be false. - * - * @param index the index of the bit - */ - void reset(uint16_t index) { - m_array[index / INT_SIZE] &= ~(1U << (index % INT_SIZE)); - } - - /** - * Toggles the but at @code index. - * - * @param index the index of the bit - */ - void flip(uint16_t index) { - m_array[index / INT_SIZE] ^= (1U << (index % INT_SIZE)); - } - - /** - * Returns the value of bit at @code index. - * - * @param index the index of the bit - * @return the bit value - */ - bool test(uint16_t index) const { - return (m_array[index / INT_SIZE] & (1U << (index % INT_SIZE))) != 0; - } - - /** - * Converts the bits into 64 bit unsigned integer - * - * @return unsigned 64 bit integer - */ - uint64_t to_uint64_t() const { - if (nBits <= 32) { - return to_uint32_t(); - } - return (((uint64_t) m_array[1]) << INT_SIZE) | ((uint32_t) m_array[0]); - } - - /** - * Converts the bits into 32 bit unsigned integer - * - * @return unsigned 32 bit integer - */ - uint32_t to_uint32_t() const { - return (uint32_t) m_array[0]; - } - - /** - * Converts the bits into 16 bit unsigned integer - * - * @return unsigned 16 bit integer - */ - uint16_t to_uint16_t() const { - return (uint16_t) (m_array[0] & pow_mask<16>::value); - } - - /** - * Converts the bits into 8 bit unsigned integer - * - * @return unsigned 8 bit integer - */ - uint8_t to_uint8_t() const { - return (uint8_t) (m_array[0] & pow_mask<8>::value); - } - - /** - * Access operator returns the bit at the given position. - * @param i the position of the bit to test - * @return the value of the bit - */ - bool operator[](const uint16_t i) const { - return test(i); - } - - /** - * Assignment operator copies the contents of the bitset. - * @param b Bitset to assign - */ - Bitset& operator=(Bitset& b) { - uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { - m_array[i] = (m_array[i] & 0) | b.m_array[i]; - } - return *this; - } - - /** - * Assignment operator copies the contents of the bitset. - * @param b Bitset to assign - */ - Bitset& operator=(const Bitset& b) { - uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { - m_array[i] = (m_array[i] & 0) | b.m_array[i]; - } - return *this; - } - - private: - /** - * Backing array of integers that contain the bites. - * Integer type arrays generally have the fastest access - * times in C++. - */ - uint32_t m_array[ceil_bits::value]; - }; + /** + * Computes the mask corresponding to the number of bits + * or the exponent in the from 2^n - 1. + * @tparam exp the number of bits, 32 or less + */ + template + struct pow_mask { + static const uint32_t value = (uint32_t) ((1 << exp) - 1); + }; + + /** + * Template specialization for 32 bits to + * prevent overflow. + */ + template<> struct pow_mask<32> { + static const uint32_t value = 0xffffffff; + }; + + /** + * Compute the minimum number of integers + * needed to store a certain number of bits. + * @tparam nBits the bits to store + */ + template + struct ceil_bits { + static const uint32_t value = (nBits + INT_SIZE - 1) / INT_SIZE; + }; + + template + class Bitset { + public: + /** + * Default Constructor creates an empty bitset. + */ + Bitset() { + memset(m_array, 0, sizeof(m_array)); + } + + /** + * Constructor creates a bitset from a number that + * can be of max 64 bit in size. + * + * @param n the number to create bitset from + */ + explicit Bitset(uint64_t n) { + setFromNumber(n); + } + + /** + * Copy constructor. + * @param b Bitset to copy + */ + Bitset(Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + } + + /** + * Copy constructor for const. + * @param b Bitset to copy + */ + Bitset(const Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + } + + /** + * Set the value of the Bitset from a number + * of maximum 64 bit size. + * @param n the number to set from + */ + void setFromNumber(uint64_t n) { + memset(m_array, 0, sizeof(m_array)); + constexpr uint32_t end = nBits / INT_SIZE; + constexpr uint32_t extra = nBits - end * INT_SIZE; + for (uint16_t i = 0; i < end; ++i) { + m_array[i] = (uint32_t) n; + n >>= INT_SIZE; + } + if (extra) { + m_array[end] = ((uint32_t) n) & pow_mask::value; + } + } + + + /** + * Sets the bit at @code index to be true. + * + * @param index the index of the bit + */ + void set(uint16_t index) { + m_array[index / INT_SIZE] |= (1U << (index % INT_SIZE)); + } + + /** + * Sets the bit at @code index to be false. + * + * @param index the index of the bit + */ + void reset(uint16_t index) { + m_array[index / INT_SIZE] &= ~(1U << (index % INT_SIZE)); + } + + /** + * Toggles the but at @code index. + * + * @param index the index of the bit + */ + void flip(uint16_t index) { + m_array[index / INT_SIZE] ^= (1U << (index % INT_SIZE)); + } + + /** + * Returns the value of bit at @code index. + * + * @param index the index of the bit + * @return the bit value + */ + bool test(uint16_t index) const { + return (m_array[index / INT_SIZE] & (1U << (index % INT_SIZE))) != 0; + } + + /** + * Converts the bits into 64 bit unsigned integer + * + * @return unsigned 64 bit integer + */ + uint64_t to_uint64_t() const { + if (nBits <= 32) { + return to_uint32_t(); + } + return (((uint64_t) m_array[1]) << INT_SIZE) | ((uint32_t) m_array[0]); + } + + /** + * Converts the bits into 32 bit unsigned integer + * + * @return unsigned 32 bit integer + */ + uint32_t to_uint32_t() const { + return (uint32_t) m_array[0]; + } + + /** + * Converts the bits into 16 bit unsigned integer + * + * @return unsigned 16 bit integer + */ + uint16_t to_uint16_t() const { + return (uint16_t) (m_array[0] & pow_mask<16>::value); + } + + /** + * Converts the bits into 8 bit unsigned integer + * + * @return unsigned 8 bit integer + */ + uint8_t to_uint8_t() const { + return (uint8_t) (m_array[0] & pow_mask<8>::value); + } + + /** + * Access operator returns the bit at the given position. + * @param i the position of the bit to test + * @return the value of the bit + */ + bool operator[](const uint16_t i) const { + return test(i); + } + + /** + * Assignment operator copies the contents of the bitset. + * @param b Bitset to assign + */ + Bitset& operator=(Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + return *this; + } + + /** + * Assignment operator copies the contents of the bitset. + * @param b Bitset to assign + */ + Bitset& operator=(const Bitset& b) { + uint32_t end = ceil_bits::value; + for (uint16_t i = 0; i < end; i++) { + m_array[i] = (m_array[i] & 0) | b.m_array[i]; + } + return *this; + } + + private: + /** + * Backing array of integers that contain the bites. + * Integer type arrays generally have the fastest access + * times in C++. + */ + uint32_t m_array[ceil_bits::value]; + }; } #endif //CORE_STL_BITSET_H diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index 4e90dcb6..f1e4fcad 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -7,342 +7,342 @@ template class StaticString { private: - char m_buffer[tSize + 1]; - uint16_t len; + char m_buffer[tSize + 1]; + uint16_t len; public: - /** - * Default constructor creates string with no character - */ - StaticString(){ - clear(); - } - - /** - * Constructor creates string using character array - * - * @param str char string - */ - StaticString(const char* str){ - uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, destSize); - m_buffer[destSize] = '\0'; - len = destSize; - } - - /** - * Constructor creates string using static string object - * - * @param str @code StaticString object - */ - StaticString(const StaticString &str){ - StaticString(str.c_str()); - } - - /** - * Assign operator assigns current object to given object - * - * @param str @code StaticString object - * @return current object - */ - StaticString operator= (const StaticString &str){ - return operator=(str.c_str()); - } - - /** - * Assign operator assigns current object to given character string - * @param str - * @return current object - */ - StaticString operator= (const char* str){ - uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, destSize); - m_buffer[destSize] = '\0'; - len = destSize; - - return *this; - } - - /** - * Provides current length of string - * - * @return string length - */ - uint16_t length() const{ - return len; - } - - /** - * Provides the maximum capacity of string - * - * @return string capacity - */ - uint16_t capacity(){ - return tSize; - } - - /** - * Checks if string is empty or not - * - * @return if string is empty or not - */ - bool empty() const { - return length() == 0; - } - - /** - * Clears the string such that there are no characters left in it - */ - void clear(){ - m_buffer[0] = '\0'; - len = 0; - } - - /** - * Element access operator gives access to character at @code pos - * - * @param pos the position of the character - * @return character at @code position - */ - char &operator[](uint16_t pos){ - return m_buffer[pos]; - } - - /** - * Element access operator gives access to character at @code pos. - * Character is constant - * - * @param pos the position of the character - * @return character at @code position - */ - const char &operator[](uint16_t pos) const{ - return m_buffer[pos]; - } - - /** - * Provides access to character at @code pos - * - * @param pos the position of the character - * @return character at @code position - */ - char &at(uint16_t pos){ - return m_buffer[pos]; - } - - /** - * Provides access to character at @code pos. Character is constant - * - * @param pos the position of the character - * @return character at @code position - */ - const char &at(uint16_t pos) const{ - return m_buffer[pos]; - } - - /** - * Provides access to the first character in the string - * - * @return the first character - */ - char &front(){ - return m_buffer[0]; - } - - /** - * Provides access to the first character in the string. Character is constant - * - * @return the first character - */ - const char &front() const{ - return m_buffer[0]; - } - - /** - * Provides access to the last character in the string - * - * @return the last character - */ - char &end(){ - if (empty()) return m_buffer[0]; - - return m_buffer[length() - 1]; - } - - /** - * Provides access to the last character in the string. Character is constant - * - * @return the last character - */ - const char &end() const{ - if (empty()) return m_buffer[0]; - - return m_buffer[length() - 1]; - } - - /** - * Modifier operator adds character to the current string. If String cannot - * hold the character, it does not add it - * - * @param c character to add - * @return the current string - */ - StaticString &operator+=(char c){ - return append(c); - } - - /** - * Modifier operator adds char string to the current string. If String cannot - * hold the given string, it does not add it - * - * @param val char string to add - * @return the current string - */ - StaticString &operator+= (const char* val){ - return append(val); - } - - /** - * Modifier operator adds @code StaticString object to the current string. If String cannot - * hold the given object string, it does not add it - * - * @param other @code StaticString string to add - * @return the current string - */ - StaticString operator+= (StaticString& other){ - return append(other); - } - - /** - * Appends a character to the current string. If String cannot - * hold the given character, it does not add it - * - * @param c character to add - * @return the current string - */ - StaticString &append(const char c){ - char array[2] = {c, '\0'}; - return append(array); - } - - /** - * Appends a character string to the current string. If String cannot - * hold the given character string, it does not add it - * - * @param str character string to add - * @return the current string - */ - StaticString &append(const char *str){ - uint16_t bufferLength = this->length(); - uint16_t otherLength = (uint16_t) strlen(str); - - for(int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++){ - m_buffer[i] = str[i-bufferLength]; - } - - len = (uint16_t)ceil(fmin(capacity(), (bufferLength + otherLength))); - - m_buffer[len] = '\0'; - - return *this; - } - - /** - * Appends a @code StaticString string to the current string. If String cannot - * hold the given string, it does not add it - * - * @param str @code StaticString string to add - * @return the current string - */ - StaticString &append(const StaticString str){ - return append(str.c_str()); - } - - /** - * Appends a character to the current string. If String cannot - * hold the given character, it does not add it - * - * @param c character to add - * @return the current string - */ - StaticString push_back(const char c){ ; - return append(c); - } - - /** - * Appends a character string to the current string. If String cannot - * hold the given character string, it does not add it - * - * @param str character string to add - * @return the current string - */ - StaticString push_back(const char *str){ ; - return append(str); - } - - /** - * Appends a @code StaticString string to the current string. If String cannot - * hold the @code StaticString string, it does not add it - * - * @param str @code StaticString string to add - * @return the current string - */ - StaticString push_back(const StaticString &str){ ; - return append(str); - } - - - /** - * Provides access to character array that string uses behind the screen - * - * @return character array - */ - const char *c_str() const{ - return m_buffer; - } - - /** - * Makes substring of the current string - * - * @param pos starting position - * @param length length of the new string - * @return new string which is a substring of current string - */ - StaticString substr(uint16_t pos, uint16_t length) const{ - char newBuffer[length + 1]; - - for(uint16_t i = pos; i < pos + length ;i++){ - newBuffer[i-pos] = m_buffer[i]; - } - - newBuffer[length] = '\0'; - - StaticString s{newBuffer}; - - return s; - } - - /** - * Compares two strings and return 0 if they are equal, less than 0 if - * given string is less than current string and greater than 0 if - * given string is greater than current string - * - * @param str @code StaticString string to compare against current string - * @return a signed number based on how strings compare - */ - int16_t compare(const StaticString &str) const{ - return compare(str.c_str()); - } - - /** - * Compares two strings and return 0 if they are equal, less than 0 if - * given string is less than current string and greater than 0 if - * given string is greater than current string - * - * @param str character string to compare against current string - * @return a signed number based on how strings compare - */ - int16_t compare(const char *str) const{ - return (int16_t) strcmp(this->c_str(), str); - } + /** + * Default constructor creates string with no character + */ + StaticString(){ + clear(); + } + + /** + * Constructor creates string using character array + * + * @param str char string + */ + StaticString(const char* str){ + uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); + strncpy(m_buffer, str, destSize); + m_buffer[destSize] = '\0'; + len = destSize; + } + + /** + * Constructor creates string using static string object + * + * @param str @code StaticString object + */ + StaticString(const StaticString &str){ + StaticString(str.c_str()); + } + + /** + * Assign operator assigns current object to given object + * + * @param str @code StaticString object + * @return current object + */ + StaticString operator= (const StaticString &str){ + return operator=(str.c_str()); + } + + /** + * Assign operator assigns current object to given character string + * @param str + * @return current object + */ + StaticString operator= (const char* str){ + uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); + strncpy(m_buffer, str, destSize); + m_buffer[destSize] = '\0'; + len = destSize; + + return *this; + } + + /** + * Provides current length of string + * + * @return string length + */ + uint16_t length() const{ + return len; + } + + /** + * Provides the maximum capacity of string + * + * @return string capacity + */ + uint16_t capacity(){ + return tSize; + } + + /** + * Checks if string is empty or not + * + * @return if string is empty or not + */ + bool empty() const { + return length() == 0; + } + + /** + * Clears the string such that there are no characters left in it + */ + void clear(){ + m_buffer[0] = '\0'; + len = 0; + } + + /** + * Element access operator gives access to character at @code pos + * + * @param pos the position of the character + * @return character at @code position + */ + char &operator[](uint16_t pos){ + return m_buffer[pos]; + } + + /** + * Element access operator gives access to character at @code pos. + * Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &operator[](uint16_t pos) const{ + return m_buffer[pos]; + } + + /** + * Provides access to character at @code pos + * + * @param pos the position of the character + * @return character at @code position + */ + char &at(uint16_t pos){ + return m_buffer[pos]; + } + + /** + * Provides access to character at @code pos. Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &at(uint16_t pos) const{ + return m_buffer[pos]; + } + + /** + * Provides access to the first character in the string + * + * @return the first character + */ + char &front(){ + return m_buffer[0]; + } + + /** + * Provides access to the first character in the string. Character is constant + * + * @return the first character + */ + const char &front() const{ + return m_buffer[0]; + } + + /** + * Provides access to the last character in the string + * + * @return the last character + */ + char &end(){ + if (empty()) return m_buffer[0]; + + return m_buffer[length() - 1]; + } + + /** + * Provides access to the last character in the string. Character is constant + * + * @return the last character + */ + const char &end() const{ + if (empty()) return m_buffer[0]; + + return m_buffer[length() - 1]; + } + + /** + * Modifier operator adds character to the current string. If String cannot + * hold the character, it does not add it + * + * @param c character to add + * @return the current string + */ + StaticString &operator+=(char c){ + return append(c); + } + + /** + * Modifier operator adds char string to the current string. If String cannot + * hold the given string, it does not add it + * + * @param val char string to add + * @return the current string + */ + StaticString &operator+= (const char* val){ + return append(val); + } + + /** + * Modifier operator adds @code StaticString object to the current string. If String cannot + * hold the given object string, it does not add it + * + * @param other @code StaticString string to add + * @return the current string + */ + StaticString operator+= (StaticString& other){ + return append(other); + } + + /** + * Appends a character to the current string. If String cannot + * hold the given character, it does not add it + * + * @param c character to add + * @return the current string + */ + StaticString &append(const char c){ + char array[2] = {c, '\0'}; + return append(array); + } + + /** + * Appends a character string to the current string. If String cannot + * hold the given character string, it does not add it + * + * @param str character string to add + * @return the current string + */ + StaticString &append(const char *str){ + uint16_t bufferLength = this->length(); + uint16_t otherLength = (uint16_t) strlen(str); + + for(int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++){ + m_buffer[i] = str[i-bufferLength]; + } + + len = (uint16_t)ceil(fmin(capacity(), (bufferLength + otherLength))); + + m_buffer[len] = '\0'; + + return *this; + } + + /** + * Appends a @code StaticString string to the current string. If String cannot + * hold the given string, it does not add it + * + * @param str @code StaticString string to add + * @return the current string + */ + StaticString &append(const StaticString str){ + return append(str.c_str()); + } + + /** + * Appends a character to the current string. If String cannot + * hold the given character, it does not add it + * + * @param c character to add + * @return the current string + */ + StaticString push_back(const char c){ ; + return append(c); + } + + /** + * Appends a character string to the current string. If String cannot + * hold the given character string, it does not add it + * + * @param str character string to add + * @return the current string + */ + StaticString push_back(const char *str){ ; + return append(str); + } + + /** + * Appends a @code StaticString string to the current string. If String cannot + * hold the @code StaticString string, it does not add it + * + * @param str @code StaticString string to add + * @return the current string + */ + StaticString push_back(const StaticString &str){ ; + return append(str); + } + + + /** + * Provides access to character array that string uses behind the screen + * + * @return character array + */ + const char *c_str() const{ + return m_buffer; + } + + /** + * Makes substring of the current string + * + * @param pos starting position + * @param length length of the new string + * @return new string which is a substring of current string + */ + StaticString substr(uint16_t pos, uint16_t length) const{ + char newBuffer[length + 1]; + + for(uint16_t i = pos; i < pos + length ;i++){ + newBuffer[i-pos] = m_buffer[i]; + } + + newBuffer[length] = '\0'; + + StaticString s{newBuffer}; + + return s; + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str @code StaticString string to compare against current string + * @return a signed number based on how strings compare + */ + int16_t compare(const StaticString &str) const{ + return compare(str.c_str()); + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str character string to compare against current string + * @return a signed number based on how strings compare + */ + int16_t compare(const char *str) const{ + return (int16_t) strcmp(this->c_str(), str); + } }; @@ -356,7 +356,7 @@ class StaticString { */ template bool operator== (const StaticString &lhs, const StaticString &rhs){ - return lhs.compare(rhs) == 0; + return lhs.compare(rhs) == 0; } /** @@ -369,7 +369,7 @@ bool operator== (const StaticString &lhs, const StaticString &rhs) */ template bool operator== (const char *lhs, const StaticString &rhs){ - return rhs.compare(lhs) == 0; + return rhs.compare(lhs) == 0; } /** @@ -382,7 +382,7 @@ bool operator== (const char *lhs, const StaticString &rhs){ */ template bool operator== (const StaticString &lhs, const char *rhs){ - return lhs.compare(rhs) == 0; + return lhs.compare(rhs) == 0; } /** @@ -395,9 +395,9 @@ bool operator== (const StaticString &lhs, const char *rhs){ */ template StaticString operator+(const StaticString &lhs, const StaticString &rhs){ - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; + StaticString newStr; + newStr.push_back(lhs).push_back(rhs); + return newStr; } /** @@ -410,9 +410,9 @@ StaticString operator+(const StaticString &lhs, const StaticString */ template StaticString operator+(const char *lhs, const StaticString &rhs){ - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; + StaticString newStr; + newStr.push_back(lhs).push_back(rhs); + return newStr; } /** @@ -425,9 +425,9 @@ StaticString operator+(const char *lhs, const StaticString &rhs){ */ template StaticString operator+(const StaticString &lhs, const char *rhs){ - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; + StaticString newStr; + newStr.push_back(lhs).push_back(rhs); + return newStr; } diff --git a/tests/stl/bitset_check.cpp b/tests/stl/bitset_check.cpp index 8627c922..92102e39 100644 --- a/tests/stl/bitset_check.cpp +++ b/tests/stl/bitset_check.cpp @@ -3,17 +3,17 @@ namespace wlp { - template - class Bitset<64>; + template + class Bitset<64>; - template - class Bitset<46>; + template + class Bitset<46>; - template - class Bitset<27>; + template + class Bitset<27>; - template - class Bitset<176>; + template + class Bitset<176>; } @@ -22,105 +22,105 @@ using namespace wlp; typedef uint16_t ui16; TEST(bitset_test, test_constructor_64) { - uint64_t n = 17316249074701521315; - bool expected[] = { - 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 - }; - Bitset<64> b(n); - for (ui16 i = 0; i < 64; i++) { - ASSERT_EQ(expected[i], b.test(i)); - } - ASSERT_EQ(n, b.to_uint64_t()); - ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); - ASSERT_EQ(n & 0xffff, b.to_uint16_t()); - ASSERT_EQ(n & 0xff, b.to_uint8_t()); + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 + }; + Bitset<64> b(n); + for (ui16 i = 0; i < 64; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n, b.to_uint64_t()); + ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); } TEST(bitset_test, test_constructor_underflow) { - uint64_t n = 17316249074701521315; - bool expected[] = { - 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - Bitset<46> b(n); - for (ui16 i = 0; i < 64; i++) { - ASSERT_EQ(expected[i], b.test(i)); - } - ASSERT_EQ(n & 0x3fffffffffff, b.to_uint64_t()); - ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); - ASSERT_EQ(n & 0xffff, b.to_uint16_t()); - ASSERT_EQ(n & 0xff, b.to_uint8_t()); + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + Bitset<46> b(n); + for (ui16 i = 0; i < 64; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n & 0x3fffffffffff, b.to_uint64_t()); + ASSERT_EQ(n & 0xffffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); } TEST(bitset_test, test_constructor_overflow) { - uint64_t n = 17316249074701521315; - bool expected[] = { - 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 - }; - Bitset<27> b(n); - for (ui16 i = 0; i < 32; i++) { - ASSERT_EQ(expected[i], b.test(i)); - } - ASSERT_EQ(n & 0x7ffffff, b.to_uint64_t()); - ASSERT_EQ(n & 0x7ffffff, b.to_uint32_t()); - ASSERT_EQ(n & 0xffff, b.to_uint16_t()); - ASSERT_EQ(n & 0xff, b.to_uint8_t()); + uint64_t n = 17316249074701521315; + bool expected[] = { + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 + }; + Bitset<27> b(n); + for (ui16 i = 0; i < 32; i++) { + ASSERT_EQ(expected[i], b.test(i)); + } + ASSERT_EQ(n & 0x7ffffff, b.to_uint64_t()); + ASSERT_EQ(n & 0x7ffffff, b.to_uint32_t()); + ASSERT_EQ(n & 0xffff, b.to_uint16_t()); + ASSERT_EQ(n & 0xff, b.to_uint8_t()); } TEST(bitset_test, test_set_reset_flip_get) { - bool sequence[] = { - 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, - 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, - 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 - }; - Bitset<176> b1; - Bitset<176> b2; - for (ui16 i = 0; i < 176; i++) { - b2.set(i); - ASSERT_EQ(1, b2[i]); - ASSERT_EQ(0, b1[i]); - if (sequence[i]) { - b1.set(i); - } else { - b2.reset(i); - } - } - for (ui16 i = 0; i < 176; i++) { - ASSERT_EQ(sequence[i], b1[i]); - ASSERT_EQ(sequence[i], b2[i]); - } - for (ui16 i = 0; i < 176; i++) { - b1.flip(i); - } - for (ui16 i = 0; i < 176; i++) { - ASSERT_NE(b1[i], b2[i]); - } + bool sequence[] = { + 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1 + }; + Bitset<176> b1; + Bitset<176> b2; + for (ui16 i = 0; i < 176; i++) { + b2.set(i); + ASSERT_EQ(1, b2[i]); + ASSERT_EQ(0, b1[i]); + if (sequence[i]) { + b1.set(i); + } else { + b2.reset(i); + } + } + for (ui16 i = 0; i < 176; i++) { + ASSERT_EQ(sequence[i], b1[i]); + ASSERT_EQ(sequence[i], b2[i]); + } + for (ui16 i = 0; i < 176; i++) { + b1.flip(i); + } + for (ui16 i = 0; i < 176; i++) { + ASSERT_NE(b1[i], b2[i]); + } } TEST(bitset_test, test_copy_constructors) { - Bitset<42> source1(17316249074701521315); - Bitset<42> source2(6426756347354645451); - const Bitset<42> copy1_1 = source1; - const Bitset<42> copy1_2 = copy1_1; - ASSERT_EQ(source1.to_uint64_t(), copy1_1.to_uint64_t()); - ASSERT_EQ(source1.to_uint64_t(), copy1_2.to_uint64_t()); - Bitset<42> copy2; - copy2 = source2; - ASSERT_EQ(copy2.to_uint64_t(), source2.to_uint64_t()); - copy2 = copy1_1; - ASSERT_EQ(copy2.to_uint64_t(), source1.to_uint64_t()); + Bitset<42> source1(17316249074701521315); + Bitset<42> source2(6426756347354645451); + const Bitset<42> copy1_1 = source1; + const Bitset<42> copy1_2 = copy1_1; + ASSERT_EQ(source1.to_uint64_t(), copy1_1.to_uint64_t()); + ASSERT_EQ(source1.to_uint64_t(), copy1_2.to_uint64_t()); + Bitset<42> copy2; + copy2 = source2; + ASSERT_EQ(copy2.to_uint64_t(), source2.to_uint64_t()); + copy2 = copy1_1; + ASSERT_EQ(copy2.to_uint64_t(), source1.to_uint64_t()); } diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index abbe38cd..1abd8367 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -4,17 +4,17 @@ #include "memory/Memory.h" TEST(static_string_tests, constructor_tests){ - StaticString<8> string1{"helloooo"}; // text given - StaticString<8> string2; // no text - StaticString<8> string3{string1}; // string object given + StaticString<8> string1{"helloooo"}; // text given + StaticString<8> string2; // no text + StaticString<8> string3{string1}; // string object given - auto *ptr = memory_alloc(75); - ptr = memory_realloc(ptr, 35); - memory_free(ptr); + auto *ptr = memory_alloc(75); + ptr = memory_realloc(ptr, 35); + memory_free(ptr); - string3.empty(); + string3.empty(); - string2.clear(); + string2.clear(); - ASSERT_EQ("helloooo", "helloooo"); + ASSERT_EQ("helloooo", "helloooo"); } \ No newline at end of file diff --git a/tests/test.cpp b/tests/test.cpp index 385b8964..d213081c 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -12,6 +12,6 @@ #include int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } From 8cf8cc0835091c4da5eb1028e98af2e30a57fd20 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Mon, 6 Nov 2017 21:13:11 -0500 Subject: [PATCH 005/102] wmake enhanced to have args documentation (#39) --- wmake | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wmake b/wmake index 90b83c3c..6b0f2d66 100755 --- a/wmake +++ b/wmake @@ -186,11 +186,16 @@ __ _ _______ _/ |_ ___________| | ____ ____ ______ The Embedded C++ code base builder Usage: - ${_ME} [--help] [build] [coverage] [clean] [run] [test] + ${_ME} [--help] [build] [coverage] [clean] [reset] [run] [test] ${_ME} -h | --help Options: - -h --help Show this screen. + -h --help Show this screen. + build Build the project and stores the build files in the bin folder + coverage Build the project and add coverage files in coverage folder + clean Cleans the project and deletes every file from the bin folder + run Execute the Examples binary + test Execute the Tests binary HEREDOC } @@ -230,7 +235,6 @@ _coverage(){ cd .. } - _clean(){ rm -f -r bin echo "Project Cleaned" From 2dd31deea0b8fce2602872d7f09283731729d55e Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 6 Nov 2017 18:34:07 -0800 Subject: [PATCH 006/102] Hash map, openly addressed and separately chained (#23) * Hash and equals * Separately chained and open addressed hash maps * Structural-refresh with many new changes (#32) * Coveralls badge added (#33) * Added repo token to coveralls.yml (#34) * Chain and Open hash sets + copy constructurs/assignment * CMakeLists-configuration (#35) * CMakeLists updated to make each individual CMakeList have its own compiler configuration * conflicts and coverage issues resolved * More unit tests * code review changes * convert tabs to spaces * StaticAllocatorPool formatting fixed --- lib/wlib/CMakeLists.txt | 10 +- lib/wlib/Wlib.h | 5 + lib/wlib/WlibConfig.h | 62 ++ lib/wlib/memory/Allocator.cpp | 9 +- lib/wlib/memory/Allocator.h | 16 +- lib/wlib/memory/Memory.cpp | 81 +- lib/wlib/memory/Memory.h | 3 +- lib/wlib/memory/StaticAllocatorPool.h | 4 +- lib/wlib/stl/Bitset.h | 11 +- lib/wlib/stl/ChainMap.h | 1197 +++++++++++++++++++++++++ lib/wlib/stl/ChainSet.h | 219 +++++ lib/wlib/stl/Equal.h | 77 ++ lib/wlib/stl/Hash.h | 126 +++ lib/wlib/stl/OpenMap.h | 993 ++++++++++++++++++++ lib/wlib/stl/OpenSet.h | 194 ++++ lib/wlib/stl/Pair.h | 110 +++ lib/wlib/strings/StaticString.h | 158 ++-- tests/CMakeLists.txt | 11 +- tests/stl/chain_map_check.cpp | 459 ++++++++++ tests/stl/equals_check.cpp | 47 + tests/stl/hash_check.cpp | 34 + tests/stl/open_map_check.cpp | 296 ++++++ tests/stl/pair_check.cpp | 33 + tests/strings/static_string_check.cpp | 3 +- tests/template_defs.h | 68 ++ 25 files changed, 4090 insertions(+), 136 deletions(-) create mode 100644 lib/wlib/WlibConfig.h create mode 100644 lib/wlib/stl/ChainMap.h create mode 100644 lib/wlib/stl/ChainSet.h create mode 100644 lib/wlib/stl/Equal.h create mode 100644 lib/wlib/stl/Hash.h create mode 100644 lib/wlib/stl/OpenMap.h create mode 100644 lib/wlib/stl/OpenSet.h create mode 100644 lib/wlib/stl/Pair.h create mode 100644 tests/stl/chain_map_check.cpp create mode 100644 tests/stl/equals_check.cpp create mode 100644 tests/stl/hash_check.cpp create mode 100644 tests/stl/open_map_check.cpp create mode 100644 tests/stl/pair_check.cpp create mode 100644 tests/template_defs.h diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index db5a3f5d..798f6c85 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,13 +1,13 @@ project(wlib) file (GLOB header_files - "Wlib.h" - "strings/*.h" - "stl/*.h" - "memory/*.h") + "*.h" + "strings/*.h" + "stl/*.h" + "memory/*.h") file (GLOB source_files - "memory/*.cpp") + "memory/*.cpp") set(HEADER_FILES ${header_files} ) set(SOURCE_FILES ${source_files}) diff --git a/lib/wlib/Wlib.h b/lib/wlib/Wlib.h index 48983b50..9349ac70 100644 --- a/lib/wlib/Wlib.h +++ b/lib/wlib/Wlib.h @@ -4,6 +4,11 @@ #define max(x, y) (((x) > (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y)) +// Multiplication by Mersenne primes reduced as bit operations +// for compilers that do not already perform this optimization +#define MUL_31(x) (((x) << 5) - (x)) +#define MUL_127(x) (((x) << 7) - (x)) + #define BYTE_SIZE 8 #define INT_SIZE (BYTE_SIZE * sizeof(uint32_t)) diff --git a/lib/wlib/WlibConfig.h b/lib/wlib/WlibConfig.h new file mode 100644 index 00000000..68bd9dd3 --- /dev/null +++ b/lib/wlib/WlibConfig.h @@ -0,0 +1,62 @@ +/** + * @file WlibConfig.h + * @brief Some basic definitions for compilers. + * + * __WLIB_CLASS_PARTIAL_SPECIALIZATION: defined if compiler supports class partial specialization + * __WLIB_PARTIAL_SPECIALIZATION_SYNTAX: defined if compiler supports partial specialization syntax + * + * @author Jeff Niu + * @date November 1, 2017 + * @bug No known bugs + */ + +/* + * TODO: might not be needed if we enforce gcc 5 all the time + */ + +#ifndef EMBEDDEDTESTS_WLIBCONFIG_H +#define EMBEDDEDTESTS_WLIBCONFIG_H + +#if defined(__sgi) && !defined(__GNUC__) +# ifdef _PARTIAL_SPECIALIZATION_OF_CLASS_TEMPLATES +# define __WLIB_CLASS_PARTIAL_SPECIALIZATION +# endif +# if (_COMPILER_VERSION >= 721) && define(_NAMESPACES) +# define __WLIB_HAS_NAMESPACES +# endif +#endif + +#ifdef __GNUC__ +#if __GNUC__ >= 2 && (__GNUC__ != 2 || __GNUC_MINOR__ >= 8) +# define __WLIB_CLASS_PARTIAL_SPECIALIZATION +# define __WLIB_HAS_NAMESPACES +#endif +#endif + +#if defined(__COMO__) +# define __WLIB_CLASS_PARTIAL_SPECIALIZATION +# define __WLIB_HAS_NAMESPACES +#endif + +#if defined(_MSC_VER) +# if _MSC_VER >= 1200 +# define __WLIB_PARTIAL_SPECIALIZATION_SYNTAX +# define __WLIB_HAS_NAMESPACES +# endif +#endif + +#if defined(__WLIB_CLASS_PARTIAL_SPECIALIZATION) || defined (__WLIB_PARTIAL_SPECIALIZATION_SYNTAX) +# define TEMPLATE_NULL template<> +#else +# define TEMPLATE_NULL +#endif + +#if defined(__WLIB_HAS_NAMESPACES) +# define NAMESPACE_START namespace wlp { +# define NAMESPACE_END } +#else +# define NAMESPACE_START +# define NAMESPACE_END +#endif + +#endif //EMBEDDEDTESTS_WLIBCONFIG_H diff --git a/lib/wlib/memory/Allocator.cpp b/lib/wlib/memory/Allocator.cpp index cd87f478..547e8a3a 100644 --- a/lib/wlib/memory/Allocator.cpp +++ b/lib/wlib/memory/Allocator.cpp @@ -24,14 +24,14 @@ wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator: m_allocations{0}, m_deallocations{0} { // lowest size of a block will be the size of Block ptr - if (m_blockSize < sizeof(wlp::Allocator::Block*)) m_blockSize = sizeof(wlp::Allocator::Block*); + if (m_blockSize < sizeof(wlp::Allocator::Block *)) m_blockSize = sizeof(wlp::Allocator::Block *); // if pool size is provided, we will use pool instead of dynamic heap allocations if (m_poolSize) { m_poolSize = max(m_blockSize, poolSize); // find the closest round number that describes the number of blocks - m_poolTotalBlockCnt = (uint16_t) round(m_poolSize / (float) m_blockSize); + m_poolTotalBlockCnt = (uint16_t) roundf(m_poolSize / (float) m_blockSize); m_poolCurrBlockCnt = m_poolTotalBlockCnt; m_totalBlockCount = m_poolTotalBlockCnt; @@ -92,11 +92,10 @@ void *wlp::Allocator::Allocate() { // Pop one free block, if any. wlp::Allocator::Block *pBlock = m_pHead; - if (pBlock){ + if (pBlock) { m_pHead = m_pHead->pNext; --m_poolCurrBlockCnt; - } - else { + } else { // Otherwise, get a 'new' one from heap. pBlock = (wlp::Allocator::Block *) new char[m_blockSize]; ++m_totalBlockCount; diff --git a/lib/wlib/memory/Allocator.h b/lib/wlib/memory/Allocator.h index a5975765..2f38eeef 100644 --- a/lib/wlib/memory/Allocator.h +++ b/lib/wlib/memory/Allocator.h @@ -80,7 +80,7 @@ namespace wlp { ~Allocator(); /** - * Allocates memory from internal memory pool/dynamic memory system and gives acces to the user + * Allocates memory from internal memory pool/dynamic memory system and gives access to the user * * @return address to memory of blockSize that is predefined */ @@ -117,7 +117,7 @@ namespace wlp { * * @return size of memory block */ - inline size_t GetBlockSize() { + inline size_t GetBlockSize() const { return m_blockSize; } @@ -126,7 +126,7 @@ namespace wlp { * * @return size of pool */ - inline size_t GetPoolSize() { + inline size_t GetPoolSize() const { return m_poolSize; } @@ -135,7 +135,7 @@ namespace wlp { * * @return number of memory blocks available in the pool */ - inline uint16_t GetNumPoolBlocksAvail() { + inline uint16_t GetNumPoolBlocksAvail() const { return m_poolCurrBlockCnt; } @@ -144,7 +144,7 @@ namespace wlp { * * @return number of memory blocks in total in the pool */ - inline uint16_t GetTotalPoolBlocks() { + inline uint16_t GetTotalPoolBlocks() const { return m_poolTotalBlockCnt; } @@ -153,7 +153,7 @@ namespace wlp { * * @return number of memory blocks in total in Allocator */ - inline uint16_t GetTotalBlocks() { + inline uint16_t GetTotalBlocks() const { return m_totalBlockCount; } @@ -162,7 +162,7 @@ namespace wlp { * * @return the number of allocations */ - inline uint16_t GetNumAllocations() { + inline uint16_t GetNumAllocations() const { return m_allocations; } @@ -171,7 +171,7 @@ namespace wlp { * * @return the number of de-allocations */ - inline uint16_t GetNumDeallocations() { + inline uint16_t GetNumDeallocations() const { return m_deallocations; } diff --git a/lib/wlib/memory/Memory.cpp b/lib/wlib/memory/Memory.cpp index 579c7548..7a13bc26 100644 --- a/lib/wlib/memory/Memory.cpp +++ b/lib/wlib/memory/Memory.cpp @@ -12,14 +12,14 @@ #include "Allocator.h" #ifndef CHAR_BIT -#define CHAR_BIT 8 +#define CHAR_BIT 8 #endif #define MAX_ALLOCATORS 10 using namespace wlp; -static Allocator* _allocators[MAX_ALLOCATORS]; +static Allocator *_allocators[MAX_ALLOCATORS]; int MemoryInitDestroy::m_srefCount = 0; @@ -39,16 +39,15 @@ MemoryInitDestroy::~MemoryInitDestroy() { * @param k value for which the higher power of two will be returned * @return the next higher power of two based on the input k */ -template -T nextHigher(T k) -{ +template +T nextHigher(T k) { k--; - for (size_t i=1; i > i); - return k+1; + return k + 1; } -void memory_init(){} +void memory_init() {} extern "C" void memory_destroy() { for (auto &_allocator : _allocators) { @@ -65,8 +64,7 @@ extern "C" void memory_destroy() { * @param size allocator blocks size * @return Allocator instance or nullptr if no allocator exists */ -static inline Allocator* find_allocator(size_t size) -{ +static inline Allocator *find_allocator(size_t size) { for (auto &_allocator : _allocators) { if (_allocator == nullptr) break; @@ -82,11 +80,9 @@ static inline Allocator* find_allocator(size_t size) * Inster an Allocator instance into the array * @param allocator an Allocator instance */ -static inline void insert_allocator(Allocator* allocator) -{ +static inline void insert_allocator(Allocator *allocator) { for (auto &_allocator : _allocators) { - if (_allocator == nullptr) - { + if (_allocator == nullptr) { _allocator = allocator; return; } @@ -99,10 +95,9 @@ static inline void insert_allocator(Allocator* allocator) * @param allocator allocator to set * @return a pointer to the client's area within the block */ -static inline void *set_block_allocator(void* block, Allocator* allocator) -{ +static inline void *set_block_allocator(void *block, Allocator *allocator) { // Cast the raw block memory to a Allocator pointer - auto ** pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast(block); // Write the size into the memory block *pAllocatorInBlock = allocator; @@ -118,14 +113,13 @@ static inline void *set_block_allocator(void* block, Allocator* allocator) * @param size client's requested block size * @return an allocator instance that handles the block size */ -extern "C" Allocator* memory_get_allocator(size_t size) -{ +extern "C" Allocator *memory_get_allocator(size_t size) { // Based on the size, find the next higher powers of two value. // Add sizeof(Allocator*) to the requested block size to hold the size // within the block memory region. Most blocks are powers of two, // however some common allocator block sizes can be explicitly defined // to minimize wasted storage. This offers application specific tuning. - size_t blockSize = size + sizeof(Allocator*); + size_t blockSize = size + sizeof(Allocator *); if (blockSize > 256 && blockSize <= 396) blockSize = 396; else if (blockSize > 512 && blockSize <= 768) @@ -133,11 +127,10 @@ extern "C" Allocator* memory_get_allocator(size_t size) else blockSize = nextHigher(blockSize); - Allocator* allocator = find_allocator(blockSize); + Allocator *allocator = find_allocator(blockSize); // If there is not an allocator already created to handle this block size - if (allocator == nullptr) - { + if (allocator == nullptr) { // Create a new allocator to handle blocks of the size required allocator = new Allocator(blockSize); @@ -156,11 +149,11 @@ extern "C" Allocator* memory_get_allocator(size_t size) */ extern "C" void *memory_alloc(size_t size) { // Allocate a raw memory block - Allocator* allocator = memory_get_allocator(size); - void* blockMemoryPtr = allocator->Allocate(); + Allocator *allocator = memory_get_allocator(size); + void *blockMemoryPtr = allocator->Allocate(); // Set the block Allocator* within the raw memory block region - void* clientsMemoryPtr = set_block_allocator(blockMemoryPtr, allocator); + void *clientsMemoryPtr = set_block_allocator(blockMemoryPtr, allocator); return clientsMemoryPtr; } @@ -169,10 +162,9 @@ extern "C" void *memory_alloc(size_t size) { * @param block a pointer to the client's memory block * @return The original allocator instance stored in the memory block */ -static inline Allocator* get_block_allocator(void* block) -{ +static inline Allocator *get_block_allocator(void *block) { // Cast the client memory to a Allocator pointer - auto ** pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast(block); // Back up one Allocator* position to get the stored allocator instance pAllocatorInBlock--; @@ -186,10 +178,9 @@ static inline Allocator* get_block_allocator(void* block) * @param block a pointer to the client's memory block * @return A pointer to the original raw memory block */ -static inline void *get_block_ptr(void* block) -{ +static inline void *get_block_ptr(void *block) { // Cast the client memory to a Allocator* pointer - auto ** pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast(block); // Back up one Allocator* position and return the original raw memory block pointer return --pAllocatorInBlock; @@ -200,16 +191,15 @@ static inline void *get_block_ptr(void* block) * returned to the fixed block allocator that originally created it * @param ptr a pointer to a block created with memory_alloc */ -extern "C" void memory_free(void* ptr) -{ +extern "C" void memory_free(void *ptr) { if (ptr == nullptr) return; // Extract the original allocator instance from the caller's block pointer - Allocator* allocator = get_block_allocator(ptr); + Allocator *allocator = get_block_allocator(ptr); // Convert the client pointer into the original raw block pointer - void* blockPtr = get_block_ptr(ptr); + void *blockPtr = get_block_ptr(ptr); // Deallocate the block allocator->Deallocate(blockPtr); @@ -221,25 +211,20 @@ extern "C" void memory_free(void* ptr) * @param size the client requested block size * @return pointer to new memory block */ -extern "C" void *memory_realloc(void *oldMem, size_t size) -{ +extern "C" void *memory_realloc(void *oldMem, size_t size) { if (oldMem == nullptr) return memory_alloc(size); - if (size == 0) - { + if (size == 0) { memory_free(oldMem); return nullptr; - } - else - { + } else { // Create a new memory block - void* newMem = memory_alloc(size); - if (newMem != nullptr) - { + void *newMem = memory_alloc(size); + if (newMem != nullptr) { // Get the original allocator instance from the old memory block - Allocator* oldAllocator = get_block_allocator(oldMem); - size_t oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator*); + Allocator *oldAllocator = get_block_allocator(oldMem); + size_t oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator *); // Copy the bytes from the old memory block into the new (as much as will fit) memcpy(newMem, oldMem, (oldSize < size) ? oldSize : size); diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 837e49c7..6673d0bd 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -27,6 +27,7 @@ class MemoryInitDestroy { public: MemoryInitDestroy(); + ~MemoryInitDestroy(); private: @@ -35,7 +36,7 @@ class MemoryInitDestroy { static MemoryInitDestroy g_smemoryInitDestroy; -extern "C"{ +extern "C" { /** diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index eafd7115..e8ebc8f2 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -14,8 +14,8 @@ using namespace wlp; -template -class StaticAllocatorPool : public Allocator{ +template +class StaticAllocatorPool : public Allocator { public: StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks), Allocator::STATIC){} private: diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index a9983671..4d2928a4 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -35,7 +35,8 @@ namespace wlp { * Template specialization for 32 bits to * prevent overflow. */ - template<> struct pow_mask<32> { + template<> + struct pow_mask<32> { static const uint32_t value = 0xffffffff; }; @@ -73,7 +74,7 @@ namespace wlp { * Copy constructor. * @param b Bitset to copy */ - Bitset(Bitset& b) { + Bitset(Bitset &b) { uint32_t end = ceil_bits::value; for (uint16_t i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; @@ -84,7 +85,7 @@ namespace wlp { * Copy constructor for const. * @param b Bitset to copy */ - Bitset(const Bitset& b) { + Bitset(const Bitset &b) { uint32_t end = ceil_bits::value; for (uint16_t i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; @@ -199,7 +200,7 @@ namespace wlp { * Assignment operator copies the contents of the bitset. * @param b Bitset to assign */ - Bitset& operator=(Bitset& b) { + Bitset &operator=(Bitset &b) { uint32_t end = ceil_bits::value; for (uint16_t i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; @@ -211,7 +212,7 @@ namespace wlp { * Assignment operator copies the contents of the bitset. * @param b Bitset to assign */ - Bitset& operator=(const Bitset& b) { + Bitset &operator=(const Bitset &b) { uint32_t end = ceil_bits::value; for (uint16_t i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h new file mode 100644 index 00000000..fd7033e3 --- /dev/null +++ b/lib/wlib/stl/ChainMap.h @@ -0,0 +1,1197 @@ +/** + * @file ChainMap.h + * @brief Hash map implementation. + * + * Hash map is implemented using separate chaining + * because someone wanted remove operations. + * + * @author Jeff Niu + * @date November 3, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDTESTS_CHAINMAP_H +#define EMBEDDEDTESTS_CHAINMAP_H + +#include "Hash.h" +#include "Equal.h" +#include "Pair.h" +#include "../memory/Allocator.h" +#include "../memory/Memory.h" + +namespace wlp { + + // Forward declaration of ChainHashMap + template + class ChainHashMap; + + // Forward declaration of ChainHashMap iterator + template + struct ChainHashMapIterator; + + // Forward declaration of const ChainHashMap iterator + template + struct ChainHashMapConstIterator; + + /** + * Hash map node comprise the elements of a hash map's + * backing array, containing an element key and corresponding value. + * Has pointer to next node in a chain. + * @tparam Key key type + * @tparam Val value type + */ + template + struct ChainHashMapNode { + typedef ChainHashMapNode map_node; + typedef Key key_type; + typedef Val val_type; + /** + * Pointer to the next node in the chain. + */ + map_node *next = nullptr; + /** + * Node element key value. + */ + key_type m_key; + /** + * Node element value. + */ + val_type m_val; + + /** + * Equality operator for const. + * @param node const node to compare + * @return true if they are equal + */ + bool operator==(const map_node &node) const { + return m_key == node.m_key && m_val == node.m_val; + } + + /** + * Equality operator. Two nodes are equal if their keys + * and values are equal. + * keys and values are equal. + * @param node the node compare + * @return true if they are equal + */ + bool operator==(map_node &node) const { + return m_key == node.m_key && m_val == node.m_val; + } + }; + + /** + * Iterator class over the elements of a ChainHashMap. Specifically, + * this class iterates through each chain and then the backing array. + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template + struct ChainHashMapIterator { + typedef ChainHashMap hash_map; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapNode map_node; + + typedef Val val_type; + + typedef uint16_t size_type; + + /** + * Pointer to the node referenced by this iterator. + */ + map_node *m_current; + /** + * Pointer to the iterated ChainHashMap. + */ + hash_map *m_hash_map; + + /** + * Default constructor. + */ + ChainHashMapIterator() {} + + /** + * Create an iterator to a ChainHashMap node. + * @param node hash map node + * @param map parent hash map + */ + ChainHashMapIterator(map_node *node, hash_map *map) + : m_current(node), m_hash_map(map) {} + + /** + * Copy constructor for const. + * @param it iterator copy + */ + ChainHashMapIterator(const iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + /** + * Copy constructor. + * @param it iterator to copy + */ + ChainHashMapIterator(iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + /** + * @return reference to the value of the node + * pointed to by the iterator + */ + val_type &operator*() const { + return m_current->m_val; + } + + /** + * @return pointer to the value of the node + * pointed to by the iterator + */ + val_type *operator->() const { + return &(operator*()); + } + + /** + * Increment the iterator to the next available element in + * the ChainHashMap. If no such element exists, returns pass-the-end + * iterator. This is pre-fix unary operator. + * @return this iterator + */ + iterator &operator++(); + + /** + * Post-fix unary operator. + * @return this iterator + */ + iterator operator++(int); + + /** + * Equality operator for const. + * @param it iterator to compare + * @return true if they are equal + */ + bool operator==(const iterator &it) const { + return m_current == it.m_current; + } + + /** + * Compare two iterators, equal of they point to the + * same node. + * @param it iterator to compare + * @return true if both point to the same node + */ + bool operator==(iterator &it) const { + return m_current == it.m_current; + } + + /** + * Compare two iterators, unequal if they point to + * different nodes. + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(const iterator &it) const { + return m_current != it.m_current; + } + + /** + * Inequality operator. + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(iterator &it) const { + return m_current != it.m_current; + } + + /** + * Assignment operator copies pointer to node + * and pointer to hash map. + * @param it iterator to copy + * @return reference to this iterator + */ + iterator &operator=(const iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + + /** + * Assignment operator copies pointer to node + * and pointer to hash map. + * @param it iterator to copy + * @return a reference to this iterator + */ + iterator &operator=(iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + + }; + + /** + * Constant iterator over a ChainHashMap. Values iterated by + * this class cannot be modified. + * + * @see ChainHashMapIterator + * + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template + struct ChainHashMapConstIterator { + typedef ChainHashMap hash_map; + typedef ChainHashMapConstIterator const_iterator; + typedef ChainHashMapNode map_node; + + typedef Val val_type; + + typedef uint16_t size_type; + + const map_node *m_current; + const hash_map *m_hash_map; + + ChainHashMapConstIterator() {} + + ChainHashMapConstIterator(map_node *node, const hash_map *map) + : m_current(node), m_hash_map(map) {} + + ChainHashMapConstIterator(const const_iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + ChainHashMapConstIterator(const_iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + const val_type &operator*() const { + return m_current->m_val; + } + + const val_type *operator->() const { + return &(operator*()); + } + + const_iterator &operator++(); + + const_iterator operator++(int); + + bool operator==(const const_iterator &it) const { + return m_current == it.m_current; + } + + bool operator==(const_iterator &it) const { + return m_current == it.m_current; + } + + bool operator!=(const const_iterator &it) const { + return m_current != it.m_current; + } + + bool operator!=(const_iterator &it) const { + return m_current != it.m_current; + } + + const_iterator &operator=(const const_iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + + const_iterator &operator=(const_iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + }; + + /** + * Hash map implemented using separate chaining, + * in the spirit of std::unordered_map. + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template, + class Equal = equals> + class ChainHashMap { + public: + typedef ChainHashMap hash_map; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapConstIterator const_iterator; + typedef ChainHashMapNode map_node; + + typedef Key key_type; + typedef Val val_type; + + typedef uint16_t size_type; + typedef uint8_t percent_type; + + friend struct ChainHashMapIterator; + friend struct ChainHashMapConstIterator; + + private: + /** + * Class hash function instance. Used to hash + * element keys. + */ + Hash m_hash; + /** + * Class key equality function. Used to test + * equality of element keys. + */ + Equal m_equal; + + /** + * Allocator to create memory for hash map nodes. + */ + Allocator m_node_allocator; + + /** + * Hash map backing array. + */ + map_node **m_buckets; + + /** + * The number of elements currently + * in the map. + */ + size_type m_num_elements; + /** + * The size of the backing array. Note that the + * number of elements in the chained hash map + * may very well exceed the size fo the backing + * array if the load factor is greater than 100. + */ + size_type m_max_elements; + /** + * The maximum load factor as an integer percent + * before the map performs a rehash. This number + * may exceed 100. + */ + percent_type m_max_load; + + public: + /** + * Create and initialize an empty hash map. The hash map uses + * {@code Allocator} to handle memory. + * + * @pre the hash map requires definition of an initial bucket array size + * and a maximum load factor before rehashing + * + * @param n initial size of the bucket list; each bucket is initialized to nullptr + * @param max_load an integer value denoting the max percent load factor, e.g. 100 = 1.00 + * @param hash hash function for the key type, default is {@code wlp::Hash} + * @param equal equality function for the key type, default is {@code wlp::Equal} + */ + explicit ChainHashMap( + size_type n = 12, + percent_type max_load = 75) + : m_hash(Hash()), + m_equal(Equal()), + m_node_allocator{sizeof(map_node), static_cast(n * sizeof(map_node))}, + m_num_elements(0), + m_max_elements(n), + m_max_load(max_load) { + init_buckets(n); + } + + /** + * Copy constructor performs a deep copy. + * @param map hash map to copy + */ + ChainHashMap(const hash_map &map); + + /** + * Copy constructor performs a deep copy. + * @param map hash map to copy + */ + ChainHashMap(hash_map &map); + + /** + * Destroy the hash map, freeing allocated nodes and + * memory allocated for the array. + */ + ~ChainHashMap(); + + private: + /** + * Function called when creating the hash map. This function + * will allocate memory for the backing array and initialize each + * element to nullptr. + * @param n the size of the backing array + */ + void init_buckets(size_type n); + + /** + * Obtain the bucket index in an array with the specified + * number of maximum elements. + * @param key the key to hash + * @param max_elements the maximum number of buckets + * @return an index i such that 0 <= i < max_elements + */ + size_type bucket_index(key_type key, size_type max_elements) const { + return m_hash(key) % max_elements; + } + + /** + * Obtain the bucket index of a key in the backing array. + * @param key the key to hash + * @return an index i such that 0 <= i < m_max_elements + */ + size_type hash(key_type key) const { + return m_hash(key) % m_max_elements; + } + + /** + * Resize and rehash the hash map if the current load factor + * exceeds or equals the maximum load factor. This function + * will double the size of the backing array, allocating a new + * array, and fully deallocating the previous array. + * + * @pre this function will create a new array allocator, however + * the same node allocator will be used, which means that + * the node allocator will start drawing from heap memory + * if the number of elements exceeds the initial max elements + */ + void ensure_capacity(); + + public: + /** + * @return the current number of elements that have been + * inserted into the map + */ + size_type size() const { + return m_num_elements; + } + + /** + * @return the current size of the backing array + */ + size_type max_size() const { + return m_max_elements; + } + + /** + * @return the maximum load before before rehash + */ + percent_type max_load() const { + return m_max_load; + } + + /** + * @return true if the map is empty + */ + bool empty() const { + return m_num_elements == 0; + } + + /** + * @return the node allocator of the map + */ + const Allocator *get_node_allocator() const { + return &m_node_allocator; + } + + /** + * Obtain an iterator to the first element in the hash map. + * Returns pass-the-end iterator if there are no elements + * in the hash map. + * @return iterator the first element + */ + iterator begin() { + if (m_num_elements == 0) { + return end(); + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + return iterator(m_buckets[i], this); + } + } + return end(); + } + + /** + * @return a pass-the-end iterator for this map + */ + iterator end() { + return iterator(nullptr, this); + } + + /** + * @see ChainHashMap::begin() + * @return a constant iterator to the first element + */ + const_iterator begin() const { + if (m_num_elements == 0) { + return end(); + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + return const_iterator(m_buckets[i], this); + } + } + return end(); + } + + /** + * @see ChainHashMap::end() + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return const_iterator(nullptr, this); + } + + /** + * Erase all elements in the map, deallocating them + * and resetting the element count to zero. + */ + void clear() noexcept; + + /** + * Attempt to insert an element into the map. + * Insertion is prevented if there already exists + * an element with the provided key + * @param key inserted element key + * @param val inserted element value + * @return a pair consisting of an iterator pointing to the + * inserted element or the element that prevented insertion + * and a bool indicating whether insertion occurred + */ + Pair insert(key_type key, val_type val); + + /** + * Attempt to insert an element into the map. + * If an element with the same key already exists, + * override the value mapped to by the provided key. + * @param key inserted element key + * @param val inserted element value + * @return a pair consisting of an iterator pointing to the + * inserted element or the assigned element, and a bool + * indicating whether insertion occurred + */ + Pair insert_or_assign(key_type key, val_type val); + + /** + * Erase an element pointed to by the provided pointer. + * @param pos element to erase + * @return the iterator to the next element in the map + * or pass-the-end if there are no more elements afterwards + */ + iterator &erase(iterator &pos); + + /** + * @see ChainHashMap::erase() + * @param pos const iterator to the element to erase + * @return const iterator to the next element or pass-the-end + */ + const_iterator &erase(const_iterator &pos); + + /** + * Erase + * @param type + * @return + */ + bool erase(key_type &key); + + /** + * Returns the value corresponding to a provided key. + * @param key the key for which to find the value + * @return the value mapped to by the key + * @throws KeyException if the key does not map to a value + */ + iterator at(const key_type &key); + + /** + * @see ChainHashMap::at() + * @param key key for which to find the value + * @return the mapped value + * @throws KeyException if the key does not exist + */ + const_iterator at(const key_type &key) const; + + /** + * @param key key for which to check existence of a value + * @return true if the key maps to a value + */ + bool contains(const key_type &key) const; + + /** + * Return an iterator to the map element corresponding + * to the provided key, or pass-the-end if the key does + * not map to any value in the map. + * @param key the key to map + * @return an iterator to the element mapped by the key + */ + iterator find(const key_type &key); + + /** + * @see ChainHashMap::find() + * @param key the key to map + * @return a const iterator to the element mapped by the key + */ + const_iterator find(const key_type &key) const; + + /** + * Access an element in the hash map by the given key. + * If the key does not map to any value in the map, + * then a new value is created and inserted using the default + * constructor. + * @param key the key whose value to access + * @return a reference to the mapped value + */ + val_type &operator[](const key_type &key); + + /** + * Assignment operator performs a deep copy of the + * contents of the assigned map. Therefore, one + * should use pass by reference or pointer unless + * assignment is absolutely necessary. + * @param map the map to copy + * @return a reference to this map + */ + hash_map &operator=(const hash_map &map); + + /** + * Assignment operator performs a deep copy of the + * contents of the assigned map. Therefore, one + * should use pass by reference or pointer unless + * assignment is absolutely necessary. + * @param map the map to copy + * @return a reference to this map + */ + hash_map &operator=(hash_map &map); + }; + + template + void ChainHashMap::init_buckets(ChainHashMap::size_type n) { + m_buckets = static_cast(memory_alloc(n * sizeof(map_node *))); + for (size_type i = 0; i < n; ++i) { + m_buckets[i] = nullptr; + } + } + + template + void ChainHashMap::ensure_capacity() { + if (m_num_elements * 100 < m_max_load * m_max_elements) { + return; + } + size_type new_max = static_cast(m_max_elements * 2); + map_node **new_buckets = static_cast(memory_alloc(new_max * sizeof(map_node *))); + for (size_type i = 0; i < new_max; ++i) { + new_buckets[i] = nullptr; + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (!m_buckets[i]) { + continue; + } + map_node *cur = m_buckets[i]; + while (cur) { + size_type k = bucket_index(cur->m_key, new_max); + map_node *first = new_buckets[k]; + map_node *next = cur->next; + cur->next = first; + new_buckets[k] = cur; + cur = next; + } + } + memory_free(m_buckets); + m_buckets = new_buckets; + m_max_elements = new_max; + } + + template + void ChainHashMap::clear() noexcept { + for (size_type i = 0; i < m_max_elements; ++i) { + map_node *cur = m_buckets[i]; + map_node *next; + while (cur) { + next = cur->next; + m_node_allocator.Deallocate(cur); + cur = next; + } + m_buckets[i] = nullptr; + } + m_num_elements = 0; + } + + template + Pair::iterator, bool> + ChainHashMap::insert(key_type key, val_type val) { + ensure_capacity(); + size_type i = hash(key); + map_node *first = m_buckets[i]; + for (map_node *cur = first; cur; cur = cur->next) { + if (m_equal(cur->m_key, key)) { + return Pair(iterator(cur, this), false); + } + } + map_node *tmp = static_cast(m_node_allocator.Allocate()); + tmp->m_key = key; + tmp->m_val = val; + tmp->next = first; + m_buckets[i] = tmp; + ++m_num_elements; + return Pair(iterator(tmp, this), true); + }; + + template + Pair::iterator, bool> + ChainHashMap::insert_or_assign(key_type key, val_type val) { + ensure_capacity(); + size_type i = hash(key); + map_node *first = m_buckets[i]; + for (map_node *cur = first; cur; cur = cur->next) { + if (m_equal(cur->m_key, key)) { + cur->m_val = val; + return Pair(iterator(cur, this), false); + } + } + map_node *tmp = static_cast(m_node_allocator.Allocate()); + tmp->m_key = key; + tmp->m_val = val; + tmp->next = first; + m_buckets[i] = tmp; + ++m_num_elements; + return Pair(iterator(tmp, this), true); + }; + + template + typename ChainHashMap::iterator & + ChainHashMap::erase(iterator &pos) { + map_node *p_node = pos.m_current; + if (p_node) { + map_node *n_node = p_node->next; + if (n_node) { + p_node->next = n_node->next; + p_node->m_key = n_node->m_key; + p_node->m_val = n_node->m_val; + m_node_allocator.Deallocate(n_node); + --m_num_elements; + return pos; + } else { + size_type i = hash(p_node->m_key); + map_node *c_node = m_buckets[i]; + if (c_node == p_node) { + m_node_allocator.Deallocate(c_node); + --m_num_elements; + m_buckets[i] = nullptr; + while (++i < m_max_elements && !m_buckets[i]); + if (i == m_max_elements) { + pos.m_current = nullptr; + return pos; + } else { + pos.m_current = m_buckets[i]; + return pos; + } + } else { + while (c_node->next != p_node) { + c_node = c_node->next; + } + m_node_allocator.Deallocate(c_node->next); + --m_num_elements; + c_node->next = nullptr; + while (++i < m_max_elements && !m_buckets[i]); + if (i == m_max_elements) { + pos.m_current = nullptr; + return pos; + } else { + pos.m_current = m_buckets[i]; + return pos; + } + } + } + } + pos.m_current = nullptr; + return pos; + } + + template + typename ChainHashMap::const_iterator & + ChainHashMap::erase(const_iterator &pos) { + const map_node *p_node = pos.m_current; + if (p_node) { + size_type i = hash(p_node->m_key); + map_node *c_node = m_buckets[i]; + if (p_node->next) { + while (c_node != p_node) { + c_node = c_node->next; + } + map_node *n_node = c_node->next; + c_node->m_key = n_node->m_key; + c_node->m_val = n_node->m_val; + c_node->next = n_node->next; + m_node_allocator.Deallocate(n_node); + --m_num_elements; + return pos; + } else { + if (c_node == p_node) { + m_node_allocator.Deallocate(c_node); + --m_num_elements; + m_buckets[i] = nullptr; + while (++i < m_max_elements && !m_buckets[i]); + if (i == m_max_elements) { + pos.m_current = nullptr; + return pos; + } else { + pos.m_current = m_buckets[i]; + return pos; + } + } else { + while (c_node->next != p_node) { + c_node = c_node->next; + } + m_node_allocator.Deallocate(c_node->next); + --m_num_elements; + c_node->next = nullptr; + while (++i < m_max_elements && !m_buckets[i]); + if (i == m_max_elements) { + pos.m_current = nullptr; + return pos; + } else { + pos.m_current = m_buckets[i]; + return pos; + } + } + } + } + pos.m_current = nullptr; + return pos; + } + + template + bool ChainHashMap::erase(key_type &key) { + size_type i = hash(key); + map_node *first = m_buckets[i]; + if (first) { + map_node *cur = first; + map_node *next = cur->next; + if (next) { + if (m_equal(key, cur->m_key)) { + cur->m_key = next->m_key; + cur->m_val = next->m_val; + cur->next = next->next; + m_node_allocator.Deallocate(next); + --m_num_elements; + return true; + } + while (next && !m_equal(key, next->m_key)) { + cur = next; + next = cur->next; + } + if (next) { + cur->next = next->next; + m_node_allocator.Deallocate(next); + --m_num_elements; + return true; + } + return false; + } else { + if (!m_equal(key, cur->m_key)) { + return false; + } + m_node_allocator.Deallocate(cur); + --m_num_elements; + m_buckets[i] = nullptr; + return true; + } + } + return false; + } + + template + typename ChainHashMap::iterator + ChainHashMap::at(const key_type &key) { + size_type i = hash(key); + map_node *cur = m_buckets[i]; + if (!cur) { + return end(); + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + if (!cur) { + return end(); + } + return iterator(cur, this); + } + + template + typename ChainHashMap::const_iterator + ChainHashMap::at(const key_type &key) const { + size_type i = hash(key); + map_node *cur = m_buckets[i]; + if (!cur) { + return end(); + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + if (!cur) { + return end(); + } + return const_iterator(cur, this); + } + + template + bool ChainHashMap::contains(const key_type &key) const { + size_type i = hash(key); + map_node *cur = m_buckets[i]; + if (!cur) { + return false; + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + return cur != nullptr; + } + + template + typename ChainHashMap::val_type & + ChainHashMap::operator[](const key_type &key) { + ensure_capacity(); + size_type i = hash(key); + map_node *first = m_buckets[i]; + map_node *cur = first; + if (!cur) { + map_node *ele = static_cast(m_node_allocator.Allocate()); + ++m_num_elements; + ele->m_key = key; + ele->m_val = val_type(); + ele->next = nullptr; + m_buckets[i] = ele; + return ele->m_val; + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + if (cur) { + return cur->m_val; + } + cur = static_cast(m_node_allocator.Allocate()); + ++m_num_elements; + cur->m_key = key; + cur->m_val = val_type(); + cur->next = nullptr; + cur->next = first; + m_buckets[i] = cur; + return cur->m_val; + } + + template + typename ChainHashMap::iterator + ChainHashMap::find(const key_type &key) { + size_type i = hash(key); + map_node *cur = m_buckets[i]; + if (!cur) { + return end(); + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + if (!cur) { + return end(); + } + return iterator(cur, this); + } + + template + typename ChainHashMap::const_iterator + ChainHashMap::find(const key_type &key) const { + size_type i = hash(key); + map_node *cur = m_buckets[i]; + if (!cur) { + return end(); + } + while (cur && !m_equal(key, cur->m_key)) { + cur = cur->next; + } + if (!cur) { + return end(); + } + return const_iterator(cur, this); + } + + template + ChainHashMap::~ChainHashMap() { + for (size_type i = 0; i < m_max_elements; ++i) { + map_node *cur = m_buckets[i]; + if (cur) { + while (cur) { + map_node *next = cur->next; + m_node_allocator.Deallocate(cur); + cur = next; + } + } + } + memory_free(m_buckets); + m_buckets = nullptr; + } + + template + ChainHashMap & + ChainHashMap::operator=(const ChainHashMap &map) { + clear(); + memory_free(m_buckets); + m_hash = map.m_hash; + m_equal = map.m_equal; + m_max_elements = map.m_max_elements; + m_max_load = map.m_max_load; + m_num_elements = map.m_num_elements; + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; ++i) { + m_buckets[i] = nullptr; + map_node *m_cur = map.m_buckets[i]; + while (m_cur) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + cur->next = m_buckets[i]; + m_buckets[i] = cur; + m_cur = m_cur->next; + } + } + return *this; + } + + template + ChainHashMap & + ChainHashMap::operator=(ChainHashMap &map) { + clear(); + memory_free(m_buckets); + m_hash = map.m_hash; + m_equal = map.m_equal; + m_max_elements = map.m_max_elements; + m_max_load = map.m_max_load; + m_num_elements = map.m_num_elements; + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; ++i) { + m_buckets[i] = nullptr; + map_node *m_cur = map.m_buckets[i]; + while (m_cur) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + cur->next = m_buckets[i]; + m_buckets[i] = cur; + m_cur = m_cur->next; + } + } + return *this; + } + + template + ChainHashMap::ChainHashMap(const hash_map &map) : + m_hash(map.m_hash), + m_equal(map.m_equal), + m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, + m_num_elements(map.m_num_elements), + m_max_elements(map.m_max_elements), + m_max_load(map.m_max_load) { + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; i++) { + m_buckets[i] = nullptr; + map_node *m_cur = map.m_buckets[i]; + while (m_cur) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + cur->next = m_buckets[i]; + m_buckets[i] = cur; + m_cur = m_cur->next; + } + } + } + + template + ChainHashMap::ChainHashMap(hash_map &map) : + m_hash(map.m_hash), + m_equal(map.m_equal), + m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, + m_num_elements(map.m_num_elements), + m_max_elements(map.m_max_elements), + m_max_load(map.m_max_load) { + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; i++) { + m_buckets[i] = nullptr; + map_node *m_cur = map.m_buckets[i]; + while (m_cur) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + cur->next = m_buckets[i]; + m_buckets[i] = cur; + m_cur = m_cur->next; + } + } + } + + template + ChainHashMapIterator & + ChainHashMapIterator::operator++() { + const map_node *old = m_current; + m_current = m_current->next; + if (!m_current) { + size_type i = m_hash_map->hash(old->m_key); + while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_max_elements) { + m_current = nullptr; + } else { + m_current = m_hash_map->m_buckets[i]; + } + } + return *this; + } + + template + inline ChainHashMapIterator + ChainHashMapIterator::operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } + + template + ChainHashMapConstIterator & + ChainHashMapConstIterator::operator++() { + const map_node *old = m_current; + m_current = m_current->next; + if (!m_current) { + size_type i = m_hash_map->hash(old->m_key); + while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_max_elements) { + m_current = nullptr; + } else { + m_current = m_hash_map->m_buckets[i]; + } + } + return *this; + } + + template + inline ChainHashMapConstIterator + ChainHashMapConstIterator::operator++(int) { + const_iterator tmp = *this; + ++*this; + return tmp; + } + +} + +#endif //EMBEDDEDTESTS_CHAINMAP_H diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h new file mode 100644 index 00000000..4690e7b7 --- /dev/null +++ b/lib/wlib/stl/ChainSet.h @@ -0,0 +1,219 @@ +/** + * @file ChainSet.h + * @brief Hash set implementation. + * + * Set implementation using a separately chained + * hash map as the backing structure. + * + * @author Jeff Niu + * @date November 4, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_CHAINSET_H +#define EMBEDDEDCPLUSPLUS_CHAINSET_H + +#include "Hash.h" +#include "Equal.h" +#include "ChainMap.h" + +namespace wlp { + + /** + * Hash set implementation using separate chaining. This implementation + * supports removal operations, unlike the open addressed set. + * @tparam Key the element type + * @tparam Hash the hash function + * @tparam Equal the equality function + */ + template, + class Equal = equals> + class ChainHashSet { + public: + typedef ChainHashSet hash_set; + typedef ChainHashMap hash_map; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapConstIterator const_iterator; + typedef hash_map::size_type size_type; + typedef hash_map::percent_type percent_type; + typedef hash_map::key_type key_type; + + private: + hash_map m_hash_map; + + public: + /** + * Construct a chained hash set, which creates + * the backing chain hash map instance. + * @param n the initial size of the backing array + * @param max_load the maximum load factor before rehash + */ + explicit ChainHashSet( + size_type n = 12, + percent_type max_load = 75) : + m_hash_map(n, max_load) {} + + /** + * @return the current number of elements in the set + */ + size_type size() const { + return m_hash_map.size(); + } + + /** + * @return the size of the backing array + */ + size_type max_size() const { + return m_hash_map.max_size(); + } + + /** + * @return the maximum load factor + */ + percent_type max_load() const { + return m_hash_map.max_load(); + } + + /** + * @return whether the hash map is empty + */ + bool empty() const { + return m_hash_map.empty(); + } + + /** + * @return a pointer to the backing map's node allocator + */ + const Allocator *get_node_allocator() const { + return m_hash_map.get_node_allocator(); + } + + /** + * @return a pointer to the backing hash map + */ + const hash_map *get_backing_hash_map() const { + return &m_hash_map; + } + + /** + * An iterator instance to the beginning of the hash set. + * The iterator order of the set is not guaranteed to + * be in any particular order. + * @return iterator to the first element, or @code end @endcode + * if the set is empty + */ + iterator begin() { + return m_hash_map.begin(); + } + + /** + * A pass-the-end iterator instance. This iterator means + * that an iterator has read past the end of the set + * and has become invalid. + * @return a pass-the-end iterator + */ + iterator end() { + return m_hash_map.end(); + } + + /** + * @return a constant iterator to the first element + */ + const_iterator begin() const { + return m_hash_map.begin(); + } + + /** + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return m_hash_map.end(); + } + + /** + * Empty the elements in the set, such that its + * size is now zero. + */ + void clear() noexcept { + m_hash_map.clear(); + } + + /** + * Insert an element into the set. This function + * returns a pair consistent of the iterator to the + * element that was inserted or to the element that + * prevented insertion. The second boolean value indicates + * whether insertion took place. + * @param key the element to insert + * @return a pair of an iterator and boolean + */ + Pair insert(key_type key) { + return m_hash_map.insert(key, key); + }; + + /** + * Check if an element is in the set. + * @param key element whose existence to check + * @return true if the element is contained in the set + */ + bool contains(const key_type &key) const { + return m_hash_map.contains(key); + } + + /** + * Obtain an iterator to an element in the set. + * @param key the element to find + * @return iterator to the element or pass-the-end + * if the element is not in the set + */ + iterator find(const key_type &key) { + return m_hash_map.find(key); + } + + /** + * Obtain a const iterator to an element in the set + * @param key the element to find + * @return const iterator to the element or pass-the-end + * if the element is not in the set + */ + const_iterator find(const key_type &key) const { + return m_hash_map.find(key); + } + + /** + * Erase an element pointed to be an iterator. + * This function will move the provided iterator + * to the next element and return a copy of + * that iterator. + * @param pos the iterator whose element to erase + * @return an iterator to the next element, or + * pass the end if the iteration has reached the end + */ + iterator &erase(iterator &pos) { + return m_hash_map.erase(pos); + } + + /** + * Erase an element pointed to by a const iterator. + * @param pos the iterator to the element to erase + * @return an iterator to the next element + */ + const_iterator &erase(const_iterator &pos) { + return m_hash_map.erase(pos); + } + + /** + * Remove a value from the set. + * @param key the value to remove + * @return true if the value was removed, + * false if the value was never in the set + */ + bool erase(key_type &key) { + return m_hash_map.erase(key); + } + }; + +} + +#endif //EMBEDDEDCPLUSPLUS_CHAINSET_H diff --git a/lib/wlib/stl/Equal.h b/lib/wlib/stl/Equal.h new file mode 100644 index 00000000..1e716d7d --- /dev/null +++ b/lib/wlib/stl/Equal.h @@ -0,0 +1,77 @@ +/** + * @file Map.h + * @brief Tests for equality for basic data types. + * + * @author Jeff Niu + * @date November 1, 2017 + * @bug No known bugs + */ + +#ifndef CORE_STL_EQUAL_H +#define CORE_STL_EQUAL_H + +#include + +#include "WlibConfig.h" +#include "strings/StaticString.h" + +namespace wlp { + + /** + * The equality function type returns whether + * two key-type values are to be considered equal. + * @tparam Key key type + */ + template + struct equals { + bool operator()(const Key &key1, const Key &key2) const { + return key1 == key2; + } + }; + + template + inline bool static_string_equals(const StaticString &str1, const StaticString &str2) { + if (str1.length() != str2.length()) { + return false; + } + for (uint16_t i = 0; i < str1.length(); ++i) { + if (str1[i] != str2[i]) { + return false; + } + } + return true; + } + + inline bool string_equals(const char *&str1, const char *&str2) { + for (; *str1 && *str2; ++str1, ++str2) { + if (*str1 != *str2) { + return false; + } + } + return *str1 == *str2; + } + + template + struct equals > { + bool operator()(const StaticString &key1, const StaticString &key2) const { + return static_string_equals(key1, key2); + } + }; + + TEMPLATE_NULL + struct equals { + bool operator()(const char *key1, const char *key2) const { + return string_equals(key1, key2); + } + }; + + TEMPLATE_NULL + struct equals { + bool operator()(const char *key1, const char *key2) const { + return string_equals(key1, key2); + } + }; + +} + +#endif //CORE_STL_EQUAL_H diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h new file mode 100644 index 00000000..503df3fb --- /dev/null +++ b/lib/wlib/stl/Hash.h @@ -0,0 +1,126 @@ +/** + * @file hash.h + * @brief Provides hash functions for basic data types. + * + * @author Jeff Niu + * @date November 1, 2017 + * @bug No known bugs + */ + +/* + * TODO: implementation of uniform hash functions + */ + +#ifndef CORE_STL_HASH_H +#define CORE_STL_HASH_H + +#include + +#include "Wlib.h" +#include "WlibConfig.h" +#include "strings/StaticString.h" + +namespace wlp { + + /** + * A basic hash function is defined to be a function that, as best + * as reasonably possible, maps a key-type value to a unique positive integer + * value. This is the parent template of hash functions for basic types in WLib. + * @tparam Key key type + * @tparam IntType the unsigned integer type to return + */ + template + struct hash { + }; + + template + inline IntType hash_static_string(StaticString &static_string) { + IntType h = 0; + for (uint16_t pos = 0; pos < static_string.length(); ++pos) { + h = MUL_127(h) + static_string[pos]; + } + return h; + }; + + template + inline IntType hash_string(const char *s) { + IntType h = 0; + for (; *s; ++s) { + h = MUL_127(h) + *s; + } + return h; + } + + template + struct hash, IntType> { + IntType operator()(StaticString &s) const { + return hash_static_string(s); + } + }; + + template + struct hash { + IntType operator()(const char *s) const { + return hash_string(s); + } + }; + + template + struct hash { + IntType operator()(const char *s) const { + return hash_string(s); + } + }; + + template + struct hash { + IntType operator()(char x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(uint8_t x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(uint16_t x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(uint32_t x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(int8_t x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(int16_t x) const { + return x; + } + }; + + template + struct hash { + IntType operator()(int32_t x) const { + return x; + } + }; + +} + +#endif //CORE_STL_HASH_H diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h new file mode 100644 index 00000000..537e537b --- /dev/null +++ b/lib/wlib/stl/OpenMap.h @@ -0,0 +1,993 @@ +/** + * @file OpenMap.h + * @brief Hash map implementation. + * + * Hash map is implemented using open addressing and linear probing, + * based on the assumption that it will be used with good knowledge + * of the needed map size. The Hash Map provides the same basic + * functionality as std::unordered_map or std::hash_map. + * + * @author Jeff Niu + * @date November 1, 2017 + * @bug No known bugs + */ + +#ifndef CORE_STL_MAP_H +#define CORE_STL_MAP_H + +#include "Hash.h" +#include "Equal.h" +#include "Pair.h" +#include "../memory/Allocator.h" +#include "../memory/Memory.h" + +namespace wlp { + + // Forward declaration of OpenHashMap + template + class OpenHashMap; + + // Forward declaration of OpenHashMap iterator + template + struct OpenHashMapIterator; + + // Forward declaration of const OpenHashMap iterator + template + struct OpenHashMapConstIterator; + + /** + * Hash map node comprise the elements of a hash map's + * backing array, containing an element key and corresponding value. + * @tparam Key key type + * @tparam Val value type + */ + template + struct OpenHashMapNode { + typedef OpenHashMapNode map_node; + typedef Key key_type; + typedef Val val_type; + /** + * The key of the node element. + */ + key_type m_key; + /** + * The value of the node element. + */ + val_type m_val; + + /** + * Nodes are equal if the keys and values are equal. + * @param node node to compare + * @return true if the keys and values are equal + */ + bool operator==(const map_node &node) const { + return m_key == node.m_key && m_val == node.m_val; + } + + /** + * Equality operator for non const. + * @param node node to compare + * @return true if they are equal + */ + bool operator==(map_node &node) const { + return m_key == node.m_key && m_val == node.m_val; + } + }; + + /** + * Iterator class over the elements of a OpenHashMap. Specifically, + * this class iterates from start to end of the OpenHashMap's backing + * array, returning past-the-end afterwards. + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template + struct OpenHashMapIterator { + typedef OpenHashMap hash_map; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapNode map_node; + + typedef Val val_type; + + typedef uint16_t size_type; + + /** + * Pointer to the node referenced by this iterator. + */ + map_node *m_current; + /** + * Pointer to the iterated OpenHashMap. + */ + hash_map *m_hash_map; + + /** + * Default constructor. + */ + OpenHashMapIterator() {} + + /** + * Create an iterator to a OpenHashMap node. + * @param node hash map node + * @param map parent hash map + */ + OpenHashMapIterator(map_node *node, hash_map *map) + : m_current(node), m_hash_map(map) {} + + /** + * Copy constructor for const. + * @param it iterator to copy + */ + OpenHashMapIterator(const iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + /** + * Copy constructor. + * @param it iterator to copy + */ + OpenHashMapIterator(iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + /** + * @return reference to the value of the node + * pointed to by the iterator + */ + val_type &operator*() const { + return m_current->m_val; + } + + /** + * @return pointer to the value of the node + * pointed to by the iterator + */ + val_type *operator->() const { + return &(operator*()); + } + + /** + * Increment the iterator to the next available element in + * the OpenHashMap. If no such element exists, returns pass-the-end + * iterator. This is pre-fix unary operator. + * @return this iterator + */ + iterator &operator++(); + + /** + * Post-fix unary operator. + * @return this iterator + */ + iterator operator++(int); + + /** + * Compare two iterators, equal of they point to the + * same node. + * @param it iterator to compare + * @return true if both point to the same node + */ + bool operator==(const iterator &it) const { + return m_current == it.m_current; + } + + /** + * Non const equality operator. + * @param it iterator to compare + * @return true if both point to the same node + */ + bool operator==(iterator &it) const { + return m_current == it.m_current; + } + + /** + * Compare two iterators, unequal if they point to + * different nodes. + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(const iterator &it) const { + return m_current != it.m_current; + } + + /** + * Non const equality operator. + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(iterator &it) const { + return m_current != it.m_current; + } + + /** + * Assignment operator copies pointers to node + * and hash map. + * @param it iterator to copy + * @return a reference to this iterator + */ + iterator &operator=(const iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + + /** + * Assignment operator for non const. + * @param it iterator to copy + * @return a reference to this iterator + */ + iterator &operator=(iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + }; + + /** + * Constant iterator over a OpenHashMap. Values iterated by + * this class cannot be modified. + * + * @see OpenHashMapIterator + * + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template + struct OpenHashMapConstIterator { + typedef OpenHashMap hash_map; + typedef OpenHashMapConstIterator const_iterator; + typedef OpenHashMapNode map_node; + + typedef Val val_type; + + typedef uint16_t size_type; + + const map_node *m_current; + const hash_map *m_hash_map; + + OpenHashMapConstIterator() {} + + OpenHashMapConstIterator(map_node *node, const hash_map *map) + : m_current(node), m_hash_map(map) {} + + OpenHashMapConstIterator(const const_iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + OpenHashMapConstIterator(const_iterator &it) + : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + + const val_type &operator*() const { + return m_current->m_val; + } + + const val_type *operator->() const { + return &(operator*()); + } + + const_iterator &operator++(); + + const_iterator operator++(int); + + bool operator==(const const_iterator &it) const { + return m_current == it.m_current; + } + + bool operator==(const_iterator &it) const { + return m_current == it.m_current; + } + + bool operator!=(const const_iterator &it) const { + return m_current != it.m_current; + } + + bool operator!=(const_iterator &it) const { + return m_current != it.m_current; + } + + const_iterator &operator=(const const_iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + + const_iterator &operator=(const_iterator &it) { + m_current = it.m_current; + m_hash_map = it.m_hash_map; + return *this; + } + }; + + /** + * Hash map implemented using open addressing and linear probing, + * in the spirit of std::unordered_map. + * @tparam Key key type + * @tparam Val value type + * @tparam Hash hash function + * @tparam Equal key equality function + */ + template, + class Equal = equals > + class OpenHashMap { + public: + typedef OpenHashMap hash_map; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapConstIterator const_iterator; + typedef OpenHashMapNode map_node; + + typedef Key key_type; + typedef Val val_type; + + typedef uint16_t size_type; + typedef uint8_t percent_type; + + friend struct OpenHashMapIterator; + friend struct OpenHashMapConstIterator; + + private: + /** + * Class hash function instance. Used to hash + * element keys. + */ + Hash m_hash; + /** + * Class key equality function. Used to test + * equality of element keys. + */ + Equal m_equal; + + /** + * Allocator to create memory for hash map nodes. + */ + Allocator m_node_allocator; + + /** + * Hash map backing array. + */ + map_node **m_buckets; + + /** + * The current number of elements that have been inserted + * into the map. + */ + size_type m_num_elements; + /** + * The size of the backing array. + */ + size_type m_max_elements; + /** + * The load factor in integer percent + * before rehashing occurs. This number + * cannot be larger than 100. + */ + percent_type m_max_load; + + public: + /** + * Create and initialize an empty hash map. The hash map uses + * {@code Allocator} to handle memory. The hash map is implemented + * with open addressing and linear probing. + * + * @pre the hash map requires definition of an initial bucket array size + * and a maximum load factor before rehashing + * + * @param n initial size of the bucket list; each bucket is initialized to nullptr + * @param max_load an integer value denoting the max percent load factory, e.g. 75 = 0.75 + * @param hash hash function for the key type, default is @code wlp::Hash @endcode + * @param equal equality function for the key type, default is @code wlp::Equal @endcode + */ + explicit OpenHashMap( + size_type n = 12, + percent_type max_load = 75) + : m_hash(Hash()), + m_equal(Equal()), + m_node_allocator{sizeof(map_node), static_cast(n * sizeof(map_node))}, + m_num_elements(0), + m_max_elements(n), + m_max_load(max_load) { + init_buckets(n); + if (max_load > 100) { + max_load = 100; + } + } + + OpenHashMap(const hash_map &map); + + OpenHashMap(hash_map &map); + + /** + * Destroy the hash map, freeing allocated nodes and + * memory allocated for the array. + */ + ~OpenHashMap(); + + private: + /** + * Function called when creating the hash map. This function + * will allocate memory for the backing array and initialize each + * element to nullptr. + * @param n the size of the backing array + */ + void init_buckets(size_type n); + + /** + * Obtain the bucket index in an array with the specified + * number of maximum elements. + * @param key the key to hash + * @param max_elements the maximum number of buckets + * @return an index i such that 0 <= i < max_elements + */ + size_type bucket_index(key_type key, size_type max_elements) const { + return m_hash(key) % max_elements; + } + + /** + * Obtain the bucket index of a key in the backing array. + * @param key the key to hash + * @return an index i such that 0 <= i < m_max_elements + */ + size_type hash(key_type key) const { + return m_hash(key) % m_max_elements; + } + + /** + * Resize and rehash the hash map if the current load factor + * exceeds or equals the maximum load factor. This function + * will double the size of the backing array, allocating a new + * array, and fully deallocating the previous array. + * + * @pre this function will create a new array allocator, however + * the same node allocator will be used, which means that + * the node allocator will start drawing from heap memory + * if the number of elements exceeds the initial max elements + */ + void ensure_capacity(); + + public: + /** + * @return the current number of elements that have been + * inserted into the map + */ + size_type size() const { + return m_num_elements; + } + + /** + * @return the current size of the backing array + */ + size_type max_size() const { + return m_max_elements; + } + + /** + * @return the maximum load before before rehash + */ + percent_type max_load() const { + return m_max_load; + } + + /** + * @return true if the map is empty + */ + bool empty() const { + return m_num_elements == 0; + } + + /** + * @return the node allocator of the map + */ + const Allocator *get_node_allocator() const { + return &m_node_allocator; + } + + /** + * Obtain an iterator to the first element in the hash map. + * Returns pass-the-end iterator if there are no elements + * in the hash map. + * @return iterator the first element + */ + iterator begin() { + if (m_num_elements == 0) { + return end(); + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + return iterator(m_buckets[i], this); + } + } + return end(); + } + + /** + * @return a pass-the-end iterator for this map + */ + iterator end() { + return iterator(nullptr, this); + } + + /** + * @see OpenHashMap::begin() + * @return a constant iterator to the first element + */ + const_iterator begin() const { + if (m_num_elements == 0) { + return end(); + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + return const_iterator(m_buckets[i], this); + } + } + return end(); + } + + /** + * @see OpenHashMap::end() + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return const_iterator(nullptr, this); + } + + /** + * Erase all elements in the map, deallocating them + * and resetting the element count to zero. + */ + void clear() noexcept; + + /** + * Attempt to insert an element into the map. + * Insertion is prevented if there already exists + * an element with the provided key + * @param key inserted element key + * @param val inserted element value + * @return a pair consisting of an iterator pointing to the + * inserted element or the element that prevented insertion + * and a bool indicating whether insertion occurred + */ + Pair insert(key_type key, val_type val); + + /** + * Attempt to insert an element into the map. + * If an element with the same key already exists, + * override the value mapped to by the provided key. + * @param key inserted element key + * @param val inserted element value + * @return a pair consisting of an iterator pointing to the + * inserted element or the assigned element, and a bool + * indicating whether insertion occurred + */ + Pair insert_or_assign(key_type key, val_type val); + + /** + * Returns the value corresponding to a provided key. + * @param key the key for which to find the value + * @return the value mapped to by the key + * @throws KeyException if the key does not map to a value + */ + iterator at(const key_type &key); + + /** + * @see OpenHashMap::at() + * @param key key for which to find the value + * @return the mapped value + * @throws KeyException if the key does not exist + */ + const_iterator at(const key_type &key) const; + + /** + * @param key key for which to check existence of a value + * @return true if the key maps to a value + */ + bool contains(const key_type &key) const; + + /** + * Return an iterator to the map element corresponding + * to the provided key, or pass-the-end if the key does + * not map to any value in the map. + * @param key the key to map + * @return an iterator to the element mapped by the key + */ + iterator find(const key_type &key); + + /** + * @see OpenHashMap::find() + * @param key the key to map + * @return a const iterator to the element mapped by the key + */ + const_iterator find(const key_type &key) const; + + /** + * Access an element in the hash map by the given key. + * If the key does not map to any value in the map, + * then a new value is created and inserted using the default + * constructor. + * @param key the key whose value to access + * @return a reference to the mapped value + */ + val_type &operator[](const key_type &key); + + /** + * Assignment operator performs a deep copy of the + * contents of the map. Therefore, pass by reference + * or by pointer value is generally desired. + * @param map map to copy + * @return a reference to this map + */ + hash_map &operator=(const hash_map &map); + + /** + * Assignment operator for non const. + * @param map map to copy + * @return a reference to this map + */ + hash_map &operator=(hash_map &map); + }; + + template + void OpenHashMap::init_buckets(OpenHashMap::size_type n) { + m_buckets = static_cast(memory_alloc(n * sizeof(map_node *))); + for (size_type i = 0; i < n; ++i) { + m_buckets[i] = nullptr; + } + } + + template + void OpenHashMap::ensure_capacity() { + if (m_num_elements * 100 < m_max_load * m_max_elements) { + return; + } + size_type new_max = static_cast(m_max_elements * 2); + map_node **new_buckets = static_cast(memory_alloc(new_max * sizeof(map_node *))); + for (size_type i = 0; i < new_max; ++i) { + new_buckets[i] = nullptr; + } + for (size_type i = 0; i < m_max_elements; ++i) { + if (!m_buckets[i]) { + continue; + } + map_node *node = m_buckets[i]; + size_type k = bucket_index(node->m_key, new_max); + while (new_buckets[k]) { + if (++k >= new_max) { + k = 0; + } + } + new_buckets[k] = node; + } + memory_free(m_buckets); + m_buckets = new_buckets; + m_max_elements = new_max; + } + + template + void OpenHashMap::clear() noexcept { + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + m_node_allocator.Deallocate(m_buckets[i]); + m_buckets[i] = nullptr; + } + } + m_num_elements = 0; + } + + template + Pair::iterator, bool> + OpenHashMap::insert(key_type key, val_type val) { + ensure_capacity(); + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return Pair(iterator(m_buckets[i], this), false); + } else { + ++m_num_elements; + map_node *node = static_cast(m_node_allocator.Allocate()); + node->m_key = key; + node->m_val = val; + m_buckets[i] = node; + return Pair(iterator(node, this), true); + } + }; + + template + Pair::iterator, bool> + OpenHashMap::insert_or_assign(key_type key, val_type val) { + ensure_capacity(); + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + m_buckets[i]->m_val = val; + return Pair(iterator(m_buckets[i], this), false); + } else { + ++m_num_elements; + map_node *node = static_cast(m_node_allocator.Allocate()); + node->m_key = key; + node->m_val = val; + m_buckets[i] = node; + return Pair(iterator(node, this), true); + } + }; + + template + typename OpenHashMap::iterator + OpenHashMap::at(const key_type &key) { + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return iterator(m_buckets[i], this); + } else { + return end(); + } + } + + template + typename OpenHashMap::const_iterator + OpenHashMap::at(const key_type &key) const { + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return const_iterator(m_buckets[i], this); + } else { + return end(); + } + } + + template + bool OpenHashMap::contains(const key_type &key) const { + size_type i = hash(key); + while (m_buckets[i]) { + if (m_equal(key, m_buckets[i]->m_key)) { + return true; + } + if (++i > +m_max_elements) { + i = 0; + } + } + return false; + } + + template + typename OpenHashMap::val_type & + OpenHashMap::operator[](const key_type &key) { + ensure_capacity(); + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return m_buckets[i]->m_val; + } else { + ++m_num_elements; + map_node *node = static_cast(m_node_allocator.Allocate()); + node->m_key = key; + node->m_val = val_type(); + m_buckets[i] = node; + return node->m_val; + } + } + + template + typename OpenHashMap::iterator + OpenHashMap::find(const key_type &key) { + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return iterator(m_buckets[i], this); + } else { + return end(); + } + } + + template + typename OpenHashMap::const_iterator + OpenHashMap::find(const key_type &key) const { + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_max_elements) { + i = 0; + } + } + if (m_buckets[i]) { + return const_iterator(m_buckets[i], this); + } else { + return end(); + } + } + + template + OpenHashMap::~OpenHashMap() { + for (size_type i = 0; i < m_max_elements; ++i) { + if (m_buckets[i]) { + m_node_allocator.Deallocate(m_buckets[i]); + m_buckets[i] = nullptr; + } + } + memory_free(m_buckets); + m_buckets = nullptr; + } + + template + OpenHashMap & + OpenHashMap::operator=(const OpenHashMap &map) { + clear(); + memory_free(m_buckets); + m_hash = map.m_hash; + m_equal = map.m_equal; + m_max_elements = map.m_max_elements; + m_max_load = map.m_max_load; + m_num_elements = map.m_num_elements; + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; ++i) { + if (map.m_buckets[i]) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + map_node *m_cur = map.m_buckets[i]; + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + m_buckets[i] = cur; + } else { + m_buckets[i] = nullptr; + } + } + return *this; + } + + template + OpenHashMap & + OpenHashMap::operator=(OpenHashMap &map) { + clear(); + memory_free(m_buckets); + m_hash = map.m_hash; + m_equal = map.m_equal; + m_max_elements = map.m_max_elements; + m_max_load = map.m_max_load; + m_num_elements = map.m_num_elements; + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; ++i) { + if (map.m_buckets[i]) { + map_node *cur = static_cast(m_node_allocator.Allocate()); + map_node *m_cur = map.m_buckets[i]; + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + m_buckets[i] = cur; + } else { + m_buckets[i] = nullptr; + } + } + return *this; + } + + template + OpenHashMap::OpenHashMap(const hash_map &map) : + m_hash(map.m_hash), + m_equal(map.m_equal), + m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, + m_num_elements(map.m_num_elements), + m_max_elements(map.m_max_elements), + m_max_load(map.m_max_load) { + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; i++) { + m_buckets[i] = nullptr; + if (map.m_buckets[i]) { + map_node *m_cur = map.m_buckets[i]; + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + m_buckets[i] = cur; + } + } + } + + template + OpenHashMap::OpenHashMap(hash_map &map) : + m_hash(map.m_hash), + m_equal(map.m_equal), + m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, + m_num_elements(map.m_num_elements), + m_max_elements(map.m_max_elements), + m_max_load(map.m_max_load) { + m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); + for (size_type i = 0; i < map.m_max_elements; i++) { + m_buckets[i] = nullptr; + if (map.m_buckets[i]) { + map_node *m_cur = map.m_buckets[i]; + map_node *cur = static_cast(m_node_allocator.Allocate()); + cur->m_key = m_cur->m_key; + cur->m_val = m_cur->m_val; + m_buckets[i] = cur; + } + } + } + + template + OpenHashMapIterator & + OpenHashMapIterator::operator++() { + size_type i = m_hash_map->hash(m_current->m_key); + while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { + if (++i >= m_hash_map->m_max_elements) { + i = 0; + } + } + while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_max_elements) { + m_current = nullptr; + } else { + m_current = m_hash_map->m_buckets[i]; + } + return *this; + } + + template + inline OpenHashMapIterator + OpenHashMapIterator::operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } + + template + OpenHashMapConstIterator & + OpenHashMapConstIterator::operator++() { + size_type i = m_hash_map->hash(m_current->m_key); + while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { + if (++i >= m_hash_map->m_max_elements) { + i = 0; + } + } + while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_max_elements) { + m_current = nullptr; + } else { + m_current = m_hash_map->m_buckets[i]; + } + return *this; + } + + template + inline OpenHashMapConstIterator + OpenHashMapConstIterator::operator++(int) { + const_iterator tmp = *this; + ++*this; + return tmp; + } + +} + +#endif //CORE_STL_MAP_H diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h new file mode 100644 index 00000000..0f5faa72 --- /dev/null +++ b/lib/wlib/stl/OpenSet.h @@ -0,0 +1,194 @@ +/** + * @file OpenSet.h + * @brief Hash set implementation. + * + * Set implementation using an open addressed + * hash map as the backing structure. + * + * @author Jeff Niu + * @date November 4, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_OPENSET_H +#define EMBEDDEDCPLUSPLUS_OPENSET_H + +#include "Hash.h" +#include "Equal.h" +#include "OpenMap.h" + +namespace wlp { + + /** + * An open hash set is created using a backing hash map, + * and all available functions are a subset of the functions + * of the hash map. The set contains unique elements. + * @tparam Key the unique element type + * @tparam Hash the hash function of the stored elements + * @tparam Equal test for equality function of the stored elements + */ + template, + class Equal = equals> + class OpenHashSet { + public: + typedef OpenHashSet hash_set; + typedef OpenHashMap hash_map; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapConstIterator const_iterator; + typedef hash_map::size_type size_type; + typedef hash_map::percent_type percent_type; + typedef hash_map::key_type key_type; + + private: + /** + * The backing hash map. + */ + hash_map m_hash_map; + + public: + /** + * Constructor creates a new hash map, and instantiates + * the backing hash map. + * + * @see OpenHashMap + * @param n the initial size of the backing array + * @param max_load the maximum load factor before rehash + */ + explicit OpenHashSet( + size_type n = 12, + percent_type max_load = 75) : + m_hash_map(n, max_load) {} + + /** + * @return the current number of elements in the set + */ + size_type size() const { + return m_hash_map.size(); + } + + /** + * @return the size of the backing array + */ + size_type max_size() const { + return m_hash_map.max_size(); + } + + /** + * @return the maximum load factor + */ + percent_type max_load() const { + return m_hash_map.max_load(); + } + + /** + * @return whether the hash map is empty + */ + bool empty() const { + return m_hash_map.empty(); + } + + /** + * @return a pointer to the backing map's node allocator + */ + const Allocator *get_node_allocator() const { + return m_hash_map.get_node_allocator(); + } + + /** + * @return a pointer to the backing hash map + */ + const hash_map *get_backing_hash_map() const { + return &m_hash_map; + } + + /** + * An iterator instance to the beginning of the hash set. + * The iterator order of the set is not guaranteed to + * be in any particular order. + * @return iterator to the first element, or @code end @endcode + * if the set is empty + */ + iterator begin() { + return m_hash_map.begin(); + } + + /** + * A pass-the-end iterator instance. This iterator means + * that an iterator has read past the end of the set + * and has become invalid. + * @return a pass-the-end iterator + */ + iterator end() { + return m_hash_map.end(); + } + + /** + * @return a constant iterator to the first element + */ + const_iterator begin() const { + return m_hash_map.begin(); + } + + /** + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return m_hash_map.end(); + } + + /** + * Empty the elements in the set, such that its + * size is now zero. + */ + void clear() noexcept { + m_hash_map.clear(); + } + + /** + * Insert an element into the set. This function + * returns a pair consistent of the iterator to the + * element that was inserted or to the element that + * prevented insertion. The second boolean value indicates + * whether insertion took place. + * @param key the element to insert + * @return a pair of an iterator and boolean + */ + Pair insert(key_type key) { + return m_hash_map.insert(key, key); + }; + + /** + * Check if an element is in the set. + * @param key element whose existence to check + * @return true if the element is contained in the set + */ + bool contains(const key_type &key) const { + return m_hash_map.contains(key); + } + + /** + * Obtain an iterator to an element in the set. + * @param key the element to find + * @return iterator to the element or pass-the-end + * if the element is not in the set + */ + iterator find(const key_type &key) { + return m_hash_map.find(key); + } + + /** + * Obtain a const iterator to an element in the set + * @param key the element to find + * @return const iterator to the element or pass-the-end + * if the element is not in the set + */ + const_iterator find(const key_type &key) const { + return m_hash_map.find(key); + } + }; + +} + + +#endif //EMBEDDEDCPLUSPLUS_OPENSET_H diff --git a/lib/wlib/stl/Pair.h b/lib/wlib/stl/Pair.h new file mode 100644 index 00000000..7944acc0 --- /dev/null +++ b/lib/wlib/stl/Pair.h @@ -0,0 +1,110 @@ +/** + * @file Pair.h + * @brief Implementation of a 2-element tuple. + * + * Created in the spirit of std::pair + * + * @author Jeff Niu + * @date November 2, 2017 + * @bug No known bugs + */ + +/* + * TODO: create and define more boolean operators + */ + +#ifndef EMBEDDEDTESTS_PAIR_H +#define EMBEDDEDTESTS_PAIR_H + +namespace wlp { + + template + struct Pair { + typedef First first_type; + typedef Second second_type; + typedef Pair pair; + + private: + /** + * First element in the pair. + */ + first_type m_first; + /** + * Second element in the pair. + */ + second_type m_second; + + public: + /** + * Default constructor creates an empty pair. + */ + Pair() {}; + + /** + * Create a pair from two values of first type and second type. + * @param first first type value + * @param second second type value + */ + Pair(first_type first, second_type second) : m_first(first), m_second(second) {} + + /** + * @return the first value in the pair + */ + first_type first() { + return m_first; + } + + /** + * @return the second value in the pair + */ + second_type second() { + return m_second; + } + + /** + * Assignment operator copies the first and second values. + * @param p pair to copy + * @return a reference to this pair + */ + pair &operator=(const pair &p) { + m_first = p.m_first; + m_second = p.m_second; + return *this; + } + + /** + * Assignment operator copies the first and second values. + * @param p pair to copy + * @return a reference to this pair + */ + pair &operator=(pair &p) { + m_first = p.m_first; + m_second = p.m_second; + return *this; + } + + /** + * Equality operator. Two pairs are equal if + * both their elements are equal. + * @param p the pair to compare + * @return true if the pairs are equal + */ + bool operator==(const pair &p) { + return m_first == p.m_first && m_second == p.m_second; + } + + /** + * Equality operator. Two pairs are equal if + * both their elements are equal. + * @param p the pair to compare + * @return true if the pairs are equal + */ + bool operator==(pair &p) { + return m_first == p.m_first && m_second == p.m_second; + } + + }; + +} + +#endif //EMBEDDEDTESTS_PAIR_H diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index f1e4fcad..461747d8 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -4,7 +4,7 @@ #include #include -template +template class StaticString { private: char m_buffer[tSize + 1]; @@ -13,7 +13,7 @@ class StaticString { /** * Default constructor creates string with no character */ - StaticString(){ + StaticString() { clear(); } @@ -22,30 +22,59 @@ class StaticString { * * @param str char string */ - StaticString(const char* str){ - uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); + StaticString(const char *str) { + uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); strncpy(m_buffer, str, destSize); m_buffer[destSize] = '\0'; len = destSize; } /** - * Constructor creates string using static string object + * Copy constructor. * - * @param str @code StaticString object + * @param str static string to copy */ - StaticString(const StaticString &str){ - StaticString(str.c_str()); + StaticString(StaticString &str) { + strncpy(m_buffer, str.m_buffer, str.len); + m_buffer[str.len] = '\0'; + len = str.len; } /** - * Assign operator assigns current object to given object + * Copy constructor for const. * - * @param str @code StaticString object - * @return current object + * @param str const static string to copy + */ + StaticString(const StaticString &str) { + strncpy(m_buffer, str.m_buffer, str.len); + m_buffer[str.len] = '\0'; + len = str.len; + } + + /** + * Assignment operator. Copies contents of assigned string. + * + * @param str string to assign + * @return reference to this static string + */ + StaticString &operator=(StaticString &str) { + strncpy(m_buffer, str.m_buffer, str.len); + m_buffer[str.len] = '\0'; + len = str.len; + return *this; + } + + /** + * Assignment operator for const. + * + * @param str const string to assign + * @return reference to this static string */ - StaticString operator= (const StaticString &str){ - return operator=(str.c_str()); + StaticString &operator=(const StaticString &str) { + strncpy(m_buffer, str.m_buffer, str.len); + m_buffer[str.len] = '\0'; + len = str.len; + return *this; } /** @@ -53,8 +82,22 @@ class StaticString { * @param str * @return current object */ - StaticString operator= (const char* str){ - uint16_t destSize = (uint16_t)ceil(fmin((uint16_t) strlen(str), capacity())); + StaticString operator=(char *str) { + uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); + strncpy(m_buffer, str, destSize); + m_buffer[destSize] = '\0'; + len = destSize; + + return *this; + } + + /** + * Assign operator assigns current object to given const character string + * @param str + * @return current object + */ + StaticString operator=(const char *str) { + uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); strncpy(m_buffer, str, destSize); m_buffer[destSize] = '\0'; len = destSize; @@ -67,7 +110,7 @@ class StaticString { * * @return string length */ - uint16_t length() const{ + uint16_t length() const { return len; } @@ -76,7 +119,7 @@ class StaticString { * * @return string capacity */ - uint16_t capacity(){ + uint16_t capacity() const { return tSize; } @@ -92,7 +135,7 @@ class StaticString { /** * Clears the string such that there are no characters left in it */ - void clear(){ + void clear() { m_buffer[0] = '\0'; len = 0; } @@ -103,7 +146,7 @@ class StaticString { * @param pos the position of the character * @return character at @code position */ - char &operator[](uint16_t pos){ + char &operator[](uint16_t pos) { return m_buffer[pos]; } @@ -114,7 +157,7 @@ class StaticString { * @param pos the position of the character * @return character at @code position */ - const char &operator[](uint16_t pos) const{ + const char &operator[](uint16_t pos) const { return m_buffer[pos]; } @@ -124,7 +167,7 @@ class StaticString { * @param pos the position of the character * @return character at @code position */ - char &at(uint16_t pos){ + char &at(uint16_t pos) { return m_buffer[pos]; } @@ -134,7 +177,7 @@ class StaticString { * @param pos the position of the character * @return character at @code position */ - const char &at(uint16_t pos) const{ + const char &at(uint16_t pos) const { return m_buffer[pos]; } @@ -143,7 +186,7 @@ class StaticString { * * @return the first character */ - char &front(){ + char &front() { return m_buffer[0]; } @@ -152,7 +195,7 @@ class StaticString { * * @return the first character */ - const char &front() const{ + const char &front() const { return m_buffer[0]; } @@ -161,7 +204,7 @@ class StaticString { * * @return the last character */ - char &end(){ + char &end() { if (empty()) return m_buffer[0]; return m_buffer[length() - 1]; @@ -172,7 +215,7 @@ class StaticString { * * @return the last character */ - const char &end() const{ + const char &end() const { if (empty()) return m_buffer[0]; return m_buffer[length() - 1]; @@ -185,7 +228,7 @@ class StaticString { * @param c character to add * @return the current string */ - StaticString &operator+=(char c){ + StaticString &operator+=(char c) { return append(c); } @@ -196,7 +239,7 @@ class StaticString { * @param val char string to add * @return the current string */ - StaticString &operator+= (const char* val){ + StaticString &operator+=(const char *val) { return append(val); } @@ -207,7 +250,7 @@ class StaticString { * @param other @code StaticString string to add * @return the current string */ - StaticString operator+= (StaticString& other){ + StaticString operator+=(StaticString &other) { return append(other); } @@ -218,7 +261,7 @@ class StaticString { * @param c character to add * @return the current string */ - StaticString &append(const char c){ + StaticString &append(const char c) { char array[2] = {c, '\0'}; return append(array); } @@ -230,15 +273,15 @@ class StaticString { * @param str character string to add * @return the current string */ - StaticString &append(const char *str){ + StaticString &append(const char *str) { uint16_t bufferLength = this->length(); uint16_t otherLength = (uint16_t) strlen(str); - for(int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++){ - m_buffer[i] = str[i-bufferLength]; + for (int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { + m_buffer[i] = str[i - bufferLength]; } - len = (uint16_t)ceil(fmin(capacity(), (bufferLength + otherLength))); + len = (uint16_t) ceil(fmin(capacity(), (bufferLength + otherLength))); m_buffer[len] = '\0'; @@ -252,7 +295,7 @@ class StaticString { * @param str @code StaticString string to add * @return the current string */ - StaticString &append(const StaticString str){ + StaticString &append(const StaticString str) { return append(str.c_str()); } @@ -263,7 +306,8 @@ class StaticString { * @param c character to add * @return the current string */ - StaticString push_back(const char c){ ; + StaticString push_back(const char c) { + ; return append(c); } @@ -274,7 +318,8 @@ class StaticString { * @param str character string to add * @return the current string */ - StaticString push_back(const char *str){ ; + StaticString push_back(const char *str) { + ; return append(str); } @@ -285,7 +330,8 @@ class StaticString { * @param str @code StaticString string to add * @return the current string */ - StaticString push_back(const StaticString &str){ ; + StaticString push_back(const StaticString &str) { + ; return append(str); } @@ -295,7 +341,7 @@ class StaticString { * * @return character array */ - const char *c_str() const{ + const char *c_str() const { return m_buffer; } @@ -306,11 +352,11 @@ class StaticString { * @param length length of the new string * @return new string which is a substring of current string */ - StaticString substr(uint16_t pos, uint16_t length) const{ + StaticString substr(uint16_t pos, uint16_t length) const { char newBuffer[length + 1]; - for(uint16_t i = pos; i < pos + length ;i++){ - newBuffer[i-pos] = m_buffer[i]; + for (uint16_t i = pos; i < pos + length; i++) { + newBuffer[i - pos] = m_buffer[i]; } newBuffer[length] = '\0'; @@ -328,7 +374,7 @@ class StaticString { * @param str @code StaticString string to compare against current string * @return a signed number based on how strings compare */ - int16_t compare(const StaticString &str) const{ + int16_t compare(const StaticString &str) const { return compare(str.c_str()); } @@ -340,7 +386,7 @@ class StaticString { * @param str character string to compare against current string * @return a signed number based on how strings compare */ - int16_t compare(const char *str) const{ + int16_t compare(const char *str) const { return (int16_t) strcmp(this->c_str(), str); } @@ -354,8 +400,8 @@ class StaticString { * @param rhs @code StaticString string as right hand side string * @return true or false based on if two strings are equal */ -template -bool operator== (const StaticString &lhs, const StaticString &rhs){ +template +bool operator==(const StaticString &lhs, const StaticString &rhs) { return lhs.compare(rhs) == 0; } @@ -367,8 +413,8 @@ bool operator== (const StaticString &lhs, const StaticString &rhs) * @param rhs @code StaticString string as right hand side string * @return true or false based on if two strings are equal */ -template -bool operator== (const char *lhs, const StaticString &rhs){ +template +bool operator==(const char *lhs, const StaticString &rhs) { return rhs.compare(lhs) == 0; } @@ -380,8 +426,8 @@ bool operator== (const char *lhs, const StaticString &rhs){ * @param rhs character string as right hand side string * @return true or false based on if two strings are equal */ -template -bool operator== (const StaticString &lhs, const char *rhs){ +template +bool operator==(const StaticString &lhs, const char *rhs) { return lhs.compare(rhs) == 0; } @@ -393,8 +439,8 @@ bool operator== (const StaticString &lhs, const char *rhs){ * @param rhs @code StaticString string as right hand side string * @return a @code StaticString that is build from left hind string and right hand string */ -template -StaticString operator+(const StaticString &lhs, const StaticString &rhs){ +template +StaticString operator+(const StaticString &lhs, const StaticString &rhs) { StaticString newStr; newStr.push_back(lhs).push_back(rhs); return newStr; @@ -408,8 +454,8 @@ StaticString operator+(const StaticString &lhs, const StaticString * @param rhs @code StaticString string as right hand side string * @return a @code StaticString that is build from left hind string and right hand string */ -template -StaticString operator+(const char *lhs, const StaticString &rhs){ +template +StaticString operator+(const char *lhs, const StaticString &rhs) { StaticString newStr; newStr.push_back(lhs).push_back(rhs); return newStr; @@ -423,8 +469,8 @@ StaticString operator+(const char *lhs, const StaticString &rhs){ * @param rhs character string as right hand side string * @return a @code StaticString that is build from left hind string and right hand string */ -template -StaticString operator+(const StaticString &lhs, const char *rhs){ +template +StaticString operator+(const StaticString &lhs, const char *rhs) { StaticString newStr; newStr.push_back(lhs).push_back(rhs); return newStr; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f9d04ecc..b19ffafc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,12 +9,13 @@ include_directories(${GTEST_INCLUDE_DIR}) include_directories(${WLIB_INCLUDE_DIR}) file(GLOB files - "test.cpp" - "stl/*.cpp" - "strings/*.cpp") + "test.cpp" + "template_defs.h" + "stl/*.cpp" + "strings/*.cpp") add_executable(tests ${files}) target_link_libraries(tests gtest) target_link_libraries(tests wlib) -ADD_DEPENDENCIES(tests wlib) -ADD_DEPENDENCIES(tests gtest) +add_dependencies(tests wlib) +add_dependencies(tests gtest) diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp new file mode 100644 index 00000000..97c614e9 --- /dev/null +++ b/tests/stl/chain_map_check.cpp @@ -0,0 +1,459 @@ +#include "gtest/gtest.h" +#include "stl/ChainMap.h" + +#include "../template_defs.h" + +using namespace wlp; + +typedef StaticString<16> string16; +typedef uint16_t ui16; +typedef ChainHashMap string_map; +typedef ChainHashMap int_map; +typedef int_map::iterator imi; +typedef Pair P_imi_b; +typedef string_map::iterator smi; +typedef Pair P_smi_b; + +TEST(chain_map_test, test_chain_map_node) { + int_map::map_node node; + node.m_key = 6; + node.m_val = 1; + imi it(&node, nullptr); + ASSERT_EQ(1, *it); + ASSERT_EQ(node, *it.m_current); + ASSERT_EQ(nullptr, it.m_hash_map); + string_map::map_node snode; + snode.m_key = string16{"hello"}; + snode.m_val = string16{"hello"}; + smi sit(&snode, nullptr); + ASSERT_EQ(5, sit->length()); + ASSERT_EQ(16, sit->capacity()); +} + +TEST(chain_map_test, test_const_iterator) { + string_map map(10, 100); + string16 key1{"key1"}; + string16 key2{"key2"}; + string16 key3{"key3"}; + string16 val1{"val1"}; + string16 val2{"val2"}; + string16 val3{"val3"}; + map[key1] = val1; + map[key2] = val2; + map[key3] = val3; + const string_map const_map = map; + ASSERT_EQ(3, const_map.size()); + ASSERT_EQ(10, const_map.max_size()); + ASSERT_EQ(100, const_map.max_load()); + string_map::iterator it = map.begin(); + string_map::const_iterator const_it = const_map.begin(); + ASSERT_EQ(*it, *const_it); + ++it; + const_it++; + ASSERT_EQ(*it, *const_it); + it++; + ++const_it; + ASSERT_EQ(*it, *const_it); + ++it; + ++const_it; + ASSERT_EQ(map.end(), it); + ASSERT_EQ(const_map.end(), const_it); +} + +TEST(chain_map_test, test_const_node_equals) { + int_map map(10, 150); + map[15] = 10; + map[10] = 9; + map[9] = 19; + imi it = map.begin(); + int_map::map_node node = *it.m_current; + ASSERT_TRUE(*map.begin().m_current == node); +} + +TEST(chain_map_test, test_iterator_constructors) { + int_map map(10, 150); + map[15] = 10; + map[10] = 9; + const imi it = map.begin(); + imi it2(it); + ASSERT_EQ(map.begin(), it2); +} + +TEST(chain_map_test, test_iterator_equals) { + int_map map(10, 15); + map[15] = 10; + map[10] = 9; + imi it = map.begin(); + ++it; + imi it2 = map.begin(); + ASSERT_FALSE(it == it2); + ASSERT_TRUE(it != it2); + it = it2; + ASSERT_EQ(it, map.begin()); +} + +TEST(chain_map_test, test_ensure_capacity_holes) { + int_map map(5, 50); + map[1] = 1; + map[6] = 6; + map[11] = 11; + map[16] = 16; + map[21] = 21; + map[26] = 26; + ASSERT_EQ(20, map.max_size()); + ui16 expected_values_traverse[] = {1, 21, 26, 6, 11, 16}; + imi it = map.begin(); + for (ui16 i = 0; i < 6; i++) { + ASSERT_EQ(expected_values_traverse[i], *it); + ++it; + } + ASSERT_EQ(map.end(), it); + map.clear(); + ASSERT_EQ(map.end(), map.begin()); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(20, map.max_size()); +} + +TEST(chain_map_test, test_erase_cases) { + int_map map(10, 255); + imi it = map.insert(1, 1).first(); + map[11] = 11; + map[21] = 21; + map[31] = 31; + map[2] = 2; + map.erase(it); + ASSERT_EQ(2, *it); + it = map.end(); + map.erase(it); + ASSERT_EQ(map.end(), it); +} + +TEST(chain_map_test, test_erase_const_iterator) { + int_map map(20, 255); + map[1] = 1; + imi it1 = map.insert(41, 11).first(); + map[21] = 21; + imi it2 = map.insert(2, 2).first(); + map[42] = 42; + map[22] = 22; + map[62] = 62; + map[3] = 3; + imi it3 = map.insert(4, 4).first(); + map[44] = 44; + imi it4 = map.insert(5, 5).first(); + imi it5 = map.insert(15, 15).first(); + int_map::const_iterator cit1(it1.m_current, it1.m_hash_map); + int_map::const_iterator cit2(it2.m_current, it2.m_hash_map); + int_map::const_iterator cit3(it3.m_current, it3.m_hash_map); + int_map::const_iterator cit4(it4.m_current, it4.m_hash_map); + int_map::const_iterator cit5(it5.m_current, it5.m_hash_map); + const int_map const_map = map; + int_map::const_iterator const_end = const_map.end(); + ASSERT_EQ(12, map.size()); + map.erase(cit1); + ASSERT_EQ(1, *cit1); + map.erase(cit2); + ASSERT_EQ(3, *cit2); + map.erase(cit4); + ASSERT_EQ(15, *cit4); + map.erase(cit5); + ASSERT_EQ(const_end, cit5); + map.erase(cit3); + ASSERT_EQ(const_end, cit3); +} + +TEST(chain_map_test, test_constructor_params) { + int_map map(10, 150); + ASSERT_EQ(10, map.max_size()); + ASSERT_EQ(150, map.max_load()); + ASSERT_EQ(0, map.size()); + ASSERT_TRUE(map.empty()); +} + +TEST(chain_map_test, test_constructor_allocator) { + string_map map(10, 100); + const size_t expected = sizeof(string_map::map_node); + ASSERT_EQ(expected, map.get_node_allocator()->GetBlockSize()); + ASSERT_EQ(expected * 10, map.get_node_allocator()->GetPoolSize()); +} + +TEST(chain_map_test, test_begin_returns_end_when_empty) { + string_map map(10, 100); + ASSERT_EQ(map.begin(), map.end()); +} + +TEST(chain_map_test, test_begin_end_const) { + const string_map map(10, 100); + ASSERT_EQ(map.begin(), map.end()); +} + +TEST(chain_map_test, test_insert_at_iterator_no_collision) { + int_map map(5, 255); + ui16 keys[] = {0, 1, 2, 3, 4}; + ui16 values[] = {0, 10, 20, 30, 40}; + P_imi_b r[] = { + map.insert(0, 0), + map.insert(1, 10), + map.insert(2, 20), + map.insert(3, 30), + map.insert(4, 40) + }; + ASSERT_EQ(5, map.size()); + for (ui16 i = 0; i < 5; i++) { + ASSERT_TRUE(r[i].second()); + ASSERT_EQ(values[i], *r[i].first()); + ASSERT_EQ(values[i], *map.at(keys[i])); + } + P_imi_b failed = map.insert(0, 10); + ASSERT_FALSE(failed.second()); + ASSERT_EQ(0, *failed.first()); + imi it = r[0].first(); + ASSERT_EQ(it, map.begin()); + ++it; + ASSERT_EQ(*r[1].first(), *it); + ASSERT_EQ(r[1].first(), it); + ++it; + ASSERT_EQ(*r[2].first(), *it); + ASSERT_EQ(r[2].first(), it); + ++it; + ASSERT_EQ(*r[3].first(), *it); + ASSERT_EQ(r[3].first(), it); + ++it; + ASSERT_EQ(*r[4].first(), *it); + ASSERT_EQ(r[4].first(), it); + ++it; + ASSERT_EQ(map.end(), it); +} + +TEST(chain_map_test, test_insert_at_iterator_collision_resolution) { + int_map map(5, 255); + ui16 keys[] = { + 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, + 10, 12, 15, 17, 20 + }; + ui16 values[] = { + 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, + 100, 120, 150, 170, 200 + }; + // ceil(2.55 * 5) = 13 + // Map will rehash before inserting 17 + P_imi_b r[15]; + for (ui16 i = 0; i < 15; i++) { + r[i] = map.insert(keys[i], values[i]); + ASSERT_TRUE(r[i].second()); + ASSERT_EQ(values[i], *r[i].first()); + } + for (ui16 i = 0; i < 15; i++) { + ASSERT_EQ(values[i], *r[i].first()); + } + ASSERT_EQ(15, map.size()); + imi it = r[14].first(); + ASSERT_EQ(it, map.begin()); + ui16 expected_values_traverse[] = { + 200, 0, 100, 10, 20, 120, + 30, 40, 50, 150, 60, 170, 70, + 80, 90 + }; + ui16 expected_r_traverse[] = { + 14, 0, 10, 1, 2, 11, + 3, 4, 5, 12, 6, 13, + 7, 8, 9 + }; + for (ui16 i = 0; i < 15; i++) { + ASSERT_EQ(expected_values_traverse[i], *it); + ASSERT_EQ(expected_values_traverse[i], *r[expected_r_traverse[i]].first()); + ASSERT_EQ(r[expected_r_traverse[i]].first(), it); + ++it; + } + ASSERT_EQ(map.end(), it); +} + +TEST(chain_map_test, test_insert_or_assign) { + string_map map(15, 255); + string16 a1{"key1"}; + string16 a2{"key2"}; + string16 v1{"value1"}; + string16 v2{"value2"}; + string16 v3{"value3"}; + P_smi_b r1 = map.insert_or_assign(a1, v1); + P_smi_b r2 = map.insert_or_assign(a2, v2); + ASSERT_EQ(2, map.size()); + ASSERT_TRUE(r1.second()); + ASSERT_TRUE(r2.second()); + ASSERT_EQ(v1, *map.at(a1)); + ASSERT_EQ(v2, *map.at(a2)); + P_smi_b r3 = map.insert_or_assign(a1, v3); + ASSERT_EQ(2, map.size()); + ASSERT_FALSE(r3.second()); + ASSERT_EQ(v3, *r3.first()); + ASSERT_EQ(v3, *map.at(a1)); +} + +TEST(chain_map_test, test_erase_key_nothing) { + string_map map(15, 255); + string16 a{"key"}; + ASSERT_FALSE(map.erase(a)); + ASSERT_EQ(0, map.size()); +} + +TEST(chain_map_test, test_erase_key) { + string_map map(15, 255); + string16 a{"key"}; + string16 b{"val"}; + map.insert(a, b); + ASSERT_EQ(1, map.size()); + ASSERT_TRUE(map.erase(a)); + ASSERT_EQ(0, map.size()); +} + +TEST(chain_map_test, test_erase_iterator) { + int_map map(5, 255); + // 0 1 _ 3 _ _ + // 20 33 + // 40 + P_imi_b r0 = map.insert(0, 0); + P_imi_b r1 = map.insert(1, 1); + P_imi_b r3 = map.insert(3, 3); + ASSERT_EQ(3, map.size()); + P_imi_b r20 = map.insert(20, 20); + P_imi_b r33 = map.insert(33, 33); + map.insert(40, 40); + ASSERT_EQ(6, map.size()); + imi it = r1.first(); + map.erase(it); + ASSERT_EQ(5, map.size()); + ASSERT_EQ(33, *it); + ASSERT_EQ(it, r33.first()); + map.erase(it); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(3, *it); + ASSERT_NE(it, r3.first()); // iterator invalidated by erase + ASSERT_EQ(*it, *r3.first()); + map.erase(it); + ASSERT_EQ(3, map.size()); + ASSERT_EQ(map.end(), it); + ASSERT_EQ(40, *map.at(40)); + ASSERT_EQ(20, *map.at(20)); + ASSERT_EQ(0, *map.at(0)); + ASSERT_EQ(map.end(), map.at(1)); + ASSERT_EQ(map.end(), map.at(3)); + ASSERT_EQ(map.end(), map.at(33)); + it = r20.first(); + map.erase(it); + ASSERT_EQ(2, map.size()); + ASSERT_EQ(0, *it); + ASSERT_NE(it, r0.first()); + ASSERT_EQ(0, *r0.first()); + map.erase(it); + ASSERT_EQ(map.end(), it); + ASSERT_EQ(1, map.size()); + ASSERT_EQ(40, *map.begin()); +} + +TEST(chain_map_test, test_contains_access_operator) { + int_map map(5, 255); + map[5] = 50; + map[15] = 150; + map[0] = 0; + map[20] = 200; + map[25] = 250; + ASSERT_EQ(5, map.size()); + map.insert(3, 30); + ASSERT_EQ(6, map.size()); + ASSERT_EQ(30, *map.at(3)); + map[3] = 33; + ASSERT_EQ(6, map.size()); + ASSERT_EQ(33, *map.at(3)); + ASSERT_EQ(50, map[5]); + ASSERT_EQ(150, map[15]); + ASSERT_EQ(200, map[20]); + ASSERT_EQ(250, map[25]); + ASSERT_TRUE(map.contains(25)); + ASSERT_TRUE(map.contains(15)); + ASSERT_TRUE(map.contains(3)); + ASSERT_FALSE(map.contains(4)); + map[14] = 14; + ASSERT_FALSE(map.contains(4)); + map[24] = 24; + ASSERT_FALSE(map.contains(4)); + ASSERT_EQ(8, map.size()); + map[4] = 4; + ASSERT_TRUE(map.contains(4)); + ASSERT_EQ(9, map.size()); +} + +TEST(chain_map, test_const_map_assignment) { + int_map map(10, 255); + map.insert(1, 1); + map.insert(25, 25); + const int_map const_map(map); + map = const_map; + ASSERT_EQ(2, map.size()); + imi it = map.begin(); + ASSERT_EQ(1, *it); + it++; + ASSERT_EQ(25, *it); + int_map b_map(10, 255); + b_map.insert(10, 10); + b_map.insert(12, 12); + b_map.insert(13, 13); + map = b_map; + ASSERT_EQ(3, map.size()); + it = map.begin(); + ASSERT_EQ(10, *it); + ++it; + ASSERT_EQ(12, *it); + ++it; + ASSERT_EQ(13, *it); + ++it; + ASSERT_EQ(map.end(), it); + int_map c_map(const_map); + ASSERT_EQ(2, c_map.size()); + it = c_map.begin(); + ASSERT_EQ(1, *it); + ++it; + ASSERT_EQ(25, *it); + ++it; + ASSERT_EQ(c_map.end(), it); +} + +TEST(chain_map_test, test_find) { + int_map map(10, 255); + map[16] = 1116; + map[21] = 1211; + map[71] = 1711; + ASSERT_EQ(map.end(), map.find(15)); + ASSERT_EQ(map.end(), map.find(0)); + ASSERT_EQ(map.end(), map.find(6)); + ASSERT_EQ(map.end(), map.find(1)); + ASSERT_EQ(1116, *map.find(16)); + ASSERT_EQ(1711, *map.find(71)); + ASSERT_EQ(1211, *map.find(21)); + imi it = map.find(71); + ++it; + ASSERT_EQ(1211, *it); + ++it; + ASSERT_EQ(1116, *it); + ++it; + ASSERT_EQ(map.end(), it); +} + +TEST(chain_map_test, test_erase_key_cases) { + int_map map(10, 255); + map[6] = 6; + map[16] = 16; + map[26] = 26; + map[46] = 46; + map[56] = 56; + map[36] = 36; + map[4] = 4; + ui16 k = 14; + ASSERT_FALSE(map.erase(k)); + k = 36; + ASSERT_TRUE(map.erase(k)); + k = 26; + ASSERT_TRUE(map.erase(k)); + k = 66; + ASSERT_FALSE(map.erase(k)); +} diff --git a/tests/stl/equals_check.cpp b/tests/stl/equals_check.cpp new file mode 100644 index 00000000..d8b29819 --- /dev/null +++ b/tests/stl/equals_check.cpp @@ -0,0 +1,47 @@ +#include "gtest/gtest.h" +#include "strings/StaticString.h" +#include "stl/Equal.h" + +#include "../template_defs.h" + +using namespace wlp; + +TEST(equals_test, test_string_equals) { + equals comparator = equals(); + char str1[] = "somestring"; + char str2[] = "somestring"; + char str3[] = "shoestring"; + char str4[] = "money"; + ASSERT_TRUE(comparator(str1, str2)); + ASSERT_FALSE(comparator(str2, str3)); + ASSERT_FALSE(comparator(str4, str3)); + ASSERT_FALSE(comparator(str2, str4)); + ASSERT_FALSE(comparator(str1, str4)); +} + +TEST(equals_test, test_static_string_equals) { + equals> comparator = equals>(); + StaticString<8> str1{"darwin"}; + StaticString<8> str2{"darwin"}; + StaticString<8> str3{"money__\""}; + StaticString<8> str4{"money__\""}; + ASSERT_TRUE(comparator(str1, str2)); + ASSERT_TRUE(comparator(str3, str4)); +} + +TEST(equals_test, test_static_string_unequal) { + equals> comparator = equals>(); + StaticString<8> str1{"darwin"}; + StaticString<8> str2{"money__\""}; + StaticString<8> str3{"houses"}; + ASSERT_FALSE(comparator(str1, str2)); + ASSERT_FALSE(comparator(str2, str3)); +} + +TEST(equals_test, test_integer_equal) { + equals comparator = equals(); + ASSERT_TRUE(comparator(1, 1)); + ASSERT_TRUE(comparator(15, 15)); + ASSERT_FALSE(comparator(1, 14)); + ASSERT_FALSE(comparator(14, 1)); +} \ No newline at end of file diff --git a/tests/stl/hash_check.cpp b/tests/stl/hash_check.cpp new file mode 100644 index 00000000..24ef2bf6 --- /dev/null +++ b/tests/stl/hash_check.cpp @@ -0,0 +1,34 @@ +#include "gtest/gtest.h" +#include "strings/StaticString.h" +#include "stl/Hash.h" + +#include "../template_defs.h" + +using namespace wlp; + +TEST(hash_test, test_hash_static_string) { + hash, uint16_t> hasher = hash, uint16_t>(); + StaticString<8> str1{"darwin"}; + StaticString<8> str2{"darwin"}; + StaticString<8> str3{"hello"}; + ASSERT_EQ(hasher(str1), hasher(str2)); + ASSERT_NE(hasher(str1), hasher(str3)); + ASSERT_NE(hasher(str2), hasher(str3)); +} + +TEST(hash_test, test_hash_string) { + hash hasher = hash(); + char str1[] = "drawing"; + char str2[] = "downward"; + char str3[] = "drawing"; + ASSERT_EQ(hasher(str1), hasher(str3)); + ASSERT_NE(hasher(str2), hasher(str1)); + ASSERT_NE(hasher(str2), hasher(str3)); +} + +TEST(hash_test, test_hash_integer) { + hash hasher = hash(); + ASSERT_EQ(4, hasher(4)); + ASSERT_EQ(hasher(10), hasher(10)); + ASSERT_EQ(1556, hasher(1556)); +} \ No newline at end of file diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp new file mode 100644 index 00000000..9d638eb5 --- /dev/null +++ b/tests/stl/open_map_check.cpp @@ -0,0 +1,296 @@ +#include "gtest/gtest.h" +#include "stl/OpenMap.h" + +#include "../template_defs.h" + +using namespace wlp; + +typedef StaticString<16> string16; +typedef OpenHashMap string_map; +typedef OpenHashMap int_map; +typedef int_map::iterator imi; +typedef Pair P_imi_b; + +TEST(open_map_test, test_constructor_parameters) { + int_map map(15, 61); + ASSERT_EQ(15, map.max_size()); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(61, map.max_load()); +} + +TEST(open_map_test, test_constructor_allocator) { + string_map map(12, 75); + const Allocator* alloc = map.get_node_allocator(); + size_t expected = sizeof(string_map::map_node); + ASSERT_EQ(expected, alloc->GetBlockSize()); + ASSERT_EQ(expected * 12, alloc->GetPoolSize()); +} + +TEST(open_map_test, test_is_empty_on_construct) { + string_map map(12, 75); + ASSERT_TRUE(map.empty()); +} + +TEST(open_map_test, test_begin_returns_end_when_empty) { + string_map map(12, 75); + ASSERT_EQ(map.begin(), map.end()); +} + +TEST(open_map_test, test_begin_end_const_and_non_const) { + const string_map map(12, 75); + string_map non_map(12, 75); + string_map::const_iterator cit = map.begin(); + const string_map::const_iterator cit_end = map.end(); + string_map::const_iterator cit1(cit); + const string_map::const_iterator cit2(cit_end); + ASSERT_EQ(cit1, cit2); + ASSERT_TRUE(cit1 == cit2); + ASSERT_TRUE(cit2 == cit1); + cit1 = cit2; + cit = cit_end; + ASSERT_EQ(cit1, cit); + cit = cit1; + ASSERT_EQ(cit1, cit); + string_map::iterator it(non_map.end()); + string_map::iterator end = non_map.end(); + it = end; + ASSERT_EQ(non_map.end(), it); + ASSERT_EQ(cit, cit_end); +} + +TEST(open_map_test, test_at_const) { + int_map map(10, 75); + map[7] = 7; + map[8] = 8; + map[9] = 9; + map[17] = 17; + const int_map const_map(map); + ASSERT_EQ(const_map.end(), const_map.at(10)); + ASSERT_EQ(7, *const_map.at(7)); + ASSERT_EQ(8, *const_map.at(8)); + ASSERT_EQ(9, *const_map.at(9)); + ASSERT_EQ(17, *const_map.at(17)); + ASSERT_EQ(const_map.at(7), const_map.find(7)); + ASSERT_EQ(const_map.at(10), const_map.find(10)); + ASSERT_EQ(const_map.at(9), const_map.find(9)); + int_map::const_iterator it = const_map.begin(); + ASSERT_EQ(17, *it); + ++it; + ASSERT_EQ(7, *it); + it++; + ASSERT_EQ(8, *it); +} + +TEST(open_map_test, test_insert_find_iterate_integer) { + int_map map(10, 61); + P_imi_b res1 = map.insert(0, 15); + P_imi_b res2 = map.insert(1, 20); + P_imi_b res3 = map.insert(0, 35); + P_imi_b res4 = map.insert(9, 90); + P_imi_b res5 = map.insert(20, 100); + P_imi_b res6 = map.insert(19, 120); + ASSERT_TRUE(res1.second()); + ASSERT_TRUE(res2.second()); + ASSERT_FALSE(res3.second()); + ASSERT_TRUE(res4.second()); + ASSERT_TRUE(res5.second()); + ASSERT_TRUE(res6.second()); + ASSERT_EQ(15, *res1.first()); + ASSERT_EQ(20, *res2.first()); + ASSERT_EQ(15, *res3.first()); + ASSERT_EQ(90, *res4.first()); + ASSERT_EQ(100, *res5.first()); + ASSERT_EQ(120, *res6.first()); + int_map::iterator it1 = res1.first(); + ++it1; + ASSERT_EQ(it1, res2.first()); + ASSERT_EQ(20, *it1); + ++it1; + ASSERT_EQ(it1, res5.first()); + ASSERT_EQ(100, *it1); + ++it1; + ASSERT_EQ(it1, res6.first()); + ASSERT_EQ(120, *it1); + ++it1; + ASSERT_EQ(it1, res4.first()); + ASSERT_EQ(90, *it1); + ++it1; + ASSERT_EQ(it1, map.end()); + ASSERT_EQ(5, map.size()); + ASSERT_EQ(10, map.max_size()); +} + +TEST(open_map_test, test_map_iterator_postfix) { + int_map map(15, 75); + P_imi_b res1 = map.insert(2, 10); + map.insert(10, 12); + imi it = res1.first(); + imi it_post = it++; + ASSERT_NE(it_post, it); + ASSERT_EQ(it_post, res1.first()); + ASSERT_EQ(*it_post, 10); + ASSERT_EQ(*it, 12); + ++it_post; + ASSERT_EQ(it_post, it); + ASSERT_EQ(2, map.size()); +} + +TEST(open_map_test, test_begin_non_empty) { + int_map map(15, 75); + map[5] = 5; + ASSERT_EQ(5, *map.begin()); + const int_map const_map(map); + ASSERT_EQ(5, *const_map.begin()); +} + +TEST(open_map_test, test_copy_constructor) { + int_map source(15, 75); + source[1] = 1; + source[3] = 3; + source[33] = 33; + int_map copy1(source); + ASSERT_EQ(3, copy1.size()); + imi it1 = copy1.begin(); + ASSERT_EQ(1, *it1); + ++it1; + ASSERT_EQ(3, *it1); + ++it1; + ASSERT_EQ(33, *it1); + ++it1; + ASSERT_EQ(copy1.end(), it1); + const int_map copy2 = source; + const int_map copy3(copy2); + int_map copy4; + copy4 = copy3; + ASSERT_EQ(3, copy4.size()); + imi it3 = copy4.begin(); + ASSERT_EQ(1, *it3); + ++it3; + ASSERT_EQ(3, *it3); + ++it3; + ASSERT_EQ(33, *it3); + ++it3; + ASSERT_EQ(copy4.end(), it3); + int_map copy5; + copy5[6] = 6; + copy5[2] = 2; + copy5 = source; + it1 = copy5.begin(); + ASSERT_EQ(1, *it1); + ++it1; + ASSERT_EQ(3, *it1); + ++it1; + ASSERT_EQ(33, *it1); + ++it1; + ASSERT_EQ(copy5.end(), it1); +} + +TEST(open_map_test, test_map_insert_or_assign) { + int_map map(10, 75); + P_imi_b res1 = map.insert_or_assign(2, 10); + P_imi_b res2 = map.insert_or_assign(3, 12); + P_imi_b res3 = map.insert_or_assign(2, 14); + ASSERT_TRUE(res1.second()); + ASSERT_TRUE(res2.second()); + ASSERT_FALSE(res3.second()); + ASSERT_EQ(14, *res1.first()); + ASSERT_EQ(12, *res2.first()); + ASSERT_EQ(14, *res3.first()); + ASSERT_EQ(2, map.size()); +} + +TEST(open_map_test, test_at_returns_value) { + int_map map(10, 75); + map.insert(10, 12); + map.insert(16, 15); + map.insert(20, 19); + map.insert(4, 16); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(12, *map.at(10)); + ASSERT_EQ(15, *map.at(16)); + ASSERT_EQ(19, *map.at(20)); + ASSERT_EQ(16, *map.at(4)); +} + +TEST(open_map_test, test_at_is_assignable) { + int_map map(10, 75); + map.insert(10, 12); + map.insert(16, 15); + ASSERT_EQ(15, *map.at(16)); + ASSERT_EQ(12, *map.at(10)); + ASSERT_EQ(2, map.size()); + *map.at(16) = 100; + *map.at(10) = 101; + ASSERT_EQ(100, *map.at(16)); + ASSERT_EQ(101, *map.at(10)); + ASSERT_EQ(2, map.size()); +} + +TEST(open_map_test, test_at_returns_pass_the_end) { + int_map map(10, 75); + ASSERT_EQ(map.end(), map.at(4)); +} + +TEST(open_map_test, test_contains_key) { + string_map map(10, 75); + string16 key1{"moshi"}; + string16 key2{"welcome"}; + string16 key3{"never"}; + string16 val1{"someval"}; + string16 val2{"anotherval"}; + string16 val3{"yetanother"}; + ASSERT_TRUE(map.insert(key1, val1).second()); + ASSERT_TRUE(map.insert(key2, val2).second()); + ASSERT_TRUE(map.insert(key3, val3).second()); + ASSERT_TRUE(map.contains(key1)); + ASSERT_TRUE(map.contains(key2)); + ASSERT_TRUE(map.contains(key3)); + ASSERT_EQ(val1, *map.at(key1)); + ASSERT_EQ(val2, *map.at(key2)); + ASSERT_EQ(val3, *map.at(key3)); +} + +TEST(open_map_test, test_find) { + int_map map(10, 75); + P_imi_b r1 = map.insert(1, 10); + P_imi_b r2 = map.insert(3, 30); + P_imi_b r3 = map.insert(5, 50); + P_imi_b r4 = map.insert(7, 70); + ASSERT_EQ(r1.first(), map.find(1)); + ASSERT_EQ(r2.first(), map.find(3)); + ASSERT_EQ(r3.first(), map.find(5)); + ASSERT_EQ(r4.first(), map.find(7)); +} + +TEST(open_map_test, test_access_operator) { + int_map map(10, 75); + map.insert(5, 100); + map[5] = 19; + map[10] = 14; + map[556] = 9901; + ASSERT_EQ(19, map[5]); + ASSERT_EQ(14, map[10]); + ASSERT_EQ(9901, map[556]); + ASSERT_FALSE(map.insert(5, 20).second()); + ASSERT_FALSE(map.insert(556, 10).second()); + ASSERT_TRUE(map.contains(10)); +} + +TEST(open_map_test, test_rehash) { + int_map map(2, 50); + map[0] = 0; + map[1] = 10; + map[2] = 20; + map[3] = 30; + map[4] = 40; + map[115] = 2115; + map[226] = 2216; + map[337] = 2317; + map[448] = 2418; + int keys[] = {0, 1, 2, 3, 4, 115, 226, 337, 448}; + int values[] = {0, 10, 20, 30, 40, 2115, 2216, 2317, 2418}; + for (uint16_t i = 0; i < 9; i++) { + ASSERT_TRUE(map.contains(keys[i])); + ASSERT_EQ(*map.find(keys[i]), values[i]); + } +} diff --git a/tests/stl/pair_check.cpp b/tests/stl/pair_check.cpp new file mode 100644 index 00000000..1f7c01e4 --- /dev/null +++ b/tests/stl/pair_check.cpp @@ -0,0 +1,33 @@ +#include "gtest/gtest.h" +#include "stl/Pair.h" + +#include "../template_defs.h" + +using namespace wlp; + +TEST(pair_test, test_pair_constructor) { + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; + Pair pair3{5, "string"}; + Pair pair4{9, "another"}; + ASSERT_TRUE(pair1 == pair3); + ASSERT_EQ(5, pair1.first()); + ASSERT_EQ(8, pair2.first()); + ASSERT_STREQ("string", pair3.second()); + ASSERT_STREQ("another", pair4.second()); +} + +TEST(pair_test, test_pair_assign_operator) { + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; + pair2 = pair1; + ASSERT_TRUE(pair1 == pair2); + ASSERT_EQ(pair1.first(), pair2.first()); + ASSERT_EQ(pair1.second(), pair2.second()); +} + +TEST(pair_test, test_pair_const_equality) { + Pair pair1{5, "string"}; + const Pair pair2{8, "nothing"}; + ASSERT_FALSE(pair1 == pair2); +} diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 1abd8367..6e2c4938 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -1,8 +1,9 @@ - #include "gtest/gtest.h" #include "strings/StaticString.h" #include "memory/Memory.h" +#include "../template_defs.h" + TEST(static_string_tests, constructor_tests){ StaticString<8> string1{"helloooo"}; // text given StaticString<8> string2; // no text diff --git a/tests/template_defs.h b/tests/template_defs.h new file mode 100644 index 00000000..ffc88b13 --- /dev/null +++ b/tests/template_defs.h @@ -0,0 +1,68 @@ +#ifndef TEMPLATE_DEFS_H +#define TEMPLATE_DEFS_H + +#include +#include "stl/ChainMap.h" +#include "stl/OpenMap.h" + +template class StaticString<8>; +template class StaticString<16>; + +namespace wlp { + template class Pair; + template class ChainHashMap, StaticString<16>>; + template class ChainHashMap; + template class Pair::iterator, bool>; + template class Pair, StaticString<16>>::iterator, bool>; + template class ChainHashMapIterator< + StaticString<16>, + StaticString<16>, + hash, uint16_t>, + equals>>; + template class ChainHashMapIterator< + uint16_t, + uint16_t, + hash, + equals>; + template class ChainHashMapConstIterator< + StaticString<16>, + StaticString<16>, + hash, uint16_t>, + equals>>; + template class ChainHashMapConstIterator< + uint16_t, + uint16_t, + hash, + equals>; + template class equals>; + template class equals; + template class hash, uint16_t>; + template class hash; + template class hash; + template class OpenHashMap, StaticString<16>>; + template class OpenHashMap; + template class Pair::iterator, bool>; + template class Pair, StaticString<16>>::iterator, bool>; + template class OpenHashMapIterator< + StaticString<16>, + StaticString<16>, + hash, uint16_t>, + equals>>; + template class OpenHashMapIterator< + uint16_t, + uint16_t, + hash, + equals>; + template class OpenHashMapConstIterator< + StaticString<16>, + StaticString<16>, + hash, uint16_t>, + equals>>; + template class OpenHashMapConstIterator< + uint16_t, + uint16_t, + hash, + equals>; +} + +#endif // TEMPLATE_DEFS_H From ee6fcf911d56b0c0e7898fa7e563f2c01be96871 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Mon, 6 Nov 2017 23:13:56 -0500 Subject: [PATCH 007/102] Static allocator hotfix (#41) * Hot fix added for StaticAllocatorPool and new DynamicAllocatorPool added --- lib/wlib/memory/DynamicAllocatorPool.h | 26 ++++++++++++++++++++++++++ lib/wlib/memory/StaticAllocatorPool.h | 9 ++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 lib/wlib/memory/DynamicAllocatorPool.h diff --git a/lib/wlib/memory/DynamicAllocatorPool.h b/lib/wlib/memory/DynamicAllocatorPool.h new file mode 100644 index 00000000..126fda91 --- /dev/null +++ b/lib/wlib/memory/DynamicAllocatorPool.h @@ -0,0 +1,26 @@ +/** + * @file DynamicAllocatorPool.h + * @brief Template class to create Dynamic memory pools + * + * This class is a generalization of the @code Allocator @endcode class and can be used for + * convenience + * + * @author Deep Dhillon + * @date November 06, 2017 + * @bug No known bugs + */ + +#ifndef FIXED_MEMORY_ALLOCATORPOOL_H +#define FIXED_MEMORY_ALLOCATORPOOL_H + +#include "Allocator.h" + +using namespace wlp; + +template +class DynamicAllocatorPool : public Allocator { +public: + DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks){} +}; + +#endif //FIXED_MEMORY_ALLOCATORPOOL_H diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index e8ebc8f2..3b25af28 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -1,9 +1,12 @@ /** * @file StaticAllocatorPool.h * @brief Template class to create static memory pools - * + * + * This class is a generalization of the @code Allocator @endcode class and can be used for + * convenience + * * @author Deep Dhillon - * @date October 22, 2017 + * @date November 06, 2017 * @bug No known bugs */ @@ -17,7 +20,7 @@ using namespace wlp; template class StaticAllocatorPool : public Allocator { public: - StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks), Allocator::STATIC){} + StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC){} private: char m_memory[tblockSize * tnumBlocks]; }; From ac530369f6d884146cf8cc596b48704cc59d2064 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 12 Nov 2017 00:51:51 -0500 Subject: [PATCH 008/102] EMB#2-test-static-strings (#14) * StaticString class updated and completely tested * test names format fixed for static tests --- lib/wlib/memory/DynamicAllocatorPool.h | 6 +- lib/wlib/memory/StaticAllocatorPool.h | 4 +- lib/wlib/strings/StaticString.h | 845 +++++++++++++------------ tests/strings/static_string_check.cpp | 260 +++++++- tests/template_defs.h | 5 +- tests/test.cpp | 2 +- 6 files changed, 708 insertions(+), 414 deletions(-) diff --git a/lib/wlib/memory/DynamicAllocatorPool.h b/lib/wlib/memory/DynamicAllocatorPool.h index 126fda91..8a42bffb 100644 --- a/lib/wlib/memory/DynamicAllocatorPool.h +++ b/lib/wlib/memory/DynamicAllocatorPool.h @@ -6,7 +6,7 @@ * convenience * * @author Deep Dhillon - * @date November 06, 2017 + * @date November 11, 2017 * @bug No known bugs */ @@ -17,10 +17,10 @@ using namespace wlp; -template +template class DynamicAllocatorPool : public Allocator { public: - DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks){} + DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks) {} }; #endif //FIXED_MEMORY_ALLOCATORPOOL_H diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index 3b25af28..705ffcec 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -6,7 +6,7 @@ * convenience * * @author Deep Dhillon - * @date November 06, 2017 + * @date November 11, 2017 * @bug No known bugs */ @@ -17,7 +17,7 @@ using namespace wlp; -template +template class StaticAllocatorPool : public Allocator { public: StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC){} diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index 461747d8..d3c857a9 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -1,480 +1,533 @@ +/** + * @file StaticString.h + * @brief StaticString provides a String that is on stack and is of fixed size + * + * @author Aditya Arora + * @author Deep Dhillon + * @date November 11, 2017 + * @bug No known bugs + */ + #ifndef WLIB_STATICSTRING_H #define WLIB_STATICSTRING_H -#include +#include #include +#include -template -class StaticString { -private: - char m_buffer[tSize + 1]; - uint16_t len; -public: - /** - * Default constructor creates string with no character - */ - StaticString() { - clear(); - } +namespace wlp { + template + class StaticString { + public: + /** + * Default constructor creates string with no character + */ + StaticString() { + clear(); + } - /** - * Constructor creates string using character array - * - * @param str char string - */ - StaticString(const char *str) { - uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, destSize); - m_buffer[destSize] = '\0'; - len = destSize; - } + /** + * Constructor creates string using static string object + * + * @param str @code StaticString @endcode object + */ + StaticString(const StaticString &str) : StaticString{str.c_str()} {} + + /** + * Constructor creates string using character array + * + * @param str char string + */ + explicit StaticString(const char *str) { + m_len = (uint16_t) strlen(str); + if (m_len > capacity()) m_len = capacity(); + + strncpy(m_buffer, str, m_len); + m_buffer[m_len] = '\0'; + } - /** - * Copy constructor. - * - * @param str static string to copy - */ - StaticString(StaticString &str) { - strncpy(m_buffer, str.m_buffer, str.len); - m_buffer[str.len] = '\0'; - len = str.len; - } + /** + * Assign operator assigns current object to given object + * + * @param str @code StaticString @endcode object + * @return current object + */ + StaticString &operator=(const StaticString &str) { + return operator=(str.c_str()); + } - /** - * Copy constructor for const. - * - * @param str const static string to copy - */ - StaticString(const StaticString &str) { - strncpy(m_buffer, str.m_buffer, str.len); - m_buffer[str.len] = '\0'; - len = str.len; - } + /** + * Assign operator assigns current object to a given character string + * + * @param str character string + * @return current object + */ + StaticString &operator=(const char *str) { + m_len = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); + strncpy(m_buffer, str, length()); + m_buffer[length()] = '\0'; + + return *this; + } - /** - * Assignment operator. Copies contents of assigned string. - * - * @param str string to assign - * @return reference to this static string - */ - StaticString &operator=(StaticString &str) { - strncpy(m_buffer, str.m_buffer, str.len); - m_buffer[str.len] = '\0'; - len = str.len; - return *this; - } + /** + * Assign operator assigns current object to given character + * + * @param c given character + * @return current object + */ + StaticString &operator=(const char c) { + char string[] = {c, '\0'}; + return operator=(string); + } - /** - * Assignment operator for const. - * - * @param str const string to assign - * @return reference to this static string - */ - StaticString &operator=(const StaticString &str) { - strncpy(m_buffer, str.m_buffer, str.len); - m_buffer[str.len] = '\0'; - len = str.len; - return *this; - } + /** + * Provides current length of string + * + * @return string length + */ + uint16_t length() const { + return m_len; + } - /** - * Assign operator assigns current object to given character string - * @param str - * @return current object - */ - StaticString operator=(char *str) { - uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, destSize); - m_buffer[destSize] = '\0'; - len = destSize; + /** + * Provides the maximum capacity of string + * + * @return string capacity + */ + uint16_t capacity() { + return tSize; + } - return *this; - } + /** + * Checks if string is empty or not + * + * @return if string is empty or not + */ + bool empty() const { + return length() == 0; + } - /** - * Assign operator assigns current object to given const character string - * @param str - * @return current object - */ - StaticString operator=(const char *str) { - uint16_t destSize = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, destSize); - m_buffer[destSize] = '\0'; - len = destSize; + /** + * Clears the string such that there are no characters left in it + */ + void clear() { + m_buffer[0] = '\0'; + m_len = 0; + } - return *this; - } + /** + * Element access operator gives access to character at @p pos + * + * @param pos the position of the character + * @return character at @p pos + */ + char &operator[](uint16_t pos) { + return at(pos); + } - /** - * Provides current length of string - * - * @return string length - */ - uint16_t length() const { - return len; - } + /** + * Element access operator gives access to character at @p pos. + * Character is constant + * + * @param pos the position of the character + * @return character at @p pos + */ + const char &operator[](uint16_t pos) const { + return at(pos); + } - /** - * Provides the maximum capacity of string - * - * @return string capacity - */ - uint16_t capacity() const { - return tSize; - } + /** + * Provides access to character at @p pos. + * If the @p pos is out of bounds, last element + * is returned + * + * @param pos the position of the character + * @return character at @p pos + */ + char &at(uint16_t pos) { + if (pos >= length()) return back(); + + return m_buffer[pos]; + } - /** - * Checks if string is empty or not - * - * @return if string is empty or not - */ - bool empty() const { - return length() == 0; - } + /** + * Provides access to character at @p pos. If the @p pos + * is out of bounds, last element is returned + * + * @param pos the position of the character + * @return character at @p pos + */ + const char &at(uint16_t pos) const { + if (pos >= length()) return back(); + + return m_buffer[pos]; + } - /** - * Clears the string such that there are no characters left in it - */ - void clear() { - m_buffer[0] = '\0'; - len = 0; - } + /** + * Provides access to the last character in the string + * + * @return the last character + */ + char &back() { + if (empty()) return m_buffer[0]; + return m_buffer[length() - 1]; + } - /** - * Element access operator gives access to character at @code pos - * - * @param pos the position of the character - * @return character at @code position - */ - char &operator[](uint16_t pos) { - return m_buffer[pos]; - } + /** + * Provides access to the last character in the string. Character is constant + * + * @return the last character + */ + const char &back() const { + if (empty()) return m_buffer[0]; + return m_buffer[length() - 1]; + } - /** - * Element access operator gives access to character at @code pos. - * Character is constant - * - * @param pos the position of the character - * @return character at @code position - */ - const char &operator[](uint16_t pos) const { - return m_buffer[pos]; - } + /** + * Provides access to the first character in the string + * + * @return the first character + */ + char &front() { + return m_buffer[0]; + } - /** - * Provides access to character at @code pos - * - * @param pos the position of the character - * @return character at @code position - */ - char &at(uint16_t pos) { - return m_buffer[pos]; - } + /** + * Provides access to the first character in the string. Character is constant + * + * @return the first character + */ + const char &front() const { + return m_buffer[0]; + } - /** - * Provides access to character at @code pos. Character is constant - * - * @param pos the position of the character - * @return character at @code position - */ - const char &at(uint16_t pos) const { - return m_buffer[pos]; - } + /** + * Modifier operator adds @code StaticString @endcode object to the current string. If String cannot + * hold the given object string, it does not add it + * + * @param other @code StaticString @endcode string to add + * @return the current string + */ + StaticString &operator+=(const StaticString &other) { + return append(other); + } - /** - * Provides access to the first character in the string - * - * @return the first character - */ - char &front() { - return m_buffer[0]; - } + /** + * Modifier operator adds char string to the current string. If String cannot + * hold the given string, it does not add it + * + * @param val char string to add + * @return the current string + */ + StaticString &operator+=(const char *val) { + return append(val); + } - /** - * Provides access to the first character in the string. Character is constant - * - * @return the first character - */ - const char &front() const { - return m_buffer[0]; - } + /** + * Modifier operator adds character to the current string. If String cannot + * hold the character, it does not add it + * + * @param c character to add + * @return the current string + */ + StaticString &operator+=(char c) { + return push_back(c); + } - /** - * Provides access to the last character in the string - * - * @return the last character - */ - char &end() { - if (empty()) return m_buffer[0]; + /** + * Appends a @code StaticString @endcode string to the current string. If String cannot + * hold the given string, it does not add it + * + * @param str @code StaticString @endcode string to add + * @return the current string + */ + StaticString &append(const StaticString &str) { + return append(str.c_str()); + } - return m_buffer[length() - 1]; - } + /** + * Appends a character string to the current string. If String cannot + * hold the given character string, it does not add it + * + * @param str character string to add + * @return the current string + */ + StaticString &append(const char *str) { + uint16_t bufferLength = this->length(); + uint16_t otherLength = (uint16_t) strlen(str); - /** - * Provides access to the last character in the string. Character is constant - * - * @return the last character - */ - const char &end() const { - if (empty()) return m_buffer[0]; + for (int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { + m_buffer[i] = str[i - bufferLength]; + } - return m_buffer[length() - 1]; - } + m_len = (uint16_t) ceil(fmin(capacity(), (bufferLength + otherLength))); - /** - * Modifier operator adds character to the current string. If String cannot - * hold the character, it does not add it - * - * @param c character to add - * @return the current string - */ - StaticString &operator+=(char c) { - return append(c); - } + m_buffer[length()] = '\0'; - /** - * Modifier operator adds char string to the current string. If String cannot - * hold the given string, it does not add it - * - * @param val char string to add - * @return the current string - */ - StaticString &operator+=(const char *val) { - return append(val); - } + return *this; + } - /** - * Modifier operator adds @code StaticString object to the current string. If String cannot - * hold the given object string, it does not add it - * - * @param other @code StaticString string to add - * @return the current string - */ - StaticString operator+=(StaticString &other) { - return append(other); - } + /** + * Appends a character to the current string. If String cannot + * hold the given character, it does not add it + * + * @param c character to add + * @return the current string + */ + StaticString &push_back(const char c) { + char str[2] = {c, '\0'}; + return append(str); + } + + /** + * Deletes the element @p pos from the String + * + * @param pos position of the element to be deleted + * @return the modified String + */ + StaticString &erase(uint16_t pos = 0){ + if (length() == 0 || pos >= length()) return *this; + + --m_len; + + for (int i = pos; i < length(); ++i) { + m_buffer[i] = m_buffer[i+1]; + } + + m_buffer[length()] = '\0'; + return *this; + } + + /** + * Deletes the last character in the String + */ + void pop_back(){ + if (length() == 0) return; + + --m_len; + m_buffer[m_len] = '\0'; + } + + /** + * Provides access to character array that string uses behind the screen + * + * @return character array + */ + const char *c_str() const { + return m_buffer; + } + + /** + * Makes substring of the current string. If the @p pos is out + * of bounds, same String is returned. If the length of substring + * is too long, then a substring from @p pos to the end is returned; + * + * @param pos starting position + * @param length length of the new string + * @return new string which is a substring of current string + */ + StaticString substr(uint16_t pos, uint16_t length) const { + if (pos >= this->length()) + return *this; + + if (pos + length >= this->length()) + length = this->length() - pos; + + char newBuffer[length + 1]; + + for (uint16_t i = pos; i < pos + length; i++) { + newBuffer[i - pos] = m_buffer[i]; + } + + newBuffer[length] = '\0'; + + StaticString s{newBuffer}; + + return s; + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str @code StaticString @endcode string to compare against current string + * @return a signed number based on how strings compare + */ + int16_t compare(const StaticString &str) const { + return compare(str.c_str()); + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str character string to compare against current string + * @return a signed number based on how strings compare + */ + int16_t compare(const char *str) const { + return (int16_t) strcmp(this->c_str(), str); + } + + /** + * Compares a string and a char and return 0 if they are equal, less than 0 if + * given char is less than current string and greater than 0 if + * given char is greater than current string + * + * @param c character to compare against current string + * @return a signed number based on how strings compare + */ + int16_t compare(char c) const { + char array[] = {c, '\0'}; + return (int16_t) strcmp(this->c_str(), array); + } + + private: + char m_buffer[tSize + 1]; + uint16_t m_len; + }; /** - * Appends a character to the current string. If String cannot - * hold the given character, it does not add it + * Comparative operator compares if two strings are equal or not * - * @param c character to add - * @return the current string + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs @code StaticString @endcode string as right hand side string + * @return true or false based on if two strings are equal */ - StaticString &append(const char c) { - char array[2] = {c, '\0'}; - return append(array); + template + bool operator==(const StaticString &lhs, const StaticString &rhs) { + return lhs.compare(rhs) == 0; } /** - * Appends a character string to the current string. If String cannot - * hold the given character string, it does not add it + * Comparative operator compares if two strings are equal or not * - * @param str character string to add - * @return the current string + * @tparam tSize size of template string + * @param lhs character string as left hand side string + * @param rhs @code StaticString @endcode string as right hand side string + * @return true or false based on if two strings are equal */ - StaticString &append(const char *str) { - uint16_t bufferLength = this->length(); - uint16_t otherLength = (uint16_t) strlen(str); - - for (int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { - m_buffer[i] = str[i - bufferLength]; - } - - len = (uint16_t) ceil(fmin(capacity(), (bufferLength + otherLength))); - - m_buffer[len] = '\0'; - - return *this; + template + bool operator==(const char *lhs, const StaticString &rhs) { + return rhs.compare(lhs) == 0; } /** - * Appends a @code StaticString string to the current string. If String cannot - * hold the given string, it does not add it + * Comparative operator compares if two strings are equal or not * - * @param str @code StaticString string to add - * @return the current string + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs character string as right hand side string + * @return true or false based on if two strings are equal */ - StaticString &append(const StaticString str) { - return append(str.c_str()); + template + bool operator==(const StaticString &lhs, const char *rhs) { + return lhs.compare(rhs) == 0; } /** - * Appends a character to the current string. If String cannot - * hold the given character, it does not add it + * Comparative operator compares if a strings and a char are equal * - * @param c character to add - * @return the current string + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs a character + * @return true or false based on the string is equal to the character */ - StaticString push_back(const char c) { - ; - return append(c); + template + bool operator==(const StaticString &lhs, const char rhs) { + return lhs.compare(rhs) == 0; } /** - * Appends a character string to the current string. If String cannot - * hold the given character string, it does not add it + * Comparative operator compares if a strings and a char are equal * - * @param str character string to add - * @return the current string + * @tparam tSize size of template string + * @param lhs a Character + * @param rhs @code StaticString @endcode string as right hand side string + * @return true or false based on the string is equal to the character */ - StaticString push_back(const char *str) { - ; - return append(str); + template + bool operator==(const char lhs, const StaticString &rhs) { + return rhs.compare(lhs) == 0; } /** - * Appends a @code StaticString string to the current string. If String cannot - * hold the @code StaticString string, it does not add it + * Additive operator adds two given strings * - * @param str @code StaticString string to add - * @return the current string + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs @code StaticString @endcode string as right hand side string + * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - StaticString push_back(const StaticString &str) { - ; - return append(str); + template + StaticString operator+(const StaticString &lhs, const StaticString &rhs) { + StaticString newStr; + newStr.append(lhs).append(rhs); + return newStr; } - /** - * Provides access to character array that string uses behind the screen + * Additive operator adds two given strings * - * @return character array + * @tparam tSize size of template string + * @param lhs character string as left hand side string + * @param rhs @code StaticString @endcode string as right hand side string + * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - const char *c_str() const { - return m_buffer; + template + StaticString operator+(const char *lhs, const StaticString &rhs) { + StaticString newStr; + newStr.append(lhs).append(rhs); + return newStr; } /** - * Makes substring of the current string + * Additive operator adds two given strings * - * @param pos starting position - * @param length length of the new string - * @return new string which is a substring of current string + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs character string as right hand side string + * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - StaticString substr(uint16_t pos, uint16_t length) const { - char newBuffer[length + 1]; - - for (uint16_t i = pos; i < pos + length; i++) { - newBuffer[i - pos] = m_buffer[i]; - } - - newBuffer[length] = '\0'; - - StaticString s{newBuffer}; - - return s; + template + StaticString operator+(const StaticString &lhs, const char *rhs) { + StaticString newStr; + newStr.append(lhs).append(rhs); + return newStr; } /** - * Compares two strings and return 0 if they are equal, less than 0 if - * given string is less than current string and greater than 0 if - * given string is greater than current string + * Additive operator adds a string with character * - * @param str @code StaticString string to compare against current string - * @return a signed number based on how strings compare + * @tparam tSize size of template string + * @param lhs @code StaticString @endcode string as left hand side string + * @param rhs character + * @return a @code StaticString @endcode that is build from left hind string and right hand character */ - int16_t compare(const StaticString &str) const { - return compare(str.c_str()); + template + StaticString operator+(const StaticString &lhs, const char rhs) { + StaticString newStr; + newStr.append(lhs).push_back(rhs); + return newStr; } /** - * Compares two strings and return 0 if they are equal, less than 0 if - * given string is less than current string and greater than 0 if - * given string is greater than current string + * Additive operator adds a string with character * - * @param str character string to compare against current string - * @return a signed number based on how strings compare + * @tparam tSize size of template string + * @param lhs character + * @param rhs @code StaticString @endcode string as right hand side string + * @return a @code StaticString @endcode that is build from right hind string and left hand character */ - int16_t compare(const char *str) const { - return (int16_t) strcmp(this->c_str(), str); + template + StaticString operator+(const char lhs, const StaticString &rhs) { + StaticString newStr; + newStr.push_back(lhs).append(rhs); + return newStr; } - -}; - -/** - * Comparative operator compares if two strings are equal or not - * - * @tparam tSize size of template string - * @param lhs @code StaticString string as left hand side string - * @param rhs @code StaticString string as right hand side string - * @return true or false based on if two strings are equal - */ -template -bool operator==(const StaticString &lhs, const StaticString &rhs) { - return lhs.compare(rhs) == 0; -} - -/** - * Comparative operator compares if two strings are equal or not - * - * @tparam tSize size of template string - * @param lhs character string as left hand side string - * @param rhs @code StaticString string as right hand side string - * @return true or false based on if two strings are equal - */ -template -bool operator==(const char *lhs, const StaticString &rhs) { - return rhs.compare(lhs) == 0; -} - -/** - * Comparative operator compares if two strings are equal or not - * - * @tparam tSize size of template string - * @param lhs @code StaticString string as left hand side string - * @param rhs character string as right hand side string - * @return true or false based on if two strings are equal - */ -template -bool operator==(const StaticString &lhs, const char *rhs) { - return lhs.compare(rhs) == 0; -} - -/** - * Additive operator adds two given strings - * - * @tparam tSize size of template string - * @param lhs @code StaticString string as left hand side string - * @param rhs @code StaticString string as right hand side string - * @return a @code StaticString that is build from left hind string and right hand string - */ -template -StaticString operator+(const StaticString &lhs, const StaticString &rhs) { - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; } -/** - * Additive operator adds two given strings - * - * @tparam tSize size of template string - * @param lhs character string as left hand side string - * @param rhs @code StaticString string as right hand side string - * @return a @code StaticString that is build from left hind string and right hand string - */ -template -StaticString operator+(const char *lhs, const StaticString &rhs) { - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; -} - -/** - * Additive operator adds two given strings - * - * @tparam tSize size of template string - * @param lhs @code StaticString string as left hand side string - * @param rhs character string as right hand side string - * @return a @code StaticString that is build from left hind string and right hand string - */ -template -StaticString operator+(const StaticString &lhs, const char *rhs) { - StaticString newStr; - newStr.push_back(lhs).push_back(rhs); - return newStr; -} - - #endif //WLIB_STATICSTRING_H diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 6e2c4938..21ff37fe 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -1,21 +1,263 @@ + +/** + * @file static_string_check.cpp + * @brief Unit Testing for StaticString class present in Wlib library + * + * @author Deep Dhillon + * @date November 11, 2017 + * @bug No known bugs + */ + #include "gtest/gtest.h" #include "strings/StaticString.h" -#include "memory/Memory.h" #include "../template_defs.h" -TEST(static_string_tests, constructor_tests){ +using namespace wlp; + +TEST(static_string_test, ctor_test) { StaticString<8> string1{"helloooo"}; // text given StaticString<8> string2; // no text - StaticString<8> string3{string1}; // string object given + StaticString<8> string3{string1}; // string object give + + ASSERT_EQ(8, string1.capacity()); + ASSERT_EQ(8, string2.capacity()); + ASSERT_EQ(8, string3.capacity()); + + ASSERT_EQ(8, string1.length()); + ASSERT_EQ(0, string2.length()); + ASSERT_EQ(8, string3.length()); + + ASSERT_STREQ("helloooo", string1.c_str()); + ASSERT_STREQ("", string2.c_str()); + ASSERT_STREQ("helloooo", string3.c_str()); +} + +TEST(static_string_test, add_operators) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"yo"}; + StaticString<16> string5{"yooooooooooooooo"}; + char char1 = '7'; + char array1[] = "hell"; + char array2[] = "123456789"; + + // object to object addition + ASSERT_STREQ("deepbye", (string1 + string2).c_str()); + ASSERT_STREQ("deepbyeyoooooooo", (string1 + string2 + string5).c_str()); + + // object plus character array addition + ASSERT_STREQ( "hibrooooooo", (string3 + "brooooooo").c_str()); + ASSERT_STREQ("123456789000045b", ("123456789000045" + string2).c_str()); + ASSERT_STREQ("helldeep", (array1 + string1).c_str()); + ASSERT_STREQ("deep123456789hel", (string1 + array2 + array1).c_str()); + + // individual char + ASSERT_STREQ("7deep", (char1 + string1).c_str()); + ASSERT_STREQ("deep77", (string1 + char1 + char1).c_str()); + ASSERT_STREQ(string5.c_str(), (string5 + char1).c_str()); +} + +TEST(static_string_test, concat_operator) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"yo"}; + StaticString<16> string5{"yooooooooooooooo"}; + char char1 = '7'; + char array1[] = "hell"; + char array2[] = "123456789"; + + // object to object append + ASSERT_STREQ("deepbye", (string1 += string2).c_str()); + ASSERT_STREQ("deepbyebyeyo", (string1 += string2 += string4).c_str()); + ASSERT_STREQ(string5.c_str(), (string5 += string1).c_str()); + + // object plus character str + ASSERT_STREQ("hibrooooooooooo", (string3 += "brooooooooooo").c_str()); + ASSERT_STREQ("yo1234567890000", (string4 += "1234567890000").c_str()); + ASSERT_STREQ("byeyohell", (string2 += array1).c_str()); + ASSERT_STREQ(string5.c_str(), (string5 += "hhjsdjhs").c_str()); + + // individual char + ASSERT_STREQ("hibrooooooooooo7", (string3 += char1).c_str()); + ASSERT_STREQ(string3.c_str(), (string3 += 'd').c_str()); +} + +TEST(static_string_test, concat_append_push_back) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"yo"}; + StaticString<16> string5{"yooooooooooooooo"}; + char char1 = '7'; + char array1[] = "hell"; + char array2[] = "123456789"; + + // object to object append + ASSERT_STREQ("deepbye", (string1.append(string2)).c_str()); + ASSERT_STREQ("deepbyebyeyo", (string1.append(string2).append(string4)).c_str()); + ASSERT_STREQ(string5.c_str(), (string5.append(string1)).c_str()); + + // object plus character str + ASSERT_STREQ("hibrooooooooooo", (string3.append("brooooooooooo")).c_str()); + ASSERT_STREQ("yo1234567890000", (string4.append("1234567890000")).c_str()); + ASSERT_STREQ("byehell", (string2.append(array1)).c_str()); + ASSERT_STREQ(string5.c_str(), (string5.append("hhjsdjhs")).c_str()); + + // individual char + ASSERT_STREQ("hibrooooooooooo7", (string3.push_back(char1)).c_str()); + ASSERT_STREQ(string3.c_str(), (string3.push_back('d')).c_str()); +} + +TEST(static_string_test, equal_to_operator) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"y"}; + + ASSERT_FALSE(string1 == string2); + ASSERT_TRUE(string1 == string1); + ASSERT_TRUE(string1 == "deep"); + ASSERT_TRUE(string4 == 'y'); + ASSERT_TRUE("deep" == string1); + ASSERT_TRUE('y' == string4); +} + +TEST(static_string_test, compare_methods) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"y"}; + StaticString<16> string5{"ye"}; - auto *ptr = memory_alloc(75); - ptr = memory_realloc(ptr, 35); - memory_free(ptr); + ASSERT_LT(string1.compare(string4), 0); + ASSERT_GT(string3.compare(string2), 0); + ASSERT_LT(string4.compare(string5), 0); + ASSERT_EQ(string1.compare(string1), 0); + ASSERT_GT(string1.compare("dee"), 0); + ASSERT_GT(string2.compare('a'), 0); +} - string3.empty(); +TEST(static_string_test, access_chars) { + const StaticString<16> string1{"deep"}; + const StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"y"}; + ASSERT_TRUE(string1[0] == 'd'); + ASSERT_TRUE(string1[4] == 'p'); + ASSERT_TRUE(string3[1] == 'i'); + ASSERT_TRUE(string3[3] == 'i'); + ASSERT_TRUE(string2[2] == 'e'); + + ASSERT_TRUE(string1.at(0) == 'd'); + ASSERT_TRUE(string1.at(7) == 'p'); + ASSERT_TRUE(string4.at(6) == 'y'); + ASSERT_FALSE(string3.at(1) == 'd'); + + ASSERT_TRUE(string1.front() == 'd'); + ASSERT_TRUE(string2.front() == 'b'); + ASSERT_TRUE(string3.front() == 'h'); + ASSERT_TRUE(string4.front() == 'y'); + + ASSERT_TRUE(string1.back() == 'p'); + ASSERT_TRUE(string2.back() == 'e'); + ASSERT_TRUE(string3.back() == 'i'); + ASSERT_TRUE(string4.back() == 'y'); +} + +TEST(static_string_test, clear_string) { + StaticString<8> string1{"deep"}; + StaticString<8> string2{"bye"}; + StaticString<8> string3{"hi"}; + StaticString<8> string4{"y"}; + + string1.clear(); string2.clear(); + string3.clear(); + string4.clear(); + + ASSERT_EQ(0, string1.length()); + ASSERT_EQ(0, string2.length()); + ASSERT_EQ(0, string3.length()); + ASSERT_EQ(0, string4.length()); + + ASSERT_EQ(8, string1.capacity()); + ASSERT_EQ(8, string2.capacity()); + ASSERT_EQ(8, string3.capacity()); + ASSERT_EQ(8, string4.capacity()); + + ASSERT_STREQ("", string1.c_str()); + ASSERT_STREQ("", string2.c_str()); + ASSERT_STREQ("", string3.c_str()); + ASSERT_STREQ("", string4.c_str()); +} + +TEST(static_string_test, assign_operator) { + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"y"}; + + string1 = string4; + string2 = "deep2"; + string3 = 'c'; + + ASSERT_STREQ(string4.c_str(), string1.c_str()); + ASSERT_STREQ("deep2", string2.c_str()); + ASSERT_STREQ("c", string3.c_str()); + ASSERT_STRNE("d", string4.c_str()); +} + +TEST(static_string_test, erase_popBack){ + StaticString<16> string1{"deep"}; + StaticString<16> string2{"bye"}; + StaticString<16> string3{"hi"}; + StaticString<16> string4{"y"}; + + string1.erase(2); + ASSERT_EQ(3, string1.length()); + ASSERT_EQ(16, string1.capacity()); + ASSERT_STREQ("dep", string1.c_str()); + + string1.erase(); + ASSERT_EQ(2, string1.length()); + ASSERT_STREQ("ep", string1.c_str()); + + string2.erase(0).erase(1); + ASSERT_EQ(1, string2.length()); + ASSERT_STREQ("y", string2.c_str()); + + string2.erase(5); + ASSERT_EQ(1, string2.length()); + ASSERT_STREQ("y", string2.c_str()); + + string2.erase().erase(); + ASSERT_EQ(0, string2.length()); + ASSERT_STREQ("", string2.c_str()); + + string3.pop_back(); + string4.pop_back(); + ASSERT_EQ(1, string3.length()); + ASSERT_STREQ("h", string3.c_str()); + ASSERT_EQ(0, string4.length()); + ASSERT_STREQ("", string4.c_str()); + + string4.pop_back(); + ASSERT_EQ(0, string4.length()); + ASSERT_STREQ("", string4.c_str()); +} + +TEST(static_string_test, substring) { + StaticString<16> string1{"deep"}; + StaticString<16> string2; - ASSERT_EQ("helloooo", "helloooo"); -} \ No newline at end of file + ASSERT_STREQ("de", string1.substr(0, 2).c_str()); + ASSERT_STREQ("deep", string1.substr(0, 4).c_str()); + ASSERT_STREQ("e", string1.substr(2, 1).c_str()); + ASSERT_STREQ("", string2.substr(0, 5).c_str()); + ASSERT_STREQ("deep", string1.substr(15, 2).c_str()); + ASSERT_STREQ("ep", string1.substr(2, 8).c_str()); +} diff --git a/tests/template_defs.h b/tests/template_defs.h index ffc88b13..641d0dc5 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -5,9 +5,6 @@ #include "stl/ChainMap.h" #include "stl/OpenMap.h" -template class StaticString<8>; -template class StaticString<16>; - namespace wlp { template class Pair; template class ChainHashMap, StaticString<16>>; @@ -63,6 +60,8 @@ namespace wlp { uint16_t, hash, equals>; + template class StaticString<8>; + template class StaticString<16>; } #endif // TEMPLATE_DEFS_H diff --git a/tests/test.cpp b/tests/test.cpp index d213081c..a04e5df2 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -11,7 +11,7 @@ #include -int main(int argc, char* argv[]) { +int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } From 097ea23485db3f51a6963d83ac1692b5a0b90f01 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 12 Nov 2017 14:31:56 -0500 Subject: [PATCH 009/102] [FT] Types (#46) * types added and existing code changed to use these types * more minor changes made * Allocator includes fixed --- lib/wlib/Types.h | 33 ++++++++++ lib/wlib/Wlib.h | 2 +- lib/wlib/memory/Allocator.cpp | 8 ++- lib/wlib/stl/Bitset.h | 35 +++++------ lib/wlib/stl/Equal.h | 5 +- lib/wlib/stl/Hash.h | 5 +- lib/wlib/strings/StaticString.h | 36 +++++------ tests/stl/chain_map_check.cpp | 36 +++++------ tests/stl/equals_check.cpp | 19 +++--- tests/stl/hash_check.cpp | 8 +-- tests/strings/static_string_check.cpp | 91 ++++++++++++++------------- tests/template_defs.h | 2 +- 12 files changed, 156 insertions(+), 124 deletions(-) create mode 100644 lib/wlib/Types.h diff --git a/lib/wlib/Types.h b/lib/wlib/Types.h new file mode 100644 index 00000000..0a67c4bc --- /dev/null +++ b/lib/wlib/Types.h @@ -0,0 +1,33 @@ +/** + * @file Types.h + * @brief type definition of all the types we will be using + * + * @author Deep Dhillon + * @date November 12, 2017 + * @bug No known bug + */ + + +#ifndef EMBEDDEDCPLUSPLUS_TYPES_H +#define EMBEDDEDCPLUSPLUS_TYPES_H + +#include +#include "strings/StaticString.h" + +// size +typedef uint16_t size_type; + +// Static Strings +typedef wlp::StaticString<8> String8; +typedef wlp::StaticString<16> String16; +typedef wlp::StaticString<32> String32; +typedef wlp::StaticString<64> String64; +typedef wlp::StaticString<128> String128; +typedef wlp::StaticString<256> String256; + +/* +// Dynamic String +typedef wlp::DynamicString String; +*/ + +#endif //EMBEDDEDCPLUSPLUS_TYPES_H diff --git a/lib/wlib/Wlib.h b/lib/wlib/Wlib.h index 9349ac70..5bd06d0a 100644 --- a/lib/wlib/Wlib.h +++ b/lib/wlib/Wlib.h @@ -10,6 +10,6 @@ #define MUL_127(x) (((x) << 7) - (x)) #define BYTE_SIZE 8 -#define INT_SIZE (BYTE_SIZE * sizeof(uint32_t)) +#define INT32_SIZE (BYTE_SIZE * sizeof(uint32_t)) #endif //EMBEDDEDTESTS_WLIB_H diff --git a/lib/wlib/memory/Allocator.cpp b/lib/wlib/memory/Allocator.cpp index 547e8a3a..0b9ec2c0 100644 --- a/lib/wlib/memory/Allocator.cpp +++ b/lib/wlib/memory/Allocator.cpp @@ -7,9 +7,11 @@ * @bug No known bugs */ -#include "Allocator.h" -#include "math.h" #include +#include + +#include "../Types.h" +#include "Allocator.h" #include "../Wlib.h" wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator::Type allocationType, void *pPool) : @@ -50,7 +52,7 @@ wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator: // Fill m_pPool with m_poolSize blocks wlp::Allocator::Block *pBlock = m_pPool; - for (uint16_t i = 1; i < m_poolTotalBlockCnt; i++) { + for (size_type i = 1; i < m_poolTotalBlockCnt; i++) { pBlock = pBlock->pNext = (wlp::Allocator::Block *) ((char *) pBlock + m_blockSize); } diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index 4d2928a4..44509e09 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -13,10 +13,9 @@ #ifndef CORE_STL_BITSET_H #define CORE_STL_BITSET_H -#include -#include #include +#include "Types.h" #include "Wlib.h" namespace wlp { @@ -47,7 +46,7 @@ namespace wlp { */ template struct ceil_bits { - static const uint32_t value = (nBits + INT_SIZE - 1) / INT_SIZE; + static const uint32_t value = (nBits + INT32_SIZE - 1) / INT32_SIZE; }; template @@ -76,7 +75,7 @@ namespace wlp { */ Bitset(Bitset &b) { uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { + for (size_type i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; } } @@ -87,7 +86,7 @@ namespace wlp { */ Bitset(const Bitset &b) { uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { + for (size_type i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; } } @@ -99,11 +98,11 @@ namespace wlp { */ void setFromNumber(uint64_t n) { memset(m_array, 0, sizeof(m_array)); - constexpr uint32_t end = nBits / INT_SIZE; - constexpr uint32_t extra = nBits - end * INT_SIZE; - for (uint16_t i = 0; i < end; ++i) { + constexpr uint32_t end = nBits / INT32_SIZE; + constexpr uint32_t extra = nBits - end * INT32_SIZE; + for (size_type i = 0; i < end; ++i) { m_array[i] = (uint32_t) n; - n >>= INT_SIZE; + n >>= INT32_SIZE; } if (extra) { m_array[end] = ((uint32_t) n) & pow_mask::value; @@ -117,7 +116,7 @@ namespace wlp { * @param index the index of the bit */ void set(uint16_t index) { - m_array[index / INT_SIZE] |= (1U << (index % INT_SIZE)); + m_array[index / INT32_SIZE] |= (1U << (index % INT32_SIZE)); } /** @@ -126,7 +125,7 @@ namespace wlp { * @param index the index of the bit */ void reset(uint16_t index) { - m_array[index / INT_SIZE] &= ~(1U << (index % INT_SIZE)); + m_array[index / INT32_SIZE] &= ~(1U << (index % INT32_SIZE)); } /** @@ -135,7 +134,7 @@ namespace wlp { * @param index the index of the bit */ void flip(uint16_t index) { - m_array[index / INT_SIZE] ^= (1U << (index % INT_SIZE)); + m_array[index / INT32_SIZE] ^= (1U << (index % INT32_SIZE)); } /** @@ -145,7 +144,7 @@ namespace wlp { * @return the bit value */ bool test(uint16_t index) const { - return (m_array[index / INT_SIZE] & (1U << (index % INT_SIZE))) != 0; + return (m_array[index / INT32_SIZE] & (1U << (index % INT32_SIZE))) != 0; } /** @@ -157,7 +156,7 @@ namespace wlp { if (nBits <= 32) { return to_uint32_t(); } - return (((uint64_t) m_array[1]) << INT_SIZE) | ((uint32_t) m_array[0]); + return (((uint64_t) m_array[1]) << INT32_SIZE) | ((uint32_t) m_array[0]); } /** @@ -200,9 +199,9 @@ namespace wlp { * Assignment operator copies the contents of the bitset. * @param b Bitset to assign */ - Bitset &operator=(Bitset &b) { + Bitset &operator=(const Bitset &b) { uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { + for (size_type i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; } return *this; @@ -212,9 +211,9 @@ namespace wlp { * Assignment operator copies the contents of the bitset. * @param b Bitset to assign */ - Bitset &operator=(const Bitset &b) { + Bitset &operator=(Bitset &b) { uint32_t end = ceil_bits::value; - for (uint16_t i = 0; i < end; i++) { + for (size_type i = 0; i < end; i++) { m_array[i] = (m_array[i] & 0) | b.m_array[i]; } return *this; diff --git a/lib/wlib/stl/Equal.h b/lib/wlib/stl/Equal.h index 1e716d7d..75f15417 100644 --- a/lib/wlib/stl/Equal.h +++ b/lib/wlib/stl/Equal.h @@ -10,8 +10,7 @@ #ifndef CORE_STL_EQUAL_H #define CORE_STL_EQUAL_H -#include - +#include "Types.h" #include "WlibConfig.h" #include "strings/StaticString.h" @@ -34,7 +33,7 @@ namespace wlp { if (str1.length() != str2.length()) { return false; } - for (uint16_t i = 0; i < str1.length(); ++i) { + for (size_type i = 0; i < str1.length(); ++i) { if (str1[i] != str2[i]) { return false; } diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index 503df3fb..275f9515 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -14,8 +14,7 @@ #ifndef CORE_STL_HASH_H #define CORE_STL_HASH_H -#include - +#include "Types.h" #include "Wlib.h" #include "WlibConfig.h" #include "strings/StaticString.h" @@ -36,7 +35,7 @@ namespace wlp { template inline IntType hash_static_string(StaticString &static_string) { IntType h = 0; - for (uint16_t pos = 0; pos < static_string.length(); ++pos) { + for (size_type pos = 0; pos < static_string.length(); ++pos) { h = MUL_127(h) + static_string[pos]; } return h; diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index d3c857a9..e6e9d843 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -11,9 +11,7 @@ #ifndef WLIB_STATICSTRING_H #define WLIB_STATICSTRING_H -#include #include -#include namespace wlp { template @@ -64,8 +62,8 @@ namespace wlp { */ StaticString &operator=(const char *str) { m_len = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); - strncpy(m_buffer, str, length()); - m_buffer[length()] = '\0'; + strncpy(m_buffer, str, m_len); + m_buffer[m_len] = '\0'; return *this; } @@ -105,7 +103,7 @@ namespace wlp { * @return if string is empty or not */ bool empty() const { - return length() == 0; + return m_len == 0; } /** @@ -146,7 +144,7 @@ namespace wlp { * @return character at @p pos */ char &at(uint16_t pos) { - if (pos >= length()) return back(); + if (pos >= m_len) return back(); return m_buffer[pos]; } @@ -159,7 +157,7 @@ namespace wlp { * @return character at @p pos */ const char &at(uint16_t pos) const { - if (pos >= length()) return back(); + if (pos >= m_len) return back(); return m_buffer[pos]; } @@ -171,7 +169,7 @@ namespace wlp { */ char &back() { if (empty()) return m_buffer[0]; - return m_buffer[length() - 1]; + return m_buffer[m_len - 1]; } /** @@ -181,7 +179,7 @@ namespace wlp { */ const char &back() const { if (empty()) return m_buffer[0]; - return m_buffer[length() - 1]; + return m_buffer[m_len - 1]; } /** @@ -254,16 +252,16 @@ namespace wlp { * @return the current string */ StaticString &append(const char *str) { - uint16_t bufferLength = this->length(); + uint16_t bufferLength = m_len; uint16_t otherLength = (uint16_t) strlen(str); - for (int i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { + for (uint16_t i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { m_buffer[i] = str[i - bufferLength]; } m_len = (uint16_t) ceil(fmin(capacity(), (bufferLength + otherLength))); - m_buffer[length()] = '\0'; + m_buffer[m_len] = '\0'; return *this; } @@ -287,15 +285,15 @@ namespace wlp { * @return the modified String */ StaticString &erase(uint16_t pos = 0){ - if (length() == 0 || pos >= length()) return *this; + if (m_len == 0 || pos >= m_len) return *this; --m_len; - for (int i = pos; i < length(); ++i) { + for (uint16_t i = pos; i < m_len; ++i) { m_buffer[i] = m_buffer[i+1]; } - m_buffer[length()] = '\0'; + m_buffer[m_len] = '\0'; return *this; } @@ -303,7 +301,7 @@ namespace wlp { * Deletes the last character in the String */ void pop_back(){ - if (length() == 0) return; + if (m_len == 0) return; --m_len; m_buffer[m_len] = '\0'; @@ -328,11 +326,11 @@ namespace wlp { * @return new string which is a substring of current string */ StaticString substr(uint16_t pos, uint16_t length) const { - if (pos >= this->length()) + if (pos >= m_len) return *this; - if (pos + length >= this->length()) - length = this->length() - pos; + if (pos + length >= m_len) + length = m_len - pos; char newBuffer[length + 1]; diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp index 97c614e9..a676b342 100644 --- a/tests/stl/chain_map_check.cpp +++ b/tests/stl/chain_map_check.cpp @@ -1,13 +1,13 @@ #include "gtest/gtest.h" #include "stl/ChainMap.h" +#include "Types.h" #include "../template_defs.h" using namespace wlp; -typedef StaticString<16> string16; typedef uint16_t ui16; -typedef ChainHashMap string_map; +typedef ChainHashMap string_map; typedef ChainHashMap int_map; typedef int_map::iterator imi; typedef Pair P_imi_b; @@ -23,8 +23,8 @@ TEST(chain_map_test, test_chain_map_node) { ASSERT_EQ(node, *it.m_current); ASSERT_EQ(nullptr, it.m_hash_map); string_map::map_node snode; - snode.m_key = string16{"hello"}; - snode.m_val = string16{"hello"}; + snode.m_key = String16{"hello"}; + snode.m_val = String16{"hello"}; smi sit(&snode, nullptr); ASSERT_EQ(5, sit->length()); ASSERT_EQ(16, sit->capacity()); @@ -32,12 +32,12 @@ TEST(chain_map_test, test_chain_map_node) { TEST(chain_map_test, test_const_iterator) { string_map map(10, 100); - string16 key1{"key1"}; - string16 key2{"key2"}; - string16 key3{"key3"}; - string16 val1{"val1"}; - string16 val2{"val2"}; - string16 val3{"val3"}; + String16 key1{"key1"}; + String16 key2{"key2"}; + String16 key3{"key3"}; + String16 val1{"val1"}; + String16 val2{"val2"}; + String16 val3{"val3"}; map[key1] = val1; map[key2] = val2; map[key3] = val3; @@ -271,11 +271,11 @@ TEST(chain_map_test, test_insert_at_iterator_collision_resolution) { TEST(chain_map_test, test_insert_or_assign) { string_map map(15, 255); - string16 a1{"key1"}; - string16 a2{"key2"}; - string16 v1{"value1"}; - string16 v2{"value2"}; - string16 v3{"value3"}; + String16 a1{"key1"}; + String16 a2{"key2"}; + String16 v1{"value1"}; + String16 v2{"value2"}; + String16 v3{"value3"}; P_smi_b r1 = map.insert_or_assign(a1, v1); P_smi_b r2 = map.insert_or_assign(a2, v2); ASSERT_EQ(2, map.size()); @@ -292,15 +292,15 @@ TEST(chain_map_test, test_insert_or_assign) { TEST(chain_map_test, test_erase_key_nothing) { string_map map(15, 255); - string16 a{"key"}; + String16 a{"key"}; ASSERT_FALSE(map.erase(a)); ASSERT_EQ(0, map.size()); } TEST(chain_map_test, test_erase_key) { string_map map(15, 255); - string16 a{"key"}; - string16 b{"val"}; + String16 a{"key"}; + String16 b{"val"}; map.insert(a, b); ASSERT_EQ(1, map.size()); ASSERT_TRUE(map.erase(a)); diff --git a/tests/stl/equals_check.cpp b/tests/stl/equals_check.cpp index d8b29819..a95d2917 100644 --- a/tests/stl/equals_check.cpp +++ b/tests/stl/equals_check.cpp @@ -2,6 +2,7 @@ #include "strings/StaticString.h" #include "stl/Equal.h" +#include "Types.h" #include "../template_defs.h" using namespace wlp; @@ -20,20 +21,20 @@ TEST(equals_test, test_string_equals) { } TEST(equals_test, test_static_string_equals) { - equals> comparator = equals>(); - StaticString<8> str1{"darwin"}; - StaticString<8> str2{"darwin"}; - StaticString<8> str3{"money__\""}; - StaticString<8> str4{"money__\""}; + equals comparator = equals(); + String8 str1{"darwin"}; + String8 str2{"darwin"}; + String8 str3{"money__\""}; + String8 str4{"money__\""}; ASSERT_TRUE(comparator(str1, str2)); ASSERT_TRUE(comparator(str3, str4)); } TEST(equals_test, test_static_string_unequal) { - equals> comparator = equals>(); - StaticString<8> str1{"darwin"}; - StaticString<8> str2{"money__\""}; - StaticString<8> str3{"houses"}; + equals comparator = equals(); + String8 str1{"darwin"}; + String8 str2{"money__\""}; + String8 str3{"houses"}; ASSERT_FALSE(comparator(str1, str2)); ASSERT_FALSE(comparator(str2, str3)); } diff --git a/tests/stl/hash_check.cpp b/tests/stl/hash_check.cpp index 24ef2bf6..f29e4d53 100644 --- a/tests/stl/hash_check.cpp +++ b/tests/stl/hash_check.cpp @@ -7,10 +7,10 @@ using namespace wlp; TEST(hash_test, test_hash_static_string) { - hash, uint16_t> hasher = hash, uint16_t>(); - StaticString<8> str1{"darwin"}; - StaticString<8> str2{"darwin"}; - StaticString<8> str3{"hello"}; + hash hasher = hash(); + String8 str1{"darwin"}; + String8 str2{"darwin"}; + String8 str3{"hello"}; ASSERT_EQ(hasher(str1), hasher(str2)); ASSERT_NE(hasher(str1), hasher(str3)); ASSERT_NE(hasher(str2), hasher(str3)); diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 21ff37fe..b375f783 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -11,14 +11,15 @@ #include "gtest/gtest.h" #include "strings/StaticString.h" +#include "Types.h" #include "../template_defs.h" using namespace wlp; TEST(static_string_test, ctor_test) { - StaticString<8> string1{"helloooo"}; // text given - StaticString<8> string2; // no text - StaticString<8> string3{string1}; // string object give + String8 string1{"helloooo"}; // text given + String8 string2; // no text + String8 string3{string1}; // string object give ASSERT_EQ(8, string1.capacity()); ASSERT_EQ(8, string2.capacity()); @@ -34,11 +35,11 @@ TEST(static_string_test, ctor_test) { } TEST(static_string_test, add_operators) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"yo"}; - StaticString<16> string5{"yooooooooooooooo"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"yo"}; + String16 string5{"yooooooooooooooo"}; char char1 = '7'; char array1[] = "hell"; char array2[] = "123456789"; @@ -60,11 +61,11 @@ TEST(static_string_test, add_operators) { } TEST(static_string_test, concat_operator) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"yo"}; - StaticString<16> string5{"yooooooooooooooo"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"yo"}; + String16 string5{"yooooooooooooooo"}; char char1 = '7'; char array1[] = "hell"; char array2[] = "123456789"; @@ -86,11 +87,11 @@ TEST(static_string_test, concat_operator) { } TEST(static_string_test, concat_append_push_back) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"yo"}; - StaticString<16> string5{"yooooooooooooooo"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"yo"}; + String16 string5{"yooooooooooooooo"}; char char1 = '7'; char array1[] = "hell"; char array2[] = "123456789"; @@ -112,10 +113,10 @@ TEST(static_string_test, concat_append_push_back) { } TEST(static_string_test, equal_to_operator) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"y"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"y"}; ASSERT_FALSE(string1 == string2); ASSERT_TRUE(string1 == string1); @@ -126,11 +127,11 @@ TEST(static_string_test, equal_to_operator) { } TEST(static_string_test, compare_methods) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"y"}; - StaticString<16> string5{"ye"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"y"}; + String16 string5{"ye"}; ASSERT_LT(string1.compare(string4), 0); ASSERT_GT(string3.compare(string2), 0); @@ -141,10 +142,10 @@ TEST(static_string_test, compare_methods) { } TEST(static_string_test, access_chars) { - const StaticString<16> string1{"deep"}; - const StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"y"}; + const String16 string1{"deep"}; + const String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"y"}; ASSERT_TRUE(string1[0] == 'd'); ASSERT_TRUE(string1[4] == 'p'); @@ -169,10 +170,10 @@ TEST(static_string_test, access_chars) { } TEST(static_string_test, clear_string) { - StaticString<8> string1{"deep"}; - StaticString<8> string2{"bye"}; - StaticString<8> string3{"hi"}; - StaticString<8> string4{"y"}; + String8 string1{"deep"}; + String8 string2{"bye"}; + String8 string3{"hi"}; + String8 string4{"y"}; string1.clear(); string2.clear(); @@ -196,10 +197,10 @@ TEST(static_string_test, clear_string) { } TEST(static_string_test, assign_operator) { - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"y"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"y"}; string1 = string4; string2 = "deep2"; @@ -212,10 +213,10 @@ TEST(static_string_test, assign_operator) { } TEST(static_string_test, erase_popBack){ - StaticString<16> string1{"deep"}; - StaticString<16> string2{"bye"}; - StaticString<16> string3{"hi"}; - StaticString<16> string4{"y"}; + String16 string1{"deep"}; + String16 string2{"bye"}; + String16 string3{"hi"}; + String16 string4{"y"}; string1.erase(2); ASSERT_EQ(3, string1.length()); @@ -251,8 +252,8 @@ TEST(static_string_test, erase_popBack){ } TEST(static_string_test, substring) { - StaticString<16> string1{"deep"}; - StaticString<16> string2; + String16 string1{"deep"}; + String16 string2; ASSERT_STREQ("de", string1.substr(0, 2).c_str()); ASSERT_STREQ("deep", string1.substr(0, 4).c_str()); diff --git a/tests/template_defs.h b/tests/template_defs.h index 641d0dc5..b7b09b84 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -1,7 +1,7 @@ #ifndef TEMPLATE_DEFS_H #define TEMPLATE_DEFS_H -#include +#include "Types.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" From 39d78138ff0a5c62311b5efad8e8ce79854e20dc Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 12 Nov 2017 15:01:13 -0500 Subject: [PATCH 010/102] [HF] Fix warnings (#47) * few changes made to fix Wconversion warnings --- lib/wlib/stl/Hash.h | 4 ++-- lib/wlib/strings/StaticString.h | 4 ++-- tests/stl/bitset_check.cpp | 10 +++++----- tests/stl/open_map_check.cpp | 4 ++-- tests/strings/static_string_check.cpp | 10 ++++------ 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index 275f9515..d877c637 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -36,7 +36,7 @@ namespace wlp { inline IntType hash_static_string(StaticString &static_string) { IntType h = 0; for (size_type pos = 0; pos < static_string.length(); ++pos) { - h = MUL_127(h) + static_string[pos]; + h = (IntType) (MUL_127(h) + static_string[pos]); } return h; }; @@ -45,7 +45,7 @@ namespace wlp { inline IntType hash_string(const char *s) { IntType h = 0; for (; *s; ++s) { - h = MUL_127(h) + *s; + h = (IntType) (MUL_127(h) + *s); } return h; } diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index e6e9d843..d2bed25b 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -330,7 +330,7 @@ namespace wlp { return *this; if (pos + length >= m_len) - length = m_len - pos; + length = (uint16_t) (m_len - pos); char newBuffer[length + 1]; @@ -528,4 +528,4 @@ namespace wlp { } } -#endif //WLIB_STATICSTRING_H +#endif //WLIB_STATICSTRING_H \ No newline at end of file diff --git a/tests/stl/bitset_check.cpp b/tests/stl/bitset_check.cpp index 92102e39..b5164710 100644 --- a/tests/stl/bitset_check.cpp +++ b/tests/stl/bitset_check.cpp @@ -22,7 +22,7 @@ using namespace wlp; typedef uint16_t ui16; TEST(bitset_test, test_constructor_64) { - uint64_t n = 17316249074701521315; + uint64_t n = 17316249074701521315u; bool expected[] = { 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, @@ -40,7 +40,7 @@ TEST(bitset_test, test_constructor_64) { } TEST(bitset_test, test_constructor_underflow) { - uint64_t n = 17316249074701521315; + uint64_t n = 17316249074701521315u; bool expected[] = { 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, @@ -58,7 +58,7 @@ TEST(bitset_test, test_constructor_underflow) { } TEST(bitset_test, test_constructor_overflow) { - uint64_t n = 17316249074701521315; + uint64_t n = 17316249074701521315u; bool expected[] = { 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 @@ -112,8 +112,8 @@ TEST(bitset_test, test_set_reset_flip_get) { } TEST(bitset_test, test_copy_constructors) { - Bitset<42> source1(17316249074701521315); - Bitset<42> source2(6426756347354645451); + Bitset<42> source1(17316249074701521315u); + Bitset<42> source2(6426756347354645451u); const Bitset<42> copy1_1 = source1; const Bitset<42> copy1_2 = copy1_1; ASSERT_EQ(source1.to_uint64_t(), copy1_1.to_uint64_t()); diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp index 9d638eb5..51358a98 100644 --- a/tests/stl/open_map_check.cpp +++ b/tests/stl/open_map_check.cpp @@ -287,8 +287,8 @@ TEST(open_map_test, test_rehash) { map[226] = 2216; map[337] = 2317; map[448] = 2418; - int keys[] = {0, 1, 2, 3, 4, 115, 226, 337, 448}; - int values[] = {0, 10, 20, 30, 40, 2115, 2216, 2317, 2418}; + uint16_t keys[] = {0, 1, 2, 3, 4, 115, 226, 337, 448}; + uint16_t values[] = {0, 10, 20, 30, 40, 2115, 2216, 2317, 2418}; for (uint16_t i = 0; i < 9; i++) { ASSERT_TRUE(map.contains(keys[i])); ASSERT_EQ(*map.find(keys[i]), values[i]); diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index b375f783..678e13d2 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -67,8 +67,7 @@ TEST(static_string_test, concat_operator) { String16 string4{"yo"}; String16 string5{"yooooooooooooooo"}; char char1 = '7'; - char array1[] = "hell"; - char array2[] = "123456789"; + char array[] = "hell"; // object to object append ASSERT_STREQ("deepbye", (string1 += string2).c_str()); @@ -78,7 +77,7 @@ TEST(static_string_test, concat_operator) { // object plus character str ASSERT_STREQ("hibrooooooooooo", (string3 += "brooooooooooo").c_str()); ASSERT_STREQ("yo1234567890000", (string4 += "1234567890000").c_str()); - ASSERT_STREQ("byeyohell", (string2 += array1).c_str()); + ASSERT_STREQ("byeyohell", (string2 += array).c_str()); ASSERT_STREQ(string5.c_str(), (string5 += "hhjsdjhs").c_str()); // individual char @@ -93,8 +92,7 @@ TEST(static_string_test, concat_append_push_back) { String16 string4{"yo"}; String16 string5{"yooooooooooooooo"}; char char1 = '7'; - char array1[] = "hell"; - char array2[] = "123456789"; + char array[] = "hell"; // object to object append ASSERT_STREQ("deepbye", (string1.append(string2)).c_str()); @@ -104,7 +102,7 @@ TEST(static_string_test, concat_append_push_back) { // object plus character str ASSERT_STREQ("hibrooooooooooo", (string3.append("brooooooooooo")).c_str()); ASSERT_STREQ("yo1234567890000", (string4.append("1234567890000")).c_str()); - ASSERT_STREQ("byehell", (string2.append(array1)).c_str()); + ASSERT_STREQ("byehell", (string2.append(array)).c_str()); ASSERT_STREQ(string5.c_str(), (string5.append("hhjsdjhs")).c_str()); // individual char From 3496859c9c6de4a2ba0ca814c53c90e556aa9ba3 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Tue, 14 Nov 2017 05:24:10 -0800 Subject: [PATCH 011/102] [HF] Namespaced typedefs in Types.h (#52) --- lib/wlib/Types.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/wlib/Types.h b/lib/wlib/Types.h index 0a67c4bc..ea9991f5 100644 --- a/lib/wlib/Types.h +++ b/lib/wlib/Types.h @@ -14,20 +14,24 @@ #include #include "strings/StaticString.h" -// size -typedef uint16_t size_type; - -// Static Strings -typedef wlp::StaticString<8> String8; -typedef wlp::StaticString<16> String16; -typedef wlp::StaticString<32> String32; -typedef wlp::StaticString<64> String64; -typedef wlp::StaticString<128> String128; -typedef wlp::StaticString<256> String256; - -/* -// Dynamic String -typedef wlp::DynamicString String; -*/ +namespace wlp { + + // size + typedef uint16_t size_type; + + // Static Strings + typedef StaticString<8> String8; + typedef StaticString<16> String16; + typedef StaticString<32> String32; + typedef StaticString<64> String64; + typedef StaticString<128> String128; + typedef StaticString<256> String256; + + /* + // Dynamic String + typedef wlp::DynamicString String; + */ + +} #endif //EMBEDDEDCPLUSPLUS_TYPES_H From 892341ee44baf11e681cf283c3d1d5b40359a2aa Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Tue, 14 Nov 2017 05:27:12 -0800 Subject: [PATCH 012/102] [Lib] A lotta stuff (#48) * Created tuple * Tuple concatenation * Finished tuples * Basic comparator type * array based list and heap * Concept checks * Concept check for random access iterator * added new concepts * map concept * refractored includes a bit * more unit tests * Namespaced typedefs in Types.h * changed uint16_t typedefs --- examples/main.cpp | 2 +- lib/wlib/CMakeLists.txt | 16 +- lib/wlib/Wlib.h | 10 + lib/wlib/memory/Allocator.cpp | 64 +- lib/wlib/memory/Allocator.h | 14 +- lib/wlib/memory/StaticAllocatorPool.h | 4 +- lib/wlib/stl/ArrayHeap.h | 649 ++++++++++++++ lib/wlib/stl/ArrayList.h | 1136 +++++++++++++++++++++++++ lib/wlib/stl/ChainMap.h | 594 ++++++------- lib/wlib/stl/ChainSet.h | 63 +- lib/wlib/stl/Comparator.h | 169 ++++ lib/wlib/stl/Concept.h | 333 ++++++++ lib/wlib/stl/Equal.h | 25 +- lib/wlib/stl/Hash.h | 45 +- lib/wlib/stl/OpenMap.h | 590 +++++++------ lib/wlib/stl/OpenSet.h | 89 +- lib/wlib/stl/Pair.h | 55 +- lib/wlib/stl/Tmp.h | 714 ++++++++++++++++ lib/wlib/stl/Tuple.h | 742 ++++++++++++++++ lib/wlib/stl/TypeTraits.h | 68 ++ lib/wlib/stl/Utility.h | 52 ++ lib/wlib/strings/StaticString.h | 1 + tests/CMakeLists.txt | 5 +- tests/stl/chain_map_check.cpp | 734 ++++++++-------- tests/stl/comparator_check.cpp | 112 +++ tests/stl/concept_check.cpp | 85 ++ tests/stl/equals_check.cpp | 56 +- tests/stl/hash_check.cpp | 36 +- tests/stl/heap_check.cpp | 160 ++++ tests/stl/list_check.cpp | 441 ++++++++++ tests/stl/open_map_check.cpp | 503 ++++++----- tests/stl/pair_check.cpp | 36 +- tests/stl/tuple_check.cpp | 142 ++++ tests/strings/static_string_check.cpp | 3 - tests/template_defs.h | 193 +++-- wmake | 11 + 36 files changed, 6546 insertions(+), 1406 deletions(-) create mode 100644 lib/wlib/stl/ArrayHeap.h create mode 100644 lib/wlib/stl/ArrayList.h create mode 100644 lib/wlib/stl/Comparator.h create mode 100644 lib/wlib/stl/Concept.h create mode 100644 lib/wlib/stl/Tmp.h create mode 100644 lib/wlib/stl/Tuple.h create mode 100644 lib/wlib/stl/TypeTraits.h create mode 100644 lib/wlib/stl/Utility.h create mode 100644 tests/stl/comparator_check.cpp create mode 100644 tests/stl/concept_check.cpp create mode 100644 tests/stl/heap_check.cpp create mode 100644 tests/stl/list_check.cpp create mode 100644 tests/stl/tuple_check.cpp diff --git a/examples/main.cpp b/examples/main.cpp index 4f65d2b8..375c6c8f 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -10,5 +10,5 @@ * @bug No known bugs */ -int main(){ +int main() { } \ No newline at end of file diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index 798f6c85..dcf8709e 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,15 +1,15 @@ project(wlib) -file (GLOB header_files - "*.h" - "strings/*.h" - "stl/*.h" - "memory/*.h") +file(GLOB header_files + "*.h" + "strings/*.h" + "stl/*.h" + "memory/*.h") -file (GLOB source_files - "memory/*.cpp") +file(GLOB source_files + "memory/*.cpp") -set(HEADER_FILES ${header_files} ) +set(HEADER_FILES ${header_files}) set(SOURCE_FILES ${source_files}) add_library(wlib STATIC ${SOURCE_FILES} ${HEADER_FILES}) diff --git a/lib/wlib/Wlib.h b/lib/wlib/Wlib.h index 5bd06d0a..b33a3d97 100644 --- a/lib/wlib/Wlib.h +++ b/lib/wlib/Wlib.h @@ -9,7 +9,17 @@ #define MUL_31(x) (((x) << 5) - (x)) #define MUL_127(x) (((x) << 7) - (x)) +// Constants for standard sizes #define BYTE_SIZE 8 #define INT32_SIZE (BYTE_SIZE * sizeof(uint32_t)) +// Variadic macro argument helpers +#define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N()) +#define __NARG_I_(...) __ARG_N(__VA_ARGS__) +#define __ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N +#define __RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 +#define _VFUNC_(name, n) name##n +#define _VFUNC(name, n) _VFUNC_(name, n) +#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__) + #endif //EMBEDDEDTESTS_WLIB_H diff --git a/lib/wlib/memory/Allocator.cpp b/lib/wlib/memory/Allocator.cpp index 0b9ec2c0..b53d83a4 100644 --- a/lib/wlib/memory/Allocator.cpp +++ b/lib/wlib/memory/Allocator.cpp @@ -10,9 +10,12 @@ #include #include -#include "../Types.h" #include "Allocator.h" -#include "../Wlib.h" + +#include "../Types.h" + +#include "../stl/Utility.h" + wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator::Type allocationType, void *pPool) : m_poolType{allocationType}, @@ -61,6 +64,63 @@ wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator: } } +wlp::Allocator::Allocator(Allocator &&allocator) + : m_poolType(move(allocator.m_poolType)), + m_blockSize(move(allocator.m_blockSize)), + m_poolSize(move(allocator.m_poolSize)), + m_pHead(move(allocator.m_pHead)), + m_pPool(move(allocator.m_pPool)), + m_poolTotalBlockCnt(move(allocator.m_poolTotalBlockCnt)), + m_poolCurrBlockCnt(move(allocator.m_poolCurrBlockCnt)), + m_totalBlockCount(move(allocator.m_totalBlockCount)), + m_allocations(move(allocator.m_allocations)), + m_deallocations(move(allocator.m_deallocations)) { + allocator.m_pHead = nullptr; + allocator.m_pPool = nullptr; + allocator.m_allocations = 0; + allocator.m_deallocations = 0; + allocator.m_totalBlockCount = 0; + allocator.m_poolCurrBlockCnt = 0; + allocator.m_poolTotalBlockCnt = 0; +} + +wlp::Allocator &wlp::Allocator::operator=(Allocator &&allocator) { + if (m_totalBlockCount > m_poolTotalBlockCnt) { + wlp::Allocator::Block *pBlock = nullptr; + while (m_pHead) { + pBlock = m_pHead; + if (pBlock) { + m_pHead = m_pHead->pNext; + if (!IsPoolBlock(pBlock)) { + delete[] (char *) pBlock; + --m_totalBlockCount; + } + } + } + } + if (m_poolType != Type::STATIC && m_pPool) { + delete[] (char *) m_pPool; + } + m_poolType = move(allocator.m_poolType); + m_blockSize = move(allocator.m_blockSize); + m_poolSize = move(allocator.m_poolSize); + m_pHead = move(allocator.m_pHead); + m_pPool = move(allocator.m_pPool); + m_poolTotalBlockCnt = move(allocator.m_poolTotalBlockCnt); + m_poolCurrBlockCnt = move(allocator.m_poolCurrBlockCnt); + m_totalBlockCount = move(allocator.m_totalBlockCount); + m_allocations = move(allocator.m_allocations); + m_deallocations = move(allocator.m_deallocations); + allocator.m_pHead = nullptr; + allocator.m_pPool = nullptr; + allocator.m_allocations = 0; + allocator.m_deallocations = 0; + allocator.m_totalBlockCount = 0; + allocator.m_poolCurrBlockCnt = 0; + allocator.m_poolTotalBlockCnt = 0; + return *this; +} + wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize) : wlp::Allocator(blockSize, poolSize, DYNAMIC, nullptr) {} diff --git a/lib/wlib/memory/Allocator.h b/lib/wlib/memory/Allocator.h index 2f38eeef..d653ec59 100644 --- a/lib/wlib/memory/Allocator.h +++ b/lib/wlib/memory/Allocator.h @@ -18,6 +18,8 @@ #include #include +#include "../Wlib.h" + namespace wlp { class Allocator { private: @@ -37,6 +39,10 @@ namespace wlp { DYNAMIC /**< this is Heap memory */ }; + Allocator(const Allocator &) = delete; + + Allocator(Allocator &&allocator); + /** * Allocator used for allocating memory where memory is acquired by the allocator. It supports a pool * where pool is created a beginning and then used throughout. If more memory is needed than there is @@ -104,7 +110,7 @@ namespace wlp { * @param pBlockVoid memory block address being verified * @return true or false based on if the given block belongs to memory pool */ - inline bool IsPoolBlock(void *pBlockVoid) { + inline bool IsPoolBlock(void *pBlockVoid) const { auto *pBlock = (Block *) pBlockVoid; if (!m_pPool)return false; @@ -175,6 +181,10 @@ namespace wlp { return m_deallocations; } + Allocator &operator=(const Allocator &) = delete; + + Allocator &operator=(Allocator &&allocator); + private: /** * Private constructor creates Allocator based on the calls made by other constructor. For more @@ -188,7 +198,7 @@ namespace wlp { explicit Allocator(uint16_t blockSize, uint16_t poolSize, Allocator::Type allocationType, void *pPool); - const Type m_poolType; + Type m_poolType; size_t m_blockSize; Block *m_pHead; Block *m_pPool; diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index 705ffcec..1606941c 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -1,10 +1,10 @@ /** * @file StaticAllocatorPool.h * @brief Template class to create static memory pools - * + * * This class is a generalization of the @code Allocator @endcode class and can be used for * convenience - * + * * @author Deep Dhillon * @date November 11, 2017 * @bug No known bugs diff --git a/lib/wlib/stl/ArrayHeap.h b/lib/wlib/stl/ArrayHeap.h new file mode 100644 index 00000000..d4bb4211 --- /dev/null +++ b/lib/wlib/stl/ArrayHeap.h @@ -0,0 +1,649 @@ +/** + * @file ArrayHeap.h + * @brief Heap manipulation and implementation. + * + * This file contains generic heap manipulation functions + * for data structures that supply a @code RandomAccessIterator @endcode + * and a general @code ArrayHeap @endcode implementation using + * @code ArrayList @endcode. + * + * @author Jeff Niu + * @date November 9, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_ARRAYHEAP_H +#define EMBEDDEDCPLUSPLUS_ARRAYHEAP_H + +#include "ArrayList.h" +#include "Comparator.h" +#include "Concept.h" +#include "TypeTraits.h" +#include "Utility.h" + +namespace wlp { + + /** + * Push heap helper function. Takes a value located + * at @code hole_index @endcode and inserts into the + * heap, preserving heap property. This version uses + * a supplied comparator. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type + * @tparam ValType the type of the inserted value + * @tparam Cmp a comparator type + * @param first iterator to the first element in the backing structure + * @param hole_index the index of the inserted element + * @param top_index the index of the first element in the heap + * @param value the value to insert + * @param cmp the comparator use for @code __lt__ @endcode + */ + template< + typename RandomAccessIterator, + typename SizeType, + typename ValType, + typename Cmp + > + void __push_heap( + RandomAccessIterator first, + SizeType hole_index, + SizeType top_index, + ValType value, + Cmp cmp + ) { + SizeType parent = static_cast((hole_index - 1) / 2); + while (hole_index > top_index && cmp.__lt__(*(first + parent), value)) { + *(first + hole_index) = *(first + parent); + hole_index = parent; + parent = static_cast((hole_index - 1) / 2); + } + *(first + hole_index) = value; + }; + + /** + * Push heap helper function. Takes a value located + * at @code hole_index @endcode and inserts into the + * heap, preserving heap property. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type + * @tparam ValType the type of the inserted value + * @param first iterator to the first element in the backing structure + * @param hole_index the index of the inserted element + * @param top_index the index of the first element in the heap + * @param value the value to insert + */ + template< + typename RandomAccessIterator, + typename SizeType, + typename ValType + > + void __push_heap( + RandomAccessIterator first, + SizeType hole_index, + SizeType top_index, + ValType value + ) { + SizeType parent = static_cast((hole_index - 1) / 2); + while (hole_index > top_index && *(first + parent) < value) { + *(first + hole_index) = *(first + parent); + hole_index = parent; + parent = static_cast((hole_index - 1) / 2); + } + *(first + hole_index) = value; + }; + + /** + * Insert a value located at the end of an array-type + * data structure into a heap structure at @code [first, last) @endcode. + * This function assumes the aforementioned range is already a heap. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam Cmp comparator type + * @tparam SizeType integer size type, acquired from the iterator type + * @tparam ValType type of the inserted value, acquired from the iterator type + * @param first iterator to the first element in the backing array + * @param last iterator to the element to be inserted + * @param cmp comparator to use + */ + template< + typename RandomAccessIterator, + typename Cmp, + typename SizeType = typename obtain_size_type::type, + typename ValType = typename obtain_val_type::type, + typename = typename enable_if< + is_random_access_iterator() && + is_comparator() + >::type + > + void push_heap( + RandomAccessIterator first, + RandomAccessIterator last, + Cmp cmp + ) { + __push_heap(first, static_cast(last - first - 1), (SizeType) 0, ValType(*(last - 1)), cmp); + } + + /** + * Insert a value located at the end of an array-type + * data structure into a heap structure at @code [first, last) @endcode. + * This function assumes the aforementioned range is already a heap. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type, acquired from the iterator type + * @tparam ValType type of the inserted value, acquired from the iterator type + * @param first iterator to the first element in the backing array + * @param last iterator to the element to be inserted + */ + template< + typename RandomAccessIterator, + typename = typename enable_if< + is_random_access_iterator() + >::type, + typename SizeType = typename obtain_size_type::type, + typename ValType = typename obtain_val_type::type + > + void push_heap( + RandomAccessIterator first, + RandomAccessIterator last + ) { + __push_heap(first, static_cast(last - first - 1), (SizeType) 0, ValType(*(last - 1))); + } + + /** + * Helper function performs heapify at the specified index. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type + * @tparam ValType value type for insertion + * @tparam Cmp comparator type + * @param first iterator to first element in the random access structure + * @param hole_index index of the value to be heapified + * @param length length of the heap section of the structure + * @param value value to heapify + * @param cmp comparator to use + */ + template< + typename RandomAccessIterator, + typename SizeType, + typename ValType, + typename Cmp + > + void __adjust_heap( + RandomAccessIterator first, + SizeType hole_index, + SizeType length, + ValType value, + Cmp cmp + ) { + SizeType top_index = hole_index; + SizeType second_child = static_cast(2 * hole_index + 2); + while (second_child < length) { + if (cmp.__lt__(*(first + second_child), *(first + second_child - 1))) { + --second_child; + } + *(first + hole_index) = *(first + second_child); + hole_index = second_child; + second_child = static_cast(2 * (second_child + 1)); + } + if (second_child == length) { + *(first + hole_index) = *(first + second_child - 1); + hole_index = static_cast(second_child - 1); + } + __push_heap(first, hole_index, top_index, value, cmp); + }; + + /** + * Helper function performs heapify at the specified index. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type + * @tparam ValType value type for insertion + * @param first iterator to first element in the random access structure + * @param hole_index index of the value to be heapified + * @param length length of the heap section of the structure + * @param value value to heapify + */ + template< + typename RandomAccessIterator, + typename SizeType, + typename ValType + > + void __adjust_heap( + RandomAccessIterator first, + SizeType hole_index, + SizeType length, + ValType value + ) { + SizeType top_index = hole_index; + SizeType second_child = static_cast(2 * hole_index + 2); + while (second_child < length) { + if (*(first + second_child) < *(first + second_child - 1)) { + --second_child; + } + *(first + hole_index) = *(first + second_child); + hole_index = second_child; + second_child = static_cast(2 * (second_child + 1)); + } + if (second_child == length) { + *(first + hole_index) = *(first + second_child - 1); + hole_index = static_cast(second_child - 1); + } + __push_heap(first, hole_index, top_index, value); + }; + + /** + * Helper function to pop an element from the heap. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam Cmp comparator type + * @tparam SizeType integer size type + * @tparam ValType value type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random access structure + * @param result iterator to the location where the popped element will be stored + * @param value the value that is popped + * @param cmp comparator to use + */ + template< + typename RandomAccessIterator, + typename Cmp, + typename SizeType = typename obtain_size_type::type, + typename ValType + > + void __pop_heap( + RandomAccessIterator first, + RandomAccessIterator last, + RandomAccessIterator result, + ValType value, + Cmp cmp + ) { + *result = *first; + __adjust_heap(first, (SizeType) 0, (SizeType) (last - first), value, cmp); + }; + + /** + * Helper function to pop an element from the heap. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType integer size type + * @tparam ValType value type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random access structure + * @param result iterator to the location where the popped element will be stored + * @param value the value that is popped + */ + template< + typename RandomAccessIterator, + typename SizeType = typename obtain_size_type::type, + typename ValType + > + void __pop_heap( + RandomAccessIterator first, + RandomAccessIterator last, + RandomAccessIterator result, + ValType value + ) { + *result = *first; + __adjust_heap(first, (SizeType) 0, (SizeType) (last - first), value); + }; + + /** + * Pop an element from heap ranging from @code [first, last) @endcode + * such that the popped element is then stored at @code last @endcode + * and the heap now ranges @code [first, last - 1) @endcode. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam Cmp comparator type + * @tparam ValType value type acquired from the iterator type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random access structure + * @param cmp comparator to use + */ + template< + typename RandomAccessIterator, + typename Cmp, + typename ValType = typename obtain_val_type::type, + typename = typename enable_if< + is_random_access_iterator() && + is_comparator() + >::type + > + void pop_heap( + RandomAccessIterator first, + RandomAccessIterator last, + Cmp cmp + ) { + __pop_heap(first, last - 1, last - 1, (ValType) *(last - 1), cmp); + }; + + /** + * Pop an element from heap ranging from @code [first, last) @endcode + * such that the popped element is then stored at @code last @endcode + * and the heap now ranges @code [first, last - 1) @endcode. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam ValType value type acquired from the iterator type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random access structure + */ + template< + typename RandomAccessIterator, + typename = typename enable_if< + is_random_access_iterator() + >::type, + typename ValType = typename obtain_val_type::type + > + void pop_heap( + RandomAccessIterator first, + RandomAccessIterator last + ) { + __pop_heap(first, last - 1, last - 1, (ValType) *(last - 1)); + }; + + /** + * Make heap will traverse a random access structure + * (typically an array or vector) and create a heap + * that ranges from @code [first, last) @endcode. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam Cmp comparator type + * @tparam SizeType size type acquired from iterator type + * @tparam ValType value type acquired from iterator type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random acces structure + * @param cmp comparator to use + */ + template< + typename RandomAccessIterator, + typename Cmp, + typename SizeType = typename obtain_size_type::type, + typename ValType = typename obtain_val_type::type, + typename = typename enable_if< + is_random_access_iterator() && + is_comparator() + >::type + > + void make_heap( + RandomAccessIterator first, + RandomAccessIterator last, + Cmp cmp + ) { + SizeType length = last - first; + if (length < 2) { + return; + } + SizeType parent = static_cast((length - 2) / 2); + for (;;) { + __adjust_heap(first, parent, length, (ValType) *(first + parent), cmp); + if (parent == 0) { + return; + } + --parent; + } + }; + + /** + * Make heap will traverse a random access structure + * (typically an array or vector) and create a heap + * that ranges from @code [first, last) @endcode. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam SizeType size type acquired from iterator type + * @tparam ValType value type acquired from iterator type + * @param first iterator to first element in random access structure + * @param last iterator to last element in random acces structure + */ + template< + typename RandomAccessIterator, + typename SizeType = typename obtain_size_type::type, + typename ValType = typename obtain_val_type::type, + typename = typename enable_if< + is_random_access_iterator() + >::type + > + void make_heap( + RandomAccessIterator first, + RandomAccessIterator last + ) { + SizeType length = last - first; + if (length < 2) { + return; + } + SizeType parent = static_cast((length - 2) / 2); + for (;;) { + __adjust_heap(first, parent, length, (ValType) *(first + parent)); + if (parent == 0) { + return; + } + --parent; + } + }; + + /** + * Rearrange the elements in a heap from @code [first, last) @endcode + * such that they are ordered from smallest to largest between + * @code [first, last) @endcode. This eliminates the heap property. + * + * @tparam RandomAccessIterator random access iterator type + * @tparam Cmp comparator type + * @param first iterator to first element in heap + * @param last iterator to last element in heap + * @param cmp comparator type + */ + template< + typename RandomAccessIterator, + typename Cmp, + typename = typename enable_if< + is_random_access_iterator() && + is_comparator::type>() + >::type> + void sort_heap( + RandomAccessIterator first, + RandomAccessIterator last, + Cmp cmp + ) { + while (last - first > 1) { + pop_heap(first, last--, cmp); + } + }; + + /** + * Rearrange the elements in a heap from @code [first, last) @endcode + * such that they are ordered from smallest to largest between + * @code [first, last) @endcode. This eliminates the heap property. + * + * @tparam RandomAccessIterator random access iterator type + * @param first iterator to first element in heap + * @param last iterator to last element in heap + */ + template< + typename RandomAccessIterator, + typename = typename enable_if< + is_random_access_iterator() + >::type> + void sort_heap( + RandomAccessIterator first, + RandomAccessIterator last + ) { + while (last - first > 1) { + pop_heap(first, last--); + } + }; + + /** + * A basic heap implementation using @code ArrayList @endcode + * as the backing structure. May be used as a priority queue. + * + * @tparam T data type + * @tparam Cmp comparator type, which uses the default + */ + template> + class ArrayHeap { + public: + typedef Cmp comparator; + typedef ArrayHeap array_heap; + typedef typename ArrayList::val_type val_type; + typedef typename ArrayList::size_type size_type; + typedef typename ArrayList::array_list array_list; + typedef typename ArrayList::iterator iterator; + typedef typename ArrayList::const_iterator const_iterator; + + private: + /** + * The backing array list. + */ + array_list m_list; + /** + * The comparator instance. + */ + comparator m_cmp; + + public: + /** + * Constructor with a specified initial capacity for the + * backing array list. + * + * @param initial_capacity initial capacity of the backing array + */ + explicit ArrayHeap(size_type initial_capacity = 12) + : m_list(initial_capacity), + m_cmp(Cmp()) { + } + + /** + * Disable copy construction. + */ + ArrayHeap(const array_heap &) = delete; + + /** + * Move copy constructor. + * + * @param heap array heap whose resources to transfer + */ + ArrayHeap(array_heap &&heap) + : m_list(move(heap.m_list)), + m_cmp(move(heap.m_cmp)) { + } + + /** + * Push an element onto the heap. + * + * @param value value to insert + */ + void push(const val_type &value) { + m_list.push_back(value); + push_heap(m_list.begin(), m_list.end(), m_cmp); + } + + /** + * Push an rvalue onto the heap. + * + * @param value rvalue to insert + */ + void push(val_type &&value) { + m_list.push_back(forward(value)); + push_heap(m_list.begin(), m_list.end(), m_cmp); + } + + /** + * Pop the top element from the heap. + */ + void pop() { + pop_heap(m_list.begin(), m_list.end(), m_cmp); + m_list.pop_back(); + } + + /** + * Get a reference to the top element on the heap. + * Modification of the element is disabled in order + * to preserve heap property. + * + * @return reference to the top element + */ + const val_type &top() { + return m_list.front(); + } + + /** + * @return whether the heap is empty + */ + bool empty() const { + return m_list.empty(); + } + + /** + * @return the number of elements in the heap + */ + size_type size() const { + return m_list.size(); + } + + /** + * @return the size of the backing array + */ + size_type capacity() const { + return m_list.capacity(); + } + + /** + * @return a pointer to the backing array list + */ + array_list *get_array_list() { + return &m_list; + } + + /** + * Disable copy assignment. + * + * @return reference to this heap + */ + array_heap &operator=(const array_heap &) = delete; + + /** + * Move assignment operator. + * + * @param heap array heap whose resources to transfer + * @return reference to this heap + */ + array_heap &operator=(array_heap &&heap) { + m_list = move(heap.m_list); + return *this; + } + }; + + /** + * Sort an array list using heap sort. + * This function uses the array list + * elements' default ordering operations, + * which may be overloaded. + * + * @tparam T list element type, inferred from array list + * @param list array list to sort + */ + template + void heap_sort(ArrayList &list) { + make_heap(list.begin(), list.end()); + sort_heap(list.begin(), list.end()); + } + + /** + * Sort an array list using heap sort. + * This function uses a supplied comparator + * type for the array list element + * + * @tparam T list element type, inferred from array list + * @tparam Cmp comparator type + * @param list array list to sort + * @param cmp comparator to use + */ + template + void heap_sort(ArrayList &list, Cmp cmp) { + make_heap(list.begin(), list.end(), cmp); + sort_heap(list.begin(), list.end(), cmp); + }; + +} + +#endif //EMBEDDEDCPLUSPLUS_ARRAYHEAP_H diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h new file mode 100644 index 00000000..5b3beeed --- /dev/null +++ b/lib/wlib/stl/ArrayList.h @@ -0,0 +1,1136 @@ +/** + * @file ArrayList.h + * @brief List implementation using an array. + * + * This file implements a random access list data structure + * using an array, and contains associated iterator types. + * + * @author Jeff Niu + * @date November 9, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_ARRAYLIST_H +#define EMBEDDEDCPLUSPLUS_ARRAYLIST_H + +#include "Utility.h" + +#include "../Types.h" + +#include "../memory/Memory.h" + +namespace wlp { + + // ArrayList forward declaration. + template + class ArrayList; + + /** + * Array list forward iterator type. + * @tparam T list element type + */ + template + class ArrayListIterator { + public: + typedef wlp::size_type size_type; + typedef T val_type; + typedef ArrayList array_list; + typedef ArrayListIterator iterator; + + private: + /** + * The array index pointed to by this iterator. + */ + size_type m_i; + /** + * Pointer to the backing array list. + */ + array_list *m_list; + + friend class ArrayList; + + public: + /** + * An empty array list iterator is invalid. + */ + ArrayListIterator() + : m_i(static_cast(-1)), + m_list(nullptr) { + } + + /** + * Copy constructor. + * + * @param it iterator to copy + */ + ArrayListIterator(const iterator &it) + : m_i(it.m_i), + m_list(it.m_list) { + check_bounds(); + } + + /** + * Move constructor. + * + * @param it iterator to move + */ + ArrayListIterator(iterator &&it) + : m_i(move(it.m_i)), + m_list(move(it.m_list)) { + check_bounds(); + } + + /** + * Constructor from an array index and + * a backing array list. + * + * @param i array index + * @param list backing array list + */ + explicit ArrayListIterator(const size_type &i, array_list *list) + : m_i(i), + m_list(list) { + check_bounds(); + } + + /** + * Constructor from an array index rvalue + * and a backing array list. + * + * @param i array index rvalue + * @param list backing array list + */ + explicit ArrayListIterator(size_type &&i, array_list *list) + : m_i(move(i)), + m_list(list) { + check_bounds(); + } + + private: + /** + * Ensure the iterator is either exactly + * pass-the-end of at the beginning. + */ + void check_bounds() { + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + } + + public: + /** + * @return a reference to the value pointed to + * by this iterator + */ + val_type &operator*() const { + return m_list->m_data[m_i]; + } + + /** + * @return a pointer to the value pointer to + * by this iterator + */ + val_type *operator->() const { + return &(operator*()); + } + + /** + * Move this iterator to the next element in the + * backing array list. Becomes a pass-the-end + * iterator if attempting to move past the + * end of the array list. + * + * @return reference to this iterator + */ + iterator &operator++() { + if (m_i == m_list->m_size) { + return *this; + } + ++m_i; + return *this; + } + + /** + * Postfix operator to move this iterator to the + * next element in the array. + * + * @return copy of this iterator before increment + */ + iterator operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } + + /** + * Addition assignment operator moves the + * iterator by the specified number of + * positions. + * + * @param d the number of positions to increment + * @return reference to this iterator + */ + iterator &operator+=(const size_type &d) { + m_i = (size_type) (m_i + d); + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + return *this; + } + + /** + * Addition assignment operator moves the + * iterator by the specified number of + * positions. + * + * @param d the number of positions to increment + * @return reference to this iterator + */ + iterator &operator+=(size_type &&d) { + m_i = (size_type) (m_i + d); + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + return *this; + } + + /** + * Decrement operator moves the iterator backwards + * one element. If the iterator points to the first + * element, does nothing. + * + * @return reference to this iterator + */ + iterator &operator--() { + if (m_i == 0) { + return *this; + } + --m_i; + return *this; + } + + /** + * Postfix decrement operator. + * + * @return a copy of the iterator before moving + */ + iterator operator--(int) { + iterator tmp = *this; + --*this; + return tmp; + } + + /** + * Subtraction assignment operator moves the iterator + * backwards a certain number of elements. + * + * @param d the number of elements to move back + * @return reference to this iterator + */ + iterator &operator-=(const size_type &d) { + if (d >= m_i) { + m_i = 0; + } else { + m_i = (size_type) (m_i - d); + } + return *this; + } + + /** + * Subtraction assignment operator moves the iterator + * backwards a certain number of elements. + * + * @param d the number of elements to move back + * @return reference to this iterator + */ + iterator &operator-=(size_type &&d) { + if (d >= m_i) { + m_i = 0; + } else { + m_i = (size_type) (m_i - d); + } + return *this; + } + + /** + * @param it iterator to compare + * @return true if they point to the same element + */ + bool operator==(iterator &it) const { + return m_i == it.m_i; + } + + /** + * @param it iterator to compare + * @return true if they point to the same element + */ + bool operator==(const iterator &it) const { + return m_i == it.m_i; + } + + /** + * @param it iterator to compare + * @return true if they point to different elements + */ + bool operator!=(iterator &it) const { + return m_i != it.m_i; + } + + /** + * @param it iterator to compare + * @return true if they point to different elements + */ + bool operator!=(const iterator &it) const { + return m_i != it.m_i; + } + + /** + * Move assignment operator. + * + * @param it iterator to move + * @return reference to this iterator + */ + iterator &operator=(iterator &&it) { + m_i = move(it.m_i); + m_list = move(it.m_list); + return *this; + } + + /** + * Copy assignment operator. + * + * @param it iterator to copy + * @return reference to this iterator + */ + iterator &operator=(const iterator &it) { + m_i = it.m_i; + m_list = it.m_list; + return *this; + } + + /** + * Addition operator returns a new iterator + * incremented by the specified number of positions. + * + * @param d number of positions to increment + * @return + */ + iterator operator+(const size_type &d) const { + return iterator(move((size_type) (m_i + d)), m_list); + } + + /** + * Addition operator returns a new iterator + * incremented by the specified number of positions. + * + * @param d number of positions to increment + * @return a new iterator + */ + iterator operator+(size_type &&d) const { + return iterator(move((size_type) (m_i + d)), m_list); + } + + /** + * Subtraction operator returns a new iterator + * decremented by the specified number of positions. + * + * @param d number of positions to decrement + * @return a new iterator + */ + iterator operator-(const size_type &d) const { + return iterator(move((size_type) (m_i - d)), m_list); + } + + /** + * Subtraction operator returns a new iterator + * decremented by the specified number of positions. + * + * @param d number of positions to decrement + * @return a new iterator + */ + iterator operator-(size_type &&d) const { + return iterator(move((size_type) (m_i - d)), m_list); + } + + /** + * Subtraction of two iterators returns the + * integer distance between them. + * + * @param it iterator to subtract + * @return the integer distance + */ + size_type operator-(const iterator &it) const { + if (m_i < it.m_i) { + return (size_type) (it.m_i - m_i); + } + return (size_type) (m_i - it.m_i); + } + + /** + * Subtraction of two iterators returns the + * integer distance between them. + * + * @param it iterator to subtract + * @return the integer distance + */ + size_type operator-(iterator &&it) const { + if (m_i < it.m_i) { + return (size_type) (it.m_i - m_i); + } + return (size_type) (m_i - it.m_i); + } + }; + + /** + * Const iterator for array list. + * + * @see ArrayListIterator + * @tparam T iterator value type + */ + template + class ArrayListConstIterator { + public: + typedef wlp::size_type size_type; + typedef T val_type; + typedef ArrayList array_list; + typedef ArrayListConstIterator const_iterator; + + private: + size_type m_i; + const array_list *m_list; + + friend class ArrayList; + + public: + ArrayListConstIterator() + : m_i(static_cast(-1)), + m_list(nullptr) { + } + + ArrayListConstIterator(const const_iterator &it) + : m_i(it.m_i), + m_list(it.m_list) { + check_bounds(); + } + + ArrayListConstIterator(const_iterator &&it) + : m_i(move(it.m_i)), + m_list(move(it.m_list)) { + check_bounds(); + } + + explicit ArrayListConstIterator(const size_type &i, const array_list *list) + : m_i(i), + m_list(list) { + check_bounds(); + } + + explicit ArrayListConstIterator(size_type &&i, const array_list *list) + : m_i(move(i)), + m_list(list) { + check_bounds(); + } + + private: + void check_bounds() { + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + } + + public: + + val_type &operator*() const { + return m_list->m_data[m_i]; + } + + val_type *operator->() const { + return &(operator*()); + } + + const_iterator &operator++() { + if (m_i == m_list->m_size) { + return *this; + } + ++m_i; + return *this; + } + + const_iterator operator++(int) { + const_iterator tmp = *this; + ++*this; + return tmp; + } + + const_iterator &operator+=(const size_type &d) { + m_i = (size_type) (m_i + d); + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + return *this; + } + + const_iterator &operator+=(size_type &&d) { + m_i = (size_type) (m_i + d); + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + return *this; + } + + const_iterator &operator--() { + if (m_i == 0) { + return *this; + } + --m_i; + return *this; + } + + const_iterator operator--(int) { + const_iterator tmp = *this; + --*this; + return tmp; + } + + const_iterator &operator-=(const size_type &d) { + if (d >= m_i) { + m_i = 0; + } else { + m_i = (size_type) (m_i - d); + } + return *this; + } + + const_iterator &operator-=(size_type &&d) { + if (d >= m_i) { + m_i = 0; + } else { + m_i = (size_type) (m_i - d); + } + return *this; + } + + bool operator==(const_iterator &it) const { + return m_i == it.m_i; + } + + bool operator==(const const_iterator &it) const { + return m_i == it.m_i; + } + + bool operator!=(const_iterator &it) const { + return m_i != it.m_i; + } + + bool operator!=(const const_iterator &it) const { + return m_i != it.m_i; + } + + const_iterator &operator=(const_iterator &&it) { + m_i = move(it.m_i); + m_list = move(it.m_list); + return *this; + } + + const_iterator &operator=(const const_iterator &it) { + m_i = it.m_i; + m_list = it.m_list; + return *this; + } + + const_iterator operator+(const size_type &d) const { + return const_iterator(move((size_type) (m_i + d)), m_list); + } + + const_iterator operator+(size_type &&d) const { + return const_iterator(move((size_type) (m_i + d)), m_list); + } + + const_iterator operator-(const size_type &d) const { + return const_iterator(move((size_type) (m_i - d)), m_list); + } + + const_iterator operator-(size_type &&d) const { + return const_iterator(move((size_type) (m_i - d)), m_list); + } + + size_type operator-(const const_iterator &it) const { + if (m_i < it.m_i) { + return (size_type) (it.m_i - m_i); + } + return (size_type) (m_i - it.m_i); + } + + size_type operator-(const_iterator &&it) const { + if (m_i < it.m_i) { + return (size_type) (it.m_i - m_i); + } + return (size_type) (m_i - move(it.m_i)); + } + }; + + /** + * List implementation using an array. This implementation + * will resize if attempting to insert into a full array. + * + * @tparam T value type + */ + template + class ArrayList { + public: + typedef wlp::size_type size_type; + typedef T val_type; + typedef ArrayList array_list; + typedef ArrayListIterator iterator; + typedef ArrayListConstIterator const_iterator; + + private: + /** + * The backing array. + */ + val_type *m_data; + /** + * The current number of elements in the list. + */ + size_type m_size; + /** + * The current size of the backing array. + */ + size_type m_capacity; + + friend class ArrayListIterator; + + friend class ArrayListConstIterator; + + public: + /** + * Constructor with an initial capacity for the + * backing array. + * + * @param initial_capacity the initial size of the backing array + */ + explicit ArrayList(size_type initial_capacity = 12) + : m_size(0), + m_capacity(initial_capacity) { + init_array(initial_capacity); + } + + /** + * Disable copy constructor. + */ + ArrayList(const array_list &) = delete; + + /** + * Move constructor. + * + * @param list array list whose resources to transfer + */ + ArrayList(array_list &&list) + : m_data(move(list.m_data)), + m_size(move(list.m_size)), + m_capacity(move(list.m_capacity)) { + list.m_data = nullptr; + list.m_size = 0; + list.m_capacity = 0; + } + + /** + * Constructor from array. The caller may specify + * a desired initial capacity, but if the capacity is + * shorter than the length, then the capacity will be + * set to the length of the array. + * + * @param values array of values + * @param length length of the array + */ + ArrayList(const val_type *values, size_type length, size_type initial_capacity) + : m_size(length), + m_capacity(initial_capacity) { + if (m_capacity < length) { + m_capacity = length; + } + init_array(m_capacity); + for (size_type i = 0; i < length; i++) { + m_data[i] = values[i]; + } + } + + /** + * Constructor from array. This constructor will set + * the backing array capacity to be equal to the + * array length. + * + * @param values array of values + * @param length length of the array + */ + ArrayList(const val_type *values, size_type length) + : ArrayList(values, length, length) { + } + + /** + * Free the memory for the array unless + * it has already been deallocated elsewhere. + */ + ~ArrayList() { + if (!m_data) { + return; + } + memory_free(m_data); + m_data = nullptr; + } + + private: + /** + * Initialize the backing array. This function + * performs no initialization of the contents of + * the array itself. + * + * @param initial_size the initial capacity for the backing array + */ + void init_array(size_type initial_size) { + m_data = static_cast(memory_alloc(initial_size * sizeof(val_type))); + } + + /** + * Normalize an index such that it is within + * the range @code [0, length) @endcode. + * + * @param i integer to normalize + */ + void normalize(size_type &i) const { + if (m_size == 0) { + i = 0; + return; + } + i %= m_size; + } + + /** + * Called before any insertion operation, + * this function will extend the size of the + * array to twice its capacity and copy + * the elements of the previous array. + */ + void ensure_capacity(); + + /** + * Shift elements in the array at position @code i @endcode + * to the right once, such that the element at position + * @code i @endcode is now present twice in the array. + * + * @param i the shift begin position + */ + void shift_right(size_type i); + + /** + * Shift elements in the array at position @code i @endcode + * to the left once, such that the element at position + * @code i @endcode is erased. + * + * @param i the shift begin position + */ + void shift_left(size_type i); + + public: + /** + * @return whether the list is empty + */ + bool empty() const { + return m_size == 0; + } + + /** + * @return the current number of elements in the list + */ + size_type size() const { + return m_size; + } + + /** + * @return the size of the backing array + */ + size_type capacity() const { + return m_capacity; + } + + /** + * Copy the elements in the current array into + * a new array such that the new array has + * a size corresponding to the new capacity. + * If the new capacity is smaller than the current + * capacity, nothing happens. + * + * @param new_capacity the size of backing array to reserve + */ + void reserve(size_type new_capacity); + + /** + * Copy the elements of the array into a + * new array whose capacity is equal to the number + * of elements in the array. + */ + void shrink(); + + /** + * Get the element at position @code i @endcode. + * + * @param i the index of the element to get + * @return reference to the element + */ + val_type &at(size_type i) { + normalize(i); + return m_data[i]; + } + + /** + * Get the element at position @code i @endcode. + * + * @param i the index of the element to get + * @return reference to the element + */ + val_type const &at(size_type i) const { + normalize(i); + return m_data[i]; + } + + /** + * Access operator returns the element + * at the specified position without bounds + * checking. + * + * @param i position to access + * @return reference to the element there + */ + val_type &operator[](size_type i) { + return m_data[i]; + } + + /** + * Access operator returns the element + * at the specified position without bounds + * checking. + * + * @param i position to access + * @return reference to the element there + */ + val_type const &operator[](size_type i) const { + return m_data[i]; + } + + /** + * @return reference to the first element in the list + */ + val_type &front() { + return m_data[0]; + } + + /** + * @return reference to the first element in the list + */ + val_type const &front() const { + return m_data[0]; + } + + /** + * @return reference to the last element in the list + */ + val_type &back() { + if (m_size == 0) { + return m_data[0]; + } + return m_data[m_size - 1]; + } + + /** + * @return reference to the last element in the list + */ + val_type const &back() const { + if (m_size == 0) { + return m_data[0]; + } + return m_data[m_size - 1]; + } + + /** + * @return a pointer to the beginning of the backing array + */ + val_type *data() { + return m_data; + } + + /** + * @return a pointer to the beginning of the backing array + */ + const val_type *data() const { + return m_data; + } + + /** + * Clear the contents of the array list + * such that it is empty. + */ + void clear() { + m_size = 0; + } + + /** + * @return iterator to the start of the array + */ + iterator begin() { + return iterator(0, this); + } + + /** + * @return iterator to the start of the array + */ + const_iterator begin() const { + return const_iterator(0, this); + } + + /** + * @return iterator to the end of the array + */ + iterator end() { + return iterator(m_size, this); + } + + /** + * @return iterator to the end of the array + */ + const_iterator end() const { + return const_iterator(m_size, this); + } + + /** + * Insert an element in the array at the specified + * position such that the previous element at the position + * and all elements after are shifted to the right. + * + * @param i position to insert + * @param t element to insert + * @return iterator to the inserted element + */ + iterator insert(size_type i, const val_type &t) { + ensure_capacity(); + normalize(i); + shift_right(i); + m_data[i] = t; + ++m_size; + return iterator(i, this); + } + + /** + * Insert an element in the array at the specified + * position such that the previous element at the position + * and all elements after are shifted to the right. + * + * @param i position to insert + * @param t element to insert + * @return iterator to the inserted element + */ + iterator insert(size_type i, val_type &&t) { + ensure_capacity(); + normalize(i); + shift_right(i); + m_data[i] = forward(t); + ++m_size; + return iterator(i, this); + } + + /** + * Insert an element at the position pointed to by + * the iterator. + * + * @param it iterator to the inserted position + * @param t element to insert + * @return iterator to the inserted element + */ + iterator &insert(iterator &it, const val_type &t) { + ensure_capacity(); + shift_right(it.m_i); + m_data[it.m_i] = t; + ++m_size; + return it; + } + + /** + * Insert an element at the position pointed to by + * the iterator. + * + * @param it iterator to the inserted position + * @param t element to insert + * @return iterator to the inserted element + */ + iterator &insert(iterator &it, val_type &&t) { + ensure_capacity(); + shift_right(it.m_i); + m_data[it.m_i] = t; + ++m_size; + return it; + } + + /** + * Remove the element at the specified position. + * + * @param i position whose element to erase. + * @return iterator to the next element in the list + */ + iterator erase(size_type i) { + if (m_size == 0) { + return end(); + } + normalize(i); + shift_left(i); + --m_size; + return iterator(i, this); + } + + /** + * Remove the element at the specified position. + * + * @param it position whose element to erase. + * @return iterator to the next element in the list + */ + iterator erase(iterator &it) { + if (m_size == 0 || it.m_i >= m_size) { + return end(); + } + shift_left(it.m_i); + --m_size; + return it; + } + + /** + * Insert an element to the back of the list. + * + * @param t element to insert + */ + void push_back(const val_type &t) { + ensure_capacity(); + m_data[m_size] = t; + ++m_size; + } + + /** + * Insert an element to the back of the list. + * + * @param t element to insert + */ + void push_back(val_type &&t) { + ensure_capacity(); + m_data[m_size] = move(t); + ++m_size; + } + + /** + * Remove the last element from the list. + */ + void pop_back() { + if (m_size > 0) { + --m_size; + } + } + + /** + * Swap the contents of two array lists. + * + * @param list array list with which to swap + */ + void swap(array_list &list) { + val_type *tmp = m_data; + m_data = list.m_data; + list.m_data = tmp; + size_type tmp_size = m_size; + m_size = list.m_size; + list.m_size = tmp_size; + size_type tmp_cap = m_capacity; + m_capacity = list.m_capacity; + list.m_capacity = tmp_cap; + } + + /** + * Disable copy assignment. + * + * @return reference to this list + */ + array_list &operator=(const array_list &) = delete; + + /** + * Move assignment operator. + * + * @param list array list to transfer + * @return reference to this list + */ + array_list &operator=(array_list &&list) { + memory_free(m_data); + m_data = move(list.m_data); + m_size = move(list.m_size); + m_capacity = move(list.m_capacity); + list.m_data = nullptr; + list.m_size = 0; + list.m_capacity = 0; + return *this; + } + + }; + + template + void ArrayList::ensure_capacity() { + if (m_size < m_capacity) { + return; + } + size_type new_capacity = (size_type) (2 * m_capacity); + val_type *new_data = static_cast(memory_alloc(new_capacity * sizeof(val_type))); + for (size_type i = 0; i < m_size; i++) { + new_data[i] = m_data[i]; + } + memory_free(m_data); + m_data = new_data; + m_capacity = new_capacity; + } + + template + void ArrayList::reserve(size_type new_capacity) { + if (new_capacity <= m_capacity) { + return; + } + val_type *new_data = static_cast(memory_alloc(new_capacity * sizeof(val_type))); + for (size_type i = 0; i < m_size; i++) { + new_data[i] = m_data[i]; + } + memory_free(m_data); + m_data = new_data; + m_capacity = new_capacity; + } + + template + void ArrayList::shrink() { + if (m_size == m_capacity) { + return; + } + val_type *new_data = static_cast(memory_alloc(m_size * sizeof(val_type))); + for (size_type i = 0; i < m_size; i++) { + new_data[i] = m_data[i]; + } + memory_free(m_data); + m_data = new_data; + m_capacity = m_size; + } + + template + inline void ArrayList::shift_right(size_type i) { + for (size_type j = m_size; j > i; j--) { + m_data[j] = m_data[j - 1]; + } + } + + template + inline void ArrayList::shift_left(size_type i) { + for (size_type j = i; j < m_size - 1; j++) { + m_data[j] = m_data[j + 1]; + } + } + +} + +#endif //EMBEDDEDCPLUSPLUS_ARRAYLIST_H diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index fd7033e3..fcb23667 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -1,8 +1,8 @@ /** * @file ChainMap.h - * @brief Hash map implementation. + * @brief Hasher map implementation. * - * Hash map is implemented using separate chaining + * Hasher map is implemented using separate chaining * because someone wanted remove operations. * * @author Jeff Niu @@ -13,9 +13,11 @@ #ifndef EMBEDDEDTESTS_CHAINMAP_H #define EMBEDDEDTESTS_CHAINMAP_H -#include "Hash.h" +#include "Utility.h" #include "Equal.h" +#include "Hash.h" #include "Pair.h" + #include "../memory/Allocator.h" #include "../memory/Memory.h" @@ -24,26 +26,26 @@ namespace wlp { // Forward declaration of ChainHashMap template + class Hasher, + class Equals> class ChainHashMap; // Forward declaration of ChainHashMap iterator template + class Hasher, + class Equals> struct ChainHashMapIterator; // Forward declaration of const ChainHashMap iterator template + class Hasher, + class Equals> struct ChainHashMapConstIterator; /** - * Hash map node comprise the elements of a hash map's + * Hasher map node comprise the elements of a hash map's * backing array, containing an element key and corresponding value. * Has pointer to next node in a chain. * @tparam Key key type @@ -51,13 +53,13 @@ namespace wlp { */ template struct ChainHashMapNode { - typedef ChainHashMapNode map_node; + typedef ChainHashMapNode node_type; typedef Key key_type; typedef Val val_type; /** * Pointer to the next node in the chain. */ - map_node *next = nullptr; + node_type *next = nullptr; /** * Node element key value. */ @@ -72,7 +74,7 @@ namespace wlp { * @param node const node to compare * @return true if they are equal */ - bool operator==(const map_node &node) const { + bool operator==(const node_type &node) const { return m_key == node.m_key && m_val == node.m_val; } @@ -83,7 +85,7 @@ namespace wlp { * @param node the node compare * @return true if they are equal */ - bool operator==(map_node &node) const { + bool operator==(node_type &node) const { return m_key == node.m_key && m_val == node.m_val; } }; @@ -93,57 +95,66 @@ namespace wlp { * this class iterates through each chain and then the backing array. * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template + class Hasher, + class Equals> struct ChainHashMapIterator { - typedef ChainHashMap hash_map; - typedef ChainHashMapIterator iterator; - typedef ChainHashMapNode map_node; + typedef ChainHashMap map_type; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapNode node_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; /** * Pointer to the node referenced by this iterator. */ - map_node *m_current; + node_type *m_current; /** * Pointer to the iterated ChainHashMap. */ - hash_map *m_hash_map; + map_type *m_hash_map; /** * Default constructor. */ - ChainHashMapIterator() {} + ChainHashMapIterator() + : m_current(nullptr), + m_hash_map(nullptr) { + } /** * Create an iterator to a ChainHashMap node. * @param node hash map node * @param map parent hash map */ - ChainHashMapIterator(map_node *node, hash_map *map) - : m_current(node), m_hash_map(map) {} + ChainHashMapIterator(node_type *node, map_type *map) + : m_current(node), + m_hash_map(map) { + } /** * Copy constructor for const. * @param it iterator copy */ ChainHashMapIterator(const iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + : m_current(it.m_current), + m_hash_map(it.m_hash_map) { + } /** * Copy constructor. * @param it iterator to copy */ - ChainHashMapIterator(iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + ChainHashMapIterator(iterator &&it) + : m_current(move(it.m_current)), + m_hash_map(move(it.m_hash_map)) { + } /** * @return reference to the value of the node @@ -231,9 +242,9 @@ namespace wlp { * @param it iterator to copy * @return a reference to this iterator */ - iterator &operator=(iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; + iterator &operator=(iterator &&it) { + m_current = move(it.m_current); + m_hash_map = move(it.m_hash_map); return *this; } @@ -247,35 +258,44 @@ namespace wlp { * * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template + class Hasher, + class Equals> struct ChainHashMapConstIterator { - typedef ChainHashMap hash_map; - typedef ChainHashMapConstIterator const_iterator; - typedef ChainHashMapNode map_node; + typedef ChainHashMap map_type; + typedef ChainHashMapConstIterator const_iterator; + typedef ChainHashMapNode node_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; - const map_node *m_current; - const hash_map *m_hash_map; + const node_type *m_current; + const map_type *m_hash_map; - ChainHashMapConstIterator() {} + ChainHashMapConstIterator() + : m_current(nullptr), + m_hash_map(nullptr) { + } - ChainHashMapConstIterator(map_node *node, const hash_map *map) - : m_current(node), m_hash_map(map) {} + ChainHashMapConstIterator(node_type *node, const map_type *map) + : m_current(node), + m_hash_map(map) { + } ChainHashMapConstIterator(const const_iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + : m_current(it.m_current), + m_hash_map(it.m_hash_map) { + } - ChainHashMapConstIterator(const_iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + ChainHashMapConstIterator(const_iterator &&it) + : m_current(move(it.m_current)), + m_hash_map(move(it.m_hash_map)) { + } const val_type &operator*() const { return m_current->m_val; @@ -311,52 +331,52 @@ namespace wlp { return *this; } - const_iterator &operator=(const_iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; + const_iterator &operator=(const_iterator &&it) { + m_current = move(it.m_current); + m_hash_map = move(it.m_hash_map); return *this; } }; /** - * Hash map implemented using separate chaining, + * Hasher map implemented using separate chaining, * in the spirit of std::unordered_map. * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template, - class Equal = equals> + class Hasher = Hash, + class Equals = Equal> class ChainHashMap { public: - typedef ChainHashMap hash_map; - typedef ChainHashMapIterator iterator; - typedef ChainHashMapConstIterator const_iterator; - typedef ChainHashMapNode map_node; + typedef ChainHashMap map_type; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapConstIterator const_iterator; + typedef ChainHashMapNode node_type; typedef Key key_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; typedef uint8_t percent_type; - friend struct ChainHashMapIterator; - friend struct ChainHashMapConstIterator; + friend struct ChainHashMapIterator; + friend struct ChainHashMapConstIterator; private: /** * Class hash function instance. Used to hash * element keys. */ - Hash m_hash; + Hasher m_hash; /** * Class key equality function. Used to test * equality of element keys. */ - Equal m_equal; + Equals m_equal; /** * Allocator to create memory for hash map nodes. @@ -364,9 +384,9 @@ namespace wlp { Allocator m_node_allocator; /** - * Hash map backing array. + * Hasher map backing array. */ - map_node **m_buckets; + node_type **m_buckets; /** * The number of elements currently @@ -379,7 +399,7 @@ namespace wlp { * may very well exceed the size fo the backing * array if the load factor is greater than 100. */ - size_type m_max_elements; + size_type m_capacity; /** * The maximum load factor as an integer percent * before the map performs a rehash. This number @@ -397,32 +417,43 @@ namespace wlp { * * @param n initial size of the bucket list; each bucket is initialized to nullptr * @param max_load an integer value denoting the max percent load factor, e.g. 100 = 1.00 - * @param hash hash function for the key type, default is {@code wlp::Hash} - * @param equal equality function for the key type, default is {@code wlp::Equal} + * @param hash hash function for the key type, default is {@code wlp::Hasher} + * @param equal equality function for the key type, default is {@code wlp::Equals} */ explicit ChainHashMap( size_type n = 12, percent_type max_load = 75) - : m_hash(Hash()), - m_equal(Equal()), - m_node_allocator{sizeof(map_node), static_cast(n * sizeof(map_node))}, + : m_hash(Hasher()), + m_equal(Equals()), + m_node_allocator{sizeof(node_type), static_cast(n * sizeof(node_type))}, m_num_elements(0), - m_max_elements(n), + m_capacity(n), m_max_load(max_load) { init_buckets(n); } /** - * Copy constructor performs a deep copy. - * @param map hash map to copy + * Disable copy constructor. */ - ChainHashMap(const hash_map &map); + ChainHashMap(const map_type &) = delete; /** - * Copy constructor performs a deep copy. + * Move constructor. + * * @param map hash map to copy */ - ChainHashMap(hash_map &map); + ChainHashMap(map_type &&map) : + m_hash(move(map.m_hash)), + m_equal(move(map.m_equal)), + m_node_allocator(move(map.m_node_allocator)), + m_buckets(move(map.m_buckets)), + m_num_elements(move(map.m_num_elements)), + m_capacity(move(map.m_capacity)), + m_max_load(move(map.m_max_load)) { + map.m_num_elements = 0; + map.m_capacity = 0; + map.m_buckets = nullptr; + } /** * Destroy the hash map, freeing allocated nodes and @@ -435,6 +466,7 @@ namespace wlp { * Function called when creating the hash map. This function * will allocate memory for the backing array and initialize each * element to nullptr. + * * @param n the size of the backing array */ void init_buckets(size_type n); @@ -442,6 +474,7 @@ namespace wlp { /** * Obtain the bucket index in an array with the specified * number of maximum elements. + * * @param key the key to hash * @param max_elements the maximum number of buckets * @return an index i such that 0 <= i < max_elements @@ -452,11 +485,12 @@ namespace wlp { /** * Obtain the bucket index of a key in the backing array. + * * @param key the key to hash * @return an index i such that 0 <= i < m_max_elements */ size_type hash(key_type key) const { - return m_hash(key) % m_max_elements; + return m_hash(key) % m_capacity; } /** @@ -484,8 +518,8 @@ namespace wlp { /** * @return the current size of the backing array */ - size_type max_size() const { - return m_max_elements; + size_type capacity() const { + return m_capacity; } /** @@ -513,13 +547,14 @@ namespace wlp { * Obtain an iterator to the first element in the hash map. * Returns pass-the-end iterator if there are no elements * in the hash map. + * * @return iterator the first element */ iterator begin() { if (m_num_elements == 0) { return end(); } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { return iterator(m_buckets[i], this); } @@ -535,14 +570,14 @@ namespace wlp { } /** - * @see ChainHashMap::begin() + * @see ChainHashMap::begin() * @return a constant iterator to the first element */ const_iterator begin() const { if (m_num_elements == 0) { return end(); } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { return const_iterator(m_buckets[i], this); } @@ -551,7 +586,7 @@ namespace wlp { } /** - * @see ChainHashMap::end() + * @see ChainHashMap::end() * @return a constant pass-the-end iterator */ const_iterator end() const { @@ -568,6 +603,7 @@ namespace wlp { * Attempt to insert an element into the map. * Insertion is prevented if there already exists * an element with the provided key + * * @param key inserted element key * @param val inserted element value * @return a pair consisting of an iterator pointing to the @@ -580,6 +616,7 @@ namespace wlp { * Attempt to insert an element into the map. * If an element with the same key already exists, * override the value mapped to by the provided key. + * * @param key inserted element key * @param val inserted element value * @return a pair consisting of an iterator pointing to the @@ -590,6 +627,7 @@ namespace wlp { /** * Erase an element pointed to by the provided pointer. + * * @param pos element to erase * @return the iterator to the next element in the map * or pass-the-end if there are no more elements afterwards @@ -597,21 +635,23 @@ namespace wlp { iterator &erase(iterator &pos); /** - * @see ChainHashMap::erase() + * @see ChainHashMap::erase() * @param pos const iterator to the element to erase * @return const iterator to the next element or pass-the-end */ const_iterator &erase(const_iterator &pos); /** - * Erase - * @param type - * @return + * Erase the element with the corresponding key. + * + * @param key the key of the element to erase + * @return true if erasure occured */ bool erase(key_type &key); /** * Returns the value corresponding to a provided key. + * * @param key the key for which to find the value * @return the value mapped to by the key * @throws KeyException if the key does not map to a value @@ -619,7 +659,7 @@ namespace wlp { iterator at(const key_type &key); /** - * @see ChainHashMap::at() + * @see ChainHashMap::at() * @param key key for which to find the value * @return the mapped value * @throws KeyException if the key does not exist @@ -636,13 +676,14 @@ namespace wlp { * Return an iterator to the map element corresponding * to the provided key, or pass-the-end if the key does * not map to any value in the map. + * * @param key the key to map * @return an iterator to the element mapped by the key */ iterator find(const key_type &key); /** - * @see ChainHashMap::find() + * @see ChainHashMap::find() * @param key the key to map * @return a const iterator to the element mapped by the key */ @@ -653,59 +694,58 @@ namespace wlp { * If the key does not map to any value in the map, * then a new value is created and inserted using the default * constructor. + * * @param key the key whose value to access * @return a reference to the mapped value */ val_type &operator[](const key_type &key); /** - * Assignment operator performs a deep copy of the - * contents of the assigned map. Therefore, one - * should use pass by reference or pointer unless - * assignment is absolutely necessary. - * @param map the map to copy - * @return a reference to this map + * Disable copy assignment. + * + * @return reference to this map */ - hash_map &operator=(const hash_map &map); + map_type &operator=(const map_type &) = delete; /** * Assignment operator performs a deep copy of the * contents of the assigned map. Therefore, one * should use pass by reference or pointer unless * assignment is absolutely necessary. + * * @param map the map to copy * @return a reference to this map */ - hash_map &operator=(hash_map &map); + map_type &operator=(map_type &&map); }; - template - void ChainHashMap::init_buckets(ChainHashMap::size_type n) { - m_buckets = static_cast(memory_alloc(n * sizeof(map_node *))); + template + void ChainHashMap::init_buckets(ChainHashMap::size_type n) { + m_buckets = static_cast(memory_alloc(n * sizeof(node_type *))); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } } - template - void ChainHashMap::ensure_capacity() { - if (m_num_elements * 100 < m_max_load * m_max_elements) { + template + void ChainHashMap::ensure_capacity() { + if (m_num_elements * 100 < m_max_load * m_capacity) { return; } - size_type new_max = static_cast(m_max_elements * 2); - map_node **new_buckets = static_cast(memory_alloc(new_max * sizeof(map_node *))); - for (size_type i = 0; i < new_max; ++i) { + size_type new_capacity = static_cast(m_capacity * 2); + node_type **new_buckets = static_cast(memory_alloc(new_capacity * sizeof(node_type *))); + for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (!m_buckets[i]) { continue; } - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; while (cur) { - size_type k = bucket_index(cur->m_key, new_max); - map_node *first = new_buckets[k]; - map_node *next = cur->next; + size_type k = bucket_index(cur->m_key, new_capacity); + node_type *first = new_buckets[k]; + node_type *next = cur->next; cur->next = first; new_buckets[k] = cur; cur = next; @@ -713,14 +753,14 @@ namespace wlp { } memory_free(m_buckets); m_buckets = new_buckets; - m_max_elements = new_max; + m_capacity = new_capacity; } - template - void ChainHashMap::clear() noexcept { - for (size_type i = 0; i < m_max_elements; ++i) { - map_node *cur = m_buckets[i]; - map_node *next; + template + void ChainHashMap::clear() noexcept { + for (size_type i = 0; i < m_capacity; ++i) { + node_type *cur = m_buckets[i]; + node_type *next; while (cur) { next = cur->next; m_node_allocator.Deallocate(cur); @@ -731,18 +771,18 @@ namespace wlp { m_num_elements = 0; } - template - Pair::iterator, bool> - ChainHashMap::insert(key_type key, val_type val) { + template + Pair::iterator, bool> + ChainHashMap::insert(key_type key, val_type val) { ensure_capacity(); size_type i = hash(key); - map_node *first = m_buckets[i]; - for (map_node *cur = first; cur; cur = cur->next) { + node_type *first = m_buckets[i]; + for (node_type *cur = first; cur; cur = cur->next) { if (m_equal(cur->m_key, key)) { return Pair(iterator(cur, this), false); } } - map_node *tmp = static_cast(m_node_allocator.Allocate()); + node_type *tmp = static_cast(m_node_allocator.Allocate()); tmp->m_key = key; tmp->m_val = val; tmp->next = first; @@ -751,19 +791,19 @@ namespace wlp { return Pair(iterator(tmp, this), true); }; - template - Pair::iterator, bool> - ChainHashMap::insert_or_assign(key_type key, val_type val) { + template + Pair::iterator, bool> + ChainHashMap::insert_or_assign(key_type key, val_type val) { ensure_capacity(); size_type i = hash(key); - map_node *first = m_buckets[i]; - for (map_node *cur = first; cur; cur = cur->next) { + node_type *first = m_buckets[i]; + for (node_type *cur = first; cur; cur = cur->next) { if (m_equal(cur->m_key, key)) { cur->m_val = val; return Pair(iterator(cur, this), false); } } - map_node *tmp = static_cast(m_node_allocator.Allocate()); + node_type *tmp = static_cast(m_node_allocator.Allocate()); tmp->m_key = key; tmp->m_val = val; tmp->next = first; @@ -772,12 +812,12 @@ namespace wlp { return Pair(iterator(tmp, this), true); }; - template - typename ChainHashMap::iterator & - ChainHashMap::erase(iterator &pos) { - map_node *p_node = pos.m_current; + template + typename ChainHashMap::iterator & + ChainHashMap::erase(iterator &pos) { + node_type *p_node = pos.m_current; if (p_node) { - map_node *n_node = p_node->next; + node_type *n_node = p_node->next; if (n_node) { p_node->next = n_node->next; p_node->m_key = n_node->m_key; @@ -787,66 +827,13 @@ namespace wlp { return pos; } else { size_type i = hash(p_node->m_key); - map_node *c_node = m_buckets[i]; - if (c_node == p_node) { - m_node_allocator.Deallocate(c_node); - --m_num_elements; - m_buckets[i] = nullptr; - while (++i < m_max_elements && !m_buckets[i]); - if (i == m_max_elements) { - pos.m_current = nullptr; - return pos; - } else { - pos.m_current = m_buckets[i]; - return pos; - } - } else { - while (c_node->next != p_node) { - c_node = c_node->next; - } - m_node_allocator.Deallocate(c_node->next); - --m_num_elements; - c_node->next = nullptr; - while (++i < m_max_elements && !m_buckets[i]); - if (i == m_max_elements) { - pos.m_current = nullptr; - return pos; - } else { - pos.m_current = m_buckets[i]; - return pos; - } - } - } - } - pos.m_current = nullptr; - return pos; - } - - template - typename ChainHashMap::const_iterator & - ChainHashMap::erase(const_iterator &pos) { - const map_node *p_node = pos.m_current; - if (p_node) { - size_type i = hash(p_node->m_key); - map_node *c_node = m_buckets[i]; - if (p_node->next) { - while (c_node != p_node) { - c_node = c_node->next; - } - map_node *n_node = c_node->next; - c_node->m_key = n_node->m_key; - c_node->m_val = n_node->m_val; - c_node->next = n_node->next; - m_node_allocator.Deallocate(n_node); - --m_num_elements; - return pos; - } else { + node_type *c_node = m_buckets[i]; if (c_node == p_node) { m_node_allocator.Deallocate(c_node); --m_num_elements; m_buckets[i] = nullptr; - while (++i < m_max_elements && !m_buckets[i]); - if (i == m_max_elements) { + while (++i < m_capacity && !m_buckets[i]); + if (i == m_capacity) { pos.m_current = nullptr; return pos; } else { @@ -860,8 +847,8 @@ namespace wlp { m_node_allocator.Deallocate(c_node->next); --m_num_elements; c_node->next = nullptr; - while (++i < m_max_elements && !m_buckets[i]); - if (i == m_max_elements) { + while (++i < m_capacity && !m_buckets[i]); + if (i == m_capacity) { pos.m_current = nullptr; return pos; } else { @@ -875,13 +862,13 @@ namespace wlp { return pos; } - template - bool ChainHashMap::erase(key_type &key) { + template + bool ChainHashMap::erase(key_type &key) { size_type i = hash(key); - map_node *first = m_buckets[i]; + node_type *first = m_buckets[i]; if (first) { - map_node *cur = first; - map_node *next = cur->next; + node_type *cur = first; + node_type *next = cur->next; if (next) { if (m_equal(key, cur->m_key)) { cur->m_key = next->m_key; @@ -915,11 +902,11 @@ namespace wlp { return false; } - template - typename ChainHashMap::iterator - ChainHashMap::at(const key_type &key) { + template + typename ChainHashMap::iterator + ChainHashMap::at(const key_type &key) { size_type i = hash(key); - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; if (!cur) { return end(); } @@ -932,11 +919,11 @@ namespace wlp { return iterator(cur, this); } - template - typename ChainHashMap::const_iterator - ChainHashMap::at(const key_type &key) const { + template + typename ChainHashMap::const_iterator + ChainHashMap::at(const key_type &key) const { size_type i = hash(key); - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; if (!cur) { return end(); } @@ -949,10 +936,10 @@ namespace wlp { return const_iterator(cur, this); } - template - bool ChainHashMap::contains(const key_type &key) const { + template + bool ChainHashMap::contains(const key_type &key) const { size_type i = hash(key); - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; if (!cur) { return false; } @@ -962,15 +949,15 @@ namespace wlp { return cur != nullptr; } - template - typename ChainHashMap::val_type & - ChainHashMap::operator[](const key_type &key) { + template + typename ChainHashMap::val_type & + ChainHashMap::operator[](const key_type &key) { ensure_capacity(); size_type i = hash(key); - map_node *first = m_buckets[i]; - map_node *cur = first; + node_type *first = m_buckets[i]; + node_type *cur = first; if (!cur) { - map_node *ele = static_cast(m_node_allocator.Allocate()); + node_type *ele = static_cast(m_node_allocator.Allocate()); ++m_num_elements; ele->m_key = key; ele->m_val = val_type(); @@ -984,7 +971,7 @@ namespace wlp { if (cur) { return cur->m_val; } - cur = static_cast(m_node_allocator.Allocate()); + cur = static_cast(m_node_allocator.Allocate()); ++m_num_elements; cur->m_key = key; cur->m_val = val_type(); @@ -994,11 +981,11 @@ namespace wlp { return cur->m_val; } - template - typename ChainHashMap::iterator - ChainHashMap::find(const key_type &key) { + template + typename ChainHashMap::iterator + ChainHashMap::find(const key_type &key) { size_type i = hash(key); - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; if (!cur) { return end(); } @@ -1011,11 +998,11 @@ namespace wlp { return iterator(cur, this); } - template - typename ChainHashMap::const_iterator - ChainHashMap::find(const key_type &key) const { + template + typename ChainHashMap::const_iterator + ChainHashMap::find(const key_type &key) const { size_type i = hash(key); - map_node *cur = m_buckets[i]; + node_type *cur = m_buckets[i]; if (!cur) { return end(); } @@ -1028,13 +1015,16 @@ namespace wlp { return const_iterator(cur, this); } - template - ChainHashMap::~ChainHashMap() { - for (size_type i = 0; i < m_max_elements; ++i) { - map_node *cur = m_buckets[i]; + template + ChainHashMap::~ChainHashMap() { + if (!m_buckets) { + return; + } + for (size_type i = 0; i < m_capacity; ++i) { + node_type *cur = m_buckets[i]; if (cur) { while (cur) { - map_node *next = cur->next; + node_type *next = cur->next; m_node_allocator.Deallocate(cur); cur = next; } @@ -1044,113 +1034,31 @@ namespace wlp { m_buckets = nullptr; } - template - ChainHashMap & - ChainHashMap::operator=(const ChainHashMap &map) { - clear(); - memory_free(m_buckets); - m_hash = map.m_hash; - m_equal = map.m_equal; - m_max_elements = map.m_max_elements; - m_max_load = map.m_max_load; - m_num_elements = map.m_num_elements; - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; ++i) { - m_buckets[i] = nullptr; - map_node *m_cur = map.m_buckets[i]; - while (m_cur) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - cur->next = m_buckets[i]; - m_buckets[i] = cur; - m_cur = m_cur->next; - } - } - return *this; - } - - template - ChainHashMap & - ChainHashMap::operator=(ChainHashMap &map) { + template + ChainHashMap & + ChainHashMap::operator=(ChainHashMap &&map) { clear(); memory_free(m_buckets); - m_hash = map.m_hash; - m_equal = map.m_equal; - m_max_elements = map.m_max_elements; - m_max_load = map.m_max_load; - m_num_elements = map.m_num_elements; - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; ++i) { - m_buckets[i] = nullptr; - map_node *m_cur = map.m_buckets[i]; - while (m_cur) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - cur->next = m_buckets[i]; - m_buckets[i] = cur; - m_cur = m_cur->next; - } - } + m_node_allocator = move(map.m_node_allocator); + m_num_elements = move(map.m_num_elements); + m_capacity = move(map.m_capacity); + m_max_load = move(map.m_max_load); + m_buckets = move(map.m_buckets); + map.m_num_elements = 0; + map.m_capacity = 0; + map.m_buckets = nullptr; return *this; } - template - ChainHashMap::ChainHashMap(const hash_map &map) : - m_hash(map.m_hash), - m_equal(map.m_equal), - m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, - m_num_elements(map.m_num_elements), - m_max_elements(map.m_max_elements), - m_max_load(map.m_max_load) { - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; i++) { - m_buckets[i] = nullptr; - map_node *m_cur = map.m_buckets[i]; - while (m_cur) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - cur->next = m_buckets[i]; - m_buckets[i] = cur; - m_cur = m_cur->next; - } - } - } - - template - ChainHashMap::ChainHashMap(hash_map &map) : - m_hash(map.m_hash), - m_equal(map.m_equal), - m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, - m_num_elements(map.m_num_elements), - m_max_elements(map.m_max_elements), - m_max_load(map.m_max_load) { - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; i++) { - m_buckets[i] = nullptr; - map_node *m_cur = map.m_buckets[i]; - while (m_cur) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - cur->next = m_buckets[i]; - m_buckets[i] = cur; - m_cur = m_cur->next; - } - } - } - - template - ChainHashMapIterator & - ChainHashMapIterator::operator++() { - const map_node *old = m_current; + template + ChainHashMapIterator & + ChainHashMapIterator::operator++() { + const node_type *old = m_current; m_current = m_current->next; if (!m_current) { size_type i = m_hash_map->hash(old->m_key); - while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); - if (i == m_hash_map->m_max_elements) { + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { m_current = m_hash_map->m_buckets[i]; @@ -1159,23 +1067,23 @@ namespace wlp { return *this; } - template - inline ChainHashMapIterator - ChainHashMapIterator::operator++(int) { + template + inline ChainHashMapIterator + ChainHashMapIterator::operator++(int) { iterator tmp = *this; ++*this; return tmp; } - template - ChainHashMapConstIterator & - ChainHashMapConstIterator::operator++() { - const map_node *old = m_current; + template + ChainHashMapConstIterator & + ChainHashMapConstIterator::operator++() { + const node_type *old = m_current; m_current = m_current->next; if (!m_current) { size_type i = m_hash_map->hash(old->m_key); - while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); - if (i == m_hash_map->m_max_elements) { + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { m_current = m_hash_map->m_buckets[i]; @@ -1184,9 +1092,9 @@ namespace wlp { return *this; } - template - inline ChainHashMapConstIterator - ChainHashMapConstIterator::operator++(int) { + template + inline ChainHashMapConstIterator + ChainHashMapConstIterator::operator++(int) { const_iterator tmp = *this; ++*this; return tmp; diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index 4690e7b7..bbf284b2 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -13,9 +13,9 @@ #ifndef EMBEDDEDCPLUSPLUS_CHAINSET_H #define EMBEDDEDCPLUSPLUS_CHAINSET_H -#include "Hash.h" -#include "Equal.h" #include "ChainMap.h" +#include "Equal.h" +#include "Hash.h" namespace wlp { @@ -27,20 +27,20 @@ namespace wlp { * @tparam Equal the equality function */ template, - class Equal = equals> + class Hash = Hash, + class Equal = Equal> class ChainHashSet { public: - typedef ChainHashSet hash_set; - typedef ChainHashMap hash_map; + typedef ChainHashSet set_type; + typedef ChainHashMap map_type; typedef ChainHashMapIterator iterator; typedef ChainHashMapConstIterator const_iterator; - typedef hash_map::size_type size_type; - typedef hash_map::percent_type percent_type; - typedef hash_map::key_type key_type; + typedef map_type::size_type size_type; + typedef map_type::percent_type percent_type; + typedef map_type::key_type key_type; private: - hash_map m_hash_map; + map_type m_hash_map; public: /** @@ -51,8 +51,23 @@ namespace wlp { */ explicit ChainHashSet( size_type n = 12, - percent_type max_load = 75) : - m_hash_map(n, max_load) {} + percent_type max_load = 75) + : m_hash_map(n, max_load) { + } + + /** + * Disable copy constructor. + */ + ChainHashSet(const set_type &) = delete; + + /** + * Move constructor. + * + * @param set hash set to move + */ + ChainHashSet(set_type &&set) + : m_hash_map(move(set.m_hash_map)) { + } /** * @return the current number of elements in the set @@ -64,8 +79,8 @@ namespace wlp { /** * @return the size of the backing array */ - size_type max_size() const { - return m_hash_map.max_size(); + size_type capacity() const { + return m_hash_map.capacity(); } /** @@ -92,7 +107,7 @@ namespace wlp { /** * @return a pointer to the backing hash map */ - const hash_map *get_backing_hash_map() const { + const map_type *get_backing_hash_map() const { return &m_hash_map; } @@ -212,6 +227,24 @@ namespace wlp { bool erase(key_type &key) { return m_hash_map.erase(key); } + + /** + * Disable copy assignment. + * + * @return reference to this set + */ + set_type &operator=(const set_type &) = delete; + + /** + * Move assignment operator. + * + * @param set hash set to move + * @return reference to this set + */ + set_type &operator=(set_type &&set) { + m_hash_map = move(set.m_hash_map); + return *this; + } }; } diff --git a/lib/wlib/stl/Comparator.h b/lib/wlib/stl/Comparator.h new file mode 100644 index 00000000..978e0f67 --- /dev/null +++ b/lib/wlib/stl/Comparator.h @@ -0,0 +1,169 @@ +/** + * @file Comparator.h + * @brief Comparator implementation for basic types. + * + * @author Jeff Niu + * @date November 9, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_COMPARATOR_H +#define EMBEDDEDCPLUSPLUS_COMPARATOR_H + +#include "Equal.h" + +#include "../Types.h" + +#include "../strings/StaticString.h" + +namespace wlp { + + /** + * String comparison function. Returns 0 for equal strings, + * a positive signed number if @code s1 @endcode is greater + * than @code s2 @endcode and a negative number otherwise. + * + * @param s1 first string to compare + * @param s2 second string to compare + * @return 0 for equal, > 0 for greater, < 0 for less than + */ + inline int8_t str_cmp(const char *s1, const char *s2) { + for (; *s1 == *s2; ++s1, ++s2) { + if (*s1 == 0) { + return 0; + } + } + return (int8_t) (*s1 - *s2); + } + + /** + * Base comparator type uses the basic comparison + * operators. + * + * @tparam T compared type + */ + template + struct Comparator { + bool __lt__(const T &t1, const T &t2) const { + return t1 < t2; + } + + bool __le__(const T &t1, const T &t2) const { + return t1 <= t2; + } + + bool __eq__(const T &t1, const T &t2) const { + return t1 == t2; + } + + bool __ne__(const T &t1, const T &t2) const { + return t1 != t2; + } + + bool __gt__(const T &t1, const T &t2) const { + return t1 > t2; + } + + bool __ge__(const T &t1, const T &t2) const { + return t1 >= t2; + } + }; + + /** + * Reverse comparator flips the semantics for + * greater than and less than comparisons. + * + * @tparam T compared type + */ + template + struct ReverseComparator { + bool __lt__(const T &t1, const T &t2) const { + return t1 > t2; + } + + bool __le__(const T &t1, const T &t2) const { + return t1 >= t2; + } + + bool __eq__(const T &t1, const T &t2) const { + return t1 == t2; + } + + bool __ne__(const T &t1, const T &t2) const { + return t1 != t2; + } + + bool __gt__(const T &t1, const T &t2) const { + return t1 < t2; + } + + bool __ge__(const T &t1, const T &t2) const { + return t1 <= t2; + } + }; + + /** + * Template specialization for C strings. + */ + template<> + struct Comparator { + bool __lt__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) < 0; + } + + bool __le__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) <= 0; + } + + bool __eq__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) == 0; + } + + bool __ne__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) != 0; + } + + bool __gt__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) > 0; + } + + bool __ge__(const char *s1, const char *s2) const { + return str_cmp(s1, s2) >= 0; + } + }; + + /** + * Template specialization for static strings. + * + * @tparam tSize static string size + */ + template + struct Comparator> { + bool __lt__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) < 0; + } + + bool __le__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) <= 0; + } + + bool __eq__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) == 0; + } + + bool __ne__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) != 0; + } + + bool __gt__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) > 0; + } + + bool __ge__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) >= 0; + } + }; + +} + +#endif //EMBEDDEDCPLUSPLUS_COMPARATOR_H diff --git a/lib/wlib/stl/Concept.h b/lib/wlib/stl/Concept.h new file mode 100644 index 00000000..a5bd5206 --- /dev/null +++ b/lib/wlib/stl/Concept.h @@ -0,0 +1,333 @@ +/** + * @file Concept.h + * @brief Concept definitions. + * + * This class is where concept definitions should be located. + * Concepts facilitate C++ polymorphism in the place of + * complex inheritance trees. + * + * @author Jeff Niu + * @date November 9, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H +#define EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H + +#include "Pair.h" +#include "Tmp.h" +#include "TypeTraits.h" + +#include "../Wlib.h" + +/** + * Definitions for a variadic macro that generates + * code to verify whether a specified type has a + * function with a function name, return type, and + * argument types. + */ +#define __HAS_FCN(...) VFUNC(__HAS_FCN, __VA_ARGS__) +#define __HAS_FCN3(TypeName, FcnName, RetType) \ + is_same().FcnName( \ + )), RetType> +#define __HAS_FCN4(TypeName, FcnName, ArgType1, RetType) \ + is_same().FcnName( \ + declval() \ + )), RetType> +#define __HAS_FCN5(TypeName, FcnName, ArgType1, ArgType2, RetType) \ + is_same().FcnName( \ + declval(), \ + declval() \ + )), RetType> +#define __HAS_FCN6(TypeName, FcnName, ArgType1, ArgType2, ArgType3, RetType) \ + is_same().FcnName( \ + declval(), \ + declval(), \ + declval() \ + )), RetType> +#define __HAS_FCN7(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, RetType) \ + is_same().FcnName( \ + declval(), \ + declval(), \ + declval(), \ + declval() \ + )), RetType> +#define __HAS_FCN8(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, RetType) \ + is_same().FcnName( \ + declval(), \ + declval(), \ + declval(), \ + declval(), \ + declval,ArgType5>() \ + )), RetType> + +namespace wlp { + + /** + * Comparator concept defines a type that implements + * the six rich comparison operators for a type. + * + * @tparam C comparator type + * @tparam CmpType the compared type + */ + template + struct comparator_concept { + private: + template + static constexpr auto check(T *) -> typename and_< + __HAS_FCN(const T, __lt__, const Q &, const Q &, bool), + __HAS_FCN(const T, __le__, const Q &, const Q &, bool), + __HAS_FCN(const T, __eq__, const Q &, const Q &, bool), + __HAS_FCN(const T, __ne__, const Q &, const Q &, bool), + __HAS_FCN(const T, __gt__, const Q &, const Q &, bool), + __HAS_FCN(const T, __ge__, const Q &, const Q &, bool) + >::type; + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + /** + * Shorthand method to check whether a class fits + * the defined comparator concept. + * + * @tparam C class to check + * @tparam T desired comparison type + * @return true if the class is a comparator + */ + template + static constexpr bool is_comparator() { + return comparator_concept::value; + } + + /** + * Base case forward iterator is false. + * + * @tparam C candidate forward iterator type + */ + template::value && has_val_type::value> + struct forward_iterator_concept { + static constexpr bool value = false; + }; + + /** + * Forward iterator concept. Defines any iterator over a + * data structure that can be moved forwards through the structure, + * visiting each value in the structure exactly once. + * + * @tparam C forward iterator type + */ + template + struct forward_iterator_concept { + private: + typedef typename C::val_type val_type; + typedef typename C::size_type size_type; + typedef C iterator; + + template + static constexpr auto check(T *) -> typename and_< + typename or_< + __HAS_FCN(const T, operator*, val_type &), + __HAS_FCN(const T, operator*, const val_type &) + >::type, + typename or_< + __HAS_FCN(T, operator->, val_type *), + __HAS_FCN(T, operator->, const val_type *) + >::type, + __HAS_FCN(T, operator++, iterator &), + __HAS_FCN(T, operator++, int, iterator), + __HAS_FCN(const T, operator==, iterator &, bool), + __HAS_FCN(const T, operator==, const iterator &, bool), + __HAS_FCN(const T, operator!=, iterator &, bool), + __HAS_FCN(const T, operator!=, const iterator &, bool), + __HAS_FCN(T, operator=, const iterator &, iterator &), + __HAS_FCN(T, operator=, iterator &&, iterator &) + >::type; + + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + /** + * Shorthand to check whether a class is a forward iterator. + * + * @tparam C candidate forward iterator type + * @return true if the class is a forward iterator + */ + template + static constexpr bool is_forward_iterator() { + return forward_iterator_concept::value; + } + + /** + * Random access iterator base case is false. + * + * @tparam C candidate random access iterator + */ + template::value && has_val_type::value> + struct random_access_iterator_concept { + static constexpr bool value = false; + }; + + /** + * Random access iterator concept. Defines any iterator + * over a random access structure, which can be used to + * access and assign to any element in the structure + * with constant time. + * + * @tparam C random access iterator type + */ + template + struct random_access_iterator_concept { + private: + typedef typename C::val_type val_type; + typedef typename C::size_type size_type; + typedef C iterator; + + template + static constexpr auto check(T *) -> typename and_< + typename or_< + __HAS_FCN(const T, operator*, val_type &), + __HAS_FCN(const T, operator*, const val_type &) + >::type, + typename or_< + __HAS_FCN(const T, operator->, val_type *), + __HAS_FCN(const T, operator->, const val_type *) + >::type, + __HAS_FCN(T, operator++, iterator &), + __HAS_FCN(T, operator++, int, iterator), + __HAS_FCN(T, operator--, iterator &), + __HAS_FCN(T, operator--, int, iterator), + __HAS_FCN(T, operator==, iterator &, bool), + __HAS_FCN(T, operator==, const iterator &, bool), + __HAS_FCN(T, operator!=, iterator &, bool), + __HAS_FCN(T, operator!=, iterator &, bool), + __HAS_FCN(T, operator=, iterator &&, iterator &), + __HAS_FCN(T, operator=, const iterator &, iterator &), + __HAS_FCN(const T, operator+, const size_type &, iterator), + __HAS_FCN(const T, operator+, size_type &&, iterator), + __HAS_FCN(const T, operator-, const size_type &, iterator), + __HAS_FCN(const T, operator-, size_type &&, iterator), + __HAS_FCN(const T, operator-, const iterator &, size_type), + __HAS_FCN(const T, operator-, iterator &&, size_type), + __HAS_FCN(T, operator-=, const size_type &, iterator &), + __HAS_FCN(T, operator-=, size_type &&, iterator &), + __HAS_FCN(T, operator+=, const size_type &, iterator &), + __HAS_FCN(T, operator+=, size_type &&, iterator &) + >::type; + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + /** + * Shorthand to check whether a class is a random + * access iterator. + * + * @tparam C candidate random access iterator + * @return true if the class is a random access iterator + */ + template + static constexpr bool is_random_access_iterator() { + return random_access_iterator_concept::value; + } + + /** + * Map concept base case is false. + * + * @tparam C candidate map type + */ + template::value && + has_val_type::value && + has_size_type::value && + has_iterator::value && + has_const_iterator::value + > + struct map_concept { + static constexpr bool value = false; + }; + + /** + * Map concept. Defines a structure that uniquely associates + * a key to a value, in such a way that the collection of the + * structure's keys contains only unique values, but the collection + * of the structure's values may not be unique. + * + * @tparam C map type + */ + template + struct map_concept { + private: + typedef typename C::key_type key_type; + typedef typename C::val_type val_type; + typedef typename C::size_type size_type; + typedef typename C::iterator iterator; + typedef typename C::const_iterator const_iterator; + typedef C map_type; + + typedef Pair insert_ret_type; + + template + static constexpr auto check(T *) -> typename and_< + __HAS_FCN(const T, size, size_type), + __HAS_FCN(const T, capacity, size_type), + __HAS_FCN(const T, empty, bool), + __HAS_FCN(T, begin, iterator), + __HAS_FCN(T, end, iterator), + __HAS_FCN(const T, begin, const_iterator), + __HAS_FCN(const T, end, const_iterator), + __HAS_FCN(T, clear, void), + __HAS_FCN(T, insert, key_type, val_type, insert_ret_type), + __HAS_FCN(T, insert_or_assign, key_type, val_type, insert_ret_type), + __HAS_FCN(T, erase, iterator &, iterator &), + __HAS_FCN(T, erase, const_iterator &, const_iterator &), + __HAS_FCN(T, erase, key_type &, bool), + __HAS_FCN(T, at, const key_type &, iterator), + __HAS_FCN(const T, at, const key_type &, const_iterator), + __HAS_FCN(const T, contains, const key_type &, bool), + __HAS_FCN(T, find, const key_type &, iterator), + __HAS_FCN(const T, find, const key_type &, const_iterator), + __HAS_FCN(T, operator[], const key_type &, val_type &), + __HAS_FCN(T, operator=, map_type &&, map_type &) + >::type; + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + /** + * Shorthand to check whether a class is a map. + * + * @tparam C candidate map type + * @return true if the class is a map + */ + template + static constexpr bool is_map() { + return map_concept::value; + } + +} + +#endif //EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H diff --git a/lib/wlib/stl/Equal.h b/lib/wlib/stl/Equal.h index 75f15417..7f9b92a5 100644 --- a/lib/wlib/stl/Equal.h +++ b/lib/wlib/stl/Equal.h @@ -10,9 +10,9 @@ #ifndef CORE_STL_EQUAL_H #define CORE_STL_EQUAL_H -#include "Types.h" -#include "WlibConfig.h" -#include "strings/StaticString.h" +#include "../Types.h" + +#include "../strings/StaticString.h" namespace wlp { @@ -22,7 +22,7 @@ namespace wlp { * @tparam Key key type */ template - struct equals { + struct Equal { bool operator()(const Key &key1, const Key &key2) const { return key1 == key2; } @@ -51,21 +51,28 @@ namespace wlp { } template - struct equals > { + struct Equal> { + bool operator()(const StaticString &key1, const StaticString &key2) const { + return static_string_equals(key1, key2); + } + }; + + template + struct Equal> { bool operator()(const StaticString &key1, const StaticString &key2) const { return static_string_equals(key1, key2); } }; - TEMPLATE_NULL - struct equals { + template<> + struct Equal { bool operator()(const char *key1, const char *key2) const { return string_equals(key1, key2); } }; - TEMPLATE_NULL - struct equals { + template<> + struct Equal { bool operator()(const char *key1, const char *key2) const { return string_equals(key1, key2); } diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index d877c637..819c6454 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -14,10 +14,11 @@ #ifndef CORE_STL_HASH_H #define CORE_STL_HASH_H -#include "Types.h" -#include "Wlib.h" -#include "WlibConfig.h" -#include "strings/StaticString.h" +#include "../Types.h" +#include "../Wlib.h" +#include "../WlibConfig.h" + +#include "../strings/StaticString.h" namespace wlp { @@ -29,7 +30,7 @@ namespace wlp { * @tparam IntType the unsigned integer type to return */ template - struct hash { + struct Hash { }; template @@ -51,72 +52,72 @@ namespace wlp { } template - struct hash, IntType> { + struct Hash, IntType> { IntType operator()(StaticString &s) const { return hash_static_string(s); } }; template - struct hash { + struct Hash { IntType operator()(const char *s) const { return hash_string(s); } }; template - struct hash { + struct Hash { IntType operator()(const char *s) const { return hash_string(s); } }; template - struct hash { + struct Hash { IntType operator()(char x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(uint8_t x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(uint16_t x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(uint32_t x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(int8_t x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(int16_t x) const { - return x; + return (IntType) x; } }; template - struct hash { + struct Hash { IntType operator()(int32_t x) const { - return x; + return (IntType) x; } }; diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index 537e537b..a6c1588f 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -5,7 +5,7 @@ * Hash map is implemented using open addressing and linear probing, * based on the assumption that it will be used with good knowledge * of the needed map size. The Hash Map provides the same basic - * functionality as std::unordered_map or std::hash_map. + * functionality as std::unordered_map or std::map_type. * * @author Jeff Niu * @date November 1, 2017 @@ -15,9 +15,11 @@ #ifndef CORE_STL_MAP_H #define CORE_STL_MAP_H -#include "Hash.h" +#include "Utility.h" #include "Equal.h" +#include "Hash.h" #include "Pair.h" + #include "../memory/Allocator.h" #include "../memory/Memory.h" @@ -26,33 +28,33 @@ namespace wlp { // Forward declaration of OpenHashMap template + class Hasher, + class Equals> class OpenHashMap; // Forward declaration of OpenHashMap iterator template + class Hasher, + class Equals> struct OpenHashMapIterator; // Forward declaration of const OpenHashMap iterator template + class Hasher, + class Equals> struct OpenHashMapConstIterator; /** - * Hash map node comprise the elements of a hash map's + * Hasher map node comprise the elements of a hash map's * backing array, containing an element key and corresponding value. * @tparam Key key type * @tparam Val value type */ template struct OpenHashMapNode { - typedef OpenHashMapNode map_node; + typedef OpenHashMapNode node_type; typedef Key key_type; typedef Val val_type; /** @@ -69,7 +71,7 @@ namespace wlp { * @param node node to compare * @return true if the keys and values are equal */ - bool operator==(const map_node &node) const { + bool operator==(const node_type &node) const { return m_key == node.m_key && m_val == node.m_val; } @@ -78,7 +80,7 @@ namespace wlp { * @param node node to compare * @return true if they are equal */ - bool operator==(map_node &node) const { + bool operator==(node_type &node) const { return m_key == node.m_key && m_val == node.m_val; } }; @@ -89,57 +91,66 @@ namespace wlp { * array, returning past-the-end afterwards. * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template + class Hasher, + class Equals> struct OpenHashMapIterator { - typedef OpenHashMap hash_map; - typedef OpenHashMapIterator iterator; - typedef OpenHashMapNode map_node; + typedef OpenHashMap map_type; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapNode node_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; /** * Pointer to the node referenced by this iterator. */ - map_node *m_current; + node_type *m_current; /** * Pointer to the iterated OpenHashMap. */ - hash_map *m_hash_map; + map_type *m_hash_map; /** * Default constructor. */ - OpenHashMapIterator() {} + OpenHashMapIterator() + : m_current(nullptr), + m_hash_map(nullptr) { + } /** * Create an iterator to a OpenHashMap node. * @param node hash map node * @param map parent hash map */ - OpenHashMapIterator(map_node *node, hash_map *map) - : m_current(node), m_hash_map(map) {} + OpenHashMapIterator(node_type *node, map_type *map) + : m_current(node), + m_hash_map(map) { + } /** * Copy constructor for const. * @param it iterator to copy */ OpenHashMapIterator(const iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + : m_current(it.m_current), + m_hash_map(it.m_hash_map) { + } /** * Copy constructor. * @param it iterator to copy */ - OpenHashMapIterator(iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + OpenHashMapIterator(iterator &&it) + : m_current(move(it.m_current)), + m_hash_map(move(it.m_hash_map)) { + } /** * @return reference to the value of the node @@ -226,9 +237,9 @@ namespace wlp { * @param it iterator to copy * @return a reference to this iterator */ - iterator &operator=(iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; + iterator &operator=(iterator &&it) { + m_current = move(it.m_current); + m_hash_map = move(it.m_hash_map); return *this; } }; @@ -241,35 +252,44 @@ namespace wlp { * * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template + class Hasher, + class Equals> struct OpenHashMapConstIterator { - typedef OpenHashMap hash_map; - typedef OpenHashMapConstIterator const_iterator; - typedef OpenHashMapNode map_node; + typedef OpenHashMap map_type; + typedef OpenHashMapConstIterator const_iterator; + typedef OpenHashMapNode node_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; - const map_node *m_current; - const hash_map *m_hash_map; + const node_type *m_current; + const map_type *m_hash_map; - OpenHashMapConstIterator() {} + OpenHashMapConstIterator() + : m_current(nullptr), + m_hash_map(nullptr) { + } - OpenHashMapConstIterator(map_node *node, const hash_map *map) - : m_current(node), m_hash_map(map) {} + OpenHashMapConstIterator(node_type *node, const map_type *map) + : m_current(node), + m_hash_map(map) { + } OpenHashMapConstIterator(const const_iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + : m_current(it.m_current), + m_hash_map(it.m_hash_map) { + } - OpenHashMapConstIterator(const_iterator &it) - : m_current(it.m_current), m_hash_map(it.m_hash_map) {} + OpenHashMapConstIterator(const_iterator &&it) + : m_current(move(it.m_current)), + m_hash_map(move(it.m_hash_map)) { + } const val_type &operator*() const { return m_current->m_val; @@ -305,52 +325,52 @@ namespace wlp { return *this; } - const_iterator &operator=(const_iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; + const_iterator &operator=(const_iterator &&it) { + m_current = move(it.m_current); + m_hash_map = move(it.m_hash_map); return *this; } }; /** - * Hash map implemented using open addressing and linear probing, + * Hasher map implemented using open addressing and linear probing, * in the spirit of std::unordered_map. * @tparam Key key type * @tparam Val value type - * @tparam Hash hash function - * @tparam Equal key equality function + * @tparam Hasher hash function + * @tparam Equals key equality function */ template, - class Equal = equals > + class Hasher = Hash , + class Equals = Equal > class OpenHashMap { public: - typedef OpenHashMap hash_map; - typedef OpenHashMapIterator iterator; - typedef OpenHashMapConstIterator const_iterator; - typedef OpenHashMapNode map_node; + typedef OpenHashMap map_type; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapConstIterator const_iterator; + typedef OpenHashMapNode node_type; typedef Key key_type; typedef Val val_type; - typedef uint16_t size_type; + typedef wlp::size_type size_type; typedef uint8_t percent_type; - friend struct OpenHashMapIterator; - friend struct OpenHashMapConstIterator; + friend struct OpenHashMapIterator; + friend struct OpenHashMapConstIterator; private: /** * Class hash function instance. Used to hash * element keys. */ - Hash m_hash; + Hasher m_hash; /** * Class key equality function. Used to test * equality of element keys. */ - Equal m_equal; + Equals m_equal; /** * Allocator to create memory for hash map nodes. @@ -358,9 +378,9 @@ namespace wlp { Allocator m_node_allocator; /** - * Hash map backing array. + * Hasher map backing array. */ - map_node **m_buckets; + node_type **m_buckets; /** * The current number of elements that have been inserted @@ -370,7 +390,7 @@ namespace wlp { /** * The size of the backing array. */ - size_type m_max_elements; + size_type m_capacity; /** * The load factor in integer percent * before rehashing occurs. This number @@ -389,27 +409,47 @@ namespace wlp { * * @param n initial size of the bucket list; each bucket is initialized to nullptr * @param max_load an integer value denoting the max percent load factory, e.g. 75 = 0.75 - * @param hash hash function for the key type, default is @code wlp::Hash @endcode - * @param equal equality function for the key type, default is @code wlp::Equal @endcode + * @param hash hash function for the key type, default is @code wlp::Hasher @endcode + * @param equal equality function for the key type, default is @code wlp::Equals @endcode */ explicit OpenHashMap( size_type n = 12, percent_type max_load = 75) - : m_hash(Hash()), - m_equal(Equal()), - m_node_allocator{sizeof(map_node), static_cast(n * sizeof(map_node))}, + : m_hash(Hasher()), + m_equal(Equals()), + m_node_allocator{sizeof(node_type), static_cast(n * sizeof(node_type))}, m_num_elements(0), - m_max_elements(n), + m_capacity(n), m_max_load(max_load) { init_buckets(n); if (max_load > 100) { - max_load = 100; + m_max_load = 100; } } - OpenHashMap(const hash_map &map); + /** + * Copy constructor is deleted to prevent + * copying of complex structures. + */ + OpenHashMap(const map_type &) = delete; - OpenHashMap(hash_map &map); + /** + * Move constructor transfers resources from + * rvalue hash map into this hash map. + * @param map map from which to transfer + */ + OpenHashMap(map_type &&map) : + m_hash(move(map.m_hash)), + m_equal(move(map.m_equal)), + m_node_allocator(move(map.m_node_allocator)), + m_buckets(move(map.m_buckets)), + m_num_elements(move(map.m_num_elements)), + m_capacity(move(map.m_capacity)), + m_max_load(move(map.m_max_load)) { + map.m_num_elements = 0; + map.m_capacity = 0; + map.m_buckets = nullptr; + } /** * Destroy the hash map, freeing allocated nodes and @@ -443,7 +483,7 @@ namespace wlp { * @return an index i such that 0 <= i < m_max_elements */ size_type hash(key_type key) const { - return m_hash(key) % m_max_elements; + return m_hash(key) % m_capacity; } /** @@ -471,8 +511,8 @@ namespace wlp { /** * @return the current size of the backing array */ - size_type max_size() const { - return m_max_elements; + size_type capacity() const { + return m_capacity; } /** @@ -506,7 +546,7 @@ namespace wlp { if (m_num_elements == 0) { return end(); } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { return iterator(m_buckets[i], this); } @@ -522,14 +562,14 @@ namespace wlp { } /** - * @see OpenHashMap::begin() + * @see OpenHashMap::begin() * @return a constant iterator to the first element */ const_iterator begin() const { if (m_num_elements == 0) { return end(); } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { return const_iterator(m_buckets[i], this); } @@ -538,7 +578,7 @@ namespace wlp { } /** - * @see OpenHashMap::end() + * @see OpenHashMap::end() * @return a constant pass-the-end iterator */ const_iterator end() const { @@ -575,6 +615,40 @@ namespace wlp { */ Pair insert_or_assign(key_type key, val_type val); + /** + * Erase the element from the map pointed to by the provided + * iterator. Be aware that erasure operations on an openly + * addressed hash map will trigger a rehash and invalidate + * all iterators other than the return value. + * @param pos iterator pointing to the element to erase + * @return iterator to the next element in the map or end + */ + iterator &erase(iterator &pos); + + /** + * Erase the element from the map pointed to by the provided + * const iterator. Be aware that erasure operations on an openly + * addressed hash map will trigger a rehash and invalidate + * all iterators other than the return value. + * @param pos const iterator pointing to the element to erase + * @return const iterator to the next element in the map or end + */ + const_iterator &erase(const_iterator &pos); + + /** + * Erase the element from the map with the provided key, if such + * an element exists. Be aware that if erasure if performed, the + * hash map will undergo a rehash. + * + * @pre If frequency use of erase operations is needed, one is + * recommended to use @code ChainHashMap @encode or a + * tree-based implementation. + * + * @param key the key whose corresponding element to erase + * @return true if an element was erased + */ + bool erase(key_type &key); + /** * Returns the value corresponding to a provided key. * @param key the key for which to find the value @@ -584,7 +658,7 @@ namespace wlp { iterator at(const key_type &key); /** - * @see OpenHashMap::at() + * @see OpenHashMap::at() * @param key key for which to find the value * @return the mapped value * @throws KeyException if the key does not exist @@ -607,7 +681,7 @@ namespace wlp { iterator find(const key_type &key); /** - * @see OpenHashMap::find() + * @see OpenHashMap::find() * @param key the key to map * @return a const iterator to the element mapped by the key */ @@ -624,48 +698,47 @@ namespace wlp { val_type &operator[](const key_type &key); /** - * Assignment operator performs a deep copy of the - * contents of the map. Therefore, pass by reference - * or by pointer value is generally desired. - * @param map map to copy - * @return a reference to this map + * Copy assignment operators are disabled. + * @return hash map reference */ - hash_map &operator=(const hash_map &map); + map_type &operator=(const map_type &) = delete; /** - * Assignment operator for non const. - * @param map map to copy - * @return a reference to this map + * Move assignment operator. Assigned hash map + * will have its resources transferred into this + * hash map. Existing resources will be released. + * @param map map to move + * @return reference to this map */ - hash_map &operator=(hash_map &map); + map_type &operator=(map_type &&map); }; - template - void OpenHashMap::init_buckets(OpenHashMap::size_type n) { - m_buckets = static_cast(memory_alloc(n * sizeof(map_node *))); + template + void OpenHashMap::init_buckets(OpenHashMap::size_type n) { + m_buckets = static_cast(memory_alloc(n * sizeof(node_type *))); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } } - template - void OpenHashMap::ensure_capacity() { - if (m_num_elements * 100 < m_max_load * m_max_elements) { + template + void OpenHashMap::ensure_capacity() { + if (m_num_elements * 100 < m_max_load * m_capacity) { return; } - size_type new_max = static_cast(m_max_elements * 2); - map_node **new_buckets = static_cast(memory_alloc(new_max * sizeof(map_node *))); - for (size_type i = 0; i < new_max; ++i) { + size_type new_capacity = static_cast(m_capacity * 2); + node_type **new_buckets = static_cast(memory_alloc(new_capacity * sizeof(node_type *))); + for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } - for (size_type i = 0; i < m_max_elements; ++i) { + for (size_type i = 0; i < m_capacity; ++i) { if (!m_buckets[i]) { continue; } - map_node *node = m_buckets[i]; - size_type k = bucket_index(node->m_key, new_max); + node_type *node = m_buckets[i]; + size_type k = bucket_index(node->m_key, new_capacity); while (new_buckets[k]) { - if (++k >= new_max) { + if (++k >= new_capacity) { k = 0; } } @@ -673,12 +746,12 @@ namespace wlp { } memory_free(m_buckets); m_buckets = new_buckets; - m_max_elements = new_max; + m_capacity = new_capacity; } - template - void OpenHashMap::clear() noexcept { - for (size_type i = 0; i < m_max_elements; ++i) { + template + void OpenHashMap::clear() noexcept { + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { m_node_allocator.Deallocate(m_buckets[i]); m_buckets[i] = nullptr; @@ -687,13 +760,13 @@ namespace wlp { m_num_elements = 0; } - template - Pair::iterator, bool> - OpenHashMap::insert(key_type key, val_type val) { + template + Pair::iterator, bool> + OpenHashMap::insert(key_type key, val_type val) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -701,7 +774,7 @@ namespace wlp { return Pair(iterator(m_buckets[i], this), false); } else { ++m_num_elements; - map_node *node = static_cast(m_node_allocator.Allocate()); + node_type *node = static_cast(m_node_allocator.Allocate()); node->m_key = key; node->m_val = val; m_buckets[i] = node; @@ -709,13 +782,13 @@ namespace wlp { } }; - template - Pair::iterator, bool> - OpenHashMap::insert_or_assign(key_type key, val_type val) { + template + Pair::iterator, bool> + OpenHashMap::insert_or_assign(key_type key, val_type val) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -724,7 +797,7 @@ namespace wlp { return Pair(iterator(m_buckets[i], this), false); } else { ++m_num_elements; - map_node *node = static_cast(m_node_allocator.Allocate()); + node_type *node = static_cast(m_node_allocator.Allocate()); node->m_key = key; node->m_val = val; m_buckets[i] = node; @@ -732,12 +805,94 @@ namespace wlp { } }; - template - typename OpenHashMap::iterator - OpenHashMap::at(const key_type &key) { + template + typename OpenHashMap::iterator & + OpenHashMap::erase(iterator &pos) { + const node_type *cur_node = pos.m_current; + if (!cur_node || pos.m_hash_map != this) { + pos.m_current = nullptr; + return pos; + } + size_type i = hash(cur_node->m_key); + while (m_buckets[i] && !m_equal(cur_node->m_key, m_buckets[i]->m_key)) { + if (++i >= m_capacity) { + i = 0; + } + } + if (!m_buckets[i]) { + pos.m_current = nullptr; + return pos; + } + --m_num_elements; + m_node_allocator.Deallocate(m_buckets[i]); + m_buckets[i] = nullptr; + while (++i < m_capacity && !m_buckets[i]); + node_type *next_node = i >= m_capacity ? nullptr : m_buckets[i]; + node_type **new_buckets = static_cast(memory_alloc(m_capacity * sizeof(node_type *))); + for (size_type k = 0; k < m_capacity; k++) { + new_buckets[k] = nullptr; + } + for (size_type k = 0; k < m_capacity; k++) { + if (!m_buckets[k]) { + continue; + } + node_type *node = m_buckets[k]; + size_type j = hash(node->m_key); + while (new_buckets[j]) { + if (++j >= m_capacity) { + j = 0; + } + } + new_buckets[j] = node; + } + memory_free(m_buckets); + m_buckets = new_buckets; + pos.m_current = next_node; + return pos; + } + + template + bool OpenHashMap::erase(key_type &key) { + size_type i = hash(key); + while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { + if (++i >= m_capacity) { + i = 0; + } + } + if (!m_buckets[i]) { + return false; + } + --m_num_elements; + m_node_allocator.Deallocate(m_buckets[i]); + m_buckets[i] = nullptr; + node_type **new_buckets = static_cast(memory_alloc(m_capacity * sizeof(node_type *))); + for (size_type k = 0; k < m_capacity; k++) { + new_buckets[k] = nullptr; + } + for (size_type k = 0; k < m_capacity; k++) { + if (!m_buckets[k]) { + continue; + } + node_type *node = m_buckets[k]; + size_type j = hash(node->m_key); + while (new_buckets[j]) { + if (++j >= m_capacity) { + j = 0; + } + } + new_buckets[j] = node; + } + memory_free(m_buckets); + m_buckets = new_buckets; + return true; + } + + template + typename OpenHashMap::iterator + OpenHashMap::at(const key_type &key) { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -748,12 +903,12 @@ namespace wlp { } } - template - typename OpenHashMap::const_iterator - OpenHashMap::at(const key_type &key) const { + template + typename OpenHashMap::const_iterator + OpenHashMap::at(const key_type &key) const { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -764,27 +919,27 @@ namespace wlp { } } - template - bool OpenHashMap::contains(const key_type &key) const { + template + bool OpenHashMap::contains(const key_type &key) const { size_type i = hash(key); while (m_buckets[i]) { if (m_equal(key, m_buckets[i]->m_key)) { return true; } - if (++i > +m_max_elements) { + if (++i > +m_capacity) { i = 0; } } return false; } - template - typename OpenHashMap::val_type & - OpenHashMap::operator[](const key_type &key) { + template + typename OpenHashMap::val_type & + OpenHashMap::operator[](const key_type &key) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -792,7 +947,7 @@ namespace wlp { return m_buckets[i]->m_val; } else { ++m_num_elements; - map_node *node = static_cast(m_node_allocator.Allocate()); + node_type *node = static_cast(m_node_allocator.Allocate()); node->m_key = key; node->m_val = val_type(); m_buckets[i] = node; @@ -800,12 +955,12 @@ namespace wlp { } } - template - typename OpenHashMap::iterator - OpenHashMap::find(const key_type &key) { + template + typename OpenHashMap::iterator + OpenHashMap::find(const key_type &key) { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -816,12 +971,12 @@ namespace wlp { } } - template - typename OpenHashMap::const_iterator - OpenHashMap::find(const key_type &key) const { + template + typename OpenHashMap::const_iterator + OpenHashMap::find(const key_type &key) const { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_max_elements) { + if (++i >= m_capacity) { i = 0; } } @@ -832,9 +987,12 @@ namespace wlp { } } - template - OpenHashMap::~OpenHashMap() { - for (size_type i = 0; i < m_max_elements; ++i) { + template + OpenHashMap::~OpenHashMap() { + if (!m_buckets) { + return; + } + for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { m_node_allocator.Deallocate(m_buckets[i]); m_buckets[i] = nullptr; @@ -844,109 +1002,33 @@ namespace wlp { m_buckets = nullptr; } - template - OpenHashMap & - OpenHashMap::operator=(const OpenHashMap &map) { + template + OpenHashMap & + OpenHashMap::operator=(OpenHashMap &&map) { clear(); memory_free(m_buckets); - m_hash = map.m_hash; - m_equal = map.m_equal; - m_max_elements = map.m_max_elements; - m_max_load = map.m_max_load; - m_num_elements = map.m_num_elements; - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; ++i) { - if (map.m_buckets[i]) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - map_node *m_cur = map.m_buckets[i]; - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - m_buckets[i] = cur; - } else { - m_buckets[i] = nullptr; - } - } - return *this; - } - - template - OpenHashMap & - OpenHashMap::operator=(OpenHashMap &map) { - clear(); - memory_free(m_buckets); - m_hash = map.m_hash; - m_equal = map.m_equal; - m_max_elements = map.m_max_elements; - m_max_load = map.m_max_load; - m_num_elements = map.m_num_elements; - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; ++i) { - if (map.m_buckets[i]) { - map_node *cur = static_cast(m_node_allocator.Allocate()); - map_node *m_cur = map.m_buckets[i]; - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - m_buckets[i] = cur; - } else { - m_buckets[i] = nullptr; - } - } + m_node_allocator = move(map.m_node_allocator); + m_capacity = move(map.m_capacity); + m_max_load = move(map.m_max_load); + m_num_elements = move(map.m_num_elements); + m_buckets = move(map.m_buckets); + map.m_capacity = 0; + map.m_num_elements = 0; + map.m_buckets = nullptr; return *this; } - template - OpenHashMap::OpenHashMap(const hash_map &map) : - m_hash(map.m_hash), - m_equal(map.m_equal), - m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, - m_num_elements(map.m_num_elements), - m_max_elements(map.m_max_elements), - m_max_load(map.m_max_load) { - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; i++) { - m_buckets[i] = nullptr; - if (map.m_buckets[i]) { - map_node *m_cur = map.m_buckets[i]; - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - m_buckets[i] = cur; - } - } - } - - template - OpenHashMap::OpenHashMap(hash_map &map) : - m_hash(map.m_hash), - m_equal(map.m_equal), - m_node_allocator{sizeof(map_node), static_cast(map.m_max_elements * sizeof(map_node))}, - m_num_elements(map.m_num_elements), - m_max_elements(map.m_max_elements), - m_max_load(map.m_max_load) { - m_buckets = static_cast(memory_alloc(map.m_max_elements * sizeof(map_node *))); - for (size_type i = 0; i < map.m_max_elements; i++) { - m_buckets[i] = nullptr; - if (map.m_buckets[i]) { - map_node *m_cur = map.m_buckets[i]; - map_node *cur = static_cast(m_node_allocator.Allocate()); - cur->m_key = m_cur->m_key; - cur->m_val = m_cur->m_val; - m_buckets[i] = cur; - } - } - } - - template - OpenHashMapIterator & - OpenHashMapIterator::operator++() { + template + OpenHashMapIterator & + OpenHashMapIterator::operator++() { size_type i = m_hash_map->hash(m_current->m_key); while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { - if (++i >= m_hash_map->m_max_elements) { + if (++i >= m_hash_map->m_capacity) { i = 0; } } - while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); - if (i == m_hash_map->m_max_elements) { + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { m_current = m_hash_map->m_buckets[i]; @@ -954,25 +1036,25 @@ namespace wlp { return *this; } - template - inline OpenHashMapIterator - OpenHashMapIterator::operator++(int) { + template + inline OpenHashMapIterator + OpenHashMapIterator::operator++(int) { iterator tmp = *this; ++*this; return tmp; } - template - OpenHashMapConstIterator & - OpenHashMapConstIterator::operator++() { + template + OpenHashMapConstIterator & + OpenHashMapConstIterator::operator++() { size_type i = m_hash_map->hash(m_current->m_key); while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { - if (++i >= m_hash_map->m_max_elements) { + if (++i >= m_hash_map->m_capacity) { i = 0; } } - while (++i < m_hash_map->m_max_elements && !m_hash_map->m_buckets[i]); - if (i == m_hash_map->m_max_elements) { + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { m_current = m_hash_map->m_buckets[i]; @@ -980,9 +1062,9 @@ namespace wlp { return *this; } - template - inline OpenHashMapConstIterator - OpenHashMapConstIterator::operator++(int) { + template + inline OpenHashMapConstIterator + OpenHashMapConstIterator::operator++(int) { const_iterator tmp = *this; ++*this; return tmp; diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index 0f5faa72..41b7bcc9 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -13,8 +13,8 @@ #ifndef EMBEDDEDCPLUSPLUS_OPENSET_H #define EMBEDDEDCPLUSPLUS_OPENSET_H -#include "Hash.h" #include "Equal.h" +#include "Hash.h" #include "OpenMap.h" namespace wlp { @@ -28,23 +28,23 @@ namespace wlp { * @tparam Equal test for equality function of the stored elements */ template, - class Equal = equals> + class Hash = Hash, + class Equal = Equal> class OpenHashSet { public: typedef OpenHashSet hash_set; - typedef OpenHashMap hash_map; + typedef OpenHashMap map_type; typedef OpenHashMapIterator iterator; typedef OpenHashMapConstIterator const_iterator; - typedef hash_map::size_type size_type; - typedef hash_map::percent_type percent_type; - typedef hash_map::key_type key_type; + typedef map_type::size_type size_type; + typedef map_type::percent_type percent_type; + typedef map_type::key_type key_type; private: /** * The backing hash map. */ - hash_map m_hash_map; + map_type m_hash_map; public: /** @@ -58,7 +58,22 @@ namespace wlp { explicit OpenHashSet( size_type n = 12, percent_type max_load = 75) : - m_hash_map(n, max_load) {} + m_hash_map(n, max_load) { + } + + /** + * Disable copy constructor. + */ + OpenHashSet(const hash_set &) = delete; + + /** + * Move constructor. + * + * @param set hash set to move + */ + OpenHashSet(hash_set &&set) + : m_hash_map(move(set.m_hash_map)) { + } /** * @return the current number of elements in the set @@ -70,8 +85,8 @@ namespace wlp { /** * @return the size of the backing array */ - size_type max_size() const { - return m_hash_map.max_size(); + size_type capacity() const { + return m_hash_map.capacity(); } /** @@ -98,7 +113,7 @@ namespace wlp { /** * @return a pointer to the backing hash map */ - const hash_map *get_backing_hash_map() const { + const map_type *get_backing_hash_map() const { return &m_hash_map; } @@ -186,6 +201,56 @@ namespace wlp { const_iterator find(const key_type &key) const { return m_hash_map.find(key); } + + /** + * Erase the element in the set pointed to by + * the iterator. + * + * @param pos iterator whose element to erase + * @return iterator to the next element in the set + */ + iterator &erase(iterator &pos) { + return m_hash_map.erase(pos); + } + + /** + * Erase the element in the set pointed to by + * the iterator. + * + * @param pos iterator whose element to erase + * @return iterator to the next element in the set + */ + const_iterator &erase(const_iterator &pos) { + return m_hash_map.erase(pos); + } + + /** + * Remove an element from the set. + * + * @param key the element to remove + * @return true if removal occured + */ + bool erase(key_type &key) { + return m_hash_map.erase(key); + } + + /** + * Disable copy assignment. + * + * @return reference to this set + */ + hash_set &operator=(const hash_set &) = delete; + + /** + * Move assignment operator. + * + * @param set hash set to move + * @return reference to this set + */ + hash_set &operator=(hash_set &&set) { + m_hash_map = move(set.m_hash_map); + return *this; + } }; } diff --git a/lib/wlib/stl/Pair.h b/lib/wlib/stl/Pair.h index 7944acc0..8a6c804d 100644 --- a/lib/wlib/stl/Pair.h +++ b/lib/wlib/stl/Pair.h @@ -16,6 +16,8 @@ #ifndef EMBEDDEDTESTS_PAIR_H #define EMBEDDEDTESTS_PAIR_H +#include "Utility.h" + namespace wlp { template @@ -24,7 +26,6 @@ namespace wlp { typedef Second second_type; typedef Pair pair; - private: /** * First element in the pair. */ @@ -34,30 +35,64 @@ namespace wlp { */ second_type m_second; - public: /** * Default constructor creates an empty pair. */ Pair() {}; + /** + * Copy constructor for const reference. + * @param pair pair to copy + */ + Pair(pair const &pair) + : m_first(pair.m_first), + m_second(pair.m_second) { + } + + /** + * Copy constructor for R-value. + * @param pair temporary pair to copy + */ + Pair(pair &&pair) + : m_first(move(pair.m_first)), + m_second(move(pair.m_second)) { + } + /** * Create a pair from two values of first type and second type. * @param first first type value * @param second second type value */ - Pair(first_type first, second_type second) : m_first(first), m_second(second) {} + Pair(first_type first, second_type second) + : m_first(first), + m_second(second) { + } /** * @return the first value in the pair */ - first_type first() { + first_type &first() { return m_first; } /** * @return the second value in the pair */ - second_type second() { + second_type &second() { + return m_second; + } + + /** + * @return unmodifiable first value in the pair + */ + first_type const &first() const { + return m_first; + } + + /** + * @return unmodifiable second value in the pair + */ + second_type const &second() const { return m_second; } @@ -73,13 +108,13 @@ namespace wlp { } /** - * Assignment operator copies the first and second values. - * @param p pair to copy + * R-value assignment operator. + * @param p temporary pair to copy * @return a reference to this pair */ - pair &operator=(pair &p) { - m_first = p.m_first; - m_second = p.m_second; + pair &operator=(pair &&p) { + m_first = move(p.m_first); + m_second = move(p.m_second); return *this; } diff --git a/lib/wlib/stl/Tmp.h b/lib/wlib/stl/Tmp.h new file mode 100644 index 00000000..5eb4e285 --- /dev/null +++ b/lib/wlib/stl/Tmp.h @@ -0,0 +1,714 @@ +/** + * @file Tmp.h + * @brief Template helper types, structs, and metafunctions + * + * This class implements helper items that facilitate template + * metaprogramming and functions that enable move semantics. + * + * @author Jeff Niu + * @date November 6, 2017 + * @bug No known bugs + */ + +/* + * TODO: Robust is_function, and_, recursive or_ + */ + +#ifndef EMBEDDEDCPLUSPLUS_TMP_H +#define EMBEDDEDCPLUSPLUS_TMP_H + +#include "../Types.h" + +namespace wlp { + + /** + * This function consumes, and does nothing with, the return + * values of parameter pack expanded function calls. This function + * enables individual functions to be called on each parameter pack + * item by consuming the expansion. + * + * @tparam Types parameter pack of arbitrary return types + * which may be void + */ + template + void swallow(Types &&...) { + } + + /** + * Forward declaration of @code is_function @endcode. + */ + template + struct is_function; + + /** + * Helper type that contains a single value of a certain type. + * @tparam T value type + * @tparam t contained value + */ + template + struct integral_constant { + static constexpr T value = t; + typedef T value_type; + typedef integral_constant type; + + constexpr operator value_type() const { + return value; + } + + constexpr value_type operator()() const { + return value; + } + }; + + /** + * Constant expression shorthand. + * @tparam T value type + * @tparam t contained value + */ + template + constexpr T integral_constant::value; + + /** + * Container for @code true @endcode. + */ + typedef integral_constant true_type; + /** + * Container for @code false @endcode. + */ + typedef integral_constant false_type; + + /** + * A boolean constant contains a value that is + * either true or false. + */ + template + using boolean_constant = integral_constant; + + /** + * Building block type for boolean metafunctions. + * This is the undefined base declaration. + */ + template + struct conditional; + + /** + * The conditional contains a true type if the specified + * condition is true. + * @tparam Condition true in the case + * @tparam IfTrue consequence of truth + * @tparam IfFalse consequence of false + */ + template + struct conditional { + typedef IfTrue type; + }; + + /** + * Template specialization for the false case. + * @tparam IfTrue consequence of truth + * @tparam IfFalse consequence of false + */ + template + struct conditional { + typedef IfFalse type; + }; + + /** + * Remove the const modifier from types for + * type comparisons only. This is the base case + * template class. + * @tparam T const type + */ + template + struct remove_const { + typedef T type; + }; + + /** + * Remove the const modifier from a type. + * Template specialization for const types. + * @tparam T const type + */ + template + struct remove_const { + typedef T type; + }; + + /** + * Base declaration for a boolean or. + * @tparam ... ignored parameteres + */ + template + struct or_; + + /** + * Template specialization; the or with + * no boolean operands is false. + */ + template<> + struct or_<> + : public false_type { + }; + + /** + * Template specialization for unary or. + * @tparam B1 boolean condition + */ + template + struct or_ + : public B1 { + }; + + /** + * Template specialization of binary or. + * @tparam B1 first boolean condition + * @tparam B2 second boolean condition + */ + template + struct or_ + : public conditional::type { + }; + + template + struct or_ + : public conditional>::type { + }; + + template + struct and_; + + template<> + struct and_<> + : public true_type { + }; + + template + struct and_ + : public B1 { + }; + + template + struct and_ + : public conditional::type { + }; + + template + struct and_ + : public conditional, B1>::type { + }; + + /** + * This type inverts the boolean value of another boolean + * constant type. + * @tparam T boolean constant type + */ + template + struct not_ + : public integral_constant { + }; + + /** + * Void checking type. Base case is false. + */ + template + struct __void__ + : public false_type { + }; + + /** + * Void checking type template specialization + * for void types is true. + */ + template<> + struct __void__ + : public true_type { + }; + + /** + * Metafunction checks if a type is void. + * @tparam T type to check + */ + template + struct is_void + : public __void__::type>::type { + }; + + /** + * L-value checking type. Base case is false. + */ + template + struct is_lvalue_reference + : public false_type { + }; + + /** + * L-value checking type template specialization + * for lvalues, which is of true type. + * @tparam T + */ + template + struct is_lvalue_reference + : public true_type { + }; + + /** + * R-value checking type. Base case is false. + */ + template + struct is_rvalue_reference + : public false_type { + }; + + /** + * R-value checking type template specialization for rvalues, + * which is of true type. + * @tparam T + */ + template + struct is_rvalue_reference + : public true_type { + }; + + /** + * Checks whether a type is either an rvalue or lvalue. + * @tparam T type to check + */ + template + struct is_reference + : public or_, is_rvalue_reference>::type { + }; + + /** + * Remove reference type. Base case for non-reference types. + * @tparam T non-reference type + */ + template + struct remove_reference { + typedef T type; + }; + + /** + * Remove reference type. Template specialization for lvalues. + * @tparam T lvalue type + */ + template + struct remove_reference { + typedef T type; + }; + + /** + * Remove reference type. Template specialization for rvalues. + * @tparam T rvalue type + */ + template + struct remove_reference { + typedef T type; + }; + + /** + * Shorthand for remove reference type. + */ + template + using remove_reference_type = typename remove_reference::type; + + /** + * Remove extent type strips the type from + * an array type. Base case for regular types. + * @tparam T non-array type + */ + template + struct remove_extent { + typedef T type; + }; + + /** + * Remove extent type template specialization for + * fixed-sized array types. + * @tparam T non-array type + * @tparam size array size + */ + template + struct remove_extent { + typedef T type; + }; + + /** + * Remove extent type template specialization + * for arrays whose sizes are not known. + * @tparam T non-array type + */ + template + struct remove_extent { + typedef T type; + }; + + /** + * Metafunction checks whether a type is an object. + * This returns true for primitives. + * @tparam T type to check if object + */ + template + struct is_object + : public not_, is_reference, is_void>>::type { + }; + + /** + * Metafunction checks whether a reference to + * the provided type is legal. + * @tparam T type to check + */ + template + struct is_referenceable + : public or_, is_reference>::type { + }; + + /** + * Template specialization to check if the + * return type of a function type and arguments type + * is referenceable. + * @tparam Result function type + * @tparam Arguments argument type pack + */ + template + struct is_referenceable + : public true_type { + }; + + /** + * Add pointer to a type. Template specialization for + * pointer types. + * @tparam T pointer type + */ + template, is_void>::value> + struct __lpointer__ { + typedef T type; + }; + + /** + * Add pointer type. Template specialization + * for non-pointer types. + * @tparam T non-pointer type. + */ + template + struct __lpointer__ { + typedef typename remove_reference::type *type; + }; + + /** + * Add a pointer to a type. + * @tparam T type to add pointer + */ + template + struct add_pointer + : public __lpointer__ { + }; + + /** + * Checks if a type is an array. Base case is false. + */ + template + struct is_array + : public false_type { + }; + + /** + * Checks if a type is an array. Template specialization + * for fixed-size arrays is true + * @tparam T non-array type + * @tparam _Size array size + */ + template + struct is_array + : public true_type { + }; + + /** + * Checks if a type is an array. Template specialization + * for arrays of unknown sizes. + * @tparam T non-array type + */ + template + struct is_array + : public true_type { + }; + + /** + * Decay metafunction strips pointers and references + * from a type, allowing comparisons of the + * pure types. + * @tparam U any type with any modifiers + * @tparam IsArray whether the type is an array + * @tparam IsFunction whether the type is a function + */ + template::value, + bool IsFunction = is_function::value> + struct __decay__; + + /** + * Case neither array nor function. + * @tparam U any type + */ + template + struct __decay__ { + typedef typename remove_const::type type; + }; + + /** + * Case is array. + * @tparam U array type + */ + template + struct __decay__ { + typedef typename remove_extent::type *type; + }; + + /** + * Case is function. + * @tparam U function type + */ + template + struct __decay__ { + typedef typename add_pointer::type type; + }; + + /** + * Decay struct strips reference and pointers + * from a type. + * @tparam T type to obtain pure type + */ + template + class decay { + typedef typename remove_reference::type remove_type; + + public: + typedef typename __decay__::type type; + }; + + /** + * Shorthand for type decay. + * @tparam T type to strip + */ + template + using decay_type = typename decay::type; + + /** + * Enable if is a template helper that can be used + * to disable visibility of functions and even classes + * via overload resolution. Base case disables. + * @tparam T + */ + template + struct enable_if { + }; + + /** + * Template specialization for the true case, + * which enables the template. + * @tparam T + */ + template + struct enable_if { + typedef T type; + }; + + /** + * Is function base case is false. + */ + template + struct is_function + : public false_type { + }; + + /** + * Is function for argument pack is true. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is function for argument lvalue pack is true. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is function for argument rvalue pack is true. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is function for const type pack is true. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is function for const lvalue type pack. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is function for const rvalue type pack. + * @tparam Result function type + * @tparam ArgTypes argument types + */ + template + struct is_function + : public true_type { + }; + + /** + * Is same checks whether two provided types are + * the same type. Base case is false. + */ + template + struct is_same + : public false_type { + }; + + /** + * Is same template specialization for the same types is true. + * @tparam T + */ + template + struct is_same + : public true_type { + }; + + /** + * Recursive function applies an operator to each + * type in a type pack. + * @return false in the base case + */ + template class> + constexpr bool is_any_of() { + return false; + } + + /** + * Recursive function applies a boolean operator + * type to each value in the type pack + * @tparam Op a boolean operator type with a bool value + * @tparam Head head type + * @tparam Tail tail types + * @return true if the operator is satisfied by any of the types + */ + template class Op, typename Head, typename... Tail> + constexpr bool is_any_of() { + return Op::value || is_any_of(); + }; + + /** + * Add lvalue reference helper. + * + * @tparam T existing lvalue type + */ + template::value> + struct __lvalue__ { + typedef T type; + }; + + /** + * Add lvalue reference helper. + * + * @tparam T non reference type + */ + template + struct __lvalue__ { + typedef T &type; + }; + + /** + * Transform a type such that it is the lvalue reference + * to that type. + * + * @tparam T type to add lvalue reference + */ + template + struct add_lvalue_reference : public __lvalue__ { + }; + + /** + * Add rvalue reference helper + * + * @tparam T existing rvalue type + */ + template::value> + struct __rvalue__ { + typedef T type; + }; + + /** + * Add rvalue reference helper. + * + * @tparam T non reference type + */ + template + struct __rvalue__ { + typedef T &&type; + }; + + /** + * Transform a type such that it is the rvalue reference + * to that type. + * + * @tparam T type to add rvalue reference + */ + template + struct add_rvalue_reference : public __rvalue__ { + }; + + /** + * Declared value helper. + * + * @tparam T type to obtain the declared value + */ + template + struct __declval__ { + static const bool __stop__ = false; + + static typename add_rvalue_reference::type __delegate__(); + }; + + /** + * Obtain a static declared value to the specified type. + * This function should only be used in metafunction contexts + * as the actual return value is undefined. This is usually + * used in conjunction with @code decltype @endcode build-in function + * to obtain the type of an unknown type. + * + * @tparam T type whose value to obtain + * @return a value of the type + */ + template + inline typename add_rvalue_reference::type declval() noexcept { + static_assert(__declval__::__stop__, "declval is not callable"); + return __declval__::__delegate__(); + } + +} + +#endif //EMBEDDEDCPLUSPLUS_TMP_H diff --git a/lib/wlib/stl/Tuple.h b/lib/wlib/stl/Tuple.h new file mode 100644 index 00000000..55995f08 --- /dev/null +++ b/lib/wlib/stl/Tuple.h @@ -0,0 +1,742 @@ +/** + * @file Tuple.h + * @brief Template oriented tuple implementation. + * + * The template oriented tuple implementation is flexible and + * performant and resolves at compile time, resulting in + * good runtime performance. + * + * @author Jeff Niu + * @date November 5, 2017 + * @bug No known bugs + */ + +/* + * TODO: implement a better tuple concatenation function, template specializations for Tuple, copy ctors + */ + +#ifndef EMBEDDEDCPLUSPLUS_TUPLE_H +#define EMBEDDEDCPLUSPLUS_TUPLE_H + +#include "Pair.h" +#include "Tmp.h" + +namespace wlp { + + /** + * Tuple is a flat implementation so that compile-time template + * instantiations are not recursive. The tuple implementation will + * inherit from an element type that contains the type index + * and the held type. The index is needed to discern multiple types. + * @tparam I the element index + * @tparam T the tuple element type + */ + template + struct TupleElement { + /** + * Value contained in this tuple element. + */ + T value; + + /** + * Assignment operator to another tuple type. This operator + * is only enabled for tuple elements at the same index + * and of the same type. + * @tparam J assigned tuple element index + * @tparam Q assigned tuple element type + * @param te tuple element to assign + * @return a reference to this element + */ + template, decay_type>::value + >::type> + TupleElement &operator=(TupleElement const &te) { + value = te.value; + return *this; + } + + /** + * Move assignment operator to another tuple type. + * @tparam J assigned tuple element index + * @tparam Q assigned tuple element type + * @param te tuple element to assign + * @return a reference to this element + */ + template, decay_type>::value + >::type> + TupleElement &operator=(TupleElement &&te) { + value = move(te.value); + return *this; + }; + + /** + * Universal constructor sets the contained + * value in the element + * @tparam U value type + * @param u value + */ + template + explicit TupleElement(U &&u) : value(forward(u)) { + } + + }; + + /** + * An index sequence is a container object for + * an index pack and is needed to expand the index + * pack to instantiate tuples. + * @tparam Indices the index pack to expand + */ + template + struct IndexSequence { + using type = IndexSequence; + }; + + /** + * This type is used in the creation of an index + * sequence and appends an index to the sequence. + * This is the undefined base type. + * @tparam I index to append + * @tparam Sequence index sequence to append to + */ + template + struct AppendIndexSequence; + + /** + * Append an index to a index sequence pack. + * This template specialization creates an + * index sequence with the appended index + * and the existing index sequence. + * @tparam I index to append + * @tparam Indices existing index pack + */ + template + struct AppendIndexSequence> + : IndexSequence { + }; + + /** + * Recursive type instantiates an index sequence + * with value up to N. + * @tparam N the current index to append + */ + template + struct MakeIndexSequence + : AppendIndexSequence::type>::type { + }; + + /** + * Base case type creates an index sequence + * with one value. + */ + template<> + struct MakeIndexSequence<1> + : IndexSequence<0> { + }; + + /** + * Recursive type contains the type in a type pack + * at a certain index. + * @tparam I the index to get the type + * @tparam Head the head of the type pack + * @tparam Tail the remaining types in the pack + */ + template + struct TypeAtIndex { + using type = typename TypeAtIndex::type; + }; + + /** + * Base case of the type grabs + * the current head type. + * @tparam Head the head of the current type pack + * @tparam Tail the remaining types, if any + */ + template + struct TypeAtIndex<0, Head, Tail...> { + using type = Head; + }; + + /** + * Shorthand to obtain the type at an index. + */ + template + using TypeAtIndexType = typename TypeAtIndex::type; + + /** + * Undefined base type of the tuple implementation. + * @tparam Sequence index sequence containing the indices + * @tparam Types tuple type pack + */ + template + struct TupleImpl; + + /** + * Boolean type for whether a type is an + * instance of TupleImpl. Base case is false. + */ + template + struct IsTupleImpl + : false_type { + }; + + /** + * Template specialization for TupleImpl + * is true type. + * @tparam Indices tuple indices + * @tparam Types tuple types + */ + template + struct IsTupleImpl, Types...>> + : true_type { + }; + + /** + * The TupleImpl is the base type for tuple that + * contains the type pack and the index pack, and + * will inherit from each tuple element. + * @tparam Indices the index pack + * @tparam Types the type pack + */ + template + struct TupleImpl, Types...> + : TupleElement ... { + + /** + * Assignment operator to another TupleImpl will expand + * the assignment operator on each individual tuple element + * from which this class inherits. + * + * @tparam OtherTypes type pack of the assigned TupleImpl + * @param tuple the TupleImpl to assign + * @return a reference to this tuple + */ + template::type> + TupleImpl, Types...> & + operator=(TupleImpl, OtherTypes...> const &tuple) { + swallow(static_cast> &>(*this).operator=( + static_cast> const &>(tuple))... + ); + return *this; + } + + /** + * Move assignment operator for TupleImpl. + * + * @tparam OtherTypes type pack of the assigned TupleImpl + * @param tuple the TupleImpl to assign + * @return a reference to this tuple + */ + template::type> + TupleImpl, Types...> & + operator=(TupleImpl, OtherTypes...> &&tuple) { + swallow(static_cast> &>(*this).operator=(move( + static_cast> &&>(tuple)))... + ); + return *this; + }; + + /** + * TupleImpl constructor will instantiate each + * of its inherit types. This is a universal constructor. + * + * @tparam OtherTypes type pack of the constructed types + * @param elements values for each tuple element + */ + template...>() + >::type> + explicit TupleImpl(OtherTypes &&... elements) + : TupleElement(forward(elements))... { + } + + }; + + /** + * Main Tuple class. Inherits from TupleImpl + * and hides the index parameter. + * + * @tparam Types the tuple types + */ + template + class Tuple + : public TupleImpl::type, Types...> { + + public: + + /** + * Shorthand for the inherited TupleImpl type. + */ + using base_type = TupleImpl::type, Types...>; + + /** + * Assignment operator for tuple casts to the inherited type + * and defers the operation there. + * + * @tparam OtherTypes types of the assigned tuple + * @param tuple assigned tuple + * @return a reference to this tuple + */ + template + Tuple &operator=(Tuple const &tuple) { + static_cast(*this) = tuple; + return *this; + } + + /** + * Move assignment operator. + * + * @tparam OtherTypes types of assigned tuple + * @param tuple assigned tuple + * @return a reference to this tuple + */ + template + Tuple &operator=(Tuple &&tuple) { + static_cast(*this) = move(tuple); + return *this; + } + + /** + * Assignment operator for a pair. Currently, a pair + * can be assigned to any tuple with at least two elements, + * and will assign to the first two of the elements. + * + * @tparam A pair first type + * @tparam B pair second type + * @param pair the pair to assign + * @return a reference to this tuple + */ + template + Tuple &operator=(Pair const &pair) { + static_cast> &>(*this).value = pair.m_first; + static_cast> &>(*this).value = pair.m_second; + return *this; + } + + /** + * Pair move assignment operator. + * + * @tparam A pair first type + * @tparam B pair second type + * @param pair the pair to assign + * @return a reference to this tuple + */ + template + Tuple &operator=(Pair &&pair) { + static_cast> &>(*this).value = move(pair.m_first); + static_cast> &>(*this).value = move(pair.m_second); + return *this; + } + + /** + * Default constructor initializes with empty values. + */ + explicit Tuple() + : base_type(forward(Types())...) { + } + + /** + * Constructor for a tuple of each its elements. + * Enabled only if the correct number of element + * values have been provided. + * + * @tparam OtherTypes types of the element values + * @param elements element values pack + */ + template::type> + explicit Tuple(OtherTypes &&... elements) + : base_type(forward(elements)...) { + } + + /** + * Copy constructor for tuple defers + * to inherited copy constructor. + * + * @tparam OtherTypes types of the copied tuple + * @param tuple copied tuple + */ + template::type> + explicit Tuple(Tuple const &tuple) + : base_type(tuple) { + } + + /** + * Move copy constructor for tuple + * defers to inherited move copy constructor. + * + * @tparam OtherTypes types of the copied tuple + * @param tuple copied tuple + */ + template::type> + explicit Tuple(Tuple &&tuple) + : base_type(move(tuple)) { + } + + }; + + /** + * Get function for const lvalue tuple. Returns the + * tuple element value at the specified index. + * @tparam I the index of the element to get + * @tparam Types the tuple types + * @param tuple the tuple from which to get + * @return the element value at the index + */ + template + TypeAtIndexType const &get(Tuple const &tuple) { + TupleElement> const &base = tuple; + return base.value; + }; + + /** + * Get function for lvalue tuple. + * @tparam I index of the element to get + * @tparam Types the tuple types + * @param tuple the tuple from which to get + * @return the element value at the index + */ + template + TypeAtIndexType &get(Tuple &tuple) { + TupleElement> &base = tuple; + return base.value; + }; + + /** + * Get function for rvalue tuple returns an rvalue + * value type. + * @tparam I index of the element to get + * @tparam Types the tuple types + * @param tuple the tuple from which to get + * @return the element value at the index + */ + template + remove_reference_type> &&get(Tuple &&tuple) { + TupleElement> base = tuple; + return forward>(base.value); + }; + + /** + * Base case for count is zero. + * @return + */ + template + constexpr int count() { + return 0; + } + + /** + * This function counts the number of times a particular + * type appears in a tuple type pack. + * @tparam T the type to count + * @tparam Head tuple head type + * @tparam Tail tuple tail types + * @return the number of types + */ + template + constexpr int count() { + return (is_same::value ? 1 : 0) + count(); + }; + + /** + * Grab the index of a type. Base + * case is not found. + * @return not found index + */ + template + constexpr int find(int) { + return -1; + } + + /** + * Find the index of a type in a tuple's type pack. + * @tparam T the type to find + * @tparam Head tuple head type + * @tparam Tail tuple tail types + * @param index the current search index + * @return the index of the type + */ + template + constexpr int find(int index = 0) { + return is_same::value ? index : find(index + 1); + }; + + /** + * Get function for a tuple by type. + * @tparam T type to get + * @tparam Types tuple types + * @param tuple tuple from which to get + * @return the value of the type + */ + template + T &get(Tuple const &tuple) { + static_assert(count() == 1, "Type must be unique in Tuple"); + return get()>(tuple); + } + + /** + * Get function for a tuple by type. + * @tparam T type to get + * @tparam Types tuple types + * @param tuple tuple from which to get + * @return the value of the type + */ + template + T &get(Tuple &tuple) { + static_assert(count() == 1, "Type must be unique in Tuple"); + return get()>(tuple); + } + + /** + * Get function for a tuple by type. + * @tparam T type to get + * @tparam Types tuple types + * @param tuple tuple from which to get + * @return the value of the type + */ + template + T &get(Tuple &&tuple) { + static_assert(count() == 1, "Type must be unique in Tuple"); + return get()>(tuple); + } + + /** + * Undefined tuple size base type. + */ + template + struct tuple_size; + + /** + * Tuple size recursively computes the + * size of a tuple at compile time. + * @tparam Types the types of the tuple + */ + template + struct tuple_size> : integral_constant { + }; + + /** + * Shorthand to obtain the size of a + * tuple at runtime. + * @tparam Types the types to count + * @return the number of types + */ + template + constexpr size_type get_tuple_size(Tuple) { + return sizeof...(Types); + } + + /** + * Forwards elements into a tuple. + * @tparam Types types to forward + * @param elements element values to forward + * @return a tuple of lvalues or rvalues + */ + template + Tuple forward_as_tuple(Types &&... elements) { + return Tuple(forward(elements)...); + } + + /** + * Ignore universal type is used during + * tuple assignment to tie to ignore a + * particular tuple value. + */ + struct ignore_type { + template + ignore_type &operator=(U &&) { + return *this; + } + } ignore; + + /** + * Tie creates a tuple of lvalues that can be + * used as a helper to quickly assign + * tuple values to variables. + * @tparam Types + * @param elements + * @return + */ + template + Tuple tie(Types &... elements) { + return Tuple(elements...); + } + + /** + * Undefined base type for type at tuple. + */ + template + struct TypeAtTuple; + + /** + * Returns the tuple at the specified index in the tuple + * @tparam I the index whose type to get + * @tparam Types the type pack + */ + template + struct TypeAtTuple> + : TypeAtIndex { + }; + + /** + * Base case pair tuple concatenation type is undefined. + */ + template + struct cat_pair_type_sub; + + /** + * Helper type for determining the resultant type of + * a tuple concatenation. + * @tparam TupleA first tuple type + * @tparam IndicesA first tuple index pack + * @tparam TupleB second tuple type + * @tparam IndicesB second tuple index pack + */ + template + struct cat_pair_type_sub< + TupleA, IndexSequence, + TupleB, IndexSequence + > { + using type = Tuple< + typename TypeAtTuple::type..., + typename TypeAtTuple::type... + >; + }; + + /** + * Obtain the resultant type of the + * concatenation of two tuples. + * @tparam TupleA the first tuple type + * @tparam TupleB the second tuple type + */ + template + struct cat_pair_type { + static constexpr size_type SizeA = tuple_size>::value; + static constexpr size_type SizeB = tuple_size>::value; + using SequenceA = typename MakeIndexSequence::type; + using SequenceB = typename MakeIndexSequence::type; + using type = typename cat_pair_type_sub< + decay_type, SequenceA, + decay_type, SequenceB + >::type; + }; + + /** + * Universal helper function to create + * a tuple from elements. + * @tparam Types the element types + * @param elements the element values + * @return a tuple sized to the number of elements + */ + template + auto make_tuple(Types &&... elements) { + return Tuple...>(forward(elements)...); + } + + /** + * Tuple concatenation helper function. + * @tparam TupleA first tuple type + * @tparam IndicesA first tuple index pack + * @tparam TupleB second tuple type + * @tparam IndicesB second tuple index pack + * @param tupleA first tuple + * @param tupleB second tuple + * @return concatenation of the two tuples + */ + template + auto tuple_cat_pair_sub( + TupleA &&tupleA, TupleB &&tupleB, + IndexSequence, IndexSequence) { + return make_tuple( + get(forward(tupleA))..., + get(forward(tupleB))... + ); + } + + /** + * Concatenate exactly two tuples together. + * @tparam TupleA first tuple type + * @tparam TupleB second tuple type + * @param tupleA first tuple to concate + * @param tupleB second tuple to concate + * @return the tuples combined + */ + template + typename cat_pair_type::type + tuple_cat_pair(TupleA &&tupleA, TupleB &&tupleB) { + return tuple_cat_pair_sub( + forward(tupleA), + forward(tupleB), + MakeIndexSequence>::value>{}, + MakeIndexSequence>::value>{} + ); + }; + + /** + * Base case tuple concatenation for a single tuple + * returns the tuple. + * @tparam HeadTuple the tuple head + * @param tuple the singular tuple + * @return forwarded tuple + */ + template + HeadTuple &&tuple_cat(HeadTuple &&tuple) { + return forward(tuple); + } + + /** + * Base case for the concatenation of two tuples + * calls the tuple pair concatenation function. + * @tparam HeadTupleA first tuple type + * @tparam HeadTupleB second tuple type + * @param tupleA first tuple + * @param tupleB second tuple + * @return the concatenated tuples + */ + template + auto tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB) { + return tuple_cat_pair( + forward(tupleA), + forward(tupleB) + ); + }; + + /** + * Concatenate an arbitrary number of tuples together. + * This concatenation method expands linearly. + * @tparam HeadTupleA first head tuple type + * @tparam HeadTupleB second head tuple tye + * @tparam TailTuples tail tuple types + * @param tupleA first tuple + * @param tupleB second tuple + * @param tail the tail tuples + * @return concatenated tuples + */ + template + auto tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB, TailTuples &&... tail) { + auto tuple = tuple_cat_pair( + forward(tupleA), + forward(tupleB) + ); + return tuple_cat( + tuple, + forward(tail)... + ); + }; + + +} + +#endif //EMBEDDEDCPLUSPLUS_TUPLE_H diff --git a/lib/wlib/stl/TypeTraits.h b/lib/wlib/stl/TypeTraits.h new file mode 100644 index 00000000..faae1e70 --- /dev/null +++ b/lib/wlib/stl/TypeTraits.h @@ -0,0 +1,68 @@ +/** + * @file TypeTraits.h + * @brief Metafunctions for types. + * + * Works in conjunction with @code Concept.h @endcode to facilitate + * C++ polymorphism. + * + * @author Jeff Niu + * @date November 9, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_TYPETRAITS_H +#define EMBEDDEDCPLUSPLUS_TYPETRAITS_H + +#include "Tmp.h" + +/** + * Code generation macro to create a metafunction + * that verifies whether a type has the specified + * typedef. + */ +#define __WLIB_HAS_TYPE(TypeName) \ +template \ +struct has_##TypeName { \ +private: \ + template \ + static constexpr typename T::TypeName test(char); \ + template \ + static constexpr void test(...); \ +public: \ + static constexpr bool value = !is_void(0))>::value; \ +}; + +/** + * Code generation macro to create a metafunction + * that obtains the type of the specified kind + * in a class. + */ +#define __WLIB_OBTAIN_TYPE(TypeName) \ +template::value \ +>::type> \ +struct obtain_##TypeName { \ + typedef typename C::TypeName type; \ +}; + +namespace wlp { + + __WLIB_HAS_TYPE(size_type) + __WLIB_HAS_TYPE(val_type) + __WLIB_HAS_TYPE(key_type) + __WLIB_HAS_TYPE(iterator) + __WLIB_HAS_TYPE(const_iterator) + __WLIB_HAS_TYPE(map_type) + __WLIB_HAS_TYPE(node_type) + + __WLIB_OBTAIN_TYPE(size_type) + __WLIB_OBTAIN_TYPE(val_type) + __WLIB_OBTAIN_TYPE(key_type) + __WLIB_OBTAIN_TYPE(iterator) + __WLIB_OBTAIN_TYPE(const_iterator) + __WLIB_OBTAIN_TYPE(map_type) + __WLIB_OBTAIN_TYPE(node_type) + +} + +#endif //EMBEDDEDCPLUSPLUS_TYPETRAITS_H diff --git a/lib/wlib/stl/Utility.h b/lib/wlib/stl/Utility.h new file mode 100644 index 00000000..0c647fee --- /dev/null +++ b/lib/wlib/stl/Utility.h @@ -0,0 +1,52 @@ +#ifndef EMBEDDEDCPLUSPLUS_UTILITY_H +#define EMBEDDEDCPLUSPLUS_UTILITY_H + +#include "Tmp.h" + +namespace wlp { + + /** + * Move function for move semantics. Transforms a universal type + * to an rvalue. + * @tparam T universal type + * @param t type value + * @return rvalue of the type + */ + template + constexpr typename remove_reference::type &&move(T &&t) noexcept { + return static_cast::type &&>(t); + } + + /** + * Forward consumes either an lvalue and rvalue and returns a universal + * rvalue type that maintains its properties. This overloads for lvalues. + * @tparam T lvalue type + * @param t type value + * @return rvalue capture + */ + template + constexpr T &&forward(typename remove_reference::type &t) noexcept { + return static_cast(t); + } + + /** + * Overloads for rvalues. + * @tparam T rvalue type + * @param t type value + * @return rvalue capture + */ + template + constexpr T &&forward(typename remove_reference::type &&t) noexcept { + return static_cast(t); + } + + template + void swap(T &v1, T &v2) { + T tmp(move(v1)); + v1 = move(v2); + v2 = move(tmp); + } + +} + +#endif //EMBEDDEDCPLUSPLUS_UTILITY_H diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index d2bed25b..a979253a 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -11,6 +11,7 @@ #ifndef WLIB_STATICSTRING_H #define WLIB_STATICSTRING_H +#include #include namespace wlp { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b19ffafc..1e5d9319 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Waddress -Warray-bounds -Wbuiltin-macro-redefined -Wconversion") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self -Wnon-virtual-dtor -Woverloaded-virtual -Wsuggest-attribute=const") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wswitch -Wunreachable-code") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self -Wnon-virtual-dtor -Woverloaded-virtual") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wswitch -Wunreachable-code") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wsuggest-attribute=const") set(GTEST_INCLUDE_DIR ${gtest_SOURCE_DIR}/include) set(WLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/lib/wlib) diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp index a676b342..2bb8462a 100644 --- a/tests/stl/chain_map_check.cpp +++ b/tests/stl/chain_map_check.cpp @@ -10,450 +10,416 @@ typedef uint16_t ui16; typedef ChainHashMap string_map; typedef ChainHashMap int_map; typedef int_map::iterator imi; +typedef int_map::const_iterator cimi; typedef Pair P_imi_b; typedef string_map::iterator smi; typedef Pair P_smi_b; TEST(chain_map_test, test_chain_map_node) { - int_map::map_node node; - node.m_key = 6; - node.m_val = 1; - imi it(&node, nullptr); - ASSERT_EQ(1, *it); - ASSERT_EQ(node, *it.m_current); - ASSERT_EQ(nullptr, it.m_hash_map); - string_map::map_node snode; - snode.m_key = String16{"hello"}; - snode.m_val = String16{"hello"}; - smi sit(&snode, nullptr); - ASSERT_EQ(5, sit->length()); - ASSERT_EQ(16, sit->capacity()); + int_map::node_type node; + node.m_key = 6; + node.m_val = 1; + imi it(&node, nullptr); + ASSERT_EQ(1, *it); + ASSERT_EQ(node, *it.m_current); + ASSERT_EQ(nullptr, it.m_hash_map); + string_map::node_type snode; + snode.m_key = String16{"hello"}; + snode.m_val = String16{"hello"}; + smi sit(&snode, nullptr); + ASSERT_EQ(5, sit->length()); + ASSERT_EQ(16, sit->capacity()); } TEST(chain_map_test, test_const_iterator) { - string_map map(10, 100); - String16 key1{"key1"}; - String16 key2{"key2"}; - String16 key3{"key3"}; - String16 val1{"val1"}; - String16 val2{"val2"}; - String16 val3{"val3"}; - map[key1] = val1; - map[key2] = val2; - map[key3] = val3; - const string_map const_map = map; - ASSERT_EQ(3, const_map.size()); - ASSERT_EQ(10, const_map.max_size()); - ASSERT_EQ(100, const_map.max_load()); - string_map::iterator it = map.begin(); - string_map::const_iterator const_it = const_map.begin(); - ASSERT_EQ(*it, *const_it); - ++it; - const_it++; - ASSERT_EQ(*it, *const_it); - it++; - ++const_it; - ASSERT_EQ(*it, *const_it); - ++it; - ++const_it; - ASSERT_EQ(map.end(), it); - ASSERT_EQ(const_map.end(), const_it); + int_map map(10, 255); + map[5] = 5; + map[6] = 6; + map[7] = 7; + const int_map const_map(move(map)); + int_map::const_iterator it = const_map.begin(); + ASSERT_EQ(5, *it); + ++it; + ASSERT_EQ(6, *it); + ++it; + ASSERT_EQ(7, *it); + ++it; + ASSERT_EQ(const_map.end(), it); } TEST(chain_map_test, test_const_node_equals) { - int_map map(10, 150); - map[15] = 10; - map[10] = 9; - map[9] = 19; - imi it = map.begin(); - int_map::map_node node = *it.m_current; - ASSERT_TRUE(*map.begin().m_current == node); + int_map map(10, 150); + map[15] = 10; + map[10] = 9; + map[9] = 19; + imi it = map.begin(); + int_map::node_type node = *it.m_current; + ASSERT_TRUE(*map.begin().m_current == node); } TEST(chain_map_test, test_iterator_constructors) { - int_map map(10, 150); - map[15] = 10; - map[10] = 9; - const imi it = map.begin(); - imi it2(it); - ASSERT_EQ(map.begin(), it2); + int_map map(10, 150); + map[15] = 10; + map[10] = 9; + const imi it = map.begin(); + imi it2(it); + ASSERT_EQ(map.begin(), it2); } TEST(chain_map_test, test_iterator_equals) { - int_map map(10, 15); - map[15] = 10; - map[10] = 9; - imi it = map.begin(); - ++it; - imi it2 = map.begin(); - ASSERT_FALSE(it == it2); - ASSERT_TRUE(it != it2); - it = it2; - ASSERT_EQ(it, map.begin()); + int_map map(10, 15); + map[15] = 10; + map[10] = 9; + imi it = map.begin(); + ++it; + imi it2 = map.begin(); + ASSERT_FALSE(it == it2); + ASSERT_TRUE(it != it2); + it = it2; + ASSERT_EQ(it, map.begin()); } TEST(chain_map_test, test_ensure_capacity_holes) { - int_map map(5, 50); - map[1] = 1; - map[6] = 6; - map[11] = 11; - map[16] = 16; - map[21] = 21; - map[26] = 26; - ASSERT_EQ(20, map.max_size()); - ui16 expected_values_traverse[] = {1, 21, 26, 6, 11, 16}; - imi it = map.begin(); - for (ui16 i = 0; i < 6; i++) { - ASSERT_EQ(expected_values_traverse[i], *it); - ++it; - } - ASSERT_EQ(map.end(), it); - map.clear(); - ASSERT_EQ(map.end(), map.begin()); - ASSERT_EQ(0, map.size()); - ASSERT_EQ(20, map.max_size()); + int_map map(5, 50); + map[1] = 1; + map[6] = 6; + map[11] = 11; + map[16] = 16; + map[21] = 21; + map[26] = 26; + ASSERT_EQ(20, map.capacity()); + ui16 expected_values_traverse[] = {1, 21, 26, 6, 11, 16}; + imi it = map.begin(); + for (ui16 i = 0; i < 6; i++) { + ASSERT_EQ(expected_values_traverse[i], *it); + ++it; + } + ASSERT_EQ(map.end(), it); + map.clear(); + ASSERT_EQ(map.end(), map.begin()); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(20, map.capacity()); } TEST(chain_map_test, test_erase_cases) { - int_map map(10, 255); - imi it = map.insert(1, 1).first(); - map[11] = 11; - map[21] = 21; - map[31] = 31; - map[2] = 2; - map.erase(it); - ASSERT_EQ(2, *it); - it = map.end(); - map.erase(it); - ASSERT_EQ(map.end(), it); -} - -TEST(chain_map_test, test_erase_const_iterator) { - int_map map(20, 255); - map[1] = 1; - imi it1 = map.insert(41, 11).first(); - map[21] = 21; - imi it2 = map.insert(2, 2).first(); - map[42] = 42; - map[22] = 22; - map[62] = 62; - map[3] = 3; - imi it3 = map.insert(4, 4).first(); - map[44] = 44; - imi it4 = map.insert(5, 5).first(); - imi it5 = map.insert(15, 15).first(); - int_map::const_iterator cit1(it1.m_current, it1.m_hash_map); - int_map::const_iterator cit2(it2.m_current, it2.m_hash_map); - int_map::const_iterator cit3(it3.m_current, it3.m_hash_map); - int_map::const_iterator cit4(it4.m_current, it4.m_hash_map); - int_map::const_iterator cit5(it5.m_current, it5.m_hash_map); - const int_map const_map = map; - int_map::const_iterator const_end = const_map.end(); - ASSERT_EQ(12, map.size()); - map.erase(cit1); - ASSERT_EQ(1, *cit1); - map.erase(cit2); - ASSERT_EQ(3, *cit2); - map.erase(cit4); - ASSERT_EQ(15, *cit4); - map.erase(cit5); - ASSERT_EQ(const_end, cit5); - map.erase(cit3); - ASSERT_EQ(const_end, cit3); + int_map map(10, 255); + imi it = map.insert(1, 1).first(); + map[11] = 11; + map[21] = 21; + map[31] = 31; + map[2] = 2; + map.erase(it); + ASSERT_EQ(2, *it); + it = map.end(); + map.erase(it); + ASSERT_EQ(map.end(), it); } TEST(chain_map_test, test_constructor_params) { - int_map map(10, 150); - ASSERT_EQ(10, map.max_size()); - ASSERT_EQ(150, map.max_load()); - ASSERT_EQ(0, map.size()); - ASSERT_TRUE(map.empty()); + int_map map(10, 150); + ASSERT_EQ(10, map.capacity()); + ASSERT_EQ(150, map.max_load()); + ASSERT_EQ(0, map.size()); + ASSERT_TRUE(map.empty()); } TEST(chain_map_test, test_constructor_allocator) { - string_map map(10, 100); - const size_t expected = sizeof(string_map::map_node); - ASSERT_EQ(expected, map.get_node_allocator()->GetBlockSize()); - ASSERT_EQ(expected * 10, map.get_node_allocator()->GetPoolSize()); + string_map map(10, 100); + const size_t expected = sizeof(string_map::node_type); + ASSERT_EQ(expected, map.get_node_allocator()->GetBlockSize()); + ASSERT_EQ(expected * 10, map.get_node_allocator()->GetPoolSize()); } TEST(chain_map_test, test_begin_returns_end_when_empty) { - string_map map(10, 100); - ASSERT_EQ(map.begin(), map.end()); + string_map map(10, 100); + ASSERT_EQ(map.begin(), map.end()); } TEST(chain_map_test, test_begin_end_const) { - const string_map map(10, 100); - ASSERT_EQ(map.begin(), map.end()); + const string_map map(10, 100); + ASSERT_EQ(map.begin(), map.end()); } TEST(chain_map_test, test_insert_at_iterator_no_collision) { - int_map map(5, 255); - ui16 keys[] = {0, 1, 2, 3, 4}; - ui16 values[] = {0, 10, 20, 30, 40}; - P_imi_b r[] = { - map.insert(0, 0), - map.insert(1, 10), - map.insert(2, 20), - map.insert(3, 30), - map.insert(4, 40) - }; - ASSERT_EQ(5, map.size()); - for (ui16 i = 0; i < 5; i++) { - ASSERT_TRUE(r[i].second()); - ASSERT_EQ(values[i], *r[i].first()); - ASSERT_EQ(values[i], *map.at(keys[i])); - } - P_imi_b failed = map.insert(0, 10); - ASSERT_FALSE(failed.second()); - ASSERT_EQ(0, *failed.first()); - imi it = r[0].first(); - ASSERT_EQ(it, map.begin()); - ++it; - ASSERT_EQ(*r[1].first(), *it); - ASSERT_EQ(r[1].first(), it); - ++it; - ASSERT_EQ(*r[2].first(), *it); - ASSERT_EQ(r[2].first(), it); - ++it; - ASSERT_EQ(*r[3].first(), *it); - ASSERT_EQ(r[3].first(), it); - ++it; - ASSERT_EQ(*r[4].first(), *it); - ASSERT_EQ(r[4].first(), it); - ++it; - ASSERT_EQ(map.end(), it); + int_map map(5, 255); + ui16 keys[] = {0, 1, 2, 3, 4}; + ui16 values[] = {0, 10, 20, 30, 40}; + P_imi_b r[] = { + map.insert(0, 0), + map.insert(1, 10), + map.insert(2, 20), + map.insert(3, 30), + map.insert(4, 40) + }; + ASSERT_EQ(5, map.size()); + for (ui16 i = 0; i < 5; i++) { + ASSERT_TRUE(r[i].second()); + ASSERT_EQ(values[i], *r[i].first()); + ASSERT_EQ(values[i], *map.at(keys[i])); + } + P_imi_b failed = map.insert(0, 10); + ASSERT_FALSE(failed.second()); + ASSERT_EQ(0, *failed.first()); + imi it = r[0].first(); + ASSERT_EQ(it, map.begin()); + ++it; + ASSERT_EQ(*r[1].first(), *it); + ASSERT_EQ(r[1].first(), it); + ++it; + ASSERT_EQ(*r[2].first(), *it); + ASSERT_EQ(r[2].first(), it); + ++it; + ASSERT_EQ(*r[3].first(), *it); + ASSERT_EQ(r[3].first(), it); + ++it; + ASSERT_EQ(*r[4].first(), *it); + ASSERT_EQ(r[4].first(), it); + ++it; + ASSERT_EQ(map.end(), it); } TEST(chain_map_test, test_insert_at_iterator_collision_resolution) { - int_map map(5, 255); - ui16 keys[] = { - 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, - 10, 12, 15, 17, 20 - }; - ui16 values[] = { - 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, - 100, 120, 150, 170, 200 - }; - // ceil(2.55 * 5) = 13 - // Map will rehash before inserting 17 - P_imi_b r[15]; - for (ui16 i = 0; i < 15; i++) { - r[i] = map.insert(keys[i], values[i]); - ASSERT_TRUE(r[i].second()); - ASSERT_EQ(values[i], *r[i].first()); - } - for (ui16 i = 0; i < 15; i++) { - ASSERT_EQ(values[i], *r[i].first()); - } - ASSERT_EQ(15, map.size()); - imi it = r[14].first(); - ASSERT_EQ(it, map.begin()); - ui16 expected_values_traverse[] = { - 200, 0, 100, 10, 20, 120, - 30, 40, 50, 150, 60, 170, 70, - 80, 90 - }; - ui16 expected_r_traverse[] = { - 14, 0, 10, 1, 2, 11, - 3, 4, 5, 12, 6, 13, - 7, 8, 9 - }; - for (ui16 i = 0; i < 15; i++) { - ASSERT_EQ(expected_values_traverse[i], *it); - ASSERT_EQ(expected_values_traverse[i], *r[expected_r_traverse[i]].first()); - ASSERT_EQ(r[expected_r_traverse[i]].first(), it); - ++it; - } - ASSERT_EQ(map.end(), it); + int_map map(5, 255); + ui16 keys[] = { + 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, + 10, 12, 15, 17, 20 + }; + ui16 values[] = { + 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, + 100, 120, 150, 170, 200 + }; + // ceil(2.55 * 5) = 13 + // Map will rehash before inserting 17 + P_imi_b r[15]; + for (ui16 i = 0; i < 15; i++) { + r[i] = map.insert(keys[i], values[i]); + ASSERT_TRUE(r[i].second()); + ASSERT_EQ(values[i], *r[i].first()); + } + for (ui16 i = 0; i < 15; i++) { + ASSERT_EQ(values[i], *r[i].first()); + } + ASSERT_EQ(15, map.size()); + imi it = r[14].first(); + ASSERT_EQ(it, map.begin()); + ui16 expected_values_traverse[] = { + 200, 0, 100, 10, 20, 120, + 30, 40, 50, 150, 60, 170, 70, + 80, 90 + }; + ui16 expected_r_traverse[] = { + 14, 0, 10, 1, 2, 11, + 3, 4, 5, 12, 6, 13, + 7, 8, 9 + }; + for (ui16 i = 0; i < 15; i++) { + ASSERT_EQ(expected_values_traverse[i], *it); + ASSERT_EQ(expected_values_traverse[i], *r[expected_r_traverse[i]].first()); + ASSERT_EQ(r[expected_r_traverse[i]].first(), it); + ++it; + } + ASSERT_EQ(map.end(), it); } TEST(chain_map_test, test_insert_or_assign) { - string_map map(15, 255); - String16 a1{"key1"}; - String16 a2{"key2"}; - String16 v1{"value1"}; - String16 v2{"value2"}; - String16 v3{"value3"}; - P_smi_b r1 = map.insert_or_assign(a1, v1); - P_smi_b r2 = map.insert_or_assign(a2, v2); - ASSERT_EQ(2, map.size()); - ASSERT_TRUE(r1.second()); - ASSERT_TRUE(r2.second()); - ASSERT_EQ(v1, *map.at(a1)); - ASSERT_EQ(v2, *map.at(a2)); - P_smi_b r3 = map.insert_or_assign(a1, v3); - ASSERT_EQ(2, map.size()); - ASSERT_FALSE(r3.second()); - ASSERT_EQ(v3, *r3.first()); - ASSERT_EQ(v3, *map.at(a1)); + string_map map(15, 255); + String16 a1{"key1"}; + String16 a2{"key2"}; + String16 v1{"value1"}; + String16 v2{"value2"}; + String16 v3{"value3"}; + P_smi_b r1 = map.insert_or_assign(a1, v1); + P_smi_b r2 = map.insert_or_assign(a2, v2); + ASSERT_EQ(2, map.size()); + ASSERT_TRUE(r1.second()); + ASSERT_TRUE(r2.second()); + ASSERT_EQ(v1, *map.at(a1)); + ASSERT_EQ(v2, *map.at(a2)); + P_smi_b r3 = map.insert_or_assign(a1, v3); + ASSERT_EQ(2, map.size()); + ASSERT_FALSE(r3.second()); + ASSERT_EQ(v3, *r3.first()); + ASSERT_EQ(v3, *map.at(a1)); } TEST(chain_map_test, test_erase_key_nothing) { - string_map map(15, 255); - String16 a{"key"}; - ASSERT_FALSE(map.erase(a)); - ASSERT_EQ(0, map.size()); + string_map map(15, 255); + String16 a{"key"}; + ASSERT_FALSE(map.erase(a)); + ASSERT_EQ(0, map.size()); } TEST(chain_map_test, test_erase_key) { - string_map map(15, 255); - String16 a{"key"}; - String16 b{"val"}; - map.insert(a, b); - ASSERT_EQ(1, map.size()); - ASSERT_TRUE(map.erase(a)); - ASSERT_EQ(0, map.size()); + string_map map(15, 255); + String16 a{"key"}; + String16 b{"val"}; + map.insert(a, b); + ASSERT_EQ(1, map.size()); + ASSERT_TRUE(map.erase(a)); + ASSERT_EQ(0, map.size()); } TEST(chain_map_test, test_erase_iterator) { - int_map map(5, 255); - // 0 1 _ 3 _ _ - // 20 33 - // 40 - P_imi_b r0 = map.insert(0, 0); - P_imi_b r1 = map.insert(1, 1); - P_imi_b r3 = map.insert(3, 3); - ASSERT_EQ(3, map.size()); - P_imi_b r20 = map.insert(20, 20); - P_imi_b r33 = map.insert(33, 33); - map.insert(40, 40); - ASSERT_EQ(6, map.size()); - imi it = r1.first(); - map.erase(it); - ASSERT_EQ(5, map.size()); - ASSERT_EQ(33, *it); - ASSERT_EQ(it, r33.first()); - map.erase(it); - ASSERT_EQ(4, map.size()); - ASSERT_EQ(3, *it); - ASSERT_NE(it, r3.first()); // iterator invalidated by erase - ASSERT_EQ(*it, *r3.first()); - map.erase(it); - ASSERT_EQ(3, map.size()); - ASSERT_EQ(map.end(), it); - ASSERT_EQ(40, *map.at(40)); - ASSERT_EQ(20, *map.at(20)); - ASSERT_EQ(0, *map.at(0)); - ASSERT_EQ(map.end(), map.at(1)); - ASSERT_EQ(map.end(), map.at(3)); - ASSERT_EQ(map.end(), map.at(33)); - it = r20.first(); - map.erase(it); - ASSERT_EQ(2, map.size()); - ASSERT_EQ(0, *it); - ASSERT_NE(it, r0.first()); - ASSERT_EQ(0, *r0.first()); - map.erase(it); - ASSERT_EQ(map.end(), it); - ASSERT_EQ(1, map.size()); - ASSERT_EQ(40, *map.begin()); + int_map map(5, 255); + // 0 1 _ 3 _ _ + // 20 33 + // 40 + P_imi_b r0 = map.insert(0, 0); + P_imi_b r1 = map.insert(1, 1); + P_imi_b r3 = map.insert(3, 3); + ASSERT_EQ(3, map.size()); + P_imi_b r20 = map.insert(20, 20); + P_imi_b r33 = map.insert(33, 33); + map.insert(40, 40); + ASSERT_EQ(6, map.size()); + imi it = r1.first(); + map.erase(it); + ASSERT_EQ(5, map.size()); + ASSERT_EQ(33, *it); + ASSERT_EQ(it, r33.first()); + map.erase(it); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(3, *it); + ASSERT_NE(it, r3.first()); // iterator invalidated by erase + ASSERT_EQ(*it, *r3.first()); + map.erase(it); + ASSERT_EQ(3, map.size()); + ASSERT_EQ(map.end(), it); + ASSERT_EQ(40, *map.at(40)); + ASSERT_EQ(20, *map.at(20)); + ASSERT_EQ(0, *map.at(0)); + ASSERT_EQ(map.end(), map.at(1)); + ASSERT_EQ(map.end(), map.at(3)); + ASSERT_EQ(map.end(), map.at(33)); + it = r20.first(); + map.erase(it); + ASSERT_EQ(2, map.size()); + ASSERT_EQ(0, *it); + ASSERT_NE(it, r0.first()); + ASSERT_EQ(0, *r0.first()); + map.erase(it); + ASSERT_EQ(map.end(), it); + ASSERT_EQ(1, map.size()); + ASSERT_EQ(40, *map.begin()); } TEST(chain_map_test, test_contains_access_operator) { - int_map map(5, 255); - map[5] = 50; - map[15] = 150; - map[0] = 0; - map[20] = 200; - map[25] = 250; - ASSERT_EQ(5, map.size()); - map.insert(3, 30); - ASSERT_EQ(6, map.size()); - ASSERT_EQ(30, *map.at(3)); - map[3] = 33; - ASSERT_EQ(6, map.size()); - ASSERT_EQ(33, *map.at(3)); - ASSERT_EQ(50, map[5]); - ASSERT_EQ(150, map[15]); - ASSERT_EQ(200, map[20]); - ASSERT_EQ(250, map[25]); - ASSERT_TRUE(map.contains(25)); - ASSERT_TRUE(map.contains(15)); - ASSERT_TRUE(map.contains(3)); - ASSERT_FALSE(map.contains(4)); - map[14] = 14; - ASSERT_FALSE(map.contains(4)); - map[24] = 24; - ASSERT_FALSE(map.contains(4)); - ASSERT_EQ(8, map.size()); - map[4] = 4; - ASSERT_TRUE(map.contains(4)); - ASSERT_EQ(9, map.size()); -} - -TEST(chain_map, test_const_map_assignment) { - int_map map(10, 255); - map.insert(1, 1); - map.insert(25, 25); - const int_map const_map(map); - map = const_map; - ASSERT_EQ(2, map.size()); - imi it = map.begin(); - ASSERT_EQ(1, *it); - it++; - ASSERT_EQ(25, *it); - int_map b_map(10, 255); - b_map.insert(10, 10); - b_map.insert(12, 12); - b_map.insert(13, 13); - map = b_map; - ASSERT_EQ(3, map.size()); - it = map.begin(); - ASSERT_EQ(10, *it); - ++it; - ASSERT_EQ(12, *it); - ++it; - ASSERT_EQ(13, *it); - ++it; - ASSERT_EQ(map.end(), it); - int_map c_map(const_map); - ASSERT_EQ(2, c_map.size()); - it = c_map.begin(); - ASSERT_EQ(1, *it); - ++it; - ASSERT_EQ(25, *it); - ++it; - ASSERT_EQ(c_map.end(), it); + int_map map(5, 255); + map[5] = 50; + map[15] = 150; + map[0] = 0; + map[20] = 200; + map[25] = 250; + ASSERT_EQ(5, map.size()); + map.insert(3, 30); + ASSERT_EQ(6, map.size()); + ASSERT_EQ(30, *map.at(3)); + map[3] = 33; + ASSERT_EQ(6, map.size()); + ASSERT_EQ(33, *map.at(3)); + ASSERT_EQ(50, map[5]); + ASSERT_EQ(150, map[15]); + ASSERT_EQ(200, map[20]); + ASSERT_EQ(250, map[25]); + ASSERT_TRUE(map.contains(25)); + ASSERT_TRUE(map.contains(15)); + ASSERT_TRUE(map.contains(3)); + ASSERT_FALSE(map.contains(4)); + map[14] = 14; + ASSERT_FALSE(map.contains(4)); + map[24] = 24; + ASSERT_FALSE(map.contains(4)); + ASSERT_EQ(8, map.size()); + map[4] = 4; + ASSERT_TRUE(map.contains(4)); + ASSERT_EQ(9, map.size()); } TEST(chain_map_test, test_find) { - int_map map(10, 255); - map[16] = 1116; - map[21] = 1211; - map[71] = 1711; - ASSERT_EQ(map.end(), map.find(15)); - ASSERT_EQ(map.end(), map.find(0)); - ASSERT_EQ(map.end(), map.find(6)); - ASSERT_EQ(map.end(), map.find(1)); - ASSERT_EQ(1116, *map.find(16)); - ASSERT_EQ(1711, *map.find(71)); - ASSERT_EQ(1211, *map.find(21)); - imi it = map.find(71); - ++it; - ASSERT_EQ(1211, *it); - ++it; - ASSERT_EQ(1116, *it); - ++it; - ASSERT_EQ(map.end(), it); + int_map map(10, 255); + map[16] = 1116; + map[21] = 1211; + map[71] = 1711; + ASSERT_EQ(map.end(), map.find(15)); + ASSERT_EQ(map.end(), map.find(0)); + ASSERT_EQ(map.end(), map.find(6)); + ASSERT_EQ(map.end(), map.find(1)); + ASSERT_EQ(1116, *map.find(16)); + ASSERT_EQ(1711, *map.find(71)); + ASSERT_EQ(1211, *map.find(21)); + imi it = map.find(71); + ++it; + ASSERT_EQ(1211, *it); + ++it; + ASSERT_EQ(1116, *it); + ++it; + ASSERT_EQ(map.end(), it); } TEST(chain_map_test, test_erase_key_cases) { - int_map map(10, 255); - map[6] = 6; - map[16] = 16; - map[26] = 26; - map[46] = 46; - map[56] = 56; - map[36] = 36; - map[4] = 4; - ui16 k = 14; - ASSERT_FALSE(map.erase(k)); - k = 36; - ASSERT_TRUE(map.erase(k)); - k = 26; - ASSERT_TRUE(map.erase(k)); - k = 66; - ASSERT_FALSE(map.erase(k)); + int_map map(10, 255); + map[6] = 6; + map[16] = 16; + map[26] = 26; + map[46] = 46; + map[56] = 56; + map[36] = 36; + map[4] = 4; + ui16 k = 14; + ASSERT_FALSE(map.erase(k)); + k = 36; + ASSERT_TRUE(map.erase(k)); + k = 26; + ASSERT_TRUE(map.erase(k)); + k = 66; + ASSERT_FALSE(map.erase(k)); +} + +TEST(chain_map_test, test_iterator_ctor) { + int_map map(10, 255); + map.insert(1, 5); + map.insert(2, 10); + map.insert(3, 15); + imi i1 = map.begin(); + ASSERT_EQ(5, *i1); + cimi ci1; + const int_map const_map(move(map)); + cimi ci2 = move(const_map.begin()); + cimi ci3(ci2); + ASSERT_EQ(ci2, ci3); + string_map s_map(10, 255); + s_map.insert(String16("key"), String16("val")); + const string_map const_s_map(move(s_map)); + string_map::const_iterator s_ci1 = const_s_map.begin(); + ASSERT_EQ(3, s_ci1->length()); + ci2 = move(const_map.begin()); + ASSERT_EQ(5, *ci2); + ci3 = move(const_map.begin()); + ci2 = ci3; + ASSERT_EQ(5, *ci2); +} + +TEST(chain_map_test, test_at_const) { + int_map map(10, 255); + map.insert(1, 5); + map.insert(2, 10); + map.insert(3, 15); + const int_map const_map(move(map)); + const int v = 3; + ASSERT_EQ(15, *const_map.at(v)); + ASSERT_EQ(15, *const_map.find(v)); +} + +TEST(chain_map_test, test_move_assignment_op) { + int_map map(10, 255); + map.insert(1, 5); + map.insert(2, 10); + map.insert(3, 15); + int_map map1(10, 255); + map1 = move(map); + ASSERT_EQ(3, map1.size()); + ASSERT_EQ(5, map1[1]); + ASSERT_EQ(10, map1[2]); + ASSERT_EQ(15, map1[3]); } diff --git a/tests/stl/comparator_check.cpp b/tests/stl/comparator_check.cpp new file mode 100644 index 00000000..4ab52d41 --- /dev/null +++ b/tests/stl/comparator_check.cpp @@ -0,0 +1,112 @@ +#include "gtest/gtest.h" + +#include "stl/Comparator.h" +#include "strings/StaticString.h" + +using namespace wlp; + +TEST(comparator_test, test_int_comparison) { + Comparator cmp; + ASSERT_TRUE(cmp.__eq__(5, 5)); + ASSERT_FALSE(cmp.__eq__(5, 6)); + + ASSERT_TRUE(cmp.__ne__(5, 6)); + ASSERT_FALSE(cmp.__ne__(5, 5)); + + ASSERT_TRUE(cmp.__gt__(6, 5)); + ASSERT_FALSE(cmp.__gt__(5, 5)); + ASSERT_FALSE(cmp.__gt__(5, 6)); + + ASSERT_TRUE(cmp.__lt__(5, 6)); + ASSERT_FALSE(cmp.__lt__(5, 5)); + ASSERT_FALSE(cmp.__lt__(6, 5)); + + ASSERT_TRUE(cmp.__le__(5, 6)); + ASSERT_TRUE(cmp.__le__(5, 5)); + ASSERT_FALSE(cmp.__le__(6, 5)); + + ASSERT_TRUE(cmp.__ge__(6, 5)); + ASSERT_TRUE(cmp.__ge__(5, 5)); + ASSERT_FALSE(cmp.__ge__(5, 6)); +} + +TEST(comparator_test, test_c_string_comparison) { + char str1[] = "hello"; + char str2[] = "hellsalem"; + Comparator cmp; + + ASSERT_TRUE(cmp.__eq__(str1, str1)); + ASSERT_FALSE(cmp.__eq__(str1, str2)); + + ASSERT_TRUE(cmp.__ne__(str1, str2)); + ASSERT_FALSE(cmp.__ne__(str1, str1)); + + ASSERT_TRUE(cmp.__gt__(str2, str1)); + ASSERT_FALSE(cmp.__gt__(str1, str2)); + ASSERT_FALSE(cmp.__gt__(str1, str1)); + + ASSERT_TRUE(cmp.__lt__(str1, str2)); + ASSERT_FALSE(cmp.__lt__(str2, str1)); + ASSERT_FALSE(cmp.__lt__(str1, str1)); + + ASSERT_TRUE(cmp.__le__(str1, str2)); + ASSERT_TRUE(cmp.__le__(str1, str1)); + ASSERT_FALSE(cmp.__le__(str2, str1)); + + ASSERT_TRUE(cmp.__ge__(str2, str1)); + ASSERT_FALSE(cmp.__ge__(str1, str2)); + ASSERT_TRUE(cmp.__ge__(str1, str1)); +} + +TEST(comparator_test, test_static_string_comparator) { + String8 str1("hello"); + String8 str2("hellsalem"); + Comparator cmp; + + ASSERT_TRUE(cmp.__eq__(str1, str1)); + ASSERT_FALSE(cmp.__eq__(str1, str2)); + + ASSERT_TRUE(cmp.__ne__(str1, str2)); + ASSERT_FALSE(cmp.__ne__(str1, str1)); + + ASSERT_TRUE(cmp.__gt__(str2, str1)); + ASSERT_FALSE(cmp.__gt__(str1, str2)); + ASSERT_FALSE(cmp.__gt__(str1, str1)); + + ASSERT_TRUE(cmp.__lt__(str1, str2)); + ASSERT_FALSE(cmp.__lt__(str2, str1)); + ASSERT_FALSE(cmp.__lt__(str1, str1)); + + ASSERT_TRUE(cmp.__le__(str1, str2)); + ASSERT_TRUE(cmp.__le__(str1, str1)); + ASSERT_FALSE(cmp.__le__(str2, str1)); + + ASSERT_TRUE(cmp.__ge__(str2, str1)); + ASSERT_FALSE(cmp.__ge__(str1, str2)); + ASSERT_TRUE(cmp.__ge__(str1, str1)); +} + +TEST(comparator_test, test_reverse_comparator) { + ReverseComparator cmp; + ASSERT_TRUE(cmp.__eq__(5, 5)); + ASSERT_FALSE(cmp.__eq__(5, 6)); + + ASSERT_TRUE(cmp.__ne__(5, 6)); + ASSERT_FALSE(cmp.__ne__(5, 5)); + + ASSERT_TRUE(cmp.__lt__(6, 5)); + ASSERT_FALSE(cmp.__lt__(5, 5)); + ASSERT_FALSE(cmp.__lt__(5, 6)); + + ASSERT_TRUE(cmp.__gt__(5, 6)); + ASSERT_FALSE(cmp.__gt__(5, 5)); + ASSERT_FALSE(cmp.__gt__(6, 5)); + + ASSERT_TRUE(cmp.__ge__(5, 6)); + ASSERT_TRUE(cmp.__ge__(5, 5)); + ASSERT_FALSE(cmp.__ge__(6, 5)); + + ASSERT_TRUE(cmp.__le__(6, 5)); + ASSERT_TRUE(cmp.__le__(5, 5)); + ASSERT_FALSE(cmp.__le__(5, 6)); +} diff --git a/tests/stl/concept_check.cpp b/tests/stl/concept_check.cpp new file mode 100644 index 00000000..dc5b3a23 --- /dev/null +++ b/tests/stl/concept_check.cpp @@ -0,0 +1,85 @@ +#include +#include "gtest/gtest.h" + +#include "stl/Concept.h" +#include "stl/Comparator.h" +#include "stl/ChainMap.h" +#include "stl/ArrayList.h" + +using namespace wlp; + +TEST(concept_checks, check_comparator_concept) { + bool c = comparator_concept, int>::value; + ASSERT_TRUE(c); + c = comparator_concept, int>::value; + ASSERT_FALSE(c); +} + +TEST(concept_checks, check_is_comparator) { + ASSERT_TRUE((is_comparator, const char *>())); + ASSERT_FALSE((is_comparator, const char *>())); + ASSERT_FALSE((is_comparator, const char *>())); + ASSERT_TRUE((is_comparator, char>())); + ASSERT_FALSE((is_comparator, uint16_t>())); +} + +TEST(concept_checks, check_has_size_val_type) { + bool c; + c = has_size_type::value; + ASSERT_FALSE(c); + c = has_size_type>::value; + ASSERT_FALSE(c); + c = has_val_type::value; + ASSERT_FALSE(c); + c = has_val_type>::value; + ASSERT_FALSE(c); + c = has_size_type>::value; + ASSERT_TRUE(c); + c = has_size_type::iterator>::value; + ASSERT_TRUE(c); + c = has_val_type>::value; + ASSERT_TRUE(c); + c = has_val_type::iterator>::value; + ASSERT_TRUE(c); +} + +TEST(concept_checks, check_random_access_iterator_concept) { + bool c; + c = random_access_iterator_concept::value; + ASSERT_FALSE(c); + c = random_access_iterator_concept>::value; + ASSERT_FALSE(c); + c = random_access_iterator_concept::iterator>::value; + ASSERT_FALSE(c); + c = random_access_iterator_concept::iterator>::value; + ASSERT_TRUE(c); + c = random_access_iterator_concept::const_iterator>::value; + ASSERT_TRUE(c); + + ASSERT_TRUE((is_random_access_iterator::iterator>())); + ASSERT_TRUE((is_random_access_iterator::const_iterator>())); + + ASSERT_FALSE((is_random_access_iterator::iterator>())); + ASSERT_FALSE((is_random_access_iterator::const_iterator>())); + ASSERT_FALSE((is_random_access_iterator::iterator>())); + ASSERT_FALSE((is_random_access_iterator::const_iterator>())); +} + +TEST(concept_checks, check_forward_iterator_concept) { + ASSERT_TRUE((is_forward_iterator::iterator>())); + ASSERT_TRUE((is_forward_iterator::const_iterator>())); + ASSERT_TRUE((is_forward_iterator::iterator>())); + ASSERT_TRUE((is_forward_iterator::const_iterator>())); + ASSERT_TRUE((is_forward_iterator::iterator>())); + ASSERT_TRUE((is_forward_iterator::const_iterator>())); + + ASSERT_FALSE((is_forward_iterator>())); + ASSERT_FALSE((is_forward_iterator>())); +} + +TEST(concept_checks, check_map_concept) { + ASSERT_TRUE((is_map>())); + ASSERT_TRUE((is_map>())); + ASSERT_FALSE((is_map())); + ASSERT_FALSE((is_map>())); +} diff --git a/tests/stl/equals_check.cpp b/tests/stl/equals_check.cpp index a95d2917..70b6e706 100644 --- a/tests/stl/equals_check.cpp +++ b/tests/stl/equals_check.cpp @@ -8,41 +8,41 @@ using namespace wlp; TEST(equals_test, test_string_equals) { - equals comparator = equals(); - char str1[] = "somestring"; - char str2[] = "somestring"; - char str3[] = "shoestring"; - char str4[] = "money"; - ASSERT_TRUE(comparator(str1, str2)); - ASSERT_FALSE(comparator(str2, str3)); - ASSERT_FALSE(comparator(str4, str3)); - ASSERT_FALSE(comparator(str2, str4)); - ASSERT_FALSE(comparator(str1, str4)); + Equal comparator = Equal(); + char str1[] = "somestring"; + char str2[] = "somestring"; + char str3[] = "shoestring"; + char str4[] = "money"; + ASSERT_TRUE(comparator(str1, str2)); + ASSERT_FALSE(comparator(str2, str3)); + ASSERT_FALSE(comparator(str4, str3)); + ASSERT_FALSE(comparator(str2, str4)); + ASSERT_FALSE(comparator(str1, str4)); } TEST(equals_test, test_static_string_equals) { - equals comparator = equals(); - String8 str1{"darwin"}; - String8 str2{"darwin"}; - String8 str3{"money__\""}; - String8 str4{"money__\""}; - ASSERT_TRUE(comparator(str1, str2)); - ASSERT_TRUE(comparator(str3, str4)); + Equal comparator = Equal(); + String8 str1{"darwin"}; + String8 str2{"darwin"}; + String8 str3{"money__\""}; + String8 str4{"money__\""}; + ASSERT_TRUE(comparator(str1, str2)); + ASSERT_TRUE(comparator(str3, str4)); } TEST(equals_test, test_static_string_unequal) { - equals comparator = equals(); - String8 str1{"darwin"}; - String8 str2{"money__\""}; - String8 str3{"houses"}; - ASSERT_FALSE(comparator(str1, str2)); - ASSERT_FALSE(comparator(str2, str3)); + Equal comparator = Equal(); + String8 str1{"darwin"}; + String8 str2{"money__\""}; + String8 str3{"houses"}; + ASSERT_FALSE(comparator(str1, str2)); + ASSERT_FALSE(comparator(str2, str3)); } TEST(equals_test, test_integer_equal) { - equals comparator = equals(); - ASSERT_TRUE(comparator(1, 1)); - ASSERT_TRUE(comparator(15, 15)); - ASSERT_FALSE(comparator(1, 14)); - ASSERT_FALSE(comparator(14, 1)); + Equal comparator = Equal(); + ASSERT_TRUE(comparator(1, 1)); + ASSERT_TRUE(comparator(15, 15)); + ASSERT_FALSE(comparator(1, 14)); + ASSERT_FALSE(comparator(14, 1)); } \ No newline at end of file diff --git a/tests/stl/hash_check.cpp b/tests/stl/hash_check.cpp index f29e4d53..2f241ba6 100644 --- a/tests/stl/hash_check.cpp +++ b/tests/stl/hash_check.cpp @@ -7,28 +7,28 @@ using namespace wlp; TEST(hash_test, test_hash_static_string) { - hash hasher = hash(); - String8 str1{"darwin"}; - String8 str2{"darwin"}; - String8 str3{"hello"}; - ASSERT_EQ(hasher(str1), hasher(str2)); - ASSERT_NE(hasher(str1), hasher(str3)); - ASSERT_NE(hasher(str2), hasher(str3)); + Hash hasher = Hash(); + String8 str1{"darwin"}; + String8 str2{"darwin"}; + String8 str3{"hello"}; + ASSERT_EQ(hasher(str1), hasher(str2)); + ASSERT_NE(hasher(str1), hasher(str3)); + ASSERT_NE(hasher(str2), hasher(str3)); } TEST(hash_test, test_hash_string) { - hash hasher = hash(); - char str1[] = "drawing"; - char str2[] = "downward"; - char str3[] = "drawing"; - ASSERT_EQ(hasher(str1), hasher(str3)); - ASSERT_NE(hasher(str2), hasher(str1)); - ASSERT_NE(hasher(str2), hasher(str3)); + Hash hasher = Hash(); + char str1[] = "drawing"; + char str2[] = "downward"; + char str3[] = "drawing"; + ASSERT_EQ(hasher(str1), hasher(str3)); + ASSERT_NE(hasher(str2), hasher(str1)); + ASSERT_NE(hasher(str2), hasher(str3)); } TEST(hash_test, test_hash_integer) { - hash hasher = hash(); - ASSERT_EQ(4, hasher(4)); - ASSERT_EQ(hasher(10), hasher(10)); - ASSERT_EQ(1556, hasher(1556)); + Hash hasher = Hash(); + ASSERT_EQ(4, hasher(4)); + ASSERT_EQ(hasher(10), hasher(10)); + ASSERT_EQ(1556, hasher(1556)); } \ No newline at end of file diff --git a/tests/stl/heap_check.cpp b/tests/stl/heap_check.cpp new file mode 100644 index 00000000..bc4fc36a --- /dev/null +++ b/tests/stl/heap_check.cpp @@ -0,0 +1,160 @@ +#include "gtest/gtest.h" + +#include "stl/ArrayHeap.h" +#include "../template_defs.h" + +using namespace wlp; + +TEST(heap_test, test_heap_push_pop) { + ArrayHeap heap; + heap.push(5); + heap.push(10); + heap.push(1); + heap.push(-1); + heap.push(3); + heap.push(-5); + ASSERT_EQ(6, heap.size()); + ASSERT_EQ(10, heap.top()); + heap.pop(); + ASSERT_EQ(5, heap.top()); + heap.pop(); + ASSERT_EQ(3, heap.top()); + heap.pop(); + ASSERT_EQ(3, heap.size()); + ASSERT_EQ(1, heap.top()); + heap.pop(); + ASSERT_EQ(-1, heap.top()); + heap.pop(); + ASSERT_EQ(-5, heap.top()); + heap.pop(); + ASSERT_EQ(0, heap.size()); +} + +TEST(heap_test, test_heap_sort) { + ArrayList list; + list.push_back(5); + list.push_back(10); + list.push_back(-1); + list.push_back(9); + list.push_back(4); + list.push_back(2); + list.push_back(7); + heap_sort(list); + int expected[] = {-1, 2, 4, 5, 7, 9, 10}; + for (ArrayList::size_type i = 0; i < list.size(); ++i) { + ASSERT_EQ(expected[i], list[i]); + } +} + +TEST(heap_test, test_heap_sort_comparator) { + int array[] = {-5, 6, -1, 10, 16, 32}; + ArrayList list(array, 6, 12); + list.push_back(0); + ReverseComparator comparator; + heap_sort(list, comparator); + int expected[] = {32, 16, 10, 6, 0, -1, -5}; + for (size_type i = 0; i < 6; i++) { + ASSERT_EQ(expected[i], list[i]); + } +} + +TEST(heap_test, test_push_heap) { + ArrayList heap(20); + heap.push_back(5); + heap.push_back(10); + heap.push_back(1); + make_heap(heap.begin(), heap.end()); + heap.push_back(15); + push_heap(heap.begin(), heap.end()); + ASSERT_EQ(15, heap.front()); +} + +TEST(heap_test, test_make_heap) { + ReverseComparator comparator; + ArrayList heap(10); + heap.push_back(5); + heap.push_back(10); + heap.push_back(1); + heap.push_back(-5); + make_heap(heap.begin(), heap.end(), comparator); + ASSERT_EQ(-5, heap.front()); + pop_heap(heap.begin(), heap.end(), comparator); + ASSERT_EQ(1, heap.front()); + ASSERT_EQ(-5, heap.back()); +} + +TEST(heap_test, test_make_heap_single) { + ArrayList heap(1); + heap.push_back(5); + make_heap(heap.begin(), heap.end()); + ASSERT_EQ(5, heap.back()); + ASSERT_EQ(5, heap.front()); + heap.clear(); + ASSERT_EQ(0, heap.size()); + heap.push_back(10); + Comparator comparator; + make_heap(heap.begin(), heap.end(), comparator); + ASSERT_EQ(10, heap.back()); + ASSERT_EQ(10, heap.front()); +} + +TEST(heap_test, test_heap_push) { + ArrayHeap heap(5); + heap.push(5); + const int v = 7; + heap.push(v); + ASSERT_EQ(2, heap.size()); + ASSERT_EQ(7, heap.top()); + heap.pop(); + ASSERT_EQ(5, heap.top()); + heap.pop(); + ASSERT_EQ(0, heap.size()); +} + +TEST(heap_test, test_move_constructor) { + ArrayHeap heap(5); + heap.push(1); + heap.push(-1); + heap.push(5); + heap.push(-5); + ArrayHeap heap0(move(heap)); + ASSERT_EQ(4, heap0.size()); + ASSERT_EQ(0, heap.size()); + ASSERT_EQ(5, heap0.capacity()); + ASSERT_EQ(0, heap.capacity()); + ASSERT_EQ(5, heap0.top()); + heap0.pop(); + ASSERT_EQ(1, heap0.top()); + heap0.pop(); + ASSERT_EQ(-1, heap0.top()); + heap0.pop(); + ASSERT_EQ(-5, heap0.top()); + heap0.pop(); + ASSERT_EQ(0, heap0.size()); + ASSERT_TRUE(heap.empty()); + ASSERT_TRUE(heap0.empty()); + ASSERT_EQ(nullptr, heap.get_array_list()->data()); +} + +TEST(heap_test, test_move_assignment_operator) { + ArrayHeap heap(5); + heap.push(5); + heap.push(2); + heap.push(11); + ArrayHeap heap0(10); + heap0.push(1); + heap0.push(10); + heap0 = move(heap); + ASSERT_EQ(0, heap.size()); + ASSERT_EQ(0, heap.capacity()); + ASSERT_EQ(nullptr, heap.get_array_list()->data()); + ASSERT_EQ(3, heap0.size()); + ASSERT_EQ(5, heap0.capacity()); + ASSERT_EQ(11, heap0.top()); + heap0.pop(); + ASSERT_EQ(5, heap0.top()); + heap0.pop(); + ASSERT_EQ(2, heap0.top()); + heap0.pop(); + ASSERT_EQ(0, heap0.size()); +} diff --git a/tests/stl/list_check.cpp b/tests/stl/list_check.cpp new file mode 100644 index 00000000..d01e76ec --- /dev/null +++ b/tests/stl/list_check.cpp @@ -0,0 +1,441 @@ +#include "gtest/gtest.h" + +#include "stl/ArrayList.h" + +#include "../template_defs.h" + +using namespace wlp; + +typedef ArrayList::const_iterator cit; + +TEST(list_test, test_constructors) { + int values[] = {1, 2, 3, 4, 5}; + ArrayList list(values, 5, 2); + ASSERT_EQ(5, list.capacity()); + ASSERT_EQ(5, list.size()); + ArrayList list0(values, 5); + ASSERT_EQ(5, list0.capacity()); + ASSERT_EQ(5, list.size()); + for (size_type i = 0; i < 5; i++) { + ASSERT_EQ(values[i], list[i]); + ASSERT_EQ(values[i], list0[i]); + } +} + +TEST(list_test, test_at) { + int values[] = {2, 3, 5, 7, 11, 13}; + ArrayList list(values, 6); + ASSERT_EQ(2, list.at(0)); + ASSERT_EQ(11, list.at(4)); + list.at(0) = 111; + ASSERT_EQ(111, list[0]); + ASSERT_EQ(111, list.front()); + list.at(1) = 222; + ASSERT_EQ(222, list.at(7)); + const ArrayList const_list(move(list)); + ASSERT_EQ(111, const_list.at(0)); + ASSERT_EQ(222, const_list.at(7)); + ASSERT_EQ(111, const_list.front()); + ASSERT_EQ(13, const_list[5]); + ASSERT_EQ(13, const_list.back()); + ASSERT_EQ(111, const_list.data()[0]); +} + +TEST(list_test, test_const_list_back_front_when_empty) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + list.clear(); + const ArrayList const_list(move(list)); + ASSERT_EQ(0, const_list.size()); + ASSERT_EQ(1, const_list.back()); + ASSERT_EQ(1, const_list.front()); +} + +TEST(list_test, test_clear) { + int values[] = {2, 3, 5, 7}; + ArrayList list(values, 4); + list.clear(); + ASSERT_EQ(0, list.size()); + ASSERT_EQ(4, list.capacity()); + list.clear(); + ASSERT_EQ(2, list.front()); + ASSERT_EQ(2, list.back()); + ASSERT_EQ(2, list.at(100)); +} + +TEST(list_test, test_list_begin_end) { + ArrayList list(5); + ASSERT_EQ(list.begin(), list.end()); + list.push_back(1); + ASSERT_EQ(1, *list.begin()); + ArrayList::iterator it = list.begin(); + ASSERT_EQ(1, *it); + ++it; + ASSERT_EQ(list.end(), it); +} + +TEST(list_test, test_const_list_begin_end) { + int values[] = {1, 2, 3, 4}; + const ArrayList const_list(values, 4); + const ArrayList empty_const_list(5); + ASSERT_EQ(empty_const_list.begin(), empty_const_list.end()); + ArrayList::const_iterator it = const_list.begin(); + ASSERT_EQ(1, *it); + ++it; + ASSERT_EQ(2, *it); + ++it; + ASSERT_EQ(3, *it); + ++it; + ASSERT_EQ(4, *it); + ++it; + ASSERT_EQ(const_list.end(), it); +} + +TEST(list_test, test_insert_index_lvalue) { + int values[] = {1, 2, 3, 4}; + ArrayList list(values, 4, 5); + ASSERT_EQ(4, list.size()); + const int v = 100; + ArrayList::iterator it = list.insert(2, v); + ASSERT_EQ(100, *it); + int expected[] = {1, 2, 100, 3, 4}; + ASSERT_EQ(5, list.size()); + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(expected[i], list[i]); + } +} + +TEST(list_test, test_insert_index_rvalue) { + int values[] = {1, 10}; + ArrayList list(values, 2, 3); + ASSERT_EQ(2, list.size()); + ArrayList::iterator it = list.insert(1, 100); + ASSERT_EQ(100, *it); + int expected[] = {1, 100, 10}; + ASSERT_EQ(3, list.size()); + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(expected[i], list[i]); + } +} + +TEST(list_test, test_insert_iterator_lvalue) { + int values[] = {1, 10}; + ArrayList list(values, 2, 3); + ArrayList::iterator it = list.end(); + const int v = 100; + it = list.insert(it, v); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(100, *it); + ++it; + ASSERT_EQ(it, list.end()); +} + +TEST(list_test, test_insert_iterator_rvalue) { + int values[] = {1, 10}; + ArrayList list(values, 2, 2); + ArrayList::iterator it = list.begin(); + it = list.insert(it, 100); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(100, *it); + ++it; + ASSERT_EQ(1, *it); + ++it; + ASSERT_EQ(10, *it); + ++it; + ASSERT_EQ(list.end(), it); +} + +TEST(list_test, test_insert_when_full) { + int values[] = {1, 10}; + ArrayList list(values, 2); + list.insert(1, 15); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(4, list.capacity()); + ASSERT_EQ(1, *list.begin()); + ASSERT_EQ(15, list.at(1)); + ASSERT_EQ(10, list.at(2)); +} + +TEST(list_test, test_insert_when_empty) { + ArrayList list(5); + list.insert(0, 10); + ASSERT_EQ(1, list.size()); + ASSERT_EQ(5, list.capacity()); + ASSERT_EQ(10, list.at(0)); +} + +TEST(list_test, test_insert_iterator_when_empty) { + ArrayList list1(5); + ArrayList::iterator it1 = list1.begin(); + it1 = list1.insert(it1, 10); + ASSERT_EQ(1, list1.size()); + ASSERT_EQ(10, list1[0]); + ASSERT_EQ(10, *it1); + ArrayList list2(5); + ArrayList::iterator it2 = list2.end(); + it2 = list2.insert(it2, 10); + ASSERT_EQ(1, list2.size()); + ASSERT_EQ(10, list2[0]); + ASSERT_EQ(10, *it2); +} + +TEST(list_test, test_push_back_when_full) { + int values[] = {1, 2}; + ArrayList list(values, 2); + ASSERT_EQ(2, list.size()); + ASSERT_EQ(2, list.capacity()); + list.push_back(3); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(4, list.capacity()); + ASSERT_EQ(3, list.at(2)); +} + +TEST(list_test, test_erase_index) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(3, list.capacity()); + ArrayList::iterator it = list.erase(1); + ASSERT_EQ(3, *it); + ++it; + ASSERT_EQ(list.end(), it); + list.erase(0); + list.erase(0); + ASSERT_EQ(0, list.size()); + ASSERT_EQ(list.end(), list.erase(100)); +} + +TEST(list_test, test_erase_iterator) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + ArrayList::iterator it = list.end(); + ASSERT_EQ(list.end(), list.erase(it)); + it = list.begin(); + it = list.erase(it); + ASSERT_EQ(2, *it); + ASSERT_EQ(2, list.size()); + it = list.erase(it); + ASSERT_EQ(3, *it); + ASSERT_EQ(1, list.size()); + it = list.erase(it); + ASSERT_EQ(list.end(), it); + ASSERT_EQ(0, list.size()); + ASSERT_EQ(list.end(), list.erase(it)); +} + +TEST(list_test, test_swap_lists) { + int values1[] = {1, 2, 3}; + int values2[] = {11, 22, 33, 44, 55}; + ArrayList list1(values1, 3, 5); + ArrayList list2(values2, 5, 10); + list1.swap(list2); + ASSERT_EQ(5, list1.size()); + ASSERT_EQ(10, list1.capacity()); + ASSERT_EQ(3, list2.size()); + ASSERT_EQ(5, list2.capacity()); + for (size_type i = 0; i < list1.size(); i++) { + ASSERT_EQ(values2[i], list1[i]); + } + for (size_type i = 0; i < list2.size(); i++) { + ASSERT_EQ(values1[i], list2[i]); + } +} + +TEST(list_test, test_reserve) { + ArrayList list(10); + ASSERT_EQ(10, list.capacity()); + list.reserve(5); + ASSERT_EQ(10, list.capacity()); + list.push_back(10); + list.push_back(5); + list.reserve(15); + ASSERT_EQ(15, list.capacity()); + ASSERT_EQ(10, list.front()); + ASSERT_EQ(5, list.back()); +} + +TEST(list_test, test_shrink) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + list.shrink(); + ASSERT_EQ(3, list.size()); + ASSERT_EQ(3, list.capacity()); + list.pop_back(); + list.pop_back(); + ASSERT_EQ(1, list.size()); + ASSERT_EQ(3, list.capacity()); + list.shrink(); + ASSERT_EQ(1, list.capacity()); + ASSERT_EQ(1, list[0]); +} + +TEST(list_iterator_test, test_default_ctor) { + ArrayList::iterator it; +} + +TEST(list_iterator_test, test_move_ctor) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + ArrayList::iterator it = list.begin(); + ASSERT_EQ(1, *it); + ArrayList::iterator it1(move(it)); + ASSERT_EQ(1, *it1); +} + +TEST(list_iterator_test, test_overflow_ctor) { + int values[] = {1, 2, 3}; + ArrayList list(values, 3); + ArrayList::iterator it(100, &list); + ASSERT_EQ(list.end(), it); +} + +TEST(list_iterator_test, test_arrow_op) { + ArrayList string_list(2); + string_list.push_back(String8("hello")); + string_list.push_back(String8("woah")); + ArrayList::iterator it = string_list.begin(); + ASSERT_EQ(5, it->length()); + ++it; + ASSERT_EQ(4, it->length()); + ++it; + ASSERT_EQ(string_list.end(), it); + ++it; + ASSERT_EQ(string_list.end(), it); + it++; + ASSERT_EQ(string_list.end(), it); + string_list.push_back(String8("boi")); + it = string_list.begin(); + it += 2; + ASSERT_EQ(3, it->length()); + it -= 2; + ASSERT_EQ(5, it->length()); + size_type v = 2; + it += v; + ASSERT_EQ(3, it->length()); + it -= v; + ASSERT_EQ(5, it->length()); + it += (size_type) 100; + ASSERT_EQ(string_list.end(), it); + it += v; + ASSERT_EQ(string_list.end(), it); + it -= 1; + ASSERT_EQ(3, it->length()); + v = 1; + it -= v; + ASSERT_EQ(4, it->length()); + --it; + --it; + --it; + ASSERT_EQ(string_list.begin(), it); +} + +TEST(list_iterator_test, test_equality_operators) { + ArrayList list(5); + ArrayList::iterator it1 = list.begin(); + ArrayList::iterator it2 = list.end(); + ASSERT_TRUE(it1 == it2); + it1 = list.insert(0, 100); + it2 = list.end(); + ASSERT_TRUE(it1 != it2); + const ArrayList::iterator it3 = list.begin(); + const ArrayList::iterator it4 = list.end(); + ASSERT_TRUE(it3 != it4); + ASSERT_FALSE(it3 == it4); +} + +TEST(list_iterator_test, test_add_subtract) { + int values[] = {1, 2, 3, 4, 5, 6, 7}; + ArrayList list(values, 7); + ArrayList::iterator it1 = list.begin(); + ArrayList::iterator it2 = it1 + 4; + ASSERT_EQ(5, *it2); + size_type v = 2; + it1 = it2 - v; + ASSERT_EQ(3, *it1); + ASSERT_EQ(7, list.begin() - list.end()); + ASSERT_EQ(7, list.end() - list.begin()); + it1 = list.end(); + ASSERT_EQ(7, list.begin() - it1); +} + +TEST(list_const_iterator_test, test_arrow_op) { + ArrayList list(5); + list.push_back(String8("hello")); + const ArrayList const_list(move(list)); + ASSERT_EQ(5, const_list.begin()->length()); +} + +TEST(list_const_iterator_test, test_bulk_functions) { + cit it0; + int values[] = {1, 2, 3, 4, 5, 6, 7, 8}; + const ArrayList list(values, 8); + cit it1 = list.begin(); + cit it2 = it1; + ASSERT_EQ(1, *it1); + ASSERT_EQ(1, *it2); + cit it3(100, &list); + ASSERT_EQ(list.end(), it3); + cit it4 = list.end(); + it4++; + ASSERT_EQ(list.end(), it4); + cit it5 = list.begin(); + size_type v = 2; + it5 += 2; + it5 += v; + ASSERT_EQ(5, *it5); + it5 += 100; + ASSERT_EQ(list.end(), it5); + cit it6 = list.begin(); + v = 100; + it6 += v; + ASSERT_EQ(list.end(), it6); + cit it7 = list.begin(); + it7--; + ASSERT_EQ(it7, list.begin()); + it7++; + it7 += 5; + ASSERT_EQ(7, *it7); + it7--; + ASSERT_EQ(6, *it7); + it7 -= 2; + ASSERT_EQ(4, *it7); + v = 2; + it7 -= v; + ASSERT_EQ(2, *it7); + it7 -= 100; + ASSERT_EQ(list.begin(), it7); + it7 += 5; + ASSERT_EQ(6, *it7); + v = 100; + it7 -= v; + ASSERT_EQ(list.begin(), it7); + cit g1 = list.begin(); + cit g2 = list.end(); + ASSERT_FALSE(g1 == g2); + ASSERT_TRUE(g1 != g2); + ASSERT_NE(g1, g2); + g1 = g2; + ASSERT_EQ(g1, g2); + cit g3; + g3 = move(g1); + ASSERT_EQ(g3, g2); + cit g4 = list.begin(); + v = 2; + cit g5 = g4 + v; + cit g6 = g4 + 2; + ASSERT_EQ(g6, g5); + ASSERT_EQ(3, *g5); + cit g7 = g5 - 1; + v = 1; + cit g8 = g5 - v; + ASSERT_EQ(g7, g8); + ASSERT_EQ(2, *g8); + ASSERT_EQ(8, list.end() - list.begin()); + ASSERT_EQ(8, list.begin() - list.end()); + g8 = list.end(); + ASSERT_EQ(8, list.begin() - g8); + g8 = list.begin(); + ASSERT_EQ(8, list.end() - g8); + cit g9 = move(g8); + ASSERT_EQ(list.begin(), g9); +} diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp index 51358a98..08c562bd 100644 --- a/tests/stl/open_map_check.cpp +++ b/tests/stl/open_map_check.cpp @@ -12,268 +12,226 @@ typedef int_map::iterator imi; typedef Pair P_imi_b; TEST(open_map_test, test_constructor_parameters) { - int_map map(15, 61); - ASSERT_EQ(15, map.max_size()); - ASSERT_EQ(0, map.size()); - ASSERT_EQ(61, map.max_load()); + int_map map(15, 61); + ASSERT_EQ(15, map.capacity()); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(61, map.max_load()); } TEST(open_map_test, test_constructor_allocator) { - string_map map(12, 75); - const Allocator* alloc = map.get_node_allocator(); - size_t expected = sizeof(string_map::map_node); - ASSERT_EQ(expected, alloc->GetBlockSize()); - ASSERT_EQ(expected * 12, alloc->GetPoolSize()); + string_map map(12, 75); + const Allocator *alloc = map.get_node_allocator(); + size_t expected = sizeof(string_map::node_type); + ASSERT_EQ(expected, alloc->GetBlockSize()); + ASSERT_EQ(expected * 12, alloc->GetPoolSize()); } TEST(open_map_test, test_is_empty_on_construct) { - string_map map(12, 75); - ASSERT_TRUE(map.empty()); + string_map map(12, 75); + ASSERT_TRUE(map.empty()); } TEST(open_map_test, test_begin_returns_end_when_empty) { - string_map map(12, 75); - ASSERT_EQ(map.begin(), map.end()); + string_map map(12, 75); + ASSERT_EQ(map.begin(), map.end()); } TEST(open_map_test, test_begin_end_const_and_non_const) { - const string_map map(12, 75); - string_map non_map(12, 75); - string_map::const_iterator cit = map.begin(); - const string_map::const_iterator cit_end = map.end(); - string_map::const_iterator cit1(cit); - const string_map::const_iterator cit2(cit_end); - ASSERT_EQ(cit1, cit2); - ASSERT_TRUE(cit1 == cit2); - ASSERT_TRUE(cit2 == cit1); - cit1 = cit2; - cit = cit_end; - ASSERT_EQ(cit1, cit); - cit = cit1; - ASSERT_EQ(cit1, cit); - string_map::iterator it(non_map.end()); - string_map::iterator end = non_map.end(); - it = end; - ASSERT_EQ(non_map.end(), it); - ASSERT_EQ(cit, cit_end); + const string_map map(12, 75); + string_map non_map(12, 75); + string_map::const_iterator cit = map.begin(); + const string_map::const_iterator cit_end = map.end(); + string_map::const_iterator cit1(cit); + const string_map::const_iterator cit2(cit_end); + ASSERT_EQ(cit1, cit2); + ASSERT_TRUE(cit1 == cit2); + ASSERT_TRUE(cit2 == cit1); + cit1 = cit2; + cit = cit_end; + ASSERT_EQ(cit1, cit); + cit = cit1; + ASSERT_EQ(cit1, cit); + string_map::iterator it(non_map.end()); + string_map::iterator end = non_map.end(); + it = end; + ASSERT_EQ(non_map.end(), it); + ASSERT_EQ(cit, cit_end); } TEST(open_map_test, test_at_const) { - int_map map(10, 75); - map[7] = 7; - map[8] = 8; - map[9] = 9; - map[17] = 17; - const int_map const_map(map); - ASSERT_EQ(const_map.end(), const_map.at(10)); - ASSERT_EQ(7, *const_map.at(7)); - ASSERT_EQ(8, *const_map.at(8)); - ASSERT_EQ(9, *const_map.at(9)); - ASSERT_EQ(17, *const_map.at(17)); - ASSERT_EQ(const_map.at(7), const_map.find(7)); - ASSERT_EQ(const_map.at(10), const_map.find(10)); - ASSERT_EQ(const_map.at(9), const_map.find(9)); - int_map::const_iterator it = const_map.begin(); - ASSERT_EQ(17, *it); - ++it; - ASSERT_EQ(7, *it); - it++; - ASSERT_EQ(8, *it); + int_map map(10, 75); + map[7] = 7; + map[8] = 8; + map[9] = 9; + map[17] = 17; + const int_map const_map(move(map)); + ASSERT_EQ(const_map.end(), const_map.at(10)); + ASSERT_EQ(7, *const_map.at(7)); + ASSERT_EQ(8, *const_map.at(8)); + ASSERT_EQ(9, *const_map.at(9)); + ASSERT_EQ(17, *const_map.at(17)); + ASSERT_EQ(const_map.at(7), const_map.find(7)); + ASSERT_EQ(const_map.at(10), const_map.find(10)); + ASSERT_EQ(const_map.at(9), const_map.find(9)); + int_map::const_iterator it = const_map.begin(); + ASSERT_EQ(17, *it); + ++it; + ASSERT_EQ(7, *it); + it++; + ASSERT_EQ(8, *it); } TEST(open_map_test, test_insert_find_iterate_integer) { - int_map map(10, 61); - P_imi_b res1 = map.insert(0, 15); - P_imi_b res2 = map.insert(1, 20); - P_imi_b res3 = map.insert(0, 35); - P_imi_b res4 = map.insert(9, 90); - P_imi_b res5 = map.insert(20, 100); - P_imi_b res6 = map.insert(19, 120); - ASSERT_TRUE(res1.second()); - ASSERT_TRUE(res2.second()); - ASSERT_FALSE(res3.second()); - ASSERT_TRUE(res4.second()); - ASSERT_TRUE(res5.second()); - ASSERT_TRUE(res6.second()); - ASSERT_EQ(15, *res1.first()); - ASSERT_EQ(20, *res2.first()); - ASSERT_EQ(15, *res3.first()); - ASSERT_EQ(90, *res4.first()); - ASSERT_EQ(100, *res5.first()); - ASSERT_EQ(120, *res6.first()); - int_map::iterator it1 = res1.first(); - ++it1; - ASSERT_EQ(it1, res2.first()); - ASSERT_EQ(20, *it1); - ++it1; - ASSERT_EQ(it1, res5.first()); - ASSERT_EQ(100, *it1); - ++it1; - ASSERT_EQ(it1, res6.first()); - ASSERT_EQ(120, *it1); - ++it1; - ASSERT_EQ(it1, res4.first()); - ASSERT_EQ(90, *it1); - ++it1; - ASSERT_EQ(it1, map.end()); - ASSERT_EQ(5, map.size()); - ASSERT_EQ(10, map.max_size()); + int_map map(10, 61); + P_imi_b res1 = map.insert(0, 15); + P_imi_b res2 = map.insert(1, 20); + P_imi_b res3 = map.insert(0, 35); + P_imi_b res4 = map.insert(9, 90); + P_imi_b res5 = map.insert(20, 100); + P_imi_b res6 = map.insert(19, 120); + ASSERT_TRUE(res1.second()); + ASSERT_TRUE(res2.second()); + ASSERT_FALSE(res3.second()); + ASSERT_TRUE(res4.second()); + ASSERT_TRUE(res5.second()); + ASSERT_TRUE(res6.second()); + ASSERT_EQ(15, *res1.first()); + ASSERT_EQ(20, *res2.first()); + ASSERT_EQ(15, *res3.first()); + ASSERT_EQ(90, *res4.first()); + ASSERT_EQ(100, *res5.first()); + ASSERT_EQ(120, *res6.first()); + int_map::iterator it1 = res1.first(); + ++it1; + ASSERT_EQ(it1, res2.first()); + ASSERT_EQ(20, *it1); + ++it1; + ASSERT_EQ(it1, res5.first()); + ASSERT_EQ(100, *it1); + ++it1; + ASSERT_EQ(it1, res6.first()); + ASSERT_EQ(120, *it1); + ++it1; + ASSERT_EQ(it1, res4.first()); + ASSERT_EQ(90, *it1); + ++it1; + ASSERT_EQ(it1, map.end()); + ASSERT_EQ(5, map.size()); + ASSERT_EQ(10, map.capacity()); } TEST(open_map_test, test_map_iterator_postfix) { - int_map map(15, 75); - P_imi_b res1 = map.insert(2, 10); - map.insert(10, 12); - imi it = res1.first(); - imi it_post = it++; - ASSERT_NE(it_post, it); - ASSERT_EQ(it_post, res1.first()); - ASSERT_EQ(*it_post, 10); - ASSERT_EQ(*it, 12); - ++it_post; - ASSERT_EQ(it_post, it); - ASSERT_EQ(2, map.size()); + int_map map(15, 75); + P_imi_b res1 = map.insert(2, 10); + map.insert(10, 12); + imi it = res1.first(); + imi it_post = it++; + ASSERT_NE(it_post, it); + ASSERT_EQ(it_post, res1.first()); + ASSERT_EQ(*it_post, 10); + ASSERT_EQ(*it, 12); + ++it_post; + ASSERT_EQ(it_post, it); + ASSERT_EQ(2, map.size()); } TEST(open_map_test, test_begin_non_empty) { - int_map map(15, 75); - map[5] = 5; - ASSERT_EQ(5, *map.begin()); - const int_map const_map(map); - ASSERT_EQ(5, *const_map.begin()); -} - -TEST(open_map_test, test_copy_constructor) { - int_map source(15, 75); - source[1] = 1; - source[3] = 3; - source[33] = 33; - int_map copy1(source); - ASSERT_EQ(3, copy1.size()); - imi it1 = copy1.begin(); - ASSERT_EQ(1, *it1); - ++it1; - ASSERT_EQ(3, *it1); - ++it1; - ASSERT_EQ(33, *it1); - ++it1; - ASSERT_EQ(copy1.end(), it1); - const int_map copy2 = source; - const int_map copy3(copy2); - int_map copy4; - copy4 = copy3; - ASSERT_EQ(3, copy4.size()); - imi it3 = copy4.begin(); - ASSERT_EQ(1, *it3); - ++it3; - ASSERT_EQ(3, *it3); - ++it3; - ASSERT_EQ(33, *it3); - ++it3; - ASSERT_EQ(copy4.end(), it3); - int_map copy5; - copy5[6] = 6; - copy5[2] = 2; - copy5 = source; - it1 = copy5.begin(); - ASSERT_EQ(1, *it1); - ++it1; - ASSERT_EQ(3, *it1); - ++it1; - ASSERT_EQ(33, *it1); - ++it1; - ASSERT_EQ(copy5.end(), it1); + int_map map(15, 75); + map[5] = 5; + ASSERT_EQ(5, *map.begin()); + const int_map const_map(move(map)); + ASSERT_EQ(5, *const_map.begin()); } TEST(open_map_test, test_map_insert_or_assign) { - int_map map(10, 75); - P_imi_b res1 = map.insert_or_assign(2, 10); - P_imi_b res2 = map.insert_or_assign(3, 12); - P_imi_b res3 = map.insert_or_assign(2, 14); - ASSERT_TRUE(res1.second()); - ASSERT_TRUE(res2.second()); - ASSERT_FALSE(res3.second()); - ASSERT_EQ(14, *res1.first()); - ASSERT_EQ(12, *res2.first()); - ASSERT_EQ(14, *res3.first()); - ASSERT_EQ(2, map.size()); + int_map map(10, 75); + P_imi_b res1 = map.insert_or_assign(2, 10); + P_imi_b res2 = map.insert_or_assign(3, 12); + P_imi_b res3 = map.insert_or_assign(2, 14); + ASSERT_TRUE(res1.second()); + ASSERT_TRUE(res2.second()); + ASSERT_FALSE(res3.second()); + ASSERT_EQ(14, *res1.first()); + ASSERT_EQ(12, *res2.first()); + ASSERT_EQ(14, *res3.first()); + ASSERT_EQ(2, map.size()); } TEST(open_map_test, test_at_returns_value) { - int_map map(10, 75); - map.insert(10, 12); - map.insert(16, 15); - map.insert(20, 19); - map.insert(4, 16); - ASSERT_EQ(4, map.size()); - ASSERT_EQ(12, *map.at(10)); - ASSERT_EQ(15, *map.at(16)); - ASSERT_EQ(19, *map.at(20)); - ASSERT_EQ(16, *map.at(4)); + int_map map(10, 75); + map.insert(10, 12); + map.insert(16, 15); + map.insert(20, 19); + map.insert(4, 16); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(12, *map.at(10)); + ASSERT_EQ(15, *map.at(16)); + ASSERT_EQ(19, *map.at(20)); + ASSERT_EQ(16, *map.at(4)); } TEST(open_map_test, test_at_is_assignable) { - int_map map(10, 75); - map.insert(10, 12); - map.insert(16, 15); - ASSERT_EQ(15, *map.at(16)); - ASSERT_EQ(12, *map.at(10)); - ASSERT_EQ(2, map.size()); - *map.at(16) = 100; - *map.at(10) = 101; - ASSERT_EQ(100, *map.at(16)); - ASSERT_EQ(101, *map.at(10)); - ASSERT_EQ(2, map.size()); + int_map map(10, 75); + map.insert(10, 12); + map.insert(16, 15); + ASSERT_EQ(15, *map.at(16)); + ASSERT_EQ(12, *map.at(10)); + ASSERT_EQ(2, map.size()); + *map.at(16) = 100; + *map.at(10) = 101; + ASSERT_EQ(100, *map.at(16)); + ASSERT_EQ(101, *map.at(10)); + ASSERT_EQ(2, map.size()); } TEST(open_map_test, test_at_returns_pass_the_end) { - int_map map(10, 75); - ASSERT_EQ(map.end(), map.at(4)); + int_map map(10, 75); + ASSERT_EQ(map.end(), map.at(4)); } TEST(open_map_test, test_contains_key) { - string_map map(10, 75); - string16 key1{"moshi"}; - string16 key2{"welcome"}; - string16 key3{"never"}; - string16 val1{"someval"}; - string16 val2{"anotherval"}; - string16 val3{"yetanother"}; - ASSERT_TRUE(map.insert(key1, val1).second()); - ASSERT_TRUE(map.insert(key2, val2).second()); - ASSERT_TRUE(map.insert(key3, val3).second()); - ASSERT_TRUE(map.contains(key1)); - ASSERT_TRUE(map.contains(key2)); - ASSERT_TRUE(map.contains(key3)); - ASSERT_EQ(val1, *map.at(key1)); - ASSERT_EQ(val2, *map.at(key2)); - ASSERT_EQ(val3, *map.at(key3)); + string_map map(10, 75); + string16 key1{"moshi"}; + string16 key2{"welcome"}; + string16 key3{"never"}; + string16 val1{"someval"}; + string16 val2{"anotherval"}; + string16 val3{"yetanother"}; + ASSERT_TRUE(map.insert(key1, val1).second()); + ASSERT_TRUE(map.insert(key2, val2).second()); + ASSERT_TRUE(map.insert(key3, val3).second()); + ASSERT_TRUE(map.contains(key1)); + ASSERT_TRUE(map.contains(key2)); + ASSERT_TRUE(map.contains(key3)); + ASSERT_EQ(val1, *map.at(key1)); + ASSERT_EQ(val2, *map.at(key2)); + ASSERT_EQ(val3, *map.at(key3)); } TEST(open_map_test, test_find) { - int_map map(10, 75); - P_imi_b r1 = map.insert(1, 10); - P_imi_b r2 = map.insert(3, 30); - P_imi_b r3 = map.insert(5, 50); - P_imi_b r4 = map.insert(7, 70); - ASSERT_EQ(r1.first(), map.find(1)); - ASSERT_EQ(r2.first(), map.find(3)); - ASSERT_EQ(r3.first(), map.find(5)); - ASSERT_EQ(r4.first(), map.find(7)); + int_map map(10, 75); + P_imi_b r1 = map.insert(1, 10); + P_imi_b r2 = map.insert(3, 30); + P_imi_b r3 = map.insert(5, 50); + P_imi_b r4 = map.insert(7, 70); + ASSERT_EQ(r1.first(), map.find(1)); + ASSERT_EQ(r2.first(), map.find(3)); + ASSERT_EQ(r3.first(), map.find(5)); + ASSERT_EQ(r4.first(), map.find(7)); } TEST(open_map_test, test_access_operator) { - int_map map(10, 75); - map.insert(5, 100); - map[5] = 19; - map[10] = 14; - map[556] = 9901; - ASSERT_EQ(19, map[5]); - ASSERT_EQ(14, map[10]); - ASSERT_EQ(9901, map[556]); - ASSERT_FALSE(map.insert(5, 20).second()); - ASSERT_FALSE(map.insert(556, 10).second()); - ASSERT_TRUE(map.contains(10)); + int_map map(10, 75); + map.insert(5, 100); + map[5] = 19; + map[10] = 14; + map[556] = 9901; + ASSERT_EQ(19, map[5]); + ASSERT_EQ(14, map[10]); + ASSERT_EQ(9901, map[556]); + ASSERT_FALSE(map.insert(5, 20).second()); + ASSERT_FALSE(map.insert(556, 10).second()); + ASSERT_TRUE(map.contains(10)); } TEST(open_map_test, test_rehash) { @@ -294,3 +252,114 @@ TEST(open_map_test, test_rehash) { ASSERT_EQ(*map.find(keys[i]), values[i]); } } + +TEST(open_map_test, test_clear_map) { + int_map map(20, 90); + map[0] = 0; + map[1] = 10; + map[2] = 20; + map[3] = 30; + map[4] = 40; + map[115] = 2115; + map[226] = 2216; + map[337] = 2317; + map[448] = 2418; + ASSERT_EQ(9, map.size()); + map.clear(); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(20, map.capacity()); + ASSERT_EQ(map.begin(), map.end()); +} + +TEST(open_map_test, test_insert_or_assign_collision) { + int_map map(20, 90); + map[0] = 0; + map[20] = 20; + map[40] = 40; + P_imi_b r1 = map.insert_or_assign(40, 45); + ASSERT_FALSE(r1.second()); + ASSERT_EQ(45, map[40]); +} + +TEST(open_map_test, test_erase_iterator_invalid_iterator) { + int_map map(20, 90); + int_map::iterator it; + map.erase(it); + ASSERT_EQ(map.end(), it); +} + +TEST(open_map_test, test_erase_iterator_invalid_node) { + int_map map(10, 90); + map[0] = 0; + map[1] = 10; + map[2] = 20; + int_map::node_type invalid_node; + invalid_node.m_key = 10; + invalid_node.m_val = 100; + int_map::iterator it; + it.m_current = &invalid_node; + it.m_hash_map = ↦ + ASSERT_EQ(map.end(), map.erase(it)); +} + +TEST(open_map_test, test_erase_iterator_rehash) { + int_map map(10, 90); + map[8] = 80; + map[88] = 880; + map[28] = 280; + map[38] = 380; + map[48] = 480; + ASSERT_EQ(10, map.capacity()); + ASSERT_EQ(5, map.size()); + imi it = map.begin(); + it = map.erase(it); + ASSERT_EQ(380, *it); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(10, map.capacity()); +} + +TEST(open_map_test, test_erase_nonexisting_key) { + int_map map(10, 90); + map[8] = 80; + map[88] = 880; + uint16_t k = 28; + ASSERT_FALSE(map.erase(k)); +} + +TEST(open_map_test, test_erase_key_rehash) { + int_map map(10, 90); + map[8] = 80; + map[88] = 880; + map[28] = 280; + map[38] = 380; + map[48] = 480; + ASSERT_EQ(10, map.capacity()); + ASSERT_EQ(5, map.size()); + uint16_t k = 28; + ASSERT_TRUE(map.erase(k)); + ASSERT_EQ(4, map.size()); + ASSERT_EQ(10, map.capacity()); +} + +TEST(open_map_test, test_move_assignment) { + int_map map(10, 90); + map[8] = 80; + map[88] = 880; + map[28] = 280; + map[38] = 380; + map[48] = 480; + int_map map1(12, 91); + map1 = move(map); + ASSERT_EQ(0, map.size()); + ASSERT_EQ(0, map.capacity()); + ASSERT_EQ(5, map1.size()); + ASSERT_EQ(10, map1.capacity()); + ASSERT_EQ(90, map1.max_load()); + imi it = map1.begin(); + uint16_t expected_traverse[] = {280, 380, 480, 80, 880}; + for (size_type i = 0; i < 5; i++) { + ASSERT_EQ(expected_traverse[i], *it); + ++it; + } + ASSERT_EQ(map1.end(), it); +} diff --git a/tests/stl/pair_check.cpp b/tests/stl/pair_check.cpp index 1f7c01e4..5e38e2cf 100644 --- a/tests/stl/pair_check.cpp +++ b/tests/stl/pair_check.cpp @@ -6,28 +6,28 @@ using namespace wlp; TEST(pair_test, test_pair_constructor) { - Pair pair1{5, "string"}; - Pair pair2{8, "nothing"}; - Pair pair3{5, "string"}; - Pair pair4{9, "another"}; - ASSERT_TRUE(pair1 == pair3); - ASSERT_EQ(5, pair1.first()); - ASSERT_EQ(8, pair2.first()); - ASSERT_STREQ("string", pair3.second()); - ASSERT_STREQ("another", pair4.second()); + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; + Pair pair3{5, "string"}; + Pair pair4{9, "another"}; + ASSERT_TRUE(pair1 == pair3); + ASSERT_EQ(5, pair1.first()); + ASSERT_EQ(8, pair2.first()); + ASSERT_STREQ("string", pair3.second()); + ASSERT_STREQ("another", pair4.second()); } TEST(pair_test, test_pair_assign_operator) { - Pair pair1{5, "string"}; - Pair pair2{8, "nothing"}; - pair2 = pair1; - ASSERT_TRUE(pair1 == pair2); - ASSERT_EQ(pair1.first(), pair2.first()); - ASSERT_EQ(pair1.second(), pair2.second()); + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; + pair2 = pair1; + ASSERT_TRUE(pair1 == pair2); + ASSERT_EQ(pair1.first(), pair2.first()); + ASSERT_EQ(pair1.second(), pair2.second()); } TEST(pair_test, test_pair_const_equality) { - Pair pair1{5, "string"}; - const Pair pair2{8, "nothing"}; - ASSERT_FALSE(pair1 == pair2); + Pair pair1{5, "string"}; + const Pair pair2{8, "nothing"}; + ASSERT_FALSE(pair1 == pair2); } diff --git a/tests/stl/tuple_check.cpp b/tests/stl/tuple_check.cpp new file mode 100644 index 00000000..b5822411 --- /dev/null +++ b/tests/stl/tuple_check.cpp @@ -0,0 +1,142 @@ +#include "gtest/gtest.h" + +#include "stl/Tuple.h" +#include "stl/OpenMap.h" + +using namespace wlp; + +TEST(tuple_test, test_tuple_create) { + Tuple tuple(34, 2.1f, "hello"); + int v1 = get<0>(tuple); + float v2 = get<1>(tuple); + const char *v3 = get<2>(tuple); + ASSERT_EQ(34, v1); + ASSERT_FLOAT_EQ(2.1f, v2); + ASSERT_STREQ("hello", v3); + get<0>(tuple) = 25; + ASSERT_EQ(25, get<0>(tuple)); + get<1>(tuple) = 0.5556f; + ASSERT_FLOAT_EQ(0.5556f, get<1>(tuple)); +} + +TEST(tuple_test, test_tuple_default) { + Tuple tuple; + ASSERT_EQ(0, get<0>(tuple)); + ASSERT_FLOAT_EQ(0, get<1>(tuple)); + ASSERT_EQ(0, get<2>(tuple)); +} + +TEST(tuple_test, test_make_tuple) { + int x = 12; + auto tuple = make_tuple(45, x, 1.246); + ASSERT_EQ(45, get<0>(tuple)); + ASSERT_EQ(12, get<1>(tuple)); + ASSERT_DOUBLE_EQ(1.246, get<2>(tuple)); +} + +TEST(tuple_test, test_tuple_size) { + auto tuple = make_tuple(1, 2, 3, 4, 5, 6); + ASSERT_EQ(6, get_tuple_size(tuple)); + ASSERT_EQ(6, tuple_size::value); +} + +TEST(tuple_test, test_tuple_cat) { + auto tupleA = make_tuple(45, 65.55, "hello"); + auto tupleB = make_tuple(77.886, "goodbye", 23); + auto tuple = tuple_cat_pair(tupleA, tupleB); + ASSERT_EQ(6, tuple_size::value); + ASSERT_EQ(6, get_tuple_size(tuple)); + ASSERT_EQ(45, get<0>(tuple)); + ASSERT_DOUBLE_EQ(65.55, get<1>(tuple)); + ASSERT_STREQ("hello", get<2>(tuple)); + ASSERT_DOUBLE_EQ(77.886, get<3>(tuple)); + ASSERT_STREQ("goodbye", get<4>(tuple)); + ASSERT_EQ(23, get<5>(tuple)); +} + +TEST(tuple_test, test_tuple_multi_cat) { + auto tupleA = make_tuple(1); + auto tupleB = make_tuple(56.65, 43.32); + auto tupleC = make_tuple("string", "string"); + auto tuple = tuple_cat(tupleA, tupleB, tupleC); + ASSERT_EQ(5, tuple_size::value); + ASSERT_EQ(1, get<0>(tuple)); + ASSERT_DOUBLE_EQ(56.65, get<1>(tuple)); + ASSERT_DOUBLE_EQ(43.32, get<2>(tuple)); + ASSERT_STREQ("string", get<3>(tuple)); + ASSERT_STREQ("string", get<4>(tuple)); + Tuple i_tuple_1(1); + Tuple i_tuple_2(2); + Tuple i_tuple_3(3); + Tuple i_tuple_4(4); + Tuple i_tuple = tuple_cat(i_tuple_1, i_tuple_2, i_tuple_3, i_tuple_4); + ASSERT_EQ(1, get<0>(i_tuple)); + ASSERT_EQ(2, get<1>(i_tuple)); + ASSERT_EQ(3, get<2>(i_tuple)); + ASSERT_EQ(4, get<3>(i_tuple)); +} + +TEST(tuple_test, test_forward_as_tuple) { + int a, d = 5; + double b; + char c; + Tuple tuple = forward_as_tuple(a, b, c, move(d)); + get<0>(tuple) = 10; + ASSERT_EQ(10, a); + get<1>(tuple) = 12.3; + ASSERT_DOUBLE_EQ(12.3, b); + get<2>(tuple) = 'h'; + ASSERT_EQ('h', c); + ASSERT_EQ(5, get<3>(tuple)); + get<3>(tuple) = 5555; + ASSERT_EQ(5555, d); +} + +TEST(tuple_test, test_assign_pair) { + Tuple tuple = make_tuple(12, 34); + ASSERT_EQ(12, get<0>(tuple)); + ASSERT_EQ(34, get<1>(tuple)); + Pair pair(16, 19); + tuple = pair; + ASSERT_EQ(16, get<0>(tuple)); + ASSERT_EQ(19, get<1>(tuple)); + OpenHashMap int_map(10, 61); + OpenHashMap::iterator it; + bool b; + tie(it, b) = int_map.insert(5, 1); + ASSERT_EQ(1, *it); + ++it; + ASSERT_EQ(int_map.end(), it); + ASSERT_TRUE(b); + tie(it, b) = int_map.insert(5, 10); + ASSERT_EQ(1, *it); + ASSERT_FALSE(b); + ++it; + ASSERT_EQ(int_map.end(), it); + tie(ignore, b) = int_map.insert(6, 4); + ASSERT_TRUE(b); + tie(ignore, b) = int_map.insert(6, 10); + ASSERT_FALSE(b); +} + +TEST(tuple_test, test_tuple_assign) { + auto tupleA = make_tuple(5, 6, 7, 8); + auto tupleB = make_tuple(0, 0, 0, 0); + tupleB = tupleA; + ASSERT_EQ(5, get<0>(tupleB)); + ASSERT_EQ(6, get<1>(tupleB)); + ASSERT_EQ(7, get<2>(tupleB)); + ASSERT_EQ(8, get<3>(tupleB)); +} + +TEST(tuple_test, test_tuple_tie) { + int a, b; + char c; + double d; + auto tuple = make_tuple(55, 66, 'g', 66.55); + tie(a, b, c, d) = tuple; + ASSERT_EQ(55, a); + ASSERT_EQ(66, b); + ASSERT_EQ('g', c); + ASSERT_DOUBLE_EQ(66.55, d); +} diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 678e13d2..22794f81 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -1,4 +1,3 @@ - /** * @file static_string_check.cpp * @brief Unit Testing for StaticString class present in Wlib library @@ -9,10 +8,8 @@ */ #include "gtest/gtest.h" -#include "strings/StaticString.h" #include "Types.h" -#include "../template_defs.h" using namespace wlp; diff --git a/tests/template_defs.h b/tests/template_defs.h index b7b09b84..dc881267 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -2,66 +2,147 @@ #define TEMPLATE_DEFS_H #include "Types.h" + +#include "stl/Utility.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" +#include "stl/ArrayHeap.h" namespace wlp { - template class Pair; - template class ChainHashMap, StaticString<16>>; - template class ChainHashMap; - template class Pair::iterator, bool>; - template class Pair, StaticString<16>>::iterator, bool>; - template class ChainHashMapIterator< - StaticString<16>, - StaticString<16>, - hash, uint16_t>, - equals>>; - template class ChainHashMapIterator< - uint16_t, - uint16_t, - hash, - equals>; - template class ChainHashMapConstIterator< - StaticString<16>, - StaticString<16>, - hash, uint16_t>, - equals>>; - template class ChainHashMapConstIterator< - uint16_t, - uint16_t, - hash, - equals>; - template class equals>; - template class equals; - template class hash, uint16_t>; - template class hash; - template class hash; - template class OpenHashMap, StaticString<16>>; - template class OpenHashMap; - template class Pair::iterator, bool>; - template class Pair, StaticString<16>>::iterator, bool>; - template class OpenHashMapIterator< - StaticString<16>, - StaticString<16>, - hash, uint16_t>, - equals>>; - template class OpenHashMapIterator< - uint16_t, - uint16_t, - hash, - equals>; - template class OpenHashMapConstIterator< - StaticString<16>, - StaticString<16>, - hash, uint16_t>, - equals>>; - template class OpenHashMapConstIterator< - uint16_t, - uint16_t, - hash, - equals>; - template class StaticString<8>; - template class StaticString<16>; + template + struct Pair; + + template + class ChainHashMap, StaticString<16>>; + + template + class ChainHashMap; + + template + struct Pair::iterator, bool>; + + template + struct Pair, StaticString<16>>::iterator, bool>; + + template + struct ChainHashMapIterator< + StaticString<16>, + StaticString<16>, + Hash, uint16_t>, + Equal>>; + + template + struct ChainHashMapIterator< + uint16_t, + uint16_t, + Hash, + Equal>; + + template + struct ChainHashMapConstIterator< + StaticString<16>, + StaticString<16>, + Hash, uint16_t>, + Equal>>; + + template + struct ChainHashMapConstIterator< + uint16_t, + uint16_t, + Hash, + Equal>; + + template + struct Equal>; + + template + struct Equal; + + template + struct Hash, uint16_t>; + + template + struct Hash; + + template + struct Hash; + + template + class OpenHashMap, StaticString<16>>; + + template + class OpenHashMap; + + template + struct Pair::iterator, bool>; + + template + struct Pair, StaticString<16>>::iterator, bool>; + + template + struct OpenHashMapIterator< + StaticString<16>, + StaticString<16>, + Hash, uint16_t>, + Equal>>; + + template + struct OpenHashMapIterator< + uint16_t, + uint16_t, + Hash, + Equal>; + + template + struct OpenHashMapConstIterator< + StaticString<16>, + StaticString<16>, + Hash, uint16_t>, + Equal>>; + + template + struct OpenHashMapConstIterator< + uint16_t, + uint16_t, + Hash, + Equal>; + + template + class ArrayHeap; + + template + class ArrayHeap; + + template + class ArrayList; + + template + class StaticString<8>; + + template + class StaticString<16>; + + template + class ArrayListIterator; + + template + class ArrayListIterator; + + template + class ArrayListConstIterator; + + template + class ArrayListConstIterator; + + template + struct Comparator; + + template + struct ReverseComparator; + + template + struct Comparator; + } #endif // TEMPLATE_DEFS_H diff --git a/wmake b/wmake index 6b0f2d66..72497e72 100755 --- a/wmake +++ b/wmake @@ -270,6 +270,17 @@ _simple() { elif [ "$1" == 'test' ]; then echo "Testing the project" _test + elif [ "$1" == 'rebuild' ]; then + echo "Rebuilding project" + _clean + _build + if ! [ $# -eq 2 ] || [ "$2" != 'notest' ]; then + _test + fi + elif [ "$1" == 'clcov' ]; then + echo "Rebuilding and coverage" + _clean + _coverage else _print_help fi From d5097562cee0582d8db12f940488f19fd201cd34 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Tue, 14 Nov 2017 13:41:37 -0500 Subject: [PATCH 013/102] [HF] namespace wlp added for Static and Dynamic Allocator (#53) * using namespace removed from StaticAllocatorPool * using namespace removed from Dynamic String * added StaticStringPool under wlp namespace * Added DynamicAllocatorPool under namespace wlp --- lib/wlib/memory/DynamicAllocatorPool.h | 14 +++++++------- lib/wlib/memory/StaticAllocatorPool.h | 17 +++++++++-------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/wlib/memory/DynamicAllocatorPool.h b/lib/wlib/memory/DynamicAllocatorPool.h index 8a42bffb..65de83f3 100644 --- a/lib/wlib/memory/DynamicAllocatorPool.h +++ b/lib/wlib/memory/DynamicAllocatorPool.h @@ -15,12 +15,12 @@ #include "Allocator.h" -using namespace wlp; - -template -class DynamicAllocatorPool : public Allocator { -public: - DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks) {} -}; +namespace wlp{ + template + class DynamicAllocatorPool : public Allocator { + public: + DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks) {} + }; +} #endif //FIXED_MEMORY_ALLOCATORPOOL_H diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index 1606941c..9c524e9a 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -15,14 +15,15 @@ #include "Allocator.h" -using namespace wlp; +namespace wlp{ + template + class StaticAllocatorPool : public Allocator { + public: + StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC){} + private: + char m_memory[tblockSize * tnumBlocks]; + }; +} -template -class StaticAllocatorPool : public Allocator { -public: - StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC){} -private: - char m_memory[tblockSize * tnumBlocks]; -}; #endif //FIXED_MEMORY_ALLOCATORPOOL_H From 9b6f960b27de46314673bef3a1736bc11009080e Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Sun, 19 Nov 2017 20:26:29 -0800 Subject: [PATCH 014/102] [HF] adding some missing docs (#54) * Added some missing docs/blame * Update Bitset.h * Update Hash.h --- lib/wlib/Types.h | 2 +- lib/wlib/memory/Allocator.h | 25 ++++++++++ lib/wlib/stl/Bitset.h | 1 + lib/wlib/stl/Equal.h | 31 +++++++++++++ lib/wlib/stl/Hash.h | 91 +++++++++++++++++-------------------- lib/wlib/stl/Pair.h | 21 +++++---- lib/wlib/stl/Tmp.h | 4 -- lib/wlib/stl/Utility.h | 19 ++++++++ 8 files changed, 130 insertions(+), 64 deletions(-) diff --git a/lib/wlib/Types.h b/lib/wlib/Types.h index ea9991f5..a3a337ab 100644 --- a/lib/wlib/Types.h +++ b/lib/wlib/Types.h @@ -1,6 +1,6 @@ /** * @file Types.h - * @brief type definition of all the types we will be using + * @brief Type definition of all the types we will be using * * @author Deep Dhillon * @date November 12, 2017 diff --git a/lib/wlib/memory/Allocator.h b/lib/wlib/memory/Allocator.h index d653ec59..55db9811 100644 --- a/lib/wlib/memory/Allocator.h +++ b/lib/wlib/memory/Allocator.h @@ -39,8 +39,18 @@ namespace wlp { DYNAMIC /**< this is Heap memory */ }; + /** + * Disable copy construction. + */ Allocator(const Allocator &) = delete; + /** + * Move constructor will transfer the resources of another + * allocator into this instance. + * + * @author Jeff Niu + * @param allocator the allocator to move + */ Allocator(Allocator &&allocator); /** @@ -181,8 +191,23 @@ namespace wlp { return m_deallocations; } + /** + * Disable copy assignment. + * + * @return reference to this allocator + */ Allocator &operator=(const Allocator &) = delete; + /** + * Move assignment operator deconstructs the current allocator + * resources and transfers the resources from the assigned allocator. + * Beware that all previous allocations with this allocator become + * invalid, as leaving them uncleared would cause memory leaks. + * + * @author Jeff Niu + * @param allocator the allocator to move + * @return reference to this allocator + */ Allocator &operator=(Allocator &&allocator); private: diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index 44509e09..cca3074f 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -5,6 +5,7 @@ * It provides setting, resetting, testing and flipping of bits * * @author Deep Dhillon + * @author Jeff Niu * @date October 28, 2017 * @bug No Known bugs */ diff --git a/lib/wlib/stl/Equal.h b/lib/wlib/stl/Equal.h index 7f9b92a5..f2066cbb 100644 --- a/lib/wlib/stl/Equal.h +++ b/lib/wlib/stl/Equal.h @@ -28,6 +28,14 @@ namespace wlp { } }; + /** + * Checks whether two static strings are equal. + * + * @tparam tSize static string size + * @param str1 first string + * @param str2 second string + * @return true if the strings are equal + */ template inline bool static_string_equals(const StaticString &str1, const StaticString &str2) { if (str1.length() != str2.length()) { @@ -41,6 +49,13 @@ namespace wlp { return true; } + /** + * Checks whether two C strings are equal. + * + * @param str1 first string + * @param str2 second string + * @return true if the strings are equal + */ inline bool string_equals(const char *&str1, const char *&str2) { for (; *str1 && *str2; ++str1, ++str2) { if (*str1 != *str2) { @@ -50,6 +65,11 @@ namespace wlp { return *str1 == *str2; } + /** + * Template specialization for static string. + * + * @tparam tSize static string size + */ template struct Equal> { bool operator()(const StaticString &key1, const StaticString &key2) const { @@ -57,6 +77,11 @@ namespace wlp { } }; + /** + * Template specialization for const static string. + * + * @tparam tSize static string size + */ template struct Equal> { bool operator()(const StaticString &key1, const StaticString &key2) const { @@ -64,6 +89,9 @@ namespace wlp { } }; + /** + * Template specialization for character arrays. + */ template<> struct Equal { bool operator()(const char *key1, const char *key2) const { @@ -71,6 +99,9 @@ namespace wlp { } }; + /** + * Template specialization for C strings. + */ template<> struct Equal { bool operator()(const char *key1, const char *key2) const { diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index 819c6454..1aa345c2 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -25,14 +25,30 @@ namespace wlp { /** * A basic hash function is defined to be a function that, as best * as reasonably possible, maps a key-type value to a unique positive integer - * value. This is the parent template of hash functions for basic types in WLib. + * value. + * + * @pre The default hash function attempts to cast to the integer type, + * which works for integer, character, and floating point types. + * * @tparam Key key type * @tparam IntType the unsigned integer type to return */ template struct Hash { + IntType operator()(const Key &key) const { + return (IntType) key; + } }; + /** + * Hash a static string by multiplying the character value + * by 127 and adding consecutively. + * + * @tparam IntType the integer return type + * @tparam tSize the static string size + * @param static_string the string to hash + * @return a hash code of the string + */ template inline IntType hash_static_string(StaticString &static_string) { IntType h = 0; @@ -42,6 +58,14 @@ namespace wlp { return h; }; + /** + * Hash a C string by multiplying the character value + * by 127 and adding consecutively. + * + * @tparam IntType the integer return type value + * @param s the string to hash + * @return a hash code of the string + */ template inline IntType hash_string(const char *s) { IntType h = 0; @@ -51,6 +75,12 @@ namespace wlp { return h; } + /** + * Template specialization for static stirng. + * + * @tparam IntType hash code integer type + * @tparam tSize static string size + */ template struct Hash, IntType> { IntType operator()(StaticString &s) const { @@ -58,6 +88,11 @@ namespace wlp { } }; + /** + * Template specialization for C strings. + * + * @tparam IntType hash code integer type + */ template struct Hash { IntType operator()(const char *s) const { @@ -65,6 +100,11 @@ namespace wlp { } }; + /** + * Template specialization for C strings. + * + * @tparam IntType hash code integer type + */ template struct Hash { IntType operator()(const char *s) const { @@ -72,55 +112,6 @@ namespace wlp { } }; - template - struct Hash { - IntType operator()(char x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(uint8_t x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(uint16_t x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(uint32_t x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(int8_t x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(int16_t x) const { - return (IntType) x; - } - }; - - template - struct Hash { - IntType operator()(int32_t x) const { - return (IntType) x; - } - }; - } #endif //CORE_STL_HASH_H diff --git a/lib/wlib/stl/Pair.h b/lib/wlib/stl/Pair.h index 8a6c804d..5f1f4772 100644 --- a/lib/wlib/stl/Pair.h +++ b/lib/wlib/stl/Pair.h @@ -9,10 +9,6 @@ * @bug No known bugs */ -/* - * TODO: create and define more boolean operators - */ - #ifndef EMBEDDEDTESTS_PAIR_H #define EMBEDDEDTESTS_PAIR_H @@ -42,6 +38,7 @@ namespace wlp { /** * Copy constructor for const reference. + * * @param pair pair to copy */ Pair(pair const &pair) @@ -51,6 +48,7 @@ namespace wlp { /** * Copy constructor for R-value. + * * @param pair temporary pair to copy */ Pair(pair &&pair) @@ -60,6 +58,7 @@ namespace wlp { /** * Create a pair from two values of first type and second type. + * * @param first first type value * @param second second type value */ @@ -98,6 +97,7 @@ namespace wlp { /** * Assignment operator copies the first and second values. + * * @param p pair to copy * @return a reference to this pair */ @@ -109,6 +109,7 @@ namespace wlp { /** * R-value assignment operator. + * * @param p temporary pair to copy * @return a reference to this pair */ @@ -121,6 +122,7 @@ namespace wlp { /** * Equality operator. Two pairs are equal if * both their elements are equal. + * * @param p the pair to compare * @return true if the pairs are equal */ @@ -129,13 +131,14 @@ namespace wlp { } /** - * Equality operator. Two pairs are equal if - * both their elements are equal. + * Inequality operator. Two pairs are unequal if + * one or more of the two elements are unequal. + * * @param p the pair to compare - * @return true if the pairs are equal + * @return true if the pairs are unequal */ - bool operator==(pair &p) { - return m_first == p.m_first && m_second == p.m_second; + bool operator!=(const pair &p) { + return m_first != p.m_first || m_second != p.m_second; } }; diff --git a/lib/wlib/stl/Tmp.h b/lib/wlib/stl/Tmp.h index 5eb4e285..57d1d416 100644 --- a/lib/wlib/stl/Tmp.h +++ b/lib/wlib/stl/Tmp.h @@ -10,10 +10,6 @@ * @bug No known bugs */ -/* - * TODO: Robust is_function, and_, recursive or_ - */ - #ifndef EMBEDDEDCPLUSPLUS_TMP_H #define EMBEDDEDCPLUSPLUS_TMP_H diff --git a/lib/wlib/stl/Utility.h b/lib/wlib/stl/Utility.h index 0c647fee..dd6fcb4d 100644 --- a/lib/wlib/stl/Utility.h +++ b/lib/wlib/stl/Utility.h @@ -1,3 +1,15 @@ +/** + * @file Utility.h + * @brief Various helper functions. + * + * This file is geared to contain helper functions are groups thereof + * that are not numerous enough to warrent their own files. + * + * @author Jeff Niu + * @date November 14, 2017 + * @bug No known bugs + */ + #ifndef EMBEDDEDCPLUSPLUS_UTILITY_H #define EMBEDDEDCPLUSPLUS_UTILITY_H @@ -40,6 +52,13 @@ namespace wlp { return static_cast(t); } + /** + * Swap two elements. + * + * @tparam T element type + * @param v1 first element + * @param v2 second element + */ template void swap(T &v1, T &v2) { T tmp(move(v1)); From 72f6b5d2e25f7ffb3ea7aa4af5026b8801c16bbf Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 19 Nov 2017 23:42:27 -0500 Subject: [PATCH 015/102] [FT] Memory improv (#55) * CMakeLists updated to make each individual CMakeList have its own compiler configuration * conflicts and coverage issues resolved * many changes made to memory * minor memory bug fixed * memory finished tests have to use new model of memory * created log2 and pow and uncommented tests * removed use of allocator and old memory * memory management completed and other files adjusted to use it * minor bug fixed in malloc * array test added for memory --- .gitignore | 2 + lib/wlib/CMakeLists.txt | 24 +- lib/wlib/Types.h | 21 +- lib/wlib/Wlib.h | 8 - lib/wlib/memory/Allocator.cpp | 30 ++- lib/wlib/memory/Allocator.h | 24 +- lib/wlib/memory/DynamicAllocatorPool.h | 12 +- lib/wlib/memory/Memory.cpp | 321 +++++++++++++++++++---- lib/wlib/memory/Memory.h | 195 +++++++++++--- lib/wlib/memory/StaticAllocatorPool.h | 13 +- lib/wlib/stl/ArrayHeap.h | 4 +- lib/wlib/stl/ArrayList.h | 22 +- lib/wlib/stl/ChainMap.h | 55 ++-- lib/wlib/stl/ChainSet.h | 7 - lib/wlib/stl/Concept.h | 2 +- lib/wlib/stl/Hash.h | 2 +- lib/wlib/stl/OpenMap.h | 59 ++--- lib/wlib/stl/OpenSet.h | 7 - lib/wlib/stl/Pair.h | 2 +- lib/wlib/stl/Tuple.h | 2 +- lib/wlib/stl/TypeTraits.h | 8 +- lib/wlib/strings/StaticString.h | 6 +- lib/wlib/strings/String.h | 30 +++ lib/wlib/{stl => utilities}/Comparator.h | 46 ++-- lib/wlib/utilities/Math.h | 25 ++ lib/wlib/{stl => utilities}/Tmp.h | 197 ++++++++++++++ lib/wlib/{stl => utilities}/Utility.h | 0 tests/CMakeLists.txt | 4 +- tests/memory/memory_check.cpp | 104 ++++++++ tests/stl/bitset_check.cpp | 1 + tests/stl/chain_map_check.cpp | 12 +- tests/stl/comparator_check.cpp | 4 +- tests/stl/concept_check.cpp | 4 +- tests/stl/equals_check.cpp | 4 +- tests/stl/hash_check.cpp | 3 +- tests/stl/heap_check.cpp | 1 + tests/stl/open_map_check.cpp | 8 - tests/stl/pair_check.cpp | 1 + tests/strings/static_string_check.cpp | 1 + tests/template_defs.h | 3 +- 40 files changed, 969 insertions(+), 305 deletions(-) create mode 100644 lib/wlib/strings/String.h rename lib/wlib/{stl => utilities}/Comparator.h (75%) create mode 100644 lib/wlib/utilities/Math.h rename lib/wlib/{stl => utilities}/Tmp.h (79%) rename lib/wlib/{stl => utilities}/Utility.h (100%) create mode 100644 tests/memory/memory_check.cpp diff --git a/.gitignore b/.gitignore index f1349a64..9f7d707d 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ fabric.properties # End of https://www.gitignore.io/api/clion .pioenvs .vscode + +.DS_Store diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index dcf8709e..6b2425a1 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,10 +1,32 @@ project(wlib) +SET(CMAKE_CXX_FLAGS_DISTRIBUTION "-fno-exceptions -fno-threadsafe-statics -fpermissive -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -flto") +SET(CMAKE_C_FLAGS_DISTRIBUTION "-std=gnu11 -fno-fat-lto-objects -g -Os -Wall -ffunction-sections -fdata-sections -flto") +set(CMAKE_CXX_STANDARD 11) + +#[[ + These definitions are used for how the memory is allocated + + MAX_ALLOCATORS - Number of allocators (how many sizes of memory blocks) + NUM_BLOCKS - Number of block each allocator will contain + + * Type of memory available. Available types: + * STATIC_POOL -> Static memory will be used and all the memory will be reserved at start + * DYNAMIC_POOL -> Dynamic memory will be used and all the memory will be reserved at start + * NO_POOL -> Dynamic memory will be used and Allocators will be expanded at run time + * + * If you don't define any of these then no memory will created at the beginning and + * memory will be expanded at run time + */ +]] +add_definitions(-DMAX_ALLOCATORS=10u -DNUM_BLOCKS=100u -DDYNAMIC_POOL) + file(GLOB header_files "*.h" "strings/*.h" "stl/*.h" - "memory/*.h") + "memory/*.h" + "utilities/*.h") file(GLOB source_files "memory/*.cpp") diff --git a/lib/wlib/Types.h b/lib/wlib/Types.h index a3a337ab..f7ef0f7a 100644 --- a/lib/wlib/Types.h +++ b/lib/wlib/Types.h @@ -7,31 +7,20 @@ * @bug No known bug */ - #ifndef EMBEDDEDCPLUSPLUS_TYPES_H #define EMBEDDEDCPLUSPLUS_TYPES_H #include -#include "strings/StaticString.h" namespace wlp { - // size + // 16 bit sizes typedef uint16_t size_type; + typedef int16_t diff_type; - // Static Strings - typedef StaticString<8> String8; - typedef StaticString<16> String16; - typedef StaticString<32> String32; - typedef StaticString<64> String64; - typedef StaticString<128> String128; - typedef StaticString<256> String256; - - /* - // Dynamic String - typedef wlp::DynamicString String; - */ - + // 32 bit sizes + typedef uint32_t size32_type; + typedef int32_t diff32_type; } #endif //EMBEDDEDCPLUSPLUS_TYPES_H diff --git a/lib/wlib/Wlib.h b/lib/wlib/Wlib.h index b33a3d97..7e386eb9 100644 --- a/lib/wlib/Wlib.h +++ b/lib/wlib/Wlib.h @@ -1,14 +1,6 @@ #ifndef EMBEDDEDTESTS_WLIB_H #define EMBEDDEDTESTS_WLIB_H -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - -// Multiplication by Mersenne primes reduced as bit operations -// for compilers that do not already perform this optimization -#define MUL_31(x) (((x) << 5) - (x)) -#define MUL_127(x) (((x) << 7) - (x)) - // Constants for standard sizes #define BYTE_SIZE 8 #define INT32_SIZE (BYTE_SIZE * sizeof(uint32_t)) diff --git a/lib/wlib/memory/Allocator.cpp b/lib/wlib/memory/Allocator.cpp index b53d83a4..8739e717 100644 --- a/lib/wlib/memory/Allocator.cpp +++ b/lib/wlib/memory/Allocator.cpp @@ -3,21 +3,19 @@ * @brief Implementation of Allocator * * @author Deep Dhillon - * @date October 22, 2017 + * @date November 19, 2017 * @bug No known bugs */ #include #include +#include "../utilities/Math.h" #include "Allocator.h" +#include "../utilities/Utility.h" -#include "../Types.h" - -#include "../stl/Utility.h" - - -wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator::Type allocationType, void *pPool) : +wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize, wlp::Allocator::Type allocationType, void *pPool) + : m_poolType{allocationType}, m_blockSize{blockSize}, m_pHead{nullptr}, @@ -36,7 +34,7 @@ wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator: m_poolSize = max(m_blockSize, poolSize); // find the closest round number that describes the number of blocks - m_poolTotalBlockCnt = (uint16_t) roundf(m_poolSize / (float) m_blockSize); + m_poolTotalBlockCnt = static_cast(roundf(m_poolSize / static_cast(m_blockSize))); m_poolCurrBlockCnt = m_poolTotalBlockCnt; m_totalBlockCount = m_poolTotalBlockCnt; @@ -56,7 +54,8 @@ wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize, wlp::Allocator: // Fill m_pPool with m_poolSize blocks wlp::Allocator::Block *pBlock = m_pPool; for (size_type i = 1; i < m_poolTotalBlockCnt; i++) { - pBlock = pBlock->pNext = (wlp::Allocator::Block *) ((char *) pBlock + m_blockSize); + pBlock = pBlock->pNext = reinterpret_cast(reinterpret_cast(pBlock) + + m_blockSize); } // Initially, all in Deallocate'd state @@ -98,9 +97,11 @@ wlp::Allocator &wlp::Allocator::operator=(Allocator &&allocator) { } } } + if (m_poolType != Type::STATIC && m_pPool) { delete[] (char *) m_pPool; } + m_poolType = move(allocator.m_poolType); m_blockSize = move(allocator.m_blockSize); m_poolSize = move(allocator.m_poolSize); @@ -121,10 +122,10 @@ wlp::Allocator &wlp::Allocator::operator=(Allocator &&allocator) { return *this; } -wlp::Allocator::Allocator(uint16_t blockSize, uint16_t poolSize) : +wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize) : wlp::Allocator(blockSize, poolSize, DYNAMIC, nullptr) {} -wlp::Allocator::Allocator(uint16_t blockSize, void *pPool, uint16_t poolSize, Type type) : +wlp::Allocator::Allocator(size32_type blockSize, void *pPool, uint32_t poolSize, Type type) : wlp::Allocator(blockSize, poolSize, type, pPool) {} wlp::Allocator::~Allocator() { @@ -158,6 +159,10 @@ void *wlp::Allocator::Allocate() { m_pHead = m_pHead->pNext; --m_poolCurrBlockCnt; } else { + // If we are using a pool we ran out of memory + if (m_poolSize > 0) + return nullptr; + // Otherwise, get a 'new' one from heap. pBlock = (wlp::Allocator::Block *) new char[m_blockSize]; ++m_totalBlockCount; @@ -175,5 +180,6 @@ void wlp::Allocator::Deallocate(void *pBlock) { pBlock1->pNext = m_pHead; m_pHead = pBlock1; ++m_deallocations; -} + m_allocations <= 0 ? m_allocations : --m_allocations; +} diff --git a/lib/wlib/memory/Allocator.h b/lib/wlib/memory/Allocator.h index 55db9811..0369b7f9 100644 --- a/lib/wlib/memory/Allocator.h +++ b/lib/wlib/memory/Allocator.h @@ -6,19 +6,17 @@ * or provided by the user. The goal is to eliminate memory fragmentation and make allocations * faster and much safer * + * This class should never be used because it is used internally + * * @author Deep Dhillon - * @date October 22, 2017 + * @date November 19, 2017 * @bug No known bugs */ #ifndef C_TEST_ALLOCATOR_H #define C_TEST_ALLOCATOR_H - -#include -#include - -#include "../Wlib.h" +#include "../Types.h" namespace wlp { class Allocator { @@ -67,7 +65,7 @@ namespace wlp { * @param blockSize size of memory blocks that can acquired at a time * @param poolSize size of memory pool to be created */ - explicit Allocator(uint16_t blockSize, uint16_t poolSize = 0); + explicit Allocator(size32_type blockSize, size32_type poolSize = 0); /** * Allocator used for allocating memory where memory is provided to the allocator. It uses the given @@ -84,7 +82,7 @@ namespace wlp { * @param poolSize size of the memory pool provided * @param type type of memory pool provided (static or dynamic) */ - Allocator(uint16_t blockSize, void *pPool, uint16_t poolSize, Type type); + Allocator(size32_type blockSize, void *pPool, size32_type poolSize, Type type); /** * Deletes memory and returns it back to the system @@ -133,7 +131,7 @@ namespace wlp { * * @return size of memory block */ - inline size_t GetBlockSize() const { + inline size32_type GetBlockSize() const { return m_blockSize; } @@ -142,7 +140,7 @@ namespace wlp { * * @return size of pool */ - inline size_t GetPoolSize() const { + inline size32_type GetPoolSize() const { return m_poolSize; } @@ -220,14 +218,14 @@ namespace wlp { * @param allocationType type of memory in memory pool * @param pPool address to memory provided */ - explicit Allocator(uint16_t blockSize, uint16_t poolSize, Allocator::Type allocationType, void *pPool); + explicit Allocator(size32_type blockSize, size32_type poolSize, Allocator::Type allocationType, void *pPool); Type m_poolType; - size_t m_blockSize; + size32_type m_blockSize; Block *m_pHead; Block *m_pPool; - size_t m_poolSize; + size32_type m_poolSize; uint16_t m_poolTotalBlockCnt; uint16_t m_poolCurrBlockCnt; uint16_t m_totalBlockCount; diff --git a/lib/wlib/memory/DynamicAllocatorPool.h b/lib/wlib/memory/DynamicAllocatorPool.h index 65de83f3..480ae843 100644 --- a/lib/wlib/memory/DynamicAllocatorPool.h +++ b/lib/wlib/memory/DynamicAllocatorPool.h @@ -10,17 +10,17 @@ * @bug No known bugs */ -#ifndef FIXED_MEMORY_ALLOCATORPOOL_H -#define FIXED_MEMORY_ALLOCATORPOOL_H +#ifndef FIXED_MEMORY_DYNAMIC_ALLOCATORPOOL_H +#define FIXED_MEMORY_DYNAMIC_ALLOCATORPOOL_H #include "Allocator.h" -namespace wlp{ - template +namespace wlp { + template class DynamicAllocatorPool : public Allocator { public: - DynamicAllocatorPool() : Allocator(tblockSize, tblockSize * tnumBlocks) {} + DynamicAllocatorPool() : Allocator(tblockSize, (tblockSize * tnumBlocks)) {} }; } -#endif //FIXED_MEMORY_ALLOCATORPOOL_H +#endif //FIXED_MEMORY_DYNAMIC_ALLOCATORPOOL_H diff --git a/lib/wlib/memory/Memory.cpp b/lib/wlib/memory/Memory.cpp index 7a13bc26..8cdd79f4 100644 --- a/lib/wlib/memory/Memory.cpp +++ b/lib/wlib/memory/Memory.cpp @@ -3,94 +3,186 @@ * @brief Implementation of Memory functions * * @author Deep Dhillon - * @date October 22, 2017 + * @date November 19, 2017 * @bug No known bugs */ #include -#include "Memory.h" -#include "Allocator.h" -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif +#include "Memory.h" +#include "StaticAllocatorPool.h" +#include "DynamicAllocatorPool.h" -#define MAX_ALLOCATORS 10 +#include "../utilities/Math.h" +#include "../Wlib.h" using namespace wlp; -static Allocator *_allocators[MAX_ALLOCATORS]; +static constexpr size_type required_extra_buffer = sizeof(Allocator *); + +/** + * This class restricts the size of blocks as the power of 2 gets bigger + */ +class RestrictSize { + static constexpr uint16_t numRestrictions = 3; // number of restrictions imposed + static constexpr uint16_t powOffsetFromZero = 9; // which pow of 2 to start restriction from + + static constexpr uint16_t restrictions[numRestrictions] = { + 300, 400, 500}; + +public: + /** + * If the @p blockSize is smaller within restriction range, apply restrictions + * otherwise return the same block + * + * @tparam pow current power of 2 + * @tparam blockSize current size of a memory block + * @return a memory block that is restricted + */ + template + static constexpr inline size32_type apply() { + return (pow >= powOffsetFromZero && + pow < (powOffsetFromZero + numRestrictions)) ? restrictions[pow - powOffsetFromZero] + : blockSize; + } +}; +static Allocator *_allocators[MAX_ALLOCATORS]; int MemoryInitDestroy::m_srefCount = 0; +/** + * Creates and initializes the memory management. It creates the memory based + * on configurations set up in @code MemoryConfiguration.h @endcode file + */ +void memory_init(); + +/** + * Deletes and disposes the allocations done internally. If a pool is used it + * promises to deallocates any pending allocations even if @code free @endcode + * is not used + */ +void memory_destroy(); + MemoryInitDestroy::MemoryInitDestroy() { - if (m_srefCount++ == 0) memory_init(); + if (m_srefCount++ == 0) { memory_init(); } } MemoryInitDestroy::~MemoryInitDestroy() { - if (--m_srefCount == 0) memory_destroy(); + if (--m_srefCount == 0) { memory_destroy(); } } /** - * Returns the next higher powers of two. For instance, pass in 12 and - * the value returned would be 16 + * Template struct to create allocators. This recursively creates allocators and hence makes + * a memory pool. This is the recursive step of the process * - * @tparam T is any class - * @param k value for which the higher power of two will be returned - * @return the next higher power of two based on the input k + * @tparam powStart starting power of 2 for memory of Allocator + * @tparam from number to start from + * @tparam to number to end at */ -template -T nextHigher(T k) { - k--; - for (size_t i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) - k |= (k >> i); - return k + 1; -} +template +struct insert { + /** + * Insert either static or dynamic memory blocks + */ + static void apply() { + constexpr size_type curr_pow = from + powStart; + constexpr size32_type blockSize = RestrictSize::apply(2, curr_pow)>(); + +#if defined(DYNAMIC_POOL) + _allocators[from] = new DynamicAllocatorPool(); +#elif defined(STATIC_POOL) + _allocators[from] = new StaticAllocatorPool(); +#endif + insert::apply(); + } +}; -void memory_init() {} +/** + * Template struct to create allocators. This recursively creates allocators and hence makes + * a memory pool. This is the terminal step + * + * @tparam powStart starting power of 2 for memory of Allocator + * @tparam from number to start from + * @tparam to number to end at + */ +template +struct insert { + /** + * Insert either static or dynamic memory blocks + */ + static void apply() { + constexpr size_type curr_pow = from + powStart; + constexpr size32_type blockSize = RestrictSize::apply(2, curr_pow)>(); + +#if defined(DYNAMIC_POOL) + _allocators[from] = new DynamicAllocatorPool(); +#elif defined(STATIC_POOL) + _allocators[from] = new StaticAllocatorPool(); +#endif + } +}; -extern "C" void memory_destroy() { +void memory_init() { + // smallest pow of 2 a block can be created + constexpr auto powStart = log2_const(required_extra_buffer) + 1; + insert::apply(); +} + +void memory_destroy() { for (auto &_allocator : _allocators) { - if (_allocator == nullptr) + if (_allocator == nullptr) { break; + } delete _allocator; _allocator = nullptr; } - } /** * Return an allocator instance matching the size provided + * * @param size allocator blocks size * @return Allocator instance or nullptr if no allocator exists */ -static inline Allocator *find_allocator(size_t size) { +static inline Allocator *find_allocator(size32_type size) { for (auto &_allocator : _allocators) { - if (_allocator == nullptr) + if (_allocator == nullptr) { break; + } +#if defined(DYNAMIC_POOL) || defined(STATIC_POOL) + if (_allocator->GetBlockSize() >= size) { + return _allocator; + } +#else if (_allocator->GetBlockSize() == size) return _allocator; +#endif } return nullptr; } /** - * Inster an Allocator instance into the array + * Insert an Allocator instance into the array + * * @param allocator an Allocator instance + * @return true or false based on if insertion is successful */ -static inline void insert_allocator(Allocator *allocator) { +static inline bool insert_allocator(Allocator *allocator) { for (auto &_allocator : _allocators) { if (_allocator == nullptr) { _allocator = allocator; - return; + return true; } } + + return false; } /** * Stored a pointer to the Allocator instance within the block region + * * @param block a pointer to the raw memory block * @param allocator allocator to set * @return a pointer to the client's area within the block @@ -107,36 +199,63 @@ static inline void *set_block_allocator(void *block, Allocator *allocator) { return ++pAllocatorInBlock; } +/** + * Returns the next higher powers of two. For instance, pass in 12 and + * the value returned would be 16 + * + * @tparam T is any class + * @param k value for which the higher power of two will be returned + * @return the next higher power of two based on the input k + */ +template +T nextHigher(T k) { + k--; + for (size_t i = 1; i < sizeof(T) * BYTE_SIZE; i <<= 1) { + k |= (k >> i); + } + return k + 1; +} + /** * Get an Allocator instance based upon the client's requested block size. * If there is no such Allocator available, create a new one + * * @param size client's requested block size * @return an allocator instance that handles the block size */ -extern "C" Allocator *memory_get_allocator(size_t size) { +Allocator *memory_get_allocator(size32_type size) { // Based on the size, find the next higher powers of two value. - // Add sizeof(Allocator*) to the requested block size to hold the size - // within the block memory region. Most blocks are powers of two, + // Add required_extra_buffer to the requested block size to hold the size + // of an Allocator* within the block memory region. Most blocks are powers of two, // however some common allocator block sizes can be explicitly defined // to minimize wasted storage. This offers application specific tuning. - size_t blockSize = size + sizeof(Allocator *); + // These restrictions can only imposed if no pool is being used + + size32_type blockSize = size + required_extra_buffer; + +#if !defined(DYNAMIC_POOL) && !defined(STATIC_POOL) + // set custom blocks if pool is not used + if (blockSize > 256 && blockSize <= 396) blockSize = 396; else if (blockSize > 512 && blockSize <= 768) blockSize = 768; else blockSize = nextHigher(blockSize); +#endif Allocator *allocator = find_allocator(blockSize); - // If there is not an allocator already created to handle this block size - if (allocator == nullptr) { +#if !defined(DYNAMIC_POOL) && !defined(STATIC_POOL) + if (allocator == nullptr){ // Create a new allocator to handle blocks of the size required allocator = new Allocator(blockSize); // Insert allocator into array - insert_allocator(allocator); + if (!insert_allocator(allocator)) + return nullptr; } +#endif return allocator; } @@ -144,14 +263,33 @@ extern "C" Allocator *memory_get_allocator(size_t size) { /** * Allocates a memory block of the requested size. The blocks are created from * the fixed block allocators + * * @param size the client's requested size of the block * @return a pointer to the memory block */ -extern "C" void *memory_alloc(size_t size) { +void *__memory_alloc(size32_type size) { // Allocate a raw memory block Allocator *allocator = memory_get_allocator(size); + + // if not enough sizes available + if (allocator == nullptr) { + return nullptr; + } + void *blockMemoryPtr = allocator->Allocate(); + // if not enough quantity of that particular size available + if (blockMemoryPtr == nullptr) { + // check if higher sizes have some blocks available and + // give a block from them if available + size32_type currBlockSize = allocator->GetBlockSize(); + if (currBlockSize < _allocators[MAX_ALLOCATORS - 1]->GetBlockSize()) { + return __memory_alloc(currBlockSize + 1); + } + + return nullptr; + } + // Set the block Allocator* within the raw memory block region void *clientsMemoryPtr = set_block_allocator(blockMemoryPtr, allocator); return clientsMemoryPtr; @@ -159,6 +297,7 @@ extern "C" void *memory_alloc(size_t size) { /** * Gets the size of the memory block stored within the block + * * @param block a pointer to the client's memory block * @return The original allocator instance stored in the memory block */ @@ -175,6 +314,7 @@ static inline Allocator *get_block_allocator(void *block) { /** * The raw memory block pointer given a client's memory pointer + * * @param block a pointer to the client's memory block * @return A pointer to the original raw memory block */ @@ -187,13 +327,15 @@ static inline void *get_block_ptr(void *block) { } /** - * Frees a memory block previously allocated with memory_alloc. The blocks are + * Frees a memory block previously allocated with @code __memory_alloc @endcode. The blocks are * returned to the fixed block allocator that originally created it - * @param ptr a pointer to a block created with memory_alloc + * + * @param ptr a pointer to a block created with __memory_alloc */ -extern "C" void memory_free(void *ptr) { - if (ptr == nullptr) +void __memory_free(void *ptr) { + if (ptr == nullptr) { return; + } // Extract the original allocator instance from the caller's block pointer Allocator *allocator = get_block_allocator(ptr); @@ -206,31 +348,33 @@ extern "C" void memory_free(void *ptr) { } /** - * Reallocates a memory block previously allocated with memory_alloc - * @param oldMem a pointer to a block created with memory_alloc + * Reallocates a memory block previously allocated with @code __memory_alloc @endcode + * + * @param oldMem a pointer to a block created with @code __memory_alloc @endcode * @param size the client requested block size * @return pointer to new memory block */ -extern "C" void *memory_realloc(void *oldMem, size_t size) { - if (oldMem == nullptr) - return memory_alloc(size); +void *__memory_realloc(void *oldMem, size32_type size) { + if (oldMem == nullptr) { + return __memory_alloc(size); + } if (size == 0) { - memory_free(oldMem); + __memory_free(oldMem); return nullptr; } else { // Create a new memory block - void *newMem = memory_alloc(size); + void *newMem = __memory_alloc(size); if (newMem != nullptr) { // Get the original allocator instance from the old memory block Allocator *oldAllocator = get_block_allocator(oldMem); - size_t oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator *); + size_type oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator *); // Copy the bytes from the old memory block into the new (as much as will fit) memcpy(newMem, oldMem, (oldSize < size) ? oldSize : size); // Free the old memory block - memory_free(oldMem); + __memory_free(oldMem); // Return the client pointer to the new memory block return newMem; @@ -238,3 +382,76 @@ extern "C" void *memory_realloc(void *oldMem, size_t size) { return nullptr; } } + +size32_type getTotalMemoryUsed() { + size32_type totalMemory = 0; + + for (auto &_allocator : _allocators) { + totalMemory += _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + } + + return totalMemory; +} + + +size32_type getTotalMemoryAvailable() { + size32_type totalMemory = 0; + + for (auto &_allocator : _allocators) { + totalMemory += _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); + } + + return totalMemory; +} + +bool isSizeAvailable(size32_type blockSize) { + for (auto &_allocator : _allocators) { + if (_allocator->GetBlockSize() == blockSize) { + return true; + } + } + + return false; +} + +bool isSizeMemAvailable(size32_type blockSize) { + for (auto &_allocator : _allocators) { + if (_allocator->GetBlockSize() == blockSize) { + uint32_t totalMemAvail = _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); + uint32_t totalMemUsed = _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + return totalMemAvail - totalMemUsed != 0; + } + } + return false; +} + +uint16_t getNumBlocksAvailable(size32_type blockSize) { + uint16_t numBlockAvail = 0; + + for (auto &_allocator : _allocators) { + if (_allocator->GetBlockSize() == blockSize) { + uint32_t totalMemAvail = _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); + uint32_t totalMemUsed = _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + numBlockAvail += (totalMemAvail - totalMemUsed) / blockSize; + } + } + + return numBlockAvail; +} + +uint16_t getNumBlocks() { + return NUM_BLOCKS; +} + +uint16_t getMaxAllocations() { + return MAX_ALLOCATORS; +} + +size_type getSmallestBlockSize() { + return static_cast(pow_const(2, log2_const(required_extra_buffer) + 1)); +} + +size32_type getFixedMemorySize(void *ptr) { + Allocator *allocator = get_block_allocator(ptr); + return allocator->GetBlockSize(); +} diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 6673d0bd..416c45f1 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -3,17 +3,25 @@ * @brief Memory is a class that provides dynamic fixed size memory * * It does not impose any restrictions on how many blocks can be borrowed and of - * what size can it be borrowed + * what size can it be borrowed. This has an option to use a memory pool which has + * restrictions on how much memory we can use. When pool is filled, any call for + * memory will return @code nullptr @endcode + * + * @pre Number of memory block sizes will depend on @code MAX_ALLOCATORS @endcode * * @author Deep Dhillon - * @date October 22, 2017 + * @date November 19, 2017 * @bug No known bugs */ #ifndef FIXED_MEMORY_MEMORY_H #define FIXED_MEMORY_MEMORY_H -#include +#include +#include "../utilities/Tmp.h" + +#include "../Types.h" + /** * @brief Helper for initializing and destroying memory management @@ -23,6 +31,8 @@ * within the translation unit and thus will be constructed first. Destruction will occur * in the reverse order so memoryInitDestroy is called last. This way any static user object * relying on Memory will be destroyed first before destroy function is called. + * + * This code should never be called and/or touched. It is used internally */ class MemoryInitDestroy { public: @@ -34,59 +44,182 @@ class MemoryInitDestroy { static int m_srefCount; }; -static MemoryInitDestroy g_smemoryInitDestroy; - -extern "C" { +/** + * This code should never be called and/or touched. It is used internally + */ +static MemoryInitDestroy __g_smemoryInitDestroy; +/** + * Used internally not for client's use + * Use the @code malloc @endcode function + */ +void *__memory_alloc(uint32_t size); /** - * This function should and must be called exactly one time before application starts. - * On C++ client code this is done automatically using MemoryInitDestroy + * Used internally not for client's use + * Use the @code realloc @endcode function */ -void memory_init(); +void *__memory_realloc(void *ptr, uint32_t size); /** - * This function should and must be called exactly one time when the application exits. This should never - * be called manually when using C++ + * Used internally not for client's use + * Use the @code free @endcode function */ -void memory_destroy(); +void __memory_free(void *ptr); /** * This allocates memory of the size provided. Memory allocated could be greater than what has been - * asked in order to accommodate fixed memory allocations + * asked in order to accommodate fixed memory allocations. If there is not a sufficient memory + * available, it returns a @code nullptr @endcode + * + * If an array of Objects is need then provide malloc with a number to specify how many objects to + * create and it will create that many objects. + * + * @pre this can also act a @code new @endcode keyword to create objects so there is no need to use + * new keyword to create an object + * + * @pre malloc creates number of blocks of given type and it does not allocate memory by proving it + * number of bytes * - * @param size size of the block to allocate + * @tparam Type pointer type + * @param num number of blocks of size @p Type * @return address to memory allocated */ -void *memory_alloc(size_t size); +template +Type *malloc(wlp::size32_type num = 1) { + void *memory = __memory_alloc(static_cast(sizeof(Type)) * num); + + if (!wlp::is_fundamental::value) { + char *pointer = static_cast(memory); + for (wlp::size32_type i = 0; i < num; ++i) { + new(pointer) Type; + pointer += sizeof(Type); + } + } + + return static_cast(memory); +} + +/** + * This reallocates the memory to accommodate the new size provided. The memory address has to be + * allocation from Memory otherwise results are undefined. If there is not a sufficient memory + * available, it returns a @code nullptr @endcode + * + * @pre realloc creates number of blocks of given type and it does not allocate memory by proving it + * number of bytes + * + * @tparam Type pointer type + * @param ptr address to memory to be reallocated + * @param size number of blocks of size @p Type + * @return address to new memory address + */ +template +Type *realloc(Type *ptr, wlp::size32_type num = 1) { + return static_cast(__memory_realloc(ptr, static_cast(sizeof(Type)) * num)); +} + +/** + * Returns the size of fixed sized block that was provided for @p ptr + * + * @param ptr memory address for which memory block is being searched + * @return the size of fixed size block + */ +wlp::size32_type getFixedMemorySize(void *ptr); /** * This frees the memory allocated. Only memory allocated using Memory will be freed and if another * type of memory is provided, results are undefined * + * If an array of Objects is to be freed then provide free with a number along with the pointer to specify + * how many objects + * + * @tparam Type pointer type * @param ptr address to memory that will be freed */ -void memory_free(void *ptr); + +template +void free(Type *ptr) { + if (!wlp::is_fundamental::value) { + wlp::size32_type num = static_cast(getFixedMemorySize(ptr) / sizeof(Type)); + + Type *pointer = ptr; + for (wlp::size32_type i = 0; i < num; ++i) { + pointer->~Type(); + ++pointer; + } + } + + __memory_free(ptr); +} /** - * This reallocates the memory to accommodate the new size provided. The memory address has to be - * allocation from Memory otherwise results are undefined + * Returns the total memory being used by the program (in bytes) * - * @param ptr address to memory to be reallocated - * @param size of new memory block - * @return address to new memory address + * @return the total memory usage */ -void *memory_realloc(void *ptr, size_t size); +wlp::size32_type getTotalMemoryUsed(); -#define MEMORY_OVERLOAD \ - public: \ - void *operator new(size_t size){ \ - return memory_alloc(size); \ - }; \ - void operator delete(void *pObject){ \ - memory_free(pObject); \ - } \ +/** + * Returns the total memory available to use (in bytes). If no pool is + * being used, this number can grow as more memory is borrowed otherwise + * this is the constant number + * + * @return the total memory available + */ +wlp::size32_type getTotalMemoryAvailable(); + +/** + * Returns if this @p blockSize is available as a size that can be borrowed. + * If no pool is being used, this size will be created even if it does not exist + * but if a pool is used, this size's availability is fixed. + * + * @pre note if this size does not exist in a pool a higher size can be + * provided + * + * @param blockSize size of the block being queried + * @return true or false based on if the block exists + */ +bool isSizeAvailable(wlp::size32_type blockSize); + +/** + * Returns if this @p blockSize is available as a size that can be borrowed but it + * also has some blocks left that the user can borrow. Rest it functions the same as + * @code isSizeAvailable() @endcode + * + * @param blockSize size of the block being queried + * @return true or false based on if the block exists and has some blocks left + */ +bool isSizeMemAvailable(wlp::size32_type blockSize); + +/** + * Returns the total number of blocks that are available for @p blockSize. if @p blockSize + * does not exist then number will be 0 + * + * @param blockSize blockSize size of the block being queried + * @return the number blocks available for @p blockSize + */ +uint16_t getNumBlocksAvailable(wlp::size32_type blockSize); + +/** + * Returns the number of blocks per Allocator if a pool is used + * + * @return the number of blocks per Allocator + */ +uint16_t getNumBlocks(); + +/** + * Returns the number Allocators (sizes) there are available in total + * + * @return the number of allocators (sizes) + */ +uint16_t getMaxAllocations(); + +/** + * Returns the smallest block of memory that is given + * + * @return the smallest block of memory + */ +wlp::size_type getSmallestBlockSize(); -}; #endif //FIXED_MEMORY_MEMORY_H diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index 9c524e9a..ff8b5929 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -10,20 +10,21 @@ * @bug No known bugs */ -#ifndef FIXED_MEMORY_ALLOCATORPOOL_H -#define FIXED_MEMORY_ALLOCATORPOOL_H +#ifndef FIXED_MEMORY_STATIC_ALLOCATORPOOL_H +#define FIXED_MEMORY_STATIC_ALLOCATORPOOL_H #include "Allocator.h" -namespace wlp{ - template +namespace wlp { + template class StaticAllocatorPool : public Allocator { public: - StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC){} + StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC) {} + private: char m_memory[tblockSize * tnumBlocks]; }; } -#endif //FIXED_MEMORY_ALLOCATORPOOL_H +#endif //FIXED_MEMORY_STATIC_ALLOCATORPOOL_H diff --git a/lib/wlib/stl/ArrayHeap.h b/lib/wlib/stl/ArrayHeap.h index d4bb4211..281936b2 100644 --- a/lib/wlib/stl/ArrayHeap.h +++ b/lib/wlib/stl/ArrayHeap.h @@ -16,10 +16,10 @@ #define EMBEDDEDCPLUSPLUS_ARRAYHEAP_H #include "ArrayList.h" -#include "Comparator.h" +#include "utilities/Comparator.h" #include "Concept.h" #include "TypeTraits.h" -#include "Utility.h" +#include "utilities/Utility.h" namespace wlp { diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index 5b3beeed..bb779e07 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -13,10 +13,8 @@ #ifndef EMBEDDEDCPLUSPLUS_ARRAYLIST_H #define EMBEDDEDCPLUSPLUS_ARRAYLIST_H -#include "Utility.h" - +#include "../utilities/Utility.h" #include "../Types.h" - #include "../memory/Memory.h" namespace wlp { @@ -675,7 +673,7 @@ namespace wlp { if (!m_data) { return; } - memory_free(m_data); + free(m_data); m_data = nullptr; } @@ -688,7 +686,7 @@ namespace wlp { * @param initial_size the initial capacity for the backing array */ void init_array(size_type initial_size) { - m_data = static_cast(memory_alloc(initial_size * sizeof(val_type))); + m_data = malloc(initial_size); } /** @@ -1062,7 +1060,7 @@ namespace wlp { * @return reference to this list */ array_list &operator=(array_list &&list) { - memory_free(m_data); + free(m_data); m_data = move(list.m_data); m_size = move(list.m_size); m_capacity = move(list.m_capacity); @@ -1080,11 +1078,11 @@ namespace wlp { return; } size_type new_capacity = (size_type) (2 * m_capacity); - val_type *new_data = static_cast(memory_alloc(new_capacity * sizeof(val_type))); + val_type *new_data = malloc(new_capacity); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; } - memory_free(m_data); + free(m_data); m_data = new_data; m_capacity = new_capacity; } @@ -1094,11 +1092,11 @@ namespace wlp { if (new_capacity <= m_capacity) { return; } - val_type *new_data = static_cast(memory_alloc(new_capacity * sizeof(val_type))); + val_type *new_data = malloc(new_capacity); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; } - memory_free(m_data); + free(m_data); m_data = new_data; m_capacity = new_capacity; } @@ -1108,11 +1106,11 @@ namespace wlp { if (m_size == m_capacity) { return; } - val_type *new_data = static_cast(memory_alloc(m_size * sizeof(val_type))); + val_type *new_data = malloc(m_size); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; } - memory_free(m_data); + free(m_data); m_data = new_data; m_capacity = m_size; } diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index fcb23667..8082c642 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -13,12 +13,11 @@ #ifndef EMBEDDEDTESTS_CHAINMAP_H #define EMBEDDEDTESTS_CHAINMAP_H -#include "Utility.h" +#include "../utilities/Utility.h" #include "Equal.h" #include "Hash.h" #include "Pair.h" -#include "../memory/Allocator.h" #include "../memory/Memory.h" namespace wlp { @@ -378,11 +377,6 @@ namespace wlp { */ Equals m_equal; - /** - * Allocator to create memory for hash map nodes. - */ - Allocator m_node_allocator; - /** * Hasher map backing array. */ @@ -409,8 +403,7 @@ namespace wlp { public: /** - * Create and initialize an empty hash map. The hash map uses - * {@code Allocator} to handle memory. + * Create and initialize an empty hash map. * * @pre the hash map requires definition of an initial bucket array size * and a maximum load factor before rehashing @@ -425,7 +418,6 @@ namespace wlp { percent_type max_load = 75) : m_hash(Hasher()), m_equal(Equals()), - m_node_allocator{sizeof(node_type), static_cast(n * sizeof(node_type))}, m_num_elements(0), m_capacity(n), m_max_load(max_load) { @@ -445,7 +437,6 @@ namespace wlp { ChainHashMap(map_type &&map) : m_hash(move(map.m_hash)), m_equal(move(map.m_equal)), - m_node_allocator(move(map.m_node_allocator)), m_buckets(move(map.m_buckets)), m_num_elements(move(map.m_num_elements)), m_capacity(move(map.m_capacity)), @@ -536,13 +527,6 @@ namespace wlp { return m_num_elements == 0; } - /** - * @return the node allocator of the map - */ - const Allocator *get_node_allocator() const { - return &m_node_allocator; - } - /** * Obtain an iterator to the first element in the hash map. * Returns pass-the-end iterator if there are no elements @@ -721,7 +705,7 @@ namespace wlp { template void ChainHashMap::init_buckets(ChainHashMap::size_type n) { - m_buckets = static_cast(memory_alloc(n * sizeof(node_type *))); + m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } @@ -733,7 +717,7 @@ namespace wlp { return; } size_type new_capacity = static_cast(m_capacity * 2); - node_type **new_buckets = static_cast(memory_alloc(new_capacity * sizeof(node_type *))); + node_type **new_buckets = malloc(new_capacity); for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } @@ -751,7 +735,7 @@ namespace wlp { cur = next; } } - memory_free(m_buckets); + free(m_buckets); m_buckets = new_buckets; m_capacity = new_capacity; } @@ -763,7 +747,7 @@ namespace wlp { node_type *next; while (cur) { next = cur->next; - m_node_allocator.Deallocate(cur); + free(cur); cur = next; } m_buckets[i] = nullptr; @@ -782,7 +766,7 @@ namespace wlp { return Pair(iterator(cur, this), false); } } - node_type *tmp = static_cast(m_node_allocator.Allocate()); + node_type *tmp = malloc(); tmp->m_key = key; tmp->m_val = val; tmp->next = first; @@ -803,7 +787,7 @@ namespace wlp { return Pair(iterator(cur, this), false); } } - node_type *tmp = static_cast(m_node_allocator.Allocate()); + node_type *tmp = malloc(); tmp->m_key = key; tmp->m_val = val; tmp->next = first; @@ -822,14 +806,14 @@ namespace wlp { p_node->next = n_node->next; p_node->m_key = n_node->m_key; p_node->m_val = n_node->m_val; - m_node_allocator.Deallocate(n_node); + free(n_node); --m_num_elements; return pos; } else { size_type i = hash(p_node->m_key); node_type *c_node = m_buckets[i]; if (c_node == p_node) { - m_node_allocator.Deallocate(c_node); + free(c_node); --m_num_elements; m_buckets[i] = nullptr; while (++i < m_capacity && !m_buckets[i]); @@ -844,7 +828,7 @@ namespace wlp { while (c_node->next != p_node) { c_node = c_node->next; } - m_node_allocator.Deallocate(c_node->next); + free(c_node->next); --m_num_elements; c_node->next = nullptr; while (++i < m_capacity && !m_buckets[i]); @@ -874,7 +858,7 @@ namespace wlp { cur->m_key = next->m_key; cur->m_val = next->m_val; cur->next = next->next; - m_node_allocator.Deallocate(next); + free(next); --m_num_elements; return true; } @@ -884,7 +868,7 @@ namespace wlp { } if (next) { cur->next = next->next; - m_node_allocator.Deallocate(next); + free(next); --m_num_elements; return true; } @@ -893,7 +877,7 @@ namespace wlp { if (!m_equal(key, cur->m_key)) { return false; } - m_node_allocator.Deallocate(cur); + free(cur); --m_num_elements; m_buckets[i] = nullptr; return true; @@ -957,7 +941,7 @@ namespace wlp { node_type *first = m_buckets[i]; node_type *cur = first; if (!cur) { - node_type *ele = static_cast(m_node_allocator.Allocate()); + node_type *ele = malloc(); ++m_num_elements; ele->m_key = key; ele->m_val = val_type(); @@ -971,7 +955,7 @@ namespace wlp { if (cur) { return cur->m_val; } - cur = static_cast(m_node_allocator.Allocate()); + cur = malloc(); ++m_num_elements; cur->m_key = key; cur->m_val = val_type(); @@ -1025,12 +1009,12 @@ namespace wlp { if (cur) { while (cur) { node_type *next = cur->next; - m_node_allocator.Deallocate(cur); + free(cur); cur = next; } } } - memory_free(m_buckets); + free(m_buckets); m_buckets = nullptr; } @@ -1038,8 +1022,7 @@ namespace wlp { ChainHashMap & ChainHashMap::operator=(ChainHashMap &&map) { clear(); - memory_free(m_buckets); - m_node_allocator = move(map.m_node_allocator); + free(m_buckets); m_num_elements = move(map.m_num_elements); m_capacity = move(map.m_capacity); m_max_load = move(map.m_max_load); diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index bbf284b2..0edd43b7 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -97,13 +97,6 @@ namespace wlp { return m_hash_map.empty(); } - /** - * @return a pointer to the backing map's node allocator - */ - const Allocator *get_node_allocator() const { - return m_hash_map.get_node_allocator(); - } - /** * @return a pointer to the backing hash map */ diff --git a/lib/wlib/stl/Concept.h b/lib/wlib/stl/Concept.h index a5bd5206..62664dec 100644 --- a/lib/wlib/stl/Concept.h +++ b/lib/wlib/stl/Concept.h @@ -15,7 +15,7 @@ #define EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H #include "Pair.h" -#include "Tmp.h" +#include "utilities/Tmp.h" #include "TypeTraits.h" #include "../Wlib.h" diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index 1aa345c2..d5e27fca 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -15,7 +15,7 @@ #define CORE_STL_HASH_H #include "../Types.h" -#include "../Wlib.h" +#include "../utilities/Math.h" #include "../WlibConfig.h" #include "../strings/StaticString.h" diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index a6c1588f..cc1fed29 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -15,12 +15,11 @@ #ifndef CORE_STL_MAP_H #define CORE_STL_MAP_H -#include "Utility.h" +#include "../utilities/Utility.h" #include "Equal.h" #include "Hash.h" #include "Pair.h" -#include "../memory/Allocator.h" #include "../memory/Memory.h" namespace wlp { @@ -372,11 +371,6 @@ namespace wlp { */ Equals m_equal; - /** - * Allocator to create memory for hash map nodes. - */ - Allocator m_node_allocator; - /** * Hasher map backing array. */ @@ -401,8 +395,7 @@ namespace wlp { public: /** * Create and initialize an empty hash map. The hash map uses - * {@code Allocator} to handle memory. The hash map is implemented - * with open addressing and linear probing. + * The hash map is implemented with open addressing and linear probing. * * @pre the hash map requires definition of an initial bucket array size * and a maximum load factor before rehashing @@ -417,7 +410,6 @@ namespace wlp { percent_type max_load = 75) : m_hash(Hasher()), m_equal(Equals()), - m_node_allocator{sizeof(node_type), static_cast(n * sizeof(node_type))}, m_num_elements(0), m_capacity(n), m_max_load(max_load) { @@ -441,7 +433,6 @@ namespace wlp { OpenHashMap(map_type &&map) : m_hash(move(map.m_hash)), m_equal(move(map.m_equal)), - m_node_allocator(move(map.m_node_allocator)), m_buckets(move(map.m_buckets)), m_num_elements(move(map.m_num_elements)), m_capacity(move(map.m_capacity)), @@ -529,13 +520,6 @@ namespace wlp { return m_num_elements == 0; } - /** - * @return the node allocator of the map - */ - const Allocator *get_node_allocator() const { - return &m_node_allocator; - } - /** * Obtain an iterator to the first element in the hash map. * Returns pass-the-end iterator if there are no elements @@ -715,7 +699,7 @@ namespace wlp { template void OpenHashMap::init_buckets(OpenHashMap::size_type n) { - m_buckets = static_cast(memory_alloc(n * sizeof(node_type *))); + m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } @@ -727,7 +711,7 @@ namespace wlp { return; } size_type new_capacity = static_cast(m_capacity * 2); - node_type **new_buckets = static_cast(memory_alloc(new_capacity * sizeof(node_type *))); + node_type **new_buckets = malloc(new_capacity); for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } @@ -744,7 +728,7 @@ namespace wlp { } new_buckets[k] = node; } - memory_free(m_buckets); + free(m_buckets); m_buckets = new_buckets; m_capacity = new_capacity; } @@ -753,7 +737,7 @@ namespace wlp { void OpenHashMap::clear() noexcept { for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { - m_node_allocator.Deallocate(m_buckets[i]); + free(m_buckets[i]); m_buckets[i] = nullptr; } } @@ -774,7 +758,7 @@ namespace wlp { return Pair(iterator(m_buckets[i], this), false); } else { ++m_num_elements; - node_type *node = static_cast(m_node_allocator.Allocate()); + node_type *node = malloc(); node->m_key = key; node->m_val = val; m_buckets[i] = node; @@ -797,7 +781,7 @@ namespace wlp { return Pair(iterator(m_buckets[i], this), false); } else { ++m_num_elements; - node_type *node = static_cast(m_node_allocator.Allocate()); + node_type *node = malloc(); node->m_key = key; node->m_val = val; m_buckets[i] = node; @@ -824,11 +808,11 @@ namespace wlp { return pos; } --m_num_elements; - m_node_allocator.Deallocate(m_buckets[i]); + free(m_buckets[i]); m_buckets[i] = nullptr; - while (++i < m_capacity && !m_buckets[i]); + while (++i < m_capacity && !m_buckets[i]) {} node_type *next_node = i >= m_capacity ? nullptr : m_buckets[i]; - node_type **new_buckets = static_cast(memory_alloc(m_capacity * sizeof(node_type *))); + node_type **new_buckets = malloc(m_capacity); for (size_type k = 0; k < m_capacity; k++) { new_buckets[k] = nullptr; } @@ -845,7 +829,7 @@ namespace wlp { } new_buckets[j] = node; } - memory_free(m_buckets); + free(m_buckets); m_buckets = new_buckets; pos.m_current = next_node; return pos; @@ -863,9 +847,9 @@ namespace wlp { return false; } --m_num_elements; - m_node_allocator.Deallocate(m_buckets[i]); + free(m_buckets[i]); m_buckets[i] = nullptr; - node_type **new_buckets = static_cast(memory_alloc(m_capacity * sizeof(node_type *))); + node_type **new_buckets = malloc(m_capacity); for (size_type k = 0; k < m_capacity; k++) { new_buckets[k] = nullptr; } @@ -882,7 +866,7 @@ namespace wlp { } new_buckets[j] = node; } - memory_free(m_buckets); + free(m_buckets); m_buckets = new_buckets; return true; } @@ -947,7 +931,7 @@ namespace wlp { return m_buckets[i]->m_val; } else { ++m_num_elements; - node_type *node = static_cast(m_node_allocator.Allocate()); + node_type *node = malloc(); node->m_key = key; node->m_val = val_type(); m_buckets[i] = node; @@ -994,11 +978,11 @@ namespace wlp { } for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { - m_node_allocator.Deallocate(m_buckets[i]); + free(m_buckets[i]); m_buckets[i] = nullptr; } } - memory_free(m_buckets); + free(m_buckets); m_buckets = nullptr; } @@ -1006,8 +990,7 @@ namespace wlp { OpenHashMap & OpenHashMap::operator=(OpenHashMap &&map) { clear(); - memory_free(m_buckets); - m_node_allocator = move(map.m_node_allocator); + free(m_buckets); m_capacity = move(map.m_capacity); m_max_load = move(map.m_max_load); m_num_elements = move(map.m_num_elements); @@ -1027,7 +1010,7 @@ namespace wlp { i = 0; } } - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { @@ -1053,7 +1036,7 @@ namespace wlp { i = 0; } } - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index 41b7bcc9..d60df1a2 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -103,13 +103,6 @@ namespace wlp { return m_hash_map.empty(); } - /** - * @return a pointer to the backing map's node allocator - */ - const Allocator *get_node_allocator() const { - return m_hash_map.get_node_allocator(); - } - /** * @return a pointer to the backing hash map */ diff --git a/lib/wlib/stl/Pair.h b/lib/wlib/stl/Pair.h index 5f1f4772..86986255 100644 --- a/lib/wlib/stl/Pair.h +++ b/lib/wlib/stl/Pair.h @@ -12,7 +12,7 @@ #ifndef EMBEDDEDTESTS_PAIR_H #define EMBEDDEDTESTS_PAIR_H -#include "Utility.h" +#include "utilities/Utility.h" namespace wlp { diff --git a/lib/wlib/stl/Tuple.h b/lib/wlib/stl/Tuple.h index 55995f08..e05beb34 100644 --- a/lib/wlib/stl/Tuple.h +++ b/lib/wlib/stl/Tuple.h @@ -19,7 +19,7 @@ #define EMBEDDEDCPLUSPLUS_TUPLE_H #include "Pair.h" -#include "Tmp.h" +#include "../utilities/Tmp.h" namespace wlp { diff --git a/lib/wlib/stl/TypeTraits.h b/lib/wlib/stl/TypeTraits.h index faae1e70..1ac10ab7 100644 --- a/lib/wlib/stl/TypeTraits.h +++ b/lib/wlib/stl/TypeTraits.h @@ -13,7 +13,7 @@ #ifndef EMBEDDEDCPLUSPLUS_TYPETRAITS_H #define EMBEDDEDCPLUSPLUS_TYPETRAITS_H -#include "Tmp.h" +#include "utilities/Tmp.h" /** * Code generation macro to create a metafunction @@ -48,11 +48,17 @@ struct obtain_##TypeName { \ namespace wlp { __WLIB_HAS_TYPE(size_type) + __WLIB_HAS_TYPE(val_type) + __WLIB_HAS_TYPE(key_type) + __WLIB_HAS_TYPE(iterator) + __WLIB_HAS_TYPE(const_iterator) + __WLIB_HAS_TYPE(map_type) + __WLIB_HAS_TYPE(node_type) __WLIB_OBTAIN_TYPE(size_type) diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index a979253a..a0037d65 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -285,13 +285,13 @@ namespace wlp { * @param pos position of the element to be deleted * @return the modified String */ - StaticString &erase(uint16_t pos = 0){ + StaticString &erase(uint16_t pos = 0) { if (m_len == 0 || pos >= m_len) return *this; --m_len; for (uint16_t i = pos; i < m_len; ++i) { - m_buffer[i] = m_buffer[i+1]; + m_buffer[i] = m_buffer[i + 1]; } m_buffer[m_len] = '\0'; @@ -301,7 +301,7 @@ namespace wlp { /** * Deletes the last character in the String */ - void pop_back(){ + void pop_back() { if (m_len == 0) return; --m_len; diff --git a/lib/wlib/strings/String.h b/lib/wlib/strings/String.h new file mode 100644 index 00000000..bd57a546 --- /dev/null +++ b/lib/wlib/strings/String.h @@ -0,0 +1,30 @@ +/** + * @file Types.h + * @brief type definition of all the string types we will be using + * + * @author Deep Dhillon + * @date November 19, 2017 + * @bug No known bug + */ + +#ifndef EMBEDDEDCPLUSPLUS_STRING_H +#define EMBEDDEDCPLUSPLUS_STRING_H + +#include "strings/StaticString.h" + +namespace wlp { + // Static Strings + typedef StaticString<8u> String8; + typedef StaticString<16u> String16; + typedef StaticString<32u> String32; + typedef StaticString<64u> String64; + typedef StaticString<128u> String128; + typedef StaticString<256u> String256; + + /* + // Dynamic String + typedef wlp::DynamicString String; + */ +} + +#endif //EMBEDDEDCPLUSPLUS_STRING_H diff --git a/lib/wlib/stl/Comparator.h b/lib/wlib/utilities/Comparator.h similarity index 75% rename from lib/wlib/stl/Comparator.h rename to lib/wlib/utilities/Comparator.h index 978e0f67..f7ae523f 100644 --- a/lib/wlib/stl/Comparator.h +++ b/lib/wlib/utilities/Comparator.h @@ -10,11 +10,11 @@ #ifndef EMBEDDEDCPLUSPLUS_COMPARATOR_H #define EMBEDDEDCPLUSPLUS_COMPARATOR_H -#include "Equal.h" +#include "stl/Equal.h" -#include "../Types.h" +#include "Types.h" -#include "../strings/StaticString.h" +#include "strings/StaticString.h" namespace wlp { @@ -138,31 +138,31 @@ namespace wlp { * @tparam tSize static string size */ template - struct Comparator> { - bool __lt__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) < 0; - } + struct Comparator> { + bool __lt__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) < 0; + } - bool __le__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) <= 0; - } + bool __le__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) <= 0; + } - bool __eq__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) == 0; - } + bool __eq__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) == 0; + } - bool __ne__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) != 0; - } + bool __ne__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) != 0; + } - bool __gt__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) > 0; - } + bool __gt__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) > 0; + } - bool __ge__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) >= 0; - } - }; + bool __ge__(const StaticString &s1, const StaticString &s2) const { + return str_cmp(s1.c_str(), s2.c_str()) >= 0; + } +}; } diff --git a/lib/wlib/utilities/Math.h b/lib/wlib/utilities/Math.h new file mode 100644 index 00000000..aaae0d1e --- /dev/null +++ b/lib/wlib/utilities/Math.h @@ -0,0 +1,25 @@ +#ifndef EMBEDDEDCPLUSPLUS_MATH_H +#define EMBEDDEDCPLUSPLUS_MATH_H + +namespace wlp { + +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +// Multiplication by Mersenne primes reduced as bit operations +// for compilers that do not already perform this optimization +#define MUL_31(x) (((x) << 5) - (x)) +#define MUL_127(x) (((x) << 7) - (x)) + + template + inline constexpr int_type log2_const(int_type n) { + return ((n < 2) ? 0 : 1 + log2_const(n / 2)); + } + + template + inline constexpr int_type pow_const(const int_type a, const int_type b) { + return (b == 0) ? 1 : (a * pow_const(a, b - 1)); + } +} + +#endif //EMBEDDEDCPLUSPLUS_MATH_H diff --git a/lib/wlib/stl/Tmp.h b/lib/wlib/utilities/Tmp.h similarity index 79% rename from lib/wlib/stl/Tmp.h rename to lib/wlib/utilities/Tmp.h index 57d1d416..2b4fed83 100644 --- a/lib/wlib/stl/Tmp.h +++ b/lib/wlib/utilities/Tmp.h @@ -17,6 +17,10 @@ namespace wlp { +#if __cplusplus >= 201103L + typedef decltype(nullptr) nullptr_t; +#endif + /** * This function consumes, and does nothing with, the return * values of parameter pack expanded function calls. This function @@ -705,6 +709,199 @@ namespace wlp { return __declval__::__delegate__(); } + template + struct remove_volatile { + typedef _Tp type; + }; + + template + struct remove_volatile<_Tp volatile> { + typedef _Tp type; + }; + + template + struct remove_cv { + typedef typename + remove_const::type>::type type; + }; + + template + struct __is_null_pointer_helper + : public false_type { + }; + + template<> + struct __is_null_pointer_helper + : public true_type { + }; + + /** + * checks if @p _Tp type is a type that is a nullptr type + * + * @tparam _Tp type being verified + */ + template + struct is_null_pointer + : public __is_null_pointer_helper::type>::type { + }; + + /** + * checks if @p _Tp type is a type that is a nullptr type + * + * @tparam _Tp type being verified + */ + template + struct __is_nullptr_t + : public is_null_pointer<_Tp> { + }; + + template + struct __is_integral_helper + : public false_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + +#ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct __is_integral_helper + : public true_type { }; +#endif + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + template<> + struct __is_integral_helper + : public true_type { + }; + + /** + * checks if @p _Tp type is an integer + * + * @tparam _Tp type being verified + */ + template + struct is_integral + : public __is_integral_helper::type>::type { + }; + + template + struct __is_floating_point_helper + : public false_type { + }; + + template<> + struct __is_floating_point_helper + : public true_type { + }; + + template<> + struct __is_floating_point_helper + : public true_type { + }; + + template<> + struct __is_floating_point_helper + : public true_type { + }; + +#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) + template<> + struct __is_floating_point_helper<__float128> + : public true_type { }; +#endif + + /** + * checks if @p _Tp type is a floating point + * + * @tparam _Tp type being verified + */ + template + struct is_floating_point + : public __is_floating_point_helper::type>::type { + }; + + /** + * checks if @p _Tp type is a type that allow arithmetic operations + * + * @tparam _Tp type being verified + */ + template + struct is_arithmetic + : public or_, is_floating_point<_Tp>>::type { + }; + + /** + * checks if @p _Tp type is a type that is a fundamental type and not an object + * + * @tparam _Tp type being verified + */ + template + struct is_fundamental + : public or_, is_void<_Tp>, + is_null_pointer<_Tp>>::type { + }; } #endif //EMBEDDEDCPLUSPLUS_TMP_H diff --git a/lib/wlib/stl/Utility.h b/lib/wlib/utilities/Utility.h similarity index 100% rename from lib/wlib/stl/Utility.h rename to lib/wlib/utilities/Utility.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1e5d9319..2ce9488c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Waddress -Warray-bounds -Wbuiltin-macro-redefined -Wconversion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self -Wnon-virtual-dtor -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wswitch -Wunreachable-code") -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wsuggest-attribute=const") set(GTEST_INCLUDE_DIR ${gtest_SOURCE_DIR}/include) set(WLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/lib/wlib) @@ -12,8 +11,9 @@ include_directories(${WLIB_INCLUDE_DIR}) file(GLOB files "test.cpp" "template_defs.h" + "strings/*.cpp" "stl/*.cpp" - "strings/*.cpp") + "memory/*.cpp") add_executable(tests ${files}) target_link_libraries(tests gtest) diff --git a/tests/memory/memory_check.cpp b/tests/memory/memory_check.cpp new file mode 100644 index 00000000..a8d39736 --- /dev/null +++ b/tests/memory/memory_check.cpp @@ -0,0 +1,104 @@ +/** + * @file memory_check.cpp + * @brief Unit Testing for Memory model used in Wlib + * + * @author Deep Dhillon + * @date November 18, 2017 + * @bug No known bugs + */ + +#include "gtest/gtest.h" + +#include "memory/Memory.h" + +class Sample{ + int constr = 0; +public: + + Sample(){ + constr += 4; + } + + ~Sample(){ + constr += 5; + } + + int getConstr(){ + return constr; + } +}; + +TEST(memory_check, general_usability) { + ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); + ASSERT_TRUE(isSizeAvailable(16)); + ASSERT_TRUE(isSizeMemAvailable(16)); + ASSERT_EQ(getNumBlocks(), getNumBlocksAvailable(16)); + + // allocate a character + auto *character = malloc(); // by default creates one char + ASSERT_NE(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); + + // allocate 2 characters + auto *character2 = malloc(2); + + // free all of them + free(character); + free(character2); + + // allocate 4 characters + auto *character4 = malloc(4); + + // reallocate + character4 = realloc(character4, 8); + + // create an object + auto *test = malloc(); + ASSERT_EQ(4, test->getConstr()); + + free(character4); + free(test); + + ASSERT_EQ(9, test->getConstr()); + ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); +} + +TEST(memory_check, malloc_and_realloc){ + int *v = malloc(75); + *v = 75; + int *v2 = malloc(); + *v2 = 68; + + v2 = realloc(v2); + ASSERT_EQ(68, *v2); + + v2 = realloc(v2, 15); + ASSERT_EQ(68, *v2); + + v2 = realloc(v, 15); + ASSERT_EQ(75, *v2); + + v2 = realloc(v2, 0); + ASSERT_EQ(nullptr, v2); + + free(v); + free(v2); +} + +TEST(memory_check, array_allocation){ + Sample *s = malloc(2); + ASSERT_EQ(8, s[0].getConstr() + s[1].getConstr()); + + free(s); + ASSERT_EQ(18, s[0].getConstr() + s[1].getConstr()); +} + +TEST(memory_check, free){ + free(nullptr); + + int *g = malloc(7); + free(g); + int *l = malloc(7); + ASSERT_EQ(l, g); + free(g); +} + diff --git a/tests/stl/bitset_check.cpp b/tests/stl/bitset_check.cpp index b5164710..a8c1c484 100644 --- a/tests/stl/bitset_check.cpp +++ b/tests/stl/bitset_check.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" + #include "stl/Bitset.h" namespace wlp { diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp index 2bb8462a..a19d4b62 100644 --- a/tests/stl/chain_map_check.cpp +++ b/tests/stl/chain_map_check.cpp @@ -1,7 +1,8 @@ #include "gtest/gtest.h" + #include "stl/ChainMap.h" +#include "strings/String.h" -#include "Types.h" #include "../template_defs.h" using namespace wlp; @@ -36,7 +37,7 @@ TEST(chain_map_test, test_const_iterator) { map[5] = 5; map[6] = 6; map[7] = 7; - const int_map const_map(move(map)); + const int_map const_map(move(map)); int_map::const_iterator it = const_map.begin(); ASSERT_EQ(5, *it); ++it; @@ -123,13 +124,6 @@ TEST(chain_map_test, test_constructor_params) { ASSERT_TRUE(map.empty()); } -TEST(chain_map_test, test_constructor_allocator) { - string_map map(10, 100); - const size_t expected = sizeof(string_map::node_type); - ASSERT_EQ(expected, map.get_node_allocator()->GetBlockSize()); - ASSERT_EQ(expected * 10, map.get_node_allocator()->GetPoolSize()); -} - TEST(chain_map_test, test_begin_returns_end_when_empty) { string_map map(10, 100); ASSERT_EQ(map.begin(), map.end()); diff --git a/tests/stl/comparator_check.cpp b/tests/stl/comparator_check.cpp index 4ab52d41..b9240b44 100644 --- a/tests/stl/comparator_check.cpp +++ b/tests/stl/comparator_check.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" -#include "stl/Comparator.h" -#include "strings/StaticString.h" +#include "utilities/Comparator.h" +#include "strings/String.h" using namespace wlp; diff --git a/tests/stl/concept_check.cpp b/tests/stl/concept_check.cpp index dc5b3a23..8b5f757a 100644 --- a/tests/stl/concept_check.cpp +++ b/tests/stl/concept_check.cpp @@ -1,9 +1,9 @@ -#include #include "gtest/gtest.h" #include "stl/Concept.h" -#include "stl/Comparator.h" +#include "utilities/Comparator.h" #include "stl/ChainMap.h" +#include "stl/OpenMap.h" #include "stl/ArrayList.h" using namespace wlp; diff --git a/tests/stl/equals_check.cpp b/tests/stl/equals_check.cpp index 70b6e706..0e093b93 100644 --- a/tests/stl/equals_check.cpp +++ b/tests/stl/equals_check.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" -#include "strings/StaticString.h" + +#include "strings/String.h" #include "stl/Equal.h" -#include "Types.h" #include "../template_defs.h" using namespace wlp; diff --git a/tests/stl/hash_check.cpp b/tests/stl/hash_check.cpp index 2f241ba6..bd546b76 100644 --- a/tests/stl/hash_check.cpp +++ b/tests/stl/hash_check.cpp @@ -1,5 +1,6 @@ #include "gtest/gtest.h" -#include "strings/StaticString.h" + +#include "strings/String.h" #include "stl/Hash.h" #include "../template_defs.h" diff --git a/tests/stl/heap_check.cpp b/tests/stl/heap_check.cpp index bc4fc36a..c2f5c87d 100644 --- a/tests/stl/heap_check.cpp +++ b/tests/stl/heap_check.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "stl/ArrayHeap.h" + #include "../template_defs.h" using namespace wlp; diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp index 08c562bd..2fc4fc66 100644 --- a/tests/stl/open_map_check.cpp +++ b/tests/stl/open_map_check.cpp @@ -18,14 +18,6 @@ TEST(open_map_test, test_constructor_parameters) { ASSERT_EQ(61, map.max_load()); } -TEST(open_map_test, test_constructor_allocator) { - string_map map(12, 75); - const Allocator *alloc = map.get_node_allocator(); - size_t expected = sizeof(string_map::node_type); - ASSERT_EQ(expected, alloc->GetBlockSize()); - ASSERT_EQ(expected * 12, alloc->GetPoolSize()); -} - TEST(open_map_test, test_is_empty_on_construct) { string_map map(12, 75); ASSERT_TRUE(map.empty()); diff --git a/tests/stl/pair_check.cpp b/tests/stl/pair_check.cpp index 5e38e2cf..c8063ab8 100644 --- a/tests/stl/pair_check.cpp +++ b/tests/stl/pair_check.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" + #include "stl/Pair.h" #include "../template_defs.h" diff --git a/tests/strings/static_string_check.cpp b/tests/strings/static_string_check.cpp index 22794f81..b529554f 100644 --- a/tests/strings/static_string_check.cpp +++ b/tests/strings/static_string_check.cpp @@ -10,6 +10,7 @@ #include "gtest/gtest.h" #include "Types.h" +#include "strings/String.h" using namespace wlp; diff --git a/tests/template_defs.h b/tests/template_defs.h index dc881267..2c38292b 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -3,7 +3,8 @@ #include "Types.h" -#include "stl/Utility.h" +#include "strings/String.h" +#include "utilities/Utility.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" #include "stl/ArrayHeap.h" From 51bedc409ff5c3fb7472656e710be72123abfdba Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 20 Nov 2017 11:48:31 -0800 Subject: [PATCH 016/102] Cleaned up the code a bit (#57) --- CMakeLists.txt | 2 +- lib/wlib/CMakeLists.txt | 6 +- lib/wlib/memory/Allocator.cpp | 98 ++++---- lib/wlib/memory/Allocator.h | 46 ++-- lib/wlib/memory/DynamicAllocatorPool.h | 4 +- lib/wlib/memory/Memory.cpp | 111 ++++----- lib/wlib/memory/Memory.h | 4 +- lib/wlib/memory/StaticAllocatorPool.h | 4 +- lib/wlib/stl/ArrayHeap.h | 5 +- lib/wlib/stl/ArrayList.h | 267 ++-------------------- lib/wlib/stl/ChainMap.h | 152 ++++-------- lib/wlib/stl/ChainSet.h | 18 +- lib/wlib/{utilities => stl}/Comparator.h | 84 +++---- lib/wlib/stl/Concept.h | 28 +-- lib/wlib/stl/Equal.h | 47 +--- lib/wlib/stl/Hash.h | 7 +- lib/wlib/stl/OpenMap.h | 137 +++-------- lib/wlib/stl/OpenSet.h | 20 +- lib/wlib/stl/Pair.h | 28 +-- lib/wlib/stl/Tuple.h | 37 ++- lib/wlib/stl/TypeTraits.h | 2 +- lib/wlib/strings/StaticString.h | 102 ++++----- lib/wlib/strings/String.h | 8 +- lib/wlib/{utilities => utility}/Math.h | 11 +- lib/wlib/{utilities => utility}/Tmp.h | 0 lib/wlib/{utilities => utility}/Utility.h | 0 tests/CMakeLists.txt | 2 + tests/stl/chain_map_check.cpp | 14 +- tests/stl/comparator_check.cpp | 2 +- tests/stl/concept_check.cpp | 2 +- tests/stl/open_map_check.cpp | 2 +- tests/stl/pair_check.cpp | 16 +- tests/template_defs.h | 2 +- wmake | 1 + 34 files changed, 430 insertions(+), 839 deletions(-) rename lib/wlib/{utilities => stl}/Comparator.h (59%) rename lib/wlib/{utilities => utility}/Math.h (63%) rename lib/wlib/{utilities => utility}/Tmp.h (100%) rename lib/wlib/{utilities => utility}/Utility.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79fc07f3..d63cba6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1) project(EmbeddedCplusplus) enable_testing() -SET(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index 6b2425a1..ae738d1a 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -1,8 +1,8 @@ project(wlib) -SET(CMAKE_CXX_FLAGS_DISTRIBUTION "-fno-exceptions -fno-threadsafe-statics -fpermissive -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -flto") -SET(CMAKE_C_FLAGS_DISTRIBUTION "-std=gnu11 -fno-fat-lto-objects -g -Os -Wall -ffunction-sections -fdata-sections -flto") set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS_DISTRIBUTION "-fno-exceptions -fno-threadsafe-statics -fpermissive -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -flto") +set(CMAKE_C_FLAGS_DISTRIBUTION "-std=gnu11 -fno-fat-lto-objects -g -Os -Wall -ffunction-sections -fdata-sections -flto") #[[ These definitions are used for how the memory is allocated @@ -26,7 +26,7 @@ file(GLOB header_files "strings/*.h" "stl/*.h" "memory/*.h" - "utilities/*.h") + "utility/*.h") file(GLOB source_files "memory/*.cpp") diff --git a/lib/wlib/memory/Allocator.cpp b/lib/wlib/memory/Allocator.cpp index 8739e717..ad7a23ea 100644 --- a/lib/wlib/memory/Allocator.cpp +++ b/lib/wlib/memory/Allocator.cpp @@ -7,34 +7,42 @@ * @bug No known bugs */ -#include -#include -#include "../utilities/Math.h" +#include // memset #include "Allocator.h" -#include "../utilities/Utility.h" - -wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize, wlp::Allocator::Type allocationType, void *pPool) - : - m_poolType{allocationType}, - m_blockSize{blockSize}, - m_pHead{nullptr}, - m_pPool{nullptr}, - m_poolSize{poolSize}, - m_poolTotalBlockCnt{0}, - m_poolCurrBlockCnt{0}, - m_totalBlockCount{0}, - m_allocations{0}, - m_deallocations{0} { + +#include "../utility/Math.h" +#include "../utility/Utility.h" + +using namespace wlp; + +__Allocator::__Allocator( + size32_type blockSize, + size32_type poolSize, + __Allocator::Type allocationType, + void *pPool) + : m_poolType{allocationType}, + m_blockSize{blockSize}, + m_pHead{nullptr}, + m_pPool{nullptr}, + m_poolSize{poolSize}, + m_poolTotalBlockCnt{0}, + m_poolCurrBlockCnt{0}, + m_totalBlockCount{0}, + m_allocations{0}, + m_deallocations{0} { // lowest size of a block will be the size of Block ptr - if (m_blockSize < sizeof(wlp::Allocator::Block *)) m_blockSize = sizeof(wlp::Allocator::Block *); + if (m_blockSize < sizeof(__Allocator::Block *)) { m_blockSize = sizeof(__Allocator::Block *); } // if pool size is provided, we will use pool instead of dynamic heap allocations if (m_poolSize) { - m_poolSize = max(m_blockSize, poolSize); + m_poolSize = MAX(m_blockSize, poolSize); // find the closest round number that describes the number of blocks - m_poolTotalBlockCnt = static_cast(roundf(m_poolSize / static_cast(m_blockSize))); + m_poolTotalBlockCnt = int_div_round( + static_cast(m_poolSize), + static_cast(m_blockSize) + ); m_poolCurrBlockCnt = m_poolTotalBlockCnt; m_totalBlockCount = m_poolTotalBlockCnt; @@ -43,19 +51,20 @@ wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize, wlp::Allo // If caller provided an external memory pool if (pPool) { - m_pPool = (wlp::Allocator::Block *) pPool; + m_pPool = (__Allocator::Block *) pPool; } else { // create a pool - m_pPool = (wlp::Allocator::Block *) new char[m_poolSize]; + m_pPool = (__Allocator::Block *) new char[m_poolSize]; } memset(m_pPool, 0, m_poolSize); // Fill m_pPool with m_poolSize blocks - wlp::Allocator::Block *pBlock = m_pPool; + __Allocator::Block *pBlock = m_pPool; for (size_type i = 1; i < m_poolTotalBlockCnt; i++) { - pBlock = pBlock->pNext = reinterpret_cast(reinterpret_cast(pBlock) + - m_blockSize); + pBlock = pBlock->pNext = reinterpret_cast<__Allocator::Block *>( + reinterpret_cast(pBlock) + m_blockSize + ); } // Initially, all in Deallocate'd state @@ -63,7 +72,7 @@ wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize, wlp::Allo } } -wlp::Allocator::Allocator(Allocator &&allocator) +__Allocator::__Allocator(__Allocator &&allocator) : m_poolType(move(allocator.m_poolType)), m_blockSize(move(allocator.m_blockSize)), m_poolSize(move(allocator.m_poolSize)), @@ -83,14 +92,14 @@ wlp::Allocator::Allocator(Allocator &&allocator) allocator.m_poolTotalBlockCnt = 0; } -wlp::Allocator &wlp::Allocator::operator=(Allocator &&allocator) { +__Allocator &__Allocator::operator=(__Allocator &&allocator) { if (m_totalBlockCount > m_poolTotalBlockCnt) { - wlp::Allocator::Block *pBlock = nullptr; + __Allocator::Block *pBlock = nullptr; while (m_pHead) { pBlock = m_pHead; if (pBlock) { m_pHead = m_pHead->pNext; - if (!IsPoolBlock(pBlock)) { + if (!isPoolBlock(pBlock)) { delete[] (char *) pBlock; --m_totalBlockCount; } @@ -122,21 +131,21 @@ wlp::Allocator &wlp::Allocator::operator=(Allocator &&allocator) { return *this; } -wlp::Allocator::Allocator(size32_type blockSize, size32_type poolSize) : - wlp::Allocator(blockSize, poolSize, DYNAMIC, nullptr) {} +__Allocator::__Allocator(size32_type blockSize, size32_type poolSize) : + __Allocator(blockSize, poolSize, DYNAMIC, nullptr) {} -wlp::Allocator::Allocator(size32_type blockSize, void *pPool, uint32_t poolSize, Type type) : - wlp::Allocator(blockSize, poolSize, type, pPool) {} +__Allocator::__Allocator(size32_type blockSize, void *pPool, uint32_t poolSize, Type type) : + __Allocator(blockSize, poolSize, type, pPool) {} -wlp::Allocator::~Allocator() { +__Allocator::~__Allocator() { // delete non pool blocks if (m_totalBlockCount > m_poolTotalBlockCnt) { - wlp::Allocator::Block *pBlock = nullptr; + __Allocator::Block *pBlock = nullptr; while (m_pHead) { pBlock = m_pHead; if (pBlock) { m_pHead = m_pHead->pNext; - if (!IsPoolBlock(pBlock)) { + if (!isPoolBlock(pBlock)) { delete[] (char *) pBlock; --m_totalBlockCount; } @@ -147,24 +156,25 @@ wlp::Allocator::~Allocator() { // only delete the pool if it is not static if (m_poolType != Type::STATIC) { // destroy the pool - if (m_pPool) delete[] (char *) m_pPool; + if (m_pPool) { delete[] (char *) m_pPool; } } } -void *wlp::Allocator::Allocate() { +void *__Allocator::allocate() { // Pop one free block, if any. - wlp::Allocator::Block *pBlock = m_pHead; + __Allocator::Block *pBlock = m_pHead; if (pBlock) { m_pHead = m_pHead->pNext; --m_poolCurrBlockCnt; } else { // If we are using a pool we ran out of memory - if (m_poolSize > 0) + if (m_poolSize > 0) { return nullptr; + } // Otherwise, get a 'new' one from heap. - pBlock = (wlp::Allocator::Block *) new char[m_blockSize]; + pBlock = (__Allocator::Block *) new char[m_blockSize]; ++m_totalBlockCount; } @@ -173,10 +183,10 @@ void *wlp::Allocator::Allocate() { return pBlock; } -void wlp::Allocator::Deallocate(void *pBlock) { - if (IsPoolBlock(pBlock)) ++m_poolCurrBlockCnt; +void __Allocator::deallocate(void *pBlock) { + if (isPoolBlock(pBlock)) { ++m_poolCurrBlockCnt; } - auto pBlock1 = (wlp::Allocator::Block *) pBlock; + auto pBlock1 = (__Allocator::Block *) pBlock; pBlock1->pNext = m_pHead; m_pHead = pBlock1; ++m_deallocations; diff --git a/lib/wlib/memory/Allocator.h b/lib/wlib/memory/Allocator.h index 0369b7f9..6fe998bf 100644 --- a/lib/wlib/memory/Allocator.h +++ b/lib/wlib/memory/Allocator.h @@ -19,13 +19,14 @@ #include "../Types.h" namespace wlp { - class Allocator { + + class __Allocator { private: /*! * Block of memory that will be provided to the user */ struct Block { - Block *pNext; /*!< linked list to keep track memory pool */ + Block *pNext; /*!< linked list to keep track memory pool */ }; public: @@ -40,7 +41,7 @@ namespace wlp { /** * Disable copy construction. */ - Allocator(const Allocator &) = delete; + __Allocator(const __Allocator &) = delete; /** * Move constructor will transfer the resources of another @@ -49,7 +50,7 @@ namespace wlp { * @author Jeff Niu * @param allocator the allocator to move */ - Allocator(Allocator &&allocator); + __Allocator(__Allocator &&allocator); /** * Allocator used for allocating memory where memory is acquired by the allocator. It supports a pool @@ -65,7 +66,7 @@ namespace wlp { * @param blockSize size of memory blocks that can acquired at a time * @param poolSize size of memory pool to be created */ - explicit Allocator(size32_type blockSize, size32_type poolSize = 0); + explicit __Allocator(size32_type blockSize, size32_type poolSize = 0); /** * Allocator used for allocating memory where memory is provided to the allocator. It uses the given @@ -82,7 +83,7 @@ namespace wlp { * @param poolSize size of the memory pool provided * @param type type of memory pool provided (static or dynamic) */ - Allocator(size32_type blockSize, void *pPool, size32_type poolSize, Type type); + __Allocator(size32_type blockSize, void *pPool, size32_type poolSize, Type type); /** * Deletes memory and returns it back to the system @@ -91,14 +92,14 @@ namespace wlp { * de-allocated the memory or not but for dynamic heap blocks gathered in runtime there is * no such promise. User has to call de-allocate on that memory */ - ~Allocator(); + ~__Allocator(); /** * Allocates memory from internal memory pool/dynamic memory system and gives access to the user * * @return address to memory of blockSize that is predefined */ - void *Allocate(); + void *allocate(); /** * De-allocates the memory so that it is available if another call for memory is made. It does not @@ -109,7 +110,7 @@ namespace wlp { * * @param pBlock address to memory block that needs de-allocation */ - void Deallocate(void *pBlock); + void deallocate(void *pBlock); /** * Gives user indication if the memory block they have belongs to the pool or it is some other dynamic @@ -118,10 +119,10 @@ namespace wlp { * @param pBlockVoid memory block address being verified * @return true or false based on if the given block belongs to memory pool */ - inline bool IsPoolBlock(void *pBlockVoid) const { + inline bool isPoolBlock(void *pBlockVoid) const { auto *pBlock = (Block *) pBlockVoid; - if (!m_pPool)return false; + if (!m_pPool) { return false; } return ((char *) pBlock >= (char *) m_pPool && (char *) pBlock <= (char *) m_pPool + m_blockSize * (m_totalBlockCount - 1)); } @@ -131,7 +132,7 @@ namespace wlp { * * @return size of memory block */ - inline size32_type GetBlockSize() const { + inline size32_type getBlockSize() const { return m_blockSize; } @@ -140,7 +141,7 @@ namespace wlp { * * @return size of pool */ - inline size32_type GetPoolSize() const { + inline size32_type getPoolSize() const { return m_poolSize; } @@ -149,7 +150,7 @@ namespace wlp { * * @return number of memory blocks available in the pool */ - inline uint16_t GetNumPoolBlocksAvail() const { + inline uint16_t getNumPoolBlocksAvail() const { return m_poolCurrBlockCnt; } @@ -158,7 +159,7 @@ namespace wlp { * * @return number of memory blocks in total in the pool */ - inline uint16_t GetTotalPoolBlocks() const { + inline uint16_t getTotalPoolBlocks() const { return m_poolTotalBlockCnt; } @@ -167,7 +168,7 @@ namespace wlp { * * @return number of memory blocks in total in Allocator */ - inline uint16_t GetTotalBlocks() const { + inline uint16_t getTotalBlocks() const { return m_totalBlockCount; } @@ -176,7 +177,7 @@ namespace wlp { * * @return the number of allocations */ - inline uint16_t GetNumAllocations() const { + inline uint16_t getNumAllocations() const { return m_allocations; } @@ -185,7 +186,7 @@ namespace wlp { * * @return the number of de-allocations */ - inline uint16_t GetNumDeallocations() const { + inline uint16_t getNumDeallocations() const { return m_deallocations; } @@ -194,7 +195,7 @@ namespace wlp { * * @return reference to this allocator */ - Allocator &operator=(const Allocator &) = delete; + __Allocator &operator=(const __Allocator &) = delete; /** * Move assignment operator deconstructs the current allocator @@ -206,7 +207,7 @@ namespace wlp { * @param allocator the allocator to move * @return reference to this allocator */ - Allocator &operator=(Allocator &&allocator); + __Allocator &operator=(__Allocator &&allocator); private: /** @@ -218,13 +219,12 @@ namespace wlp { * @param allocationType type of memory in memory pool * @param pPool address to memory provided */ - explicit Allocator(size32_type blockSize, size32_type poolSize, Allocator::Type allocationType, void *pPool); - + explicit __Allocator(size32_type blockSize, size32_type poolSize, __Allocator::Type allocationType, void *pPool); Type m_poolType; - size32_type m_blockSize; Block *m_pHead; Block *m_pPool; + size32_type m_blockSize; size32_type m_poolSize; uint16_t m_poolTotalBlockCnt; uint16_t m_poolCurrBlockCnt; diff --git a/lib/wlib/memory/DynamicAllocatorPool.h b/lib/wlib/memory/DynamicAllocatorPool.h index 480ae843..798dbb48 100644 --- a/lib/wlib/memory/DynamicAllocatorPool.h +++ b/lib/wlib/memory/DynamicAllocatorPool.h @@ -17,9 +17,9 @@ namespace wlp { template - class DynamicAllocatorPool : public Allocator { + class DynamicAllocatorPool : public __Allocator { public: - DynamicAllocatorPool() : Allocator(tblockSize, (tblockSize * tnumBlocks)) {} + DynamicAllocatorPool() : __Allocator(tblockSize, (tblockSize * tnumBlocks)) {} }; } diff --git a/lib/wlib/memory/Memory.cpp b/lib/wlib/memory/Memory.cpp index 8cdd79f4..225b253f 100644 --- a/lib/wlib/memory/Memory.cpp +++ b/lib/wlib/memory/Memory.cpp @@ -13,12 +13,12 @@ #include "StaticAllocatorPool.h" #include "DynamicAllocatorPool.h" -#include "../utilities/Math.h" #include "../Wlib.h" +#include "../utility/Math.h" using namespace wlp; -static constexpr size_type required_extra_buffer = sizeof(Allocator *); +static constexpr size_type REQUIRED_EXTRA_BUFFER = sizeof(__Allocator *); /** * This class restricts the size of blocks as the power of 2 gets bigger @@ -28,7 +28,8 @@ class RestrictSize { static constexpr uint16_t powOffsetFromZero = 9; // which pow of 2 to start restriction from static constexpr uint16_t restrictions[numRestrictions] = { - 300, 400, 500}; + 300, 400, 500 + }; public: /** @@ -47,7 +48,7 @@ class RestrictSize { } }; -static Allocator *_allocators[MAX_ALLOCATORS]; +static __Allocator *__allocators[MAX_ALLOCATORS]; int MemoryInitDestroy::m_srefCount = 0; /** @@ -89,7 +90,7 @@ struct insert { constexpr size32_type blockSize = RestrictSize::apply(2, curr_pow)>(); #if defined(DYNAMIC_POOL) - _allocators[from] = new DynamicAllocatorPool(); + __allocators[from] = new DynamicAllocatorPool(); #elif defined(STATIC_POOL) _allocators[from] = new StaticAllocatorPool(); #endif @@ -115,7 +116,7 @@ struct insert { constexpr size32_type blockSize = RestrictSize::apply(2, curr_pow)>(); #if defined(DYNAMIC_POOL) - _allocators[from] = new DynamicAllocatorPool(); + __allocators[from] = new DynamicAllocatorPool(); #elif defined(STATIC_POOL) _allocators[from] = new StaticAllocatorPool(); #endif @@ -124,17 +125,17 @@ struct insert { void memory_init() { // smallest pow of 2 a block can be created - constexpr auto powStart = log2_const(required_extra_buffer) + 1; + constexpr auto powStart = log2_const(REQUIRED_EXTRA_BUFFER) + 1; insert::apply(); } void memory_destroy() { - for (auto &_allocator : _allocators) { - if (_allocator == nullptr) { + for (auto &allocator : __allocators) { + if (allocator == nullptr) { break; } - delete _allocator; - _allocator = nullptr; + delete allocator; + allocator = nullptr; } } @@ -144,15 +145,15 @@ void memory_destroy() { * @param size allocator blocks size * @return Allocator instance or nullptr if no allocator exists */ -static inline Allocator *find_allocator(size32_type size) { - for (auto &_allocator : _allocators) { - if (_allocator == nullptr) { +static inline __Allocator *find_allocator(size32_type size) { + for (auto &allocator : __allocators) { + if (allocator == nullptr) { break; } #if defined(DYNAMIC_POOL) || defined(STATIC_POOL) - if (_allocator->GetBlockSize() >= size) { - return _allocator; + if (allocator->getBlockSize() >= size) { + return allocator; } #else if (_allocator->GetBlockSize() == size) @@ -166,13 +167,13 @@ static inline Allocator *find_allocator(size32_type size) { /** * Insert an Allocator instance into the array * - * @param allocator an Allocator instance + * @param new_allocator an Allocator instance * @return true or false based on if insertion is successful */ -static inline bool insert_allocator(Allocator *allocator) { - for (auto &_allocator : _allocators) { - if (_allocator == nullptr) { - _allocator = allocator; +static inline bool insert_allocator(__Allocator *new_allocator) { + for (auto &allocator : __allocators) { + if (allocator == nullptr) { + allocator = new_allocator; return true; } } @@ -187,9 +188,9 @@ static inline bool insert_allocator(Allocator *allocator) { * @param allocator allocator to set * @return a pointer to the client's area within the block */ -static inline void *set_block_allocator(void *block, Allocator *allocator) { +static inline void *set_block_allocator(void *block, __Allocator *allocator) { // Cast the raw block memory to a Allocator pointer - auto **pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast<__Allocator **>(block); // Write the size into the memory block *pAllocatorInBlock = allocator; @@ -223,15 +224,15 @@ T nextHigher(T k) { * @param size client's requested block size * @return an allocator instance that handles the block size */ -Allocator *memory_get_allocator(size32_type size) { +__Allocator *memory_get_allocator(size32_type size) { // Based on the size, find the next higher powers of two value. - // Add required_extra_buffer to the requested block size to hold the size + // Add REQUIRED_EXTRA_BUFFER to the requested block size to hold the size // of an Allocator* within the block memory region. Most blocks are powers of two, // however some common allocator block sizes can be explicitly defined // to minimize wasted storage. This offers application specific tuning. // These restrictions can only imposed if no pool is being used - size32_type blockSize = size + required_extra_buffer; + size32_type blockSize = size + REQUIRED_EXTRA_BUFFER; #if !defined(DYNAMIC_POOL) && !defined(STATIC_POOL) // set custom blocks if pool is not used @@ -244,7 +245,7 @@ Allocator *memory_get_allocator(size32_type size) { blockSize = nextHigher(blockSize); #endif - Allocator *allocator = find_allocator(blockSize); + __Allocator *allocator = find_allocator(blockSize); #if !defined(DYNAMIC_POOL) && !defined(STATIC_POOL) if (allocator == nullptr){ @@ -269,21 +270,21 @@ Allocator *memory_get_allocator(size32_type size) { */ void *__memory_alloc(size32_type size) { // Allocate a raw memory block - Allocator *allocator = memory_get_allocator(size); + __Allocator *allocator = memory_get_allocator(size); // if not enough sizes available if (allocator == nullptr) { return nullptr; } - void *blockMemoryPtr = allocator->Allocate(); + void *blockMemoryPtr = allocator->allocate(); // if not enough quantity of that particular size available if (blockMemoryPtr == nullptr) { // check if higher sizes have some blocks available and // give a block from them if available - size32_type currBlockSize = allocator->GetBlockSize(); - if (currBlockSize < _allocators[MAX_ALLOCATORS - 1]->GetBlockSize()) { + size32_type currBlockSize = allocator->getBlockSize(); + if (currBlockSize < __allocators[MAX_ALLOCATORS - 1]->getBlockSize()) { return __memory_alloc(currBlockSize + 1); } @@ -301,9 +302,9 @@ void *__memory_alloc(size32_type size) { * @param block a pointer to the client's memory block * @return The original allocator instance stored in the memory block */ -static inline Allocator *get_block_allocator(void *block) { +static inline __Allocator *get_block_allocator(void *block) { // Cast the client memory to a Allocator pointer - auto **pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast<__Allocator **>(block); // Back up one Allocator* position to get the stored allocator instance pAllocatorInBlock--; @@ -320,7 +321,7 @@ static inline Allocator *get_block_allocator(void *block) { */ static inline void *get_block_ptr(void *block) { // Cast the client memory to a Allocator* pointer - auto **pAllocatorInBlock = static_cast(block); + auto **pAllocatorInBlock = static_cast<__Allocator **>(block); // Back up one Allocator* position and return the original raw memory block pointer return --pAllocatorInBlock; @@ -338,13 +339,13 @@ void __memory_free(void *ptr) { } // Extract the original allocator instance from the caller's block pointer - Allocator *allocator = get_block_allocator(ptr); + __Allocator *allocator = get_block_allocator(ptr); // Convert the client pointer into the original raw block pointer void *blockPtr = get_block_ptr(ptr); // Deallocate the block - allocator->Deallocate(blockPtr); + allocator->deallocate(blockPtr); } /** @@ -367,8 +368,8 @@ void *__memory_realloc(void *oldMem, size32_type size) { void *newMem = __memory_alloc(size); if (newMem != nullptr) { // Get the original allocator instance from the old memory block - Allocator *oldAllocator = get_block_allocator(oldMem); - size_type oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator *); + __Allocator *oldAllocator = get_block_allocator(oldMem); + size_type oldSize = oldAllocator->getBlockSize() - sizeof(__Allocator *); // Copy the bytes from the old memory block into the new (as much as will fit) memcpy(newMem, oldMem, (oldSize < size) ? oldSize : size); @@ -386,8 +387,8 @@ void *__memory_realloc(void *oldMem, size32_type size) { size32_type getTotalMemoryUsed() { size32_type totalMemory = 0; - for (auto &_allocator : _allocators) { - totalMemory += _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + for (auto &_allocator : __allocators) { + totalMemory += _allocator->getNumAllocations() * _allocator->getBlockSize(); } return totalMemory; @@ -397,16 +398,16 @@ size32_type getTotalMemoryUsed() { size32_type getTotalMemoryAvailable() { size32_type totalMemory = 0; - for (auto &_allocator : _allocators) { - totalMemory += _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); + for (auto &_allocator : __allocators) { + totalMemory += _allocator->getTotalBlocks() * _allocator->getBlockSize(); } return totalMemory; } bool isSizeAvailable(size32_type blockSize) { - for (auto &_allocator : _allocators) { - if (_allocator->GetBlockSize() == blockSize) { + for (auto &_allocator : __allocators) { + if (_allocator->getBlockSize() == blockSize) { return true; } } @@ -415,10 +416,10 @@ bool isSizeAvailable(size32_type blockSize) { } bool isSizeMemAvailable(size32_type blockSize) { - for (auto &_allocator : _allocators) { - if (_allocator->GetBlockSize() == blockSize) { - uint32_t totalMemAvail = _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); - uint32_t totalMemUsed = _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + for (auto &_allocator : __allocators) { + if (_allocator->getBlockSize() == blockSize) { + uint32_t totalMemAvail = _allocator->getTotalBlocks() * _allocator->getBlockSize(); + uint32_t totalMemUsed = _allocator->getNumAllocations() * _allocator->getBlockSize(); return totalMemAvail - totalMemUsed != 0; } } @@ -428,10 +429,10 @@ bool isSizeMemAvailable(size32_type blockSize) { uint16_t getNumBlocksAvailable(size32_type blockSize) { uint16_t numBlockAvail = 0; - for (auto &_allocator : _allocators) { - if (_allocator->GetBlockSize() == blockSize) { - uint32_t totalMemAvail = _allocator->GetTotalBlocks() * _allocator->GetBlockSize(); - uint32_t totalMemUsed = _allocator->GetNumAllocations() * _allocator->GetBlockSize(); + for (auto &_allocator : __allocators) { + if (_allocator->getBlockSize() == blockSize) { + uint32_t totalMemAvail = _allocator->getTotalBlocks() * _allocator->getBlockSize(); + uint32_t totalMemUsed = _allocator->getNumAllocations() * _allocator->getBlockSize(); numBlockAvail += (totalMemAvail - totalMemUsed) / blockSize; } } @@ -448,10 +449,10 @@ uint16_t getMaxAllocations() { } size_type getSmallestBlockSize() { - return static_cast(pow_const(2, log2_const(required_extra_buffer) + 1)); + return static_cast(pow_const(2, log2_const(REQUIRED_EXTRA_BUFFER) + 1)); } size32_type getFixedMemorySize(void *ptr) { - Allocator *allocator = get_block_allocator(ptr); - return allocator->GetBlockSize(); + __Allocator *allocator = get_block_allocator(ptr); + return allocator->getBlockSize(); } diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 416c45f1..b9db1338 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -17,11 +17,9 @@ #ifndef FIXED_MEMORY_MEMORY_H #define FIXED_MEMORY_MEMORY_H -#include -#include "../utilities/Tmp.h" - #include "../Types.h" +#include "../utility/Tmp.h" /** * @brief Helper for initializing and destroying memory management diff --git a/lib/wlib/memory/StaticAllocatorPool.h b/lib/wlib/memory/StaticAllocatorPool.h index ff8b5929..7977f6b7 100644 --- a/lib/wlib/memory/StaticAllocatorPool.h +++ b/lib/wlib/memory/StaticAllocatorPool.h @@ -17,9 +17,9 @@ namespace wlp { template - class StaticAllocatorPool : public Allocator { + class StaticAllocatorPool : public __Allocator { public: - StaticAllocatorPool() : Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, Allocator::STATIC) {} + StaticAllocatorPool() : __Allocator(tblockSize, m_memory, tblockSize * tnumBlocks, __Allocator::STATIC) {} private: char m_memory[tblockSize * tnumBlocks]; diff --git a/lib/wlib/stl/ArrayHeap.h b/lib/wlib/stl/ArrayHeap.h index 281936b2..352ef98a 100644 --- a/lib/wlib/stl/ArrayHeap.h +++ b/lib/wlib/stl/ArrayHeap.h @@ -16,10 +16,11 @@ #define EMBEDDEDCPLUSPLUS_ARRAYHEAP_H #include "ArrayList.h" -#include "utilities/Comparator.h" +#include "Comparator.h" #include "Concept.h" #include "TypeTraits.h" -#include "utilities/Utility.h" + +#include "utility/Utility.h" namespace wlp { diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index bb779e07..343fbaa4 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -13,9 +13,10 @@ #ifndef EMBEDDEDCPLUSPLUS_ARRAYLIST_H #define EMBEDDEDCPLUSPLUS_ARRAYLIST_H -#include "../utilities/Utility.h" #include "../Types.h" + #include "../memory/Memory.h" +#include "../utility/Utility.h" namespace wlp { @@ -67,17 +68,6 @@ namespace wlp { check_bounds(); } - /** - * Move constructor. - * - * @param it iterator to move - */ - ArrayListIterator(iterator &&it) - : m_i(move(it.m_i)), - m_list(move(it.m_list)) { - check_bounds(); - } - /** * Constructor from an array index and * a backing array list. @@ -91,19 +81,6 @@ namespace wlp { check_bounds(); } - /** - * Constructor from an array index rvalue - * and a backing array list. - * - * @param i array index rvalue - * @param list backing array list - */ - explicit ArrayListIterator(size_type &&i, array_list *list) - : m_i(move(i)), - m_list(list) { - check_bounds(); - } - private: /** * Ensure the iterator is either exactly @@ -169,23 +146,7 @@ namespace wlp { * @return reference to this iterator */ iterator &operator+=(const size_type &d) { - m_i = (size_type) (m_i + d); - if (m_i > m_list->m_size) { - m_i = m_list->m_size; - } - return *this; - } - - /** - * Addition assignment operator moves the - * iterator by the specified number of - * positions. - * - * @param d the number of positions to increment - * @return reference to this iterator - */ - iterator &operator+=(size_type &&d) { - m_i = (size_type) (m_i + d); + m_i = static_cast(m_i + d); if (m_i > m_list->m_size) { m_i = m_list->m_size; } @@ -229,35 +190,11 @@ namespace wlp { if (d >= m_i) { m_i = 0; } else { - m_i = (size_type) (m_i - d); - } - return *this; - } - - /** - * Subtraction assignment operator moves the iterator - * backwards a certain number of elements. - * - * @param d the number of elements to move back - * @return reference to this iterator - */ - iterator &operator-=(size_type &&d) { - if (d >= m_i) { - m_i = 0; - } else { - m_i = (size_type) (m_i - d); + m_i = static_cast(m_i - d); } return *this; } - /** - * @param it iterator to compare - * @return true if they point to the same element - */ - bool operator==(iterator &it) const { - return m_i == it.m_i; - } - /** * @param it iterator to compare * @return true if they point to the same element @@ -266,14 +203,6 @@ namespace wlp { return m_i == it.m_i; } - /** - * @param it iterator to compare - * @return true if they point to different elements - */ - bool operator!=(iterator &it) const { - return m_i != it.m_i; - } - /** * @param it iterator to compare * @return true if they point to different elements @@ -282,18 +211,6 @@ namespace wlp { return m_i != it.m_i; } - /** - * Move assignment operator. - * - * @param it iterator to move - * @return reference to this iterator - */ - iterator &operator=(iterator &&it) { - m_i = move(it.m_i); - m_list = move(it.m_list); - return *this; - } - /** * Copy assignment operator. * @@ -314,18 +231,7 @@ namespace wlp { * @return */ iterator operator+(const size_type &d) const { - return iterator(move((size_type) (m_i + d)), m_list); - } - - /** - * Addition operator returns a new iterator - * incremented by the specified number of positions. - * - * @param d number of positions to increment - * @return a new iterator - */ - iterator operator+(size_type &&d) const { - return iterator(move((size_type) (m_i + d)), m_list); + return iterator(static_cast(m_i + d), m_list); } /** @@ -336,18 +242,7 @@ namespace wlp { * @return a new iterator */ iterator operator-(const size_type &d) const { - return iterator(move((size_type) (m_i - d)), m_list); - } - - /** - * Subtraction operator returns a new iterator - * decremented by the specified number of positions. - * - * @param d number of positions to decrement - * @return a new iterator - */ - iterator operator-(size_type &&d) const { - return iterator(move((size_type) (m_i - d)), m_list); + return iterator(static_cast(m_i - d), m_list); } /** @@ -359,24 +254,11 @@ namespace wlp { */ size_type operator-(const iterator &it) const { if (m_i < it.m_i) { - return (size_type) (it.m_i - m_i); + return static_cast(it.m_i - m_i); } - return (size_type) (m_i - it.m_i); + return static_cast(m_i - it.m_i); } - /** - * Subtraction of two iterators returns the - * integer distance between them. - * - * @param it iterator to subtract - * @return the integer distance - */ - size_type operator-(iterator &&it) const { - if (m_i < it.m_i) { - return (size_type) (it.m_i - m_i); - } - return (size_type) (m_i - it.m_i); - } }; /** @@ -411,24 +293,12 @@ namespace wlp { check_bounds(); } - ArrayListConstIterator(const_iterator &&it) - : m_i(move(it.m_i)), - m_list(move(it.m_list)) { - check_bounds(); - } - explicit ArrayListConstIterator(const size_type &i, const array_list *list) : m_i(i), m_list(list) { check_bounds(); } - explicit ArrayListConstIterator(size_type &&i, const array_list *list) - : m_i(move(i)), - m_list(list) { - check_bounds(); - } - private: void check_bounds() { if (m_i > m_list->m_size) { @@ -461,15 +331,7 @@ namespace wlp { } const_iterator &operator+=(const size_type &d) { - m_i = (size_type) (m_i + d); - if (m_i > m_list->m_size) { - m_i = m_list->m_size; - } - return *this; - } - - const_iterator &operator+=(size_type &&d) { - m_i = (size_type) (m_i + d); + m_i = static_cast(m_i + d); if (m_i > m_list->m_size) { m_i = m_list->m_size; } @@ -494,42 +356,19 @@ namespace wlp { if (d >= m_i) { m_i = 0; } else { - m_i = (size_type) (m_i - d); + m_i = static_cast(m_i - d); } return *this; } - const_iterator &operator-=(size_type &&d) { - if (d >= m_i) { - m_i = 0; - } else { - m_i = (size_type) (m_i - d); - } - return *this; - } - - bool operator==(const_iterator &it) const { - return m_i == it.m_i; - } - bool operator==(const const_iterator &it) const { return m_i == it.m_i; } - bool operator!=(const_iterator &it) const { - return m_i != it.m_i; - } - bool operator!=(const const_iterator &it) const { return m_i != it.m_i; } - const_iterator &operator=(const_iterator &&it) { - m_i = move(it.m_i); - m_list = move(it.m_list); - return *this; - } - const_iterator &operator=(const const_iterator &it) { m_i = it.m_i; m_list = it.m_list; @@ -537,34 +376,20 @@ namespace wlp { } const_iterator operator+(const size_type &d) const { - return const_iterator(move((size_type) (m_i + d)), m_list); - } - - const_iterator operator+(size_type &&d) const { - return const_iterator(move((size_type) (m_i + d)), m_list); + return const_iterator(static_cast(m_i + d), m_list); } const_iterator operator-(const size_type &d) const { - return const_iterator(move((size_type) (m_i - d)), m_list); - } - - const_iterator operator-(size_type &&d) const { - return const_iterator(move((size_type) (m_i - d)), m_list); + return const_iterator(static_cast(m_i - d), m_list); } size_type operator-(const const_iterator &it) const { if (m_i < it.m_i) { - return (size_type) (it.m_i - m_i); + return static_cast(it.m_i - m_i); } - return (size_type) (m_i - it.m_i); + return static_cast(m_i - it.m_i); } - size_type operator-(const_iterator &&it) const { - if (m_i < it.m_i) { - return (size_type) (it.m_i - m_i); - } - return (size_type) (m_i - move(it.m_i)); - } }; /** @@ -908,49 +733,16 @@ namespace wlp { * @param t element to insert * @return iterator to the inserted element */ - iterator insert(size_type i, const val_type &t) { + template + iterator insert(size_type i, V &&val) { ensure_capacity(); normalize(i); shift_right(i); - m_data[i] = t; + m_data[i] = forward(val); ++m_size; return iterator(i, this); } - /** - * Insert an element in the array at the specified - * position such that the previous element at the position - * and all elements after are shifted to the right. - * - * @param i position to insert - * @param t element to insert - * @return iterator to the inserted element - */ - iterator insert(size_type i, val_type &&t) { - ensure_capacity(); - normalize(i); - shift_right(i); - m_data[i] = forward(t); - ++m_size; - return iterator(i, this); - } - - /** - * Insert an element at the position pointed to by - * the iterator. - * - * @param it iterator to the inserted position - * @param t element to insert - * @return iterator to the inserted element - */ - iterator &insert(iterator &it, const val_type &t) { - ensure_capacity(); - shift_right(it.m_i); - m_data[it.m_i] = t; - ++m_size; - return it; - } - /** * Insert an element at the position pointed to by * the iterator. @@ -959,10 +751,11 @@ namespace wlp { * @param t element to insert * @return iterator to the inserted element */ - iterator &insert(iterator &it, val_type &&t) { + template + iterator insert(const iterator &it, V &&val) { ensure_capacity(); shift_right(it.m_i); - m_data[it.m_i] = t; + m_data[it.m_i] = forward(val); ++m_size; return it; } @@ -989,7 +782,7 @@ namespace wlp { * @param it position whose element to erase. * @return iterator to the next element in the list */ - iterator erase(iterator &it) { + iterator erase(const iterator &it) { if (m_size == 0 || it.m_i >= m_size) { return end(); } @@ -1003,20 +796,10 @@ namespace wlp { * * @param t element to insert */ - void push_back(const val_type &t) { - ensure_capacity(); - m_data[m_size] = t; - ++m_size; - } - - /** - * Insert an element to the back of the list. - * - * @param t element to insert - */ - void push_back(val_type &&t) { + template + void push_back(V &&val) { ensure_capacity(); - m_data[m_size] = move(t); + m_data[m_size] = forward(val); ++m_size; } @@ -1077,7 +860,7 @@ namespace wlp { if (m_size < m_capacity) { return; } - size_type new_capacity = (size_type) (2 * m_capacity); + size_type new_capacity = static_cast(2 * m_capacity); val_type *new_data = malloc(new_capacity); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index 8082c642..1919db63 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -13,12 +13,12 @@ #ifndef EMBEDDEDTESTS_CHAINMAP_H #define EMBEDDEDTESTS_CHAINMAP_H -#include "../utilities/Utility.h" #include "Equal.h" #include "Hash.h" #include "Pair.h" #include "../memory/Memory.h" +#include "../utility/Utility.h" namespace wlp { @@ -77,16 +77,6 @@ namespace wlp { return m_key == node.m_key && m_val == node.m_val; } - /** - * Equality operator. Two nodes are equal if their keys - * and values are equal. - * keys and values are equal. - * @param node the node compare - * @return true if they are equal - */ - bool operator==(node_type &node) const { - return m_key == node.m_key && m_val == node.m_val; - } }; /** @@ -146,15 +136,6 @@ namespace wlp { m_hash_map(it.m_hash_map) { } - /** - * Copy constructor. - * @param it iterator to copy - */ - ChainHashMapIterator(iterator &&it) - : m_current(move(it.m_current)), - m_hash_map(move(it.m_hash_map)) { - } - /** * @return reference to the value of the node * pointed to by the iterator @@ -194,16 +175,6 @@ namespace wlp { return m_current == it.m_current; } - /** - * Compare two iterators, equal of they point to the - * same node. - * @param it iterator to compare - * @return true if both point to the same node - */ - bool operator==(iterator &it) const { - return m_current == it.m_current; - } - /** * Compare two iterators, unequal if they point to * different nodes. @@ -214,15 +185,6 @@ namespace wlp { return m_current != it.m_current; } - /** - * Inequality operator. - * @param it iterator to compare - * @return true if they point to different nodes - */ - bool operator!=(iterator &it) const { - return m_current != it.m_current; - } - /** * Assignment operator copies pointer to node * and pointer to hash map. @@ -235,18 +197,6 @@ namespace wlp { return *this; } - /** - * Assignment operator copies pointer to node - * and pointer to hash map. - * @param it iterator to copy - * @return a reference to this iterator - */ - iterator &operator=(iterator &&it) { - m_current = move(it.m_current); - m_hash_map = move(it.m_hash_map); - return *this; - } - }; /** @@ -291,11 +241,6 @@ namespace wlp { m_hash_map(it.m_hash_map) { } - ChainHashMapConstIterator(const_iterator &&it) - : m_current(move(it.m_current)), - m_hash_map(move(it.m_hash_map)) { - } - const val_type &operator*() const { return m_current->m_val; } @@ -312,29 +257,16 @@ namespace wlp { return m_current == it.m_current; } - bool operator==(const_iterator &it) const { - return m_current == it.m_current; - } - bool operator!=(const const_iterator &it) const { return m_current != it.m_current; } - bool operator!=(const_iterator &it) const { - return m_current != it.m_current; - } - const_iterator &operator=(const const_iterator &it) { m_current = it.m_current; m_hash_map = it.m_hash_map; return *this; } - const_iterator &operator=(const_iterator &&it) { - m_current = move(it.m_current); - m_hash_map = move(it.m_hash_map); - return *this; - } }; /** @@ -470,7 +402,7 @@ namespace wlp { * @param max_elements the maximum number of buckets * @return an index i such that 0 <= i < max_elements */ - size_type bucket_index(key_type key, size_type max_elements) const { + size_type bucket_index(const key_type &key, size_type max_elements) const { return m_hash(key) % max_elements; } @@ -480,7 +412,7 @@ namespace wlp { * @param key the key to hash * @return an index i such that 0 <= i < m_max_elements */ - size_type hash(key_type key) const { + size_type hash(const key_type &key) const { return m_hash(key) % m_capacity; } @@ -594,7 +526,8 @@ namespace wlp { * inserted element or the element that prevented insertion * and a bool indicating whether insertion occurred */ - Pair insert(key_type key, val_type val); + template + Pair insert(K &&key, V &&val); /** * Attempt to insert an element into the map. @@ -607,7 +540,8 @@ namespace wlp { * inserted element or the assigned element, and a bool * indicating whether insertion occurred */ - Pair insert_or_assign(key_type key, val_type val); + template + Pair insert_or_assign(K &&key, V &&val); /** * Erase an element pointed to by the provided pointer. @@ -616,14 +550,7 @@ namespace wlp { * @return the iterator to the next element in the map * or pass-the-end if there are no more elements afterwards */ - iterator &erase(iterator &pos); - - /** - * @see ChainHashMap::erase() - * @param pos const iterator to the element to erase - * @return const iterator to the next element or pass-the-end - */ - const_iterator &erase(const_iterator &pos); + iterator erase(const iterator &pos); /** * Erase the element with the corresponding key. @@ -631,7 +558,7 @@ namespace wlp { * @param key the key of the element to erase * @return true if erasure occured */ - bool erase(key_type &key); + bool erase(const key_type &key); /** * Returns the value corresponding to a provided key. @@ -682,7 +609,8 @@ namespace wlp { * @param key the key whose value to access * @return a reference to the mapped value */ - val_type &operator[](const key_type &key); + template + val_type &operator[](K &&key); /** * Disable copy assignment. @@ -755,9 +683,10 @@ namespace wlp { m_num_elements = 0; } - template - Pair::iterator, bool> - ChainHashMap::insert(key_type key, val_type val) { + template + template + Pair::iterator, bool> + ChainHashMap::insert(K &&key, V &&val) { ensure_capacity(); size_type i = hash(key); node_type *first = m_buckets[i]; @@ -767,17 +696,18 @@ namespace wlp { } } node_type *tmp = malloc(); - tmp->m_key = key; - tmp->m_val = val; + tmp->m_key = forward(key); + tmp->m_val = forward(val); tmp->next = first; m_buckets[i] = tmp; ++m_num_elements; return Pair(iterator(tmp, this), true); }; - template - Pair::iterator, bool> - ChainHashMap::insert_or_assign(key_type key, val_type val) { + template + template + Pair::iterator, bool> + ChainHashMap::insert_or_assign(K &&key, V &&val) { ensure_capacity(); size_type i = hash(key); node_type *first = m_buckets[i]; @@ -788,8 +718,8 @@ namespace wlp { } } node_type *tmp = malloc(); - tmp->m_key = key; - tmp->m_val = val; + tmp->m_key = forward(key); + tmp->m_val = forward(val); tmp->next = first; m_buckets[i] = tmp; ++m_num_elements; @@ -797,8 +727,8 @@ namespace wlp { }; template - typename ChainHashMap::iterator & - ChainHashMap::erase(iterator &pos) { + typename ChainHashMap::iterator + ChainHashMap::erase(const iterator &pos) { node_type *p_node = pos.m_current; if (p_node) { node_type *n_node = p_node->next; @@ -816,13 +746,11 @@ namespace wlp { free(c_node); --m_num_elements; m_buckets[i] = nullptr; - while (++i < m_capacity && !m_buckets[i]); + while (++i < m_capacity && !m_buckets[i]) {} if (i == m_capacity) { - pos.m_current = nullptr; - return pos; + return end(); } else { - pos.m_current = m_buckets[i]; - return pos; + return iterator(m_buckets[i], this); } } else { while (c_node->next != p_node) { @@ -831,23 +759,20 @@ namespace wlp { free(c_node->next); --m_num_elements; c_node->next = nullptr; - while (++i < m_capacity && !m_buckets[i]); + while (++i < m_capacity && !m_buckets[i]) {} if (i == m_capacity) { - pos.m_current = nullptr; - return pos; + return end(); } else { - pos.m_current = m_buckets[i]; - return pos; + return iterator(m_buckets[i], this); } } } } - pos.m_current = nullptr; - return pos; + return end(); } template - bool ChainHashMap::erase(key_type &key) { + bool ChainHashMap::erase(const key_type &key) { size_type i = hash(key); node_type *first = m_buckets[i]; if (first) { @@ -934,8 +859,9 @@ namespace wlp { } template + template typename ChainHashMap::val_type & - ChainHashMap::operator[](const key_type &key) { + ChainHashMap::operator[](K &&key) { ensure_capacity(); size_type i = hash(key); node_type *first = m_buckets[i]; @@ -943,7 +869,7 @@ namespace wlp { if (!cur) { node_type *ele = malloc(); ++m_num_elements; - ele->m_key = key; + ele->m_key = forward(key); ele->m_val = val_type(); ele->next = nullptr; m_buckets[i] = ele; @@ -957,7 +883,7 @@ namespace wlp { } cur = malloc(); ++m_num_elements; - cur->m_key = key; + cur->m_key = forward(key); cur->m_val = val_type(); cur->next = nullptr; cur->next = first; @@ -1040,7 +966,7 @@ namespace wlp { m_current = m_current->next; if (!m_current) { size_type i = m_hash_map->hash(old->m_key); - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { @@ -1065,7 +991,7 @@ namespace wlp { m_current = m_current->next; if (!m_current) { size_type i = m_hash_map->hash(old->m_key); - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]); + while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} if (i == m_hash_map->m_capacity) { m_current = nullptr; } else { diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index 0edd43b7..9daacc6d 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -156,8 +156,9 @@ namespace wlp { * @param key the element to insert * @return a pair of an iterator and boolean */ - Pair insert(key_type key) { - return m_hash_map.insert(key, key); + template + Pair insert(K &&key) { + return m_hash_map.insert(forward(key), forward(key)); }; /** @@ -198,16 +199,7 @@ namespace wlp { * @return an iterator to the next element, or * pass the end if the iteration has reached the end */ - iterator &erase(iterator &pos) { - return m_hash_map.erase(pos); - } - - /** - * Erase an element pointed to by a const iterator. - * @param pos the iterator to the element to erase - * @return an iterator to the next element - */ - const_iterator &erase(const_iterator &pos) { + iterator erase(const iterator &pos) { return m_hash_map.erase(pos); } @@ -217,7 +209,7 @@ namespace wlp { * @return true if the value was removed, * false if the value was never in the set */ - bool erase(key_type &key) { + bool erase(const key_type &key) { return m_hash_map.erase(key); } diff --git a/lib/wlib/utilities/Comparator.h b/lib/wlib/stl/Comparator.h similarity index 59% rename from lib/wlib/utilities/Comparator.h rename to lib/wlib/stl/Comparator.h index f7ae523f..c8ca6b45 100644 --- a/lib/wlib/utilities/Comparator.h +++ b/lib/wlib/stl/Comparator.h @@ -10,32 +10,16 @@ #ifndef EMBEDDEDCPLUSPLUS_COMPARATOR_H #define EMBEDDEDCPLUSPLUS_COMPARATOR_H -#include "stl/Equal.h" +#include // strcmp #include "Types.h" +#include "stl/Equal.h" +#include "strings/String.h" #include "strings/StaticString.h" namespace wlp { - /** - * String comparison function. Returns 0 for equal strings, - * a positive signed number if @code s1 @endcode is greater - * than @code s2 @endcode and a negative number otherwise. - * - * @param s1 first string to compare - * @param s2 second string to compare - * @return 0 for equal, > 0 for greater, < 0 for less than - */ - inline int8_t str_cmp(const char *s1, const char *s2) { - for (; *s1 == *s2; ++s1, ++s2) { - if (*s1 == 0) { - return 0; - } - } - return (int8_t) (*s1 - *s2); - } - /** * Base comparator type uses the basic comparison * operators. @@ -108,27 +92,27 @@ namespace wlp { template<> struct Comparator { bool __lt__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) < 0; + return strcmp(s1, s2) < 0; } bool __le__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) <= 0; + return strcmp(s1, s2) <= 0; } bool __eq__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) == 0; + return strcmp(s1, s2) == 0; } bool __ne__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) != 0; + return strcmp(s1, s2) != 0; } bool __gt__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) > 0; + return strcmp(s1, s2) > 0; } bool __ge__(const char *s1, const char *s2) const { - return str_cmp(s1, s2) >= 0; + return strcmp(s1, s2) >= 0; } }; @@ -138,31 +122,31 @@ namespace wlp { * @tparam tSize static string size */ template - struct Comparator> { - bool __lt__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) < 0; - } - - bool __le__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) <= 0; - } - - bool __eq__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) == 0; - } - - bool __ne__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) != 0; - } - - bool __gt__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) > 0; - } - - bool __ge__(const StaticString &s1, const StaticString &s2) const { - return str_cmp(s1.c_str(), s2.c_str()) >= 0; - } -}; + struct Comparator> { + bool __lt__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) < 0; + } + + bool __le__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) <= 0; + } + + bool __eq__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) == 0; + } + + bool __ne__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) != 0; + } + + bool __gt__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) > 0; + } + + bool __ge__(const StaticString &s1, const StaticString &s2) const { + return strcmp(s1.c_str(), s2.c_str()) >= 0; + } + }; } diff --git a/lib/wlib/stl/Concept.h b/lib/wlib/stl/Concept.h index 62664dec..577971ed 100644 --- a/lib/wlib/stl/Concept.h +++ b/lib/wlib/stl/Concept.h @@ -15,10 +15,10 @@ #define EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H #include "Pair.h" -#include "utilities/Tmp.h" #include "TypeTraits.h" #include "../Wlib.h" +#include "../utility/Tmp.h" /** * Definitions for a variadic macro that generates @@ -141,12 +141,9 @@ namespace wlp { >::type, __HAS_FCN(T, operator++, iterator &), __HAS_FCN(T, operator++, int, iterator), - __HAS_FCN(const T, operator==, iterator &, bool), __HAS_FCN(const T, operator==, const iterator &, bool), - __HAS_FCN(const T, operator!=, iterator &, bool), __HAS_FCN(const T, operator!=, const iterator &, bool), - __HAS_FCN(T, operator=, const iterator &, iterator &), - __HAS_FCN(T, operator=, iterator &&, iterator &) + __HAS_FCN(T, operator=, const iterator &, iterator &) >::type; @@ -209,22 +206,14 @@ namespace wlp { __HAS_FCN(T, operator++, int, iterator), __HAS_FCN(T, operator--, iterator &), __HAS_FCN(T, operator--, int, iterator), - __HAS_FCN(T, operator==, iterator &, bool), __HAS_FCN(T, operator==, const iterator &, bool), - __HAS_FCN(T, operator!=, iterator &, bool), - __HAS_FCN(T, operator!=, iterator &, bool), - __HAS_FCN(T, operator=, iterator &&, iterator &), + __HAS_FCN(T, operator!=, const iterator &, bool), __HAS_FCN(T, operator=, const iterator &, iterator &), __HAS_FCN(const T, operator+, const size_type &, iterator), - __HAS_FCN(const T, operator+, size_type &&, iterator), __HAS_FCN(const T, operator-, const size_type &, iterator), - __HAS_FCN(const T, operator-, size_type &&, iterator), __HAS_FCN(const T, operator-, const iterator &, size_type), - __HAS_FCN(const T, operator-, iterator &&, size_type), __HAS_FCN(T, operator-=, const size_type &, iterator &), - __HAS_FCN(T, operator-=, size_type &&, iterator &), - __HAS_FCN(T, operator+=, const size_type &, iterator &), - __HAS_FCN(T, operator+=, size_type &&, iterator &) + __HAS_FCN(T, operator+=, const size_type &, iterator &) >::type; template @@ -294,11 +283,10 @@ namespace wlp { __HAS_FCN(const T, begin, const_iterator), __HAS_FCN(const T, end, const_iterator), __HAS_FCN(T, clear, void), - __HAS_FCN(T, insert, key_type, val_type, insert_ret_type), - __HAS_FCN(T, insert_or_assign, key_type, val_type, insert_ret_type), - __HAS_FCN(T, erase, iterator &, iterator &), - __HAS_FCN(T, erase, const_iterator &, const_iterator &), - __HAS_FCN(T, erase, key_type &, bool), + __HAS_FCN(T, insert, const key_type &, const val_type &, insert_ret_type), + __HAS_FCN(T, insert_or_assign, const key_type &, const val_type &, insert_ret_type), + __HAS_FCN(T, erase, const key_type &, bool), + __HAS_FCN(T, erase, const iterator &, iterator), __HAS_FCN(T, at, const key_type &, iterator), __HAS_FCN(const T, at, const key_type &, const_iterator), __HAS_FCN(const T, contains, const key_type &, bool), diff --git a/lib/wlib/stl/Equal.h b/lib/wlib/stl/Equal.h index f2066cbb..c44432de 100644 --- a/lib/wlib/stl/Equal.h +++ b/lib/wlib/stl/Equal.h @@ -10,6 +10,8 @@ #ifndef CORE_STL_EQUAL_H #define CORE_STL_EQUAL_H +#include // strcmp + #include "../Types.h" #include "../strings/StaticString.h" @@ -28,43 +30,6 @@ namespace wlp { } }; - /** - * Checks whether two static strings are equal. - * - * @tparam tSize static string size - * @param str1 first string - * @param str2 second string - * @return true if the strings are equal - */ - template - inline bool static_string_equals(const StaticString &str1, const StaticString &str2) { - if (str1.length() != str2.length()) { - return false; - } - for (size_type i = 0; i < str1.length(); ++i) { - if (str1[i] != str2[i]) { - return false; - } - } - return true; - } - - /** - * Checks whether two C strings are equal. - * - * @param str1 first string - * @param str2 second string - * @return true if the strings are equal - */ - inline bool string_equals(const char *&str1, const char *&str2) { - for (; *str1 && *str2; ++str1, ++str2) { - if (*str1 != *str2) { - return false; - } - } - return *str1 == *str2; - } - /** * Template specialization for static string. * @@ -73,7 +38,7 @@ namespace wlp { template struct Equal> { bool operator()(const StaticString &key1, const StaticString &key2) const { - return static_string_equals(key1, key2); + return strcmp(key1.c_str(), key2.c_str()) == 0; } }; @@ -85,7 +50,7 @@ namespace wlp { template struct Equal> { bool operator()(const StaticString &key1, const StaticString &key2) const { - return static_string_equals(key1, key2); + return strcmp(key1.c_str(), key2.c_str()) == 0; } }; @@ -95,7 +60,7 @@ namespace wlp { template<> struct Equal { bool operator()(const char *key1, const char *key2) const { - return string_equals(key1, key2); + return strcmp(key1, key2) == 0; } }; @@ -105,7 +70,7 @@ namespace wlp { template<> struct Equal { bool operator()(const char *key1, const char *key2) const { - return string_equals(key1, key2); + return strcmp(key1, key2) == 0; } }; diff --git a/lib/wlib/stl/Hash.h b/lib/wlib/stl/Hash.h index d5e27fca..b90b955a 100644 --- a/lib/wlib/stl/Hash.h +++ b/lib/wlib/stl/Hash.h @@ -15,9 +15,8 @@ #define CORE_STL_HASH_H #include "../Types.h" -#include "../utilities/Math.h" #include "../WlibConfig.h" - +#include "../utility/Math.h" #include "../strings/StaticString.h" namespace wlp { @@ -50,7 +49,7 @@ namespace wlp { * @return a hash code of the string */ template - inline IntType hash_static_string(StaticString &static_string) { + inline IntType hash_static_string(const StaticString &static_string) { IntType h = 0; for (size_type pos = 0; pos < static_string.length(); ++pos) { h = (IntType) (MUL_127(h) + static_string[pos]); @@ -83,7 +82,7 @@ namespace wlp { */ template struct Hash, IntType> { - IntType operator()(StaticString &s) const { + IntType operator()(const StaticString &s) const { return hash_static_string(s); } }; diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index cc1fed29..0bfcc4be 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -15,12 +15,12 @@ #ifndef CORE_STL_MAP_H #define CORE_STL_MAP_H -#include "../utilities/Utility.h" #include "Equal.h" #include "Hash.h" #include "Pair.h" #include "../memory/Memory.h" +#include "../utility/Utility.h" namespace wlp { @@ -73,15 +73,6 @@ namespace wlp { bool operator==(const node_type &node) const { return m_key == node.m_key && m_val == node.m_val; } - - /** - * Equality operator for non const. - * @param node node to compare - * @return true if they are equal - */ - bool operator==(node_type &node) const { - return m_key == node.m_key && m_val == node.m_val; - } }; /** @@ -142,15 +133,6 @@ namespace wlp { m_hash_map(it.m_hash_map) { } - /** - * Copy constructor. - * @param it iterator to copy - */ - OpenHashMapIterator(iterator &&it) - : m_current(move(it.m_current)), - m_hash_map(move(it.m_hash_map)) { - } - /** * @return reference to the value of the node * pointed to by the iterator @@ -191,15 +173,6 @@ namespace wlp { return m_current == it.m_current; } - /** - * Non const equality operator. - * @param it iterator to compare - * @return true if both point to the same node - */ - bool operator==(iterator &it) const { - return m_current == it.m_current; - } - /** * Compare two iterators, unequal if they point to * different nodes. @@ -210,15 +183,6 @@ namespace wlp { return m_current != it.m_current; } - /** - * Non const equality operator. - * @param it iterator to compare - * @return true if they point to different nodes - */ - bool operator!=(iterator &it) const { - return m_current != it.m_current; - } - /** * Assignment operator copies pointers to node * and hash map. @@ -231,16 +195,6 @@ namespace wlp { return *this; } - /** - * Assignment operator for non const. - * @param it iterator to copy - * @return a reference to this iterator - */ - iterator &operator=(iterator &&it) { - m_current = move(it.m_current); - m_hash_map = move(it.m_hash_map); - return *this; - } }; /** @@ -285,11 +239,6 @@ namespace wlp { m_hash_map(it.m_hash_map) { } - OpenHashMapConstIterator(const_iterator &&it) - : m_current(move(it.m_current)), - m_hash_map(move(it.m_hash_map)) { - } - const val_type &operator*() const { return m_current->m_val; } @@ -306,29 +255,16 @@ namespace wlp { return m_current == it.m_current; } - bool operator==(const_iterator &it) const { - return m_current == it.m_current; - } - bool operator!=(const const_iterator &it) const { return m_current != it.m_current; } - bool operator!=(const_iterator &it) const { - return m_current != it.m_current; - } - const_iterator &operator=(const const_iterator &it) { m_current = it.m_current; m_hash_map = it.m_hash_map; return *this; } - const_iterator &operator=(const_iterator &&it) { - m_current = move(it.m_current); - m_hash_map = move(it.m_hash_map); - return *this; - } }; /** @@ -464,7 +400,7 @@ namespace wlp { * @param max_elements the maximum number of buckets * @return an index i such that 0 <= i < max_elements */ - size_type bucket_index(key_type key, size_type max_elements) const { + size_type bucket_index(const key_type &key, size_type max_elements) const { return m_hash(key) % max_elements; } @@ -473,7 +409,7 @@ namespace wlp { * @param key the key to hash * @return an index i such that 0 <= i < m_max_elements */ - size_type hash(key_type key) const { + size_type hash(const key_type &key) const { return m_hash(key) % m_capacity; } @@ -579,45 +515,40 @@ namespace wlp { * Attempt to insert an element into the map. * Insertion is prevented if there already exists * an element with the provided key + * * @param key inserted element key * @param val inserted element value * @return a pair consisting of an iterator pointing to the * inserted element or the element that prevented insertion * and a bool indicating whether insertion occurred */ - Pair insert(key_type key, val_type val); + template + Pair insert(K &&key, V &&val); /** * Attempt to insert an element into the map. * If an element with the same key already exists, * override the value mapped to by the provided key. + * * @param key inserted element key * @param val inserted element value * @return a pair consisting of an iterator pointing to the * inserted element or the assigned element, and a bool * indicating whether insertion occurred */ - Pair insert_or_assign(key_type key, val_type val); + template + Pair insert_or_assign(K &&key, V &&val); /** * Erase the element from the map pointed to by the provided * iterator. Be aware that erasure operations on an openly * addressed hash map will trigger a rehash and invalidate * all iterators other than the return value. + * * @param pos iterator pointing to the element to erase * @return iterator to the next element in the map or end */ - iterator &erase(iterator &pos); - - /** - * Erase the element from the map pointed to by the provided - * const iterator. Be aware that erasure operations on an openly - * addressed hash map will trigger a rehash and invalidate - * all iterators other than the return value. - * @param pos const iterator pointing to the element to erase - * @return const iterator to the next element in the map or end - */ - const_iterator &erase(const_iterator &pos); + iterator erase(const iterator &pos); /** * Erase the element from the map with the provided key, if such @@ -631,10 +562,11 @@ namespace wlp { * @param key the key whose corresponding element to erase * @return true if an element was erased */ - bool erase(key_type &key); + bool erase(const key_type &key); /** * Returns the value corresponding to a provided key. + * * @param key the key for which to find the value * @return the value mapped to by the key * @throws KeyException if the key does not map to a value @@ -659,6 +591,7 @@ namespace wlp { * Return an iterator to the map element corresponding * to the provided key, or pass-the-end if the key does * not map to any value in the map. + * * @param key the key to map * @return an iterator to the element mapped by the key */ @@ -676,13 +609,16 @@ namespace wlp { * If the key does not map to any value in the map, * then a new value is created and inserted using the default * constructor. + * * @param key the key whose value to access * @return a reference to the mapped value */ - val_type &operator[](const key_type &key); + template + val_type &operator[](K &&key); /** * Copy assignment operators are disabled. + * * @return hash map reference */ map_type &operator=(const map_type &) = delete; @@ -691,6 +627,7 @@ namespace wlp { * Move assignment operator. Assigned hash map * will have its resources transferred into this * hash map. Existing resources will be released. + * * @param map map to move * @return reference to this map */ @@ -745,8 +682,9 @@ namespace wlp { } template + template Pair::iterator, bool> - OpenHashMap::insert(key_type key, val_type val) { + OpenHashMap::insert(K &&key, V &&val) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { @@ -759,16 +697,17 @@ namespace wlp { } else { ++m_num_elements; node_type *node = malloc(); - node->m_key = key; - node->m_val = val; + node->m_key = forward(key); + node->m_val = forward(val); m_buckets[i] = node; return Pair(iterator(node, this), true); } }; template + template Pair::iterator, bool> - OpenHashMap::insert_or_assign(key_type key, val_type val) { + OpenHashMap::insert_or_assign(K &&key, V &&val) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { @@ -777,25 +716,24 @@ namespace wlp { } } if (m_buckets[i]) { - m_buckets[i]->m_val = val; + m_buckets[i]->m_val = forward(val); return Pair(iterator(m_buckets[i], this), false); } else { ++m_num_elements; node_type *node = malloc(); - node->m_key = key; - node->m_val = val; + node->m_key = forward(key); + node->m_val = forward(val); m_buckets[i] = node; return Pair(iterator(node, this), true); } }; template - typename OpenHashMap::iterator & - OpenHashMap::erase(iterator &pos) { + typename OpenHashMap::iterator + OpenHashMap::erase(const iterator &pos) { const node_type *cur_node = pos.m_current; if (!cur_node || pos.m_hash_map != this) { - pos.m_current = nullptr; - return pos; + return end(); } size_type i = hash(cur_node->m_key); while (m_buckets[i] && !m_equal(cur_node->m_key, m_buckets[i]->m_key)) { @@ -804,8 +742,7 @@ namespace wlp { } } if (!m_buckets[i]) { - pos.m_current = nullptr; - return pos; + return end(); } --m_num_elements; free(m_buckets[i]); @@ -831,12 +768,11 @@ namespace wlp { } free(m_buckets); m_buckets = new_buckets; - pos.m_current = next_node; - return pos; + return iterator(next_node, this); } template - bool OpenHashMap::erase(key_type &key) { + bool OpenHashMap::erase(const key_type &key) { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { if (++i >= m_capacity) { @@ -918,8 +854,9 @@ namespace wlp { } template + template typename OpenHashMap::val_type & - OpenHashMap::operator[](const key_type &key) { + OpenHashMap::operator[](K &&key) { ensure_capacity(); size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { @@ -932,7 +869,7 @@ namespace wlp { } else { ++m_num_elements; node_type *node = malloc(); - node->m_key = key; + node->m_key = forward(key); node->m_val = val_type(); m_buckets[i] = node; return node->m_val; diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index d60df1a2..663138fb 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -162,8 +162,9 @@ namespace wlp { * @param key the element to insert * @return a pair of an iterator and boolean */ - Pair insert(key_type key) { - return m_hash_map.insert(key, key); + template + Pair insert(K &&key) { + return m_hash_map.insert(forward(key), forward(key)); }; /** @@ -202,18 +203,7 @@ namespace wlp { * @param pos iterator whose element to erase * @return iterator to the next element in the set */ - iterator &erase(iterator &pos) { - return m_hash_map.erase(pos); - } - - /** - * Erase the element in the set pointed to by - * the iterator. - * - * @param pos iterator whose element to erase - * @return iterator to the next element in the set - */ - const_iterator &erase(const_iterator &pos) { + iterator erase(const iterator &pos) { return m_hash_map.erase(pos); } @@ -223,7 +213,7 @@ namespace wlp { * @param key the element to remove * @return true if removal occured */ - bool erase(key_type &key) { + bool erase(const key_type &key) { return m_hash_map.erase(key); } diff --git a/lib/wlib/stl/Pair.h b/lib/wlib/stl/Pair.h index 86986255..0e51b897 100644 --- a/lib/wlib/stl/Pair.h +++ b/lib/wlib/stl/Pair.h @@ -12,7 +12,7 @@ #ifndef EMBEDDEDTESTS_PAIR_H #define EMBEDDEDTESTS_PAIR_H -#include "utilities/Utility.h" +#include "../utility/Utility.h" namespace wlp { @@ -62,9 +62,10 @@ namespace wlp { * @param first first type value * @param second second type value */ - Pair(first_type first, second_type second) - : m_first(first), - m_second(second) { + template + Pair(FirstType &&first, SecondType &&second) + : m_first(forward(first)), + m_second(forward(second)) { } /** @@ -101,21 +102,10 @@ namespace wlp { * @param p pair to copy * @return a reference to this pair */ - pair &operator=(const pair &p) { - m_first = p.m_first; - m_second = p.m_second; - return *this; - } - - /** - * R-value assignment operator. - * - * @param p temporary pair to copy - * @return a reference to this pair - */ - pair &operator=(pair &&p) { - m_first = move(p.m_first); - m_second = move(p.m_second); + template + pair &operator=(P &&p) { + m_first = forward(p.m_first); + m_second = forward(p.m_second); return *this; } diff --git a/lib/wlib/stl/Tuple.h b/lib/wlib/stl/Tuple.h index e05beb34..dadd6571 100644 --- a/lib/wlib/stl/Tuple.h +++ b/lib/wlib/stl/Tuple.h @@ -19,7 +19,7 @@ #define EMBEDDEDCPLUSPLUS_TUPLE_H #include "Pair.h" -#include "../utilities/Tmp.h" +#include "../utility/Tmp.h" namespace wlp { @@ -641,7 +641,7 @@ namespace wlp { * @return a tuple sized to the number of elements */ template - auto make_tuple(Types &&... elements) { + Tuple...> make_tuple(Types &&... elements) { return Tuple...>(forward(elements)...); } @@ -656,7 +656,11 @@ namespace wlp { * @return concatenation of the two tuples */ template - auto tuple_cat_pair_sub( + Tuple< + typename TypeAtTuple>::type..., + typename TypeAtTuple>::type... + > + tuple_cat_pair_sub( TupleA &&tupleA, TupleB &&tupleB, IndexSequence, IndexSequence) { return make_tuple( @@ -706,13 +710,35 @@ namespace wlp { * @return the concatenated tuples */ template - auto tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB) { + typename cat_pair_type::type + tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB) { return tuple_cat_pair( forward(tupleA), forward(tupleB) ); }; + template + struct tuple_cat_type; + + template + struct tuple_cat_type { + typedef Tuple type; + }; + + template + struct tuple_cat_type { + typedef typename cat_pair_type::type type; + }; + + template + struct tuple_cat_type { + private: + typedef typename cat_pair_type::type pair_type; + public: + typedef typename tuple_cat_type::type type; + }; + /** * Concatenate an arbitrary number of tuples together. * This concatenation method expands linearly. @@ -725,7 +751,8 @@ namespace wlp { * @return concatenated tuples */ template - auto tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB, TailTuples &&... tail) { + typename tuple_cat_type::type + tuple_cat(HeadTupleA &&tupleA, HeadTupleB &&tupleB, TailTuples &&... tail) { auto tuple = tuple_cat_pair( forward(tupleA), forward(tupleB) diff --git a/lib/wlib/stl/TypeTraits.h b/lib/wlib/stl/TypeTraits.h index 1ac10ab7..024a5fdf 100644 --- a/lib/wlib/stl/TypeTraits.h +++ b/lib/wlib/stl/TypeTraits.h @@ -13,7 +13,7 @@ #ifndef EMBEDDEDCPLUSPLUS_TYPETRAITS_H #define EMBEDDEDCPLUSPLUS_TYPETRAITS_H -#include "utilities/Tmp.h" +#include "../utility/Tmp.h" /** * Code generation macro to create a metafunction diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index a0037d65..dacbcd69 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -11,11 +11,13 @@ #ifndef WLIB_STATICSTRING_H #define WLIB_STATICSTRING_H -#include -#include +#include // strlen, strncpy, strcmp + +#include "../Types.h" +#include "../utility/Math.h" namespace wlp { - template + template class StaticString { public: /** @@ -30,7 +32,8 @@ namespace wlp { * * @param str @code StaticString @endcode object */ - StaticString(const StaticString &str) : StaticString{str.c_str()} {} + StaticString(const StaticString &str) + : StaticString{str.c_str()} {} /** * Constructor creates string using character array @@ -38,9 +41,8 @@ namespace wlp { * @param str char string */ explicit StaticString(const char *str) { - m_len = (uint16_t) strlen(str); - if (m_len > capacity()) m_len = capacity(); - + m_len = static_cast(strlen(str)); + if (m_len > capacity()) { m_len = capacity(); } strncpy(m_buffer, str, m_len); m_buffer[m_len] = '\0'; } @@ -62,7 +64,7 @@ namespace wlp { * @return current object */ StaticString &operator=(const char *str) { - m_len = (uint16_t) ceil(fmin((uint16_t) strlen(str), capacity())); + m_len = MIN(static_cast(strlen(str)), tSize); strncpy(m_buffer, str, m_len); m_buffer[m_len] = '\0'; @@ -85,7 +87,7 @@ namespace wlp { * * @return string length */ - uint16_t length() const { + size_type length() const { return m_len; } @@ -94,7 +96,7 @@ namespace wlp { * * @return string capacity */ - uint16_t capacity() { + size_type capacity() { return tSize; } @@ -121,7 +123,7 @@ namespace wlp { * @param pos the position of the character * @return character at @p pos */ - char &operator[](uint16_t pos) { + char &operator[](size_type pos) { return at(pos); } @@ -132,7 +134,7 @@ namespace wlp { * @param pos the position of the character * @return character at @p pos */ - const char &operator[](uint16_t pos) const { + const char &operator[](size_type pos) const { return at(pos); } @@ -144,8 +146,8 @@ namespace wlp { * @param pos the position of the character * @return character at @p pos */ - char &at(uint16_t pos) { - if (pos >= m_len) return back(); + char &at(size_type pos) { + if (pos >= m_len) { return back(); } return m_buffer[pos]; } @@ -157,8 +159,8 @@ namespace wlp { * @param pos the position of the character * @return character at @p pos */ - const char &at(uint16_t pos) const { - if (pos >= m_len) return back(); + const char &at(size_type pos) const { + if (pos >= m_len) { return back(); } return m_buffer[pos]; } @@ -169,7 +171,7 @@ namespace wlp { * @return the last character */ char &back() { - if (empty()) return m_buffer[0]; + if (empty()) { return m_buffer[0]; } return m_buffer[m_len - 1]; } @@ -179,7 +181,7 @@ namespace wlp { * @return the last character */ const char &back() const { - if (empty()) return m_buffer[0]; + if (empty()) { return m_buffer[0]; } return m_buffer[m_len - 1]; } @@ -253,17 +255,13 @@ namespace wlp { * @return the current string */ StaticString &append(const char *str) { - uint16_t bufferLength = m_len; - uint16_t otherLength = (uint16_t) strlen(str); - - for (uint16_t i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { + size_type bufferLength = m_len; + size_type otherLength = static_cast(strlen(str)); + for (size_type i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { m_buffer[i] = str[i - bufferLength]; } - - m_len = (uint16_t) ceil(fmin(capacity(), (bufferLength + otherLength))); - + m_len = MIN(tSize, bufferLength + otherLength); m_buffer[m_len] = '\0'; - return *this; } @@ -285,15 +283,12 @@ namespace wlp { * @param pos position of the element to be deleted * @return the modified String */ - StaticString &erase(uint16_t pos = 0) { - if (m_len == 0 || pos >= m_len) return *this; - + StaticString &erase(size_type pos = 0) { + if (m_len == 0 || pos >= m_len) { return *this; } --m_len; - - for (uint16_t i = pos; i < m_len; ++i) { + for (size_type i = pos; i < m_len; ++i) { m_buffer[i] = m_buffer[i + 1]; } - m_buffer[m_len] = '\0'; return *this; } @@ -302,8 +297,7 @@ namespace wlp { * Deletes the last character in the String */ void pop_back() { - if (m_len == 0) return; - + if (m_len == 0) { return; } --m_len; m_buffer[m_len] = '\0'; } @@ -326,23 +320,19 @@ namespace wlp { * @param length length of the new string * @return new string which is a substring of current string */ - StaticString substr(uint16_t pos, uint16_t length) const { - if (pos >= m_len) + StaticString substr(size_type pos, size_type length) const { + if (pos >= m_len) { return *this; - - if (pos + length >= m_len) - length = (uint16_t) (m_len - pos); - + } + if (pos + length >= m_len) { + length = static_cast(m_len - pos); + } char newBuffer[length + 1]; - - for (uint16_t i = pos; i < pos + length; i++) { + for (size_type i = pos; i < pos + length; i++) { newBuffer[i - pos] = m_buffer[i]; } - newBuffer[length] = '\0'; - StaticString s{newBuffer}; - return s; } @@ -385,7 +375,7 @@ namespace wlp { private: char m_buffer[tSize + 1]; - uint16_t m_len; + size_type m_len; }; /** @@ -396,7 +386,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return true or false based on if two strings are equal */ - template + template bool operator==(const StaticString &lhs, const StaticString &rhs) { return lhs.compare(rhs) == 0; } @@ -409,7 +399,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return true or false based on if two strings are equal */ - template + template bool operator==(const char *lhs, const StaticString &rhs) { return rhs.compare(lhs) == 0; } @@ -422,7 +412,7 @@ namespace wlp { * @param rhs character string as right hand side string * @return true or false based on if two strings are equal */ - template + template bool operator==(const StaticString &lhs, const char *rhs) { return lhs.compare(rhs) == 0; } @@ -435,7 +425,7 @@ namespace wlp { * @param rhs a character * @return true or false based on the string is equal to the character */ - template + template bool operator==(const StaticString &lhs, const char rhs) { return lhs.compare(rhs) == 0; } @@ -448,7 +438,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return true or false based on the string is equal to the character */ - template + template bool operator==(const char lhs, const StaticString &rhs) { return rhs.compare(lhs) == 0; } @@ -461,7 +451,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - template + template StaticString operator+(const StaticString &lhs, const StaticString &rhs) { StaticString newStr; newStr.append(lhs).append(rhs); @@ -476,7 +466,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - template + template StaticString operator+(const char *lhs, const StaticString &rhs) { StaticString newStr; newStr.append(lhs).append(rhs); @@ -491,7 +481,7 @@ namespace wlp { * @param rhs character string as right hand side string * @return a @code StaticString @endcode that is build from left hind string and right hand string */ - template + template StaticString operator+(const StaticString &lhs, const char *rhs) { StaticString newStr; newStr.append(lhs).append(rhs); @@ -506,7 +496,7 @@ namespace wlp { * @param rhs character * @return a @code StaticString @endcode that is build from left hind string and right hand character */ - template + template StaticString operator+(const StaticString &lhs, const char rhs) { StaticString newStr; newStr.append(lhs).push_back(rhs); @@ -521,7 +511,7 @@ namespace wlp { * @param rhs @code StaticString @endcode string as right hand side string * @return a @code StaticString @endcode that is build from right hind string and left hand character */ - template + template StaticString operator+(const char lhs, const StaticString &rhs) { StaticString newStr; newStr.push_back(lhs).append(rhs); diff --git a/lib/wlib/strings/String.h b/lib/wlib/strings/String.h index bd57a546..5cf6538a 100644 --- a/lib/wlib/strings/String.h +++ b/lib/wlib/strings/String.h @@ -7,12 +7,13 @@ * @bug No known bug */ -#ifndef EMBEDDEDCPLUSPLUS_STRING_H -#define EMBEDDEDCPLUSPLUS_STRING_H +#ifndef EMBEDDEDCPLUSPLUS_STRINGTYPES_H +#define EMBEDDEDCPLUSPLUS_STRINGTYPES_H #include "strings/StaticString.h" namespace wlp { + // Static Strings typedef StaticString<8u> String8; typedef StaticString<16u> String16; @@ -25,6 +26,7 @@ namespace wlp { // Dynamic String typedef wlp::DynamicString String; */ + } -#endif //EMBEDDEDCPLUSPLUS_STRING_H +#endif //EMBEDDEDCPLUSPLUS_STRINGTYPES_H diff --git a/lib/wlib/utilities/Math.h b/lib/wlib/utility/Math.h similarity index 63% rename from lib/wlib/utilities/Math.h rename to lib/wlib/utility/Math.h index aaae0d1e..16cc5c03 100644 --- a/lib/wlib/utilities/Math.h +++ b/lib/wlib/utility/Math.h @@ -3,8 +3,8 @@ namespace wlp { -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) // Multiplication by Mersenne primes reduced as bit operations // for compilers that do not already perform this optimization @@ -17,9 +17,14 @@ namespace wlp { } template - inline constexpr int_type pow_const(const int_type a, const int_type b) { + inline constexpr int_type pow_const(int_type a, int_type b) { return (b == 0) ? 1 : (a * pow_const(a, b - 1)); } + + template + inline int_type int_div_round(int_type n, int_type d) { + return ((n < 0) ^ (d < 0)) ? ((n - d / 2) / d) : ((n + d / 2) / d); + } } #endif //EMBEDDEDCPLUSPLUS_MATH_H diff --git a/lib/wlib/utilities/Tmp.h b/lib/wlib/utility/Tmp.h similarity index 100% rename from lib/wlib/utilities/Tmp.h rename to lib/wlib/utility/Tmp.h diff --git a/lib/wlib/utilities/Utility.h b/lib/wlib/utility/Utility.h similarity index 100% rename from lib/wlib/utilities/Utility.h rename to lib/wlib/utility/Utility.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2ce9488c..544be407 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,5 @@ +set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Waddress -Warray-bounds -Wbuiltin-macro-redefined -Wconversion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self -Wnon-virtual-dtor -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wswitch -Wunreachable-code") diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp index a19d4b62..d50bfaba 100644 --- a/tests/stl/chain_map_check.cpp +++ b/tests/stl/chain_map_check.cpp @@ -9,7 +9,7 @@ using namespace wlp; typedef uint16_t ui16; typedef ChainHashMap string_map; -typedef ChainHashMap int_map; +typedef ChainHashMap int_map; typedef int_map::iterator imi; typedef int_map::const_iterator cimi; typedef Pair P_imi_b; @@ -109,7 +109,7 @@ TEST(chain_map_test, test_erase_cases) { map[21] = 21; map[31] = 31; map[2] = 2; - map.erase(it); + it = map.erase(it); ASSERT_EQ(2, *it); it = map.end(); map.erase(it); @@ -268,16 +268,16 @@ TEST(chain_map_test, test_erase_iterator) { map.insert(40, 40); ASSERT_EQ(6, map.size()); imi it = r1.first(); - map.erase(it); + it = map.erase(it); ASSERT_EQ(5, map.size()); ASSERT_EQ(33, *it); ASSERT_EQ(it, r33.first()); - map.erase(it); + it = map.erase(it); ASSERT_EQ(4, map.size()); ASSERT_EQ(3, *it); ASSERT_NE(it, r3.first()); // iterator invalidated by erase ASSERT_EQ(*it, *r3.first()); - map.erase(it); + it = map.erase(it); ASSERT_EQ(3, map.size()); ASSERT_EQ(map.end(), it); ASSERT_EQ(40, *map.at(40)); @@ -287,12 +287,12 @@ TEST(chain_map_test, test_erase_iterator) { ASSERT_EQ(map.end(), map.at(3)); ASSERT_EQ(map.end(), map.at(33)); it = r20.first(); - map.erase(it); + it = map.erase(it); ASSERT_EQ(2, map.size()); ASSERT_EQ(0, *it); ASSERT_NE(it, r0.first()); ASSERT_EQ(0, *r0.first()); - map.erase(it); + it = map.erase(it); ASSERT_EQ(map.end(), it); ASSERT_EQ(1, map.size()); ASSERT_EQ(40, *map.begin()); diff --git a/tests/stl/comparator_check.cpp b/tests/stl/comparator_check.cpp index b9240b44..04caf936 100644 --- a/tests/stl/comparator_check.cpp +++ b/tests/stl/comparator_check.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" -#include "utilities/Comparator.h" +#include "stl/Comparator.h" #include "strings/String.h" using namespace wlp; diff --git a/tests/stl/concept_check.cpp b/tests/stl/concept_check.cpp index 8b5f757a..54db1067 100644 --- a/tests/stl/concept_check.cpp +++ b/tests/stl/concept_check.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "stl/Concept.h" -#include "utilities/Comparator.h" +#include "stl/Comparator.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" #include "stl/ArrayList.h" diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp index 2fc4fc66..f65eaad9 100644 --- a/tests/stl/open_map_check.cpp +++ b/tests/stl/open_map_check.cpp @@ -7,7 +7,7 @@ using namespace wlp; typedef StaticString<16> string16; typedef OpenHashMap string_map; -typedef OpenHashMap int_map; +typedef OpenHashMap int_map; typedef int_map::iterator imi; typedef Pair P_imi_b; diff --git a/tests/stl/pair_check.cpp b/tests/stl/pair_check.cpp index c8063ab8..79e61fd9 100644 --- a/tests/stl/pair_check.cpp +++ b/tests/stl/pair_check.cpp @@ -7,10 +7,10 @@ using namespace wlp; TEST(pair_test, test_pair_constructor) { - Pair pair1{5, "string"}; - Pair pair2{8, "nothing"}; - Pair pair3{5, "string"}; - Pair pair4{9, "another"}; + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; + Pair pair3{5, "string"}; + Pair pair4{9, "another"}; ASSERT_TRUE(pair1 == pair3); ASSERT_EQ(5, pair1.first()); ASSERT_EQ(8, pair2.first()); @@ -19,8 +19,8 @@ TEST(pair_test, test_pair_constructor) { } TEST(pair_test, test_pair_assign_operator) { - Pair pair1{5, "string"}; - Pair pair2{8, "nothing"}; + Pair pair1{5, "string"}; + Pair pair2{8, "nothing"}; pair2 = pair1; ASSERT_TRUE(pair1 == pair2); ASSERT_EQ(pair1.first(), pair2.first()); @@ -28,7 +28,7 @@ TEST(pair_test, test_pair_assign_operator) { } TEST(pair_test, test_pair_const_equality) { - Pair pair1{5, "string"}; - const Pair pair2{8, "nothing"}; + Pair pair1{5, "string"}; + const Pair pair2{8, "nothing"}; ASSERT_FALSE(pair1 == pair2); } diff --git a/tests/template_defs.h b/tests/template_defs.h index 2c38292b..fc4fd50f 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -4,7 +4,7 @@ #include "Types.h" #include "strings/String.h" -#include "utilities/Utility.h" +#include "utility/Utility.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" #include "stl/ArrayHeap.h" diff --git a/wmake b/wmake index 72497e72..054afbe9 100755 --- a/wmake +++ b/wmake @@ -246,6 +246,7 @@ _run(){ } _test(){ + find ./bin/tests/CMakeFiles/tests.dir/ -name '*.gcda' -delete ./bin/tests/tests echo "Tests Finished Running" } From 4715dd7c0b6e0ed6cb2aac4100a94ee3dfd3bfd7 Mon Sep 17 00:00:00 2001 From: "Ambareesh \"Amby\" Balaji" Date: Mon, 20 Nov 2017 21:34:26 -0500 Subject: [PATCH 017/102] Implement STL List (#29) * Implement STL List * Implement tests for list * Implement iterators --- lib/wlib/stl/LinkedList.h | 644 ++++++++++++++++++ .../{list_check.cpp => array_list_check.cpp} | 0 tests/stl/linked_list_check.cpp | 113 +++ tests/template_defs.h | 4 + wmake | 2 +- 5 files changed, 762 insertions(+), 1 deletion(-) create mode 100644 lib/wlib/stl/LinkedList.h rename tests/stl/{list_check.cpp => array_list_check.cpp} (100%) create mode 100644 tests/stl/linked_list_check.cpp diff --git a/lib/wlib/stl/LinkedList.h b/lib/wlib/stl/LinkedList.h new file mode 100644 index 00000000..c8304798 --- /dev/null +++ b/lib/wlib/stl/LinkedList.h @@ -0,0 +1,644 @@ +/** + * @file List.h + * @brief List is an implementation of the stl doubly-linked link + * + * It provides functionality for pushing popping from front and back + * and search and indexing + * + * @author Ambareesh Balaji + * @author Jeff Niu + * @date November 4, 2017 + * @bug No Known bugs + */ + +#ifndef CORE_STL_LIST_H +#define CORE_STL_LIST_H + +#include "memory/Memory.h" +#include "memory/Allocator.h" +#include "../utility/Utility.h" + +namespace wlp { + + template + struct LinkedListNode { + typedef T val_type; + typedef LinkedListNode node_type; + + val_type m_val; + node_type *m_next, *m_prev; + }; + + // Forward Declaration of List class + template + class LinkedList; + + /** + * Iterator class over the elements of a List. + * + * @tparam T value type + */ + template + struct LinkedListIterator { + typedef T val_type; + typedef wlp::size_type size_type; + typedef LinkedListNode node_type; + typedef LinkedListIterator iterator; + typedef LinkedList list_type; + + /** + * Pointer to the node referenced by this iterator. + */ + node_type *m_current; + /** + * Pointer to the iterated List. + */ + list_type *m_list; + + /** + * Default constructor. + */ + LinkedListIterator() + : m_current(nullptr), + m_list(nullptr) {} + + /** + * Create an iterator to a List node. + * + * @param node linked list node + * @param list parent linked list + */ + LinkedListIterator(node_type *node, list_type *list) + : m_current(node), + m_list(list) {} + + /** + * Copy constructor. + * + * @param it iterator copy + */ + LinkedListIterator(const iterator &it) + : m_current(it.m_current), + m_list(it.m_list) {} + + /** + * @return reference to the value of the node + * pointed to by the iterator + */ + val_type &operator*() const { + return m_current->m_val; + } + + /** + * @return pointer to the value of the node + * pointed to by the iterator + */ + val_type *operator->() const { + return &(operator*()); + } + + /** + * Increment the iterator to the next available element in + * the List. If no such element exists, returns pass-the-end + * iterator. This is pre-fix unary operator. + * + * @return this iterator + */ + iterator &operator++() { + if (m_current) { + m_current = m_current->m_next; + } + return *this; + } + + /** + * Post-fix unary operator. + * + * @return this iterator + */ + iterator operator++(int) { + iterator clone(*this); + ++*this; + return clone; + } + + /** + * Decrement the iterator by moving it + * to the previous element in the list. If the iterator + * is already at the beginning of the list, + * the iterator does not move. + * + * @return reference to this iterator + */ + iterator &operator--() { + if (m_current && m_current != m_list->m_head) { + m_current = m_current->m_prev; + } + return *this; + } + + /** + * Post-fix decrement operator. + * + * @return reference to this iterator + */ + iterator operator--(int) { + iterator clone(*this); + --*this; + return *this; + } + + /** + * Equality operator. + * + * @param it iterator to compare + * @return true if they are equal + */ + bool operator==(const iterator &it) const { + return m_current == it.m_current; + } + + /** + * Compare two iterators, unequal if they point to + * different nodes. + * + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(const iterator &it) const { + return m_current != it.m_current; + } + + /** + * Assignment operator copies pointer to node + * and pointer to linked list. + * + * @param it iterator to copy + * @return reference to this iterator + */ + iterator &operator=(const iterator &it) { + m_current = it.m_current; + m_list = it.m_list; + return *this; + } + }; + + /** + * Constant iterator over a List. Values iterated by + * this class cannot be modified. + * + * @see ListIterator + * @tparam T value type + */ + template + struct LinkedListConstIterator { + typedef T val_type; + typedef wlp::size_type size_type; + typedef LinkedListNode node_type; + typedef LinkedListConstIterator const_iterator; + typedef LinkedList list_type; + + const node_type *m_current; + const list_type *m_list; + + LinkedListConstIterator() + : m_current(nullptr), + m_list(nullptr) {} + + LinkedListConstIterator(const node_type *node, const list_type *list) + : m_current(node), + m_list(list) {} + + LinkedListConstIterator(const const_iterator &it) + : m_current(it.m_current), + m_list(it.m_list) {} + + const val_type &operator*() const { + return m_current->m_val; + } + + const val_type *operator->() const { + return &(operator*()); + } + + const_iterator &operator++() { + if (m_current) { + m_current = m_current->m_next; + } + return *this; + } + + const_iterator operator++(int) { + const_iterator clone(*this); + ++*this; + return clone; + } + + const_iterator &operator--() { + if (m_current && m_current != m_list->m_head) { + m_current = m_current->m_prev; + } + return *this; + } + + const_iterator operator--(int) { + const_iterator clone(*this); + --*this; + return *this; + } + + bool operator==(const const_iterator &it) const { + return m_current == it.m_current; + } + + bool operator!=(const const_iterator &it) const { + return m_current != it.m_current; + } + + const_iterator &operator=(const const_iterator &it) { + m_current = it.m_current; + m_list = it.m_list; + return *this; + } + }; + + /** + * List implementation as a Doubly-Linked list. + * + * @tparam T value type + */ + template + class LinkedList { + public: + typedef T val_type; + typedef wlp::size_type size_type; + typedef LinkedList list_type; + typedef LinkedListNode node_type; + typedef LinkedListIterator iterator; + typedef LinkedListConstIterator const_iterator; + + private: + /** + * The number of elements in the list. + */ + size_type m_size; + /** + * Pointer to first node in the list. + */ + node_type *m_head; + /** + * Pointer to last node in the list. + */ + node_type *m_tail; + + friend struct LinkedListIterator; + + friend struct LinkedListConstIterator; + + public: + /** + * Default Constructor creates an empty List. + */ + LinkedList() + : m_size(0), + m_head(nullptr), + m_tail(nullptr) {} + + /** + * Disable copy construction. + */ + LinkedList(const list_type &) = delete; + + /** + * Move constructor takes the pointers to the head and tail + * nodes and copies them into this list. The transferred list + * is set to an empty list. + * + * @param list the list to move + */ + LinkedList(list_type &&list) : + m_size(move(list.m_size)), + m_head(move(list.m_head)), + m_tail(move(list.m_tail)) { + list.m_size = 0; + list.m_head = nullptr; + list.m_tail = nullptr; + } + + /** + * Default Destructor deallocates all the nodes. + */ + ~LinkedList(); + + /** + * Creates a new node and pushes it to the back of the list. + * + * @param value the value to store at the new node + */ + template + void push_back(V &&val) { + node_type *node = malloc(); + node->m_val = forward(val); + node->m_next = nullptr; + if (m_head == nullptr) { + m_head = node; + node->m_prev = nullptr; + } else { + m_tail->m_next = node; + node->m_prev = m_tail; + } + m_tail = node; + ++m_size; + } + + /** + * Creates a new node and pushes it to the front of the list. + * + * @param value the value to store at the new node + */ + template + void push_front(V &&val) { + node_type *node = malloc(); + node->m_val = forward(val); + node->m_prev = nullptr; + + if (m_tail == nullptr) { + m_tail = node; + node->m_next = nullptr; + } else { + m_head->m_prev = node; + node->m_next = m_head; + } + m_head = node; + m_size++; + } + + void pop_back() { + if (!m_tail) { + return; + } + node_type *pTmp = m_tail; + m_tail = m_tail->m_prev; + if (m_tail != nullptr) { + m_tail->m_next = nullptr; + } else { + m_head = nullptr; + } + free(pTmp); + m_size--; + } + + void pop_front() { + if (!m_head) { + return; + } + node_type *pTmp = m_head; + m_head = m_head->m_next; + if (m_head != nullptr) { + m_head->m_prev = nullptr; + } else { + m_tail = nullptr; + } + free(pTmp); + m_size--; + } + + /** + * @return a reference to the value at the start of the List + */ + val_type &front() { + return m_head->m_val; + } + + /** + * @return a const reference to the value at the start of the List + */ + const val_type &front() const { + return m_head->m_val; + } + + /** + * @return a reference to the value at the end of the List + */ + val_type &back() { + return m_tail->m_val; + } + + /** + * @return a const reference to the value at the end of the List + */ + const val_type &back() const { + return m_tail->m_val; + } + + /** + * Returns the length of the List + * + * @return the length of the list + */ + size_type size() const { + return m_size; + } + + void clear() noexcept; + + /** + * Removes the value stored at the given index + * + * @param index the index to remove at + */ + void erase(size_type index); + + /** + * Return a reference to the value stored at the `index` + * + * @param index to get + * @return reference to the value at that index + */ + val_type &at(size_type index); + + /** + * Return a reference to the value stored at the `index` (const variant) + * + * @param index to get + * @return reference to the value at that index + */ + const val_type &at(size_type index) const; + + /** + * Array indexing operator + * `at` behind the scenes + * + * @param index to get + * @return reference to the value at that index + */ + val_type &operator[](size_type index) { + return at(index); + } + + /** + * Array indexing operator const variant + * `at` behind the scenes + * + * @param index to get + * @return reference to the value at that index + */ + const val_type &operator[](size_type index) const { + return at(index); + } + + /** + * indexOf from Javascript land that finds the index of the + * first element from the beginning of the List that equals `value` + * but returns the length of the array instead of -1 on failure + * + * @param value value to search for + * @return reference to the value at that index + */ + size_type indexOf(const T &value); + + /** + * Obtain an iterator to the first element in the list. + * Returns pass-the-end iterator (nullptr) if + * there are no elements (m_pStart == nullptr) + * + * @return iterator the first element + */ + iterator begin() { + return iterator(m_head, this); + } + + /** + * @return a pass-the-end iterator for this map + */ + iterator end() { + return iterator(nullptr, this); + } + + /** + * @see List::begin() + * @return a constant iterator to the first element in the list + */ + const_iterator begin() const { + return const_iterator(m_head, this); + } + + /** + * @see List::end() + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return const_iterator(nullptr, this); + } + + /** + * Delete copy assignment. + * + * @return reference to this list + */ + list_type &operator=(const list_type &) = delete; + + /** + * Move assignment operator. + * + * @param list the list to move + * @return a reference to this list + */ + list_type &operator=(list_type &&list) { + m_size = list.m_size; + m_head = list.m_head; + m_tail = list.m_tail; + list.m_size = 0; + list.m_head = nullptr; + list.m_tail = nullptr; + return *this; + } + }; + + template + LinkedList::~LinkedList() { + clear(); + } + + template + void LinkedList::clear() noexcept { + node_type *pTmp; + while (m_head != nullptr) { + pTmp = m_head; + m_head = m_head->m_next; + free(pTmp); + } + m_size = 0; + m_tail = nullptr; + } + + template + void LinkedList::erase(size_type index) { + if (!m_size) { + return; + } + if (index >= m_size) { + index %= m_size; + } + node_type *pTmp = m_head; + while (index-- > 0) { + pTmp = pTmp->m_next; + } + if (pTmp->m_prev != nullptr) { + pTmp->m_prev->m_next = pTmp->m_next; + } else { + m_head = pTmp->m_next; + } + if (pTmp->m_next != nullptr) { + pTmp->m_next->m_prev = pTmp->m_prev; + } else { + m_tail = pTmp->m_prev; + } + free(pTmp); + m_size--; + } + + template + typename LinkedList::val_type & + LinkedList::at(size_type index) { + if (index >= m_size) { + if (m_size) { index %= m_size; } + else { index = 0; } + } + node_type *pTmp = m_head; + while (index-- > 0) { + pTmp = pTmp->m_next; + } + return pTmp->m_val; + } + + template + const typename LinkedList::val_type & + LinkedList::at(size_type index) const { + if (index >= m_size) { + if (m_size) { index %= m_size; } + else { index = 0; } + } + node_type *pTmp = m_head; + while (index-- > 0) { + pTmp = pTmp->m_next; + } + return pTmp->m_val; + } + + template + typename LinkedList::size_type + LinkedList::indexOf(const T &value) { + node_type *pTmp = m_head; + for (size_type i = 0; i < m_size; i++) { + if (pTmp->m_val == value) { + return i; + } + pTmp = pTmp->m_next; + } + return m_size; + } + +} + +#endif // CORE_STL_LIST_H diff --git a/tests/stl/list_check.cpp b/tests/stl/array_list_check.cpp similarity index 100% rename from tests/stl/list_check.cpp rename to tests/stl/array_list_check.cpp diff --git a/tests/stl/linked_list_check.cpp b/tests/stl/linked_list_check.cpp new file mode 100644 index 00000000..93e5db30 --- /dev/null +++ b/tests/stl/linked_list_check.cpp @@ -0,0 +1,113 @@ +#include "gtest/gtest.h" +#include "stl/LinkedList.h" + +#include "../template_defs.h" + +using namespace wlp; + +TEST(list_tests, constructor_tests) { + LinkedList numlist; + ASSERT_EQ(numlist.size(), 0); +} + +TEST(list_tests, push_pop_remove_tests) { + LinkedList numlist; + numlist.push_back(1); + numlist.push_back(2); + numlist.push_front(3); // 3 1 2 + ASSERT_EQ(numlist.front(), 3); + ASSERT_EQ(numlist.back(), 2); + ASSERT_EQ(numlist.size(), 3); + numlist.pop_back(); + numlist.pop_front(); + ASSERT_EQ(numlist.front(), 1); + ASSERT_EQ(numlist.back(), 1); + numlist.push_front(4); + numlist.push_back(5); + numlist.erase(1); + ASSERT_EQ(numlist.size(), 2); + numlist.erase(1); + ASSERT_EQ(numlist.size(), 1); + numlist.pop_front(); + ASSERT_EQ(numlist.size(), 0); + // does nothing, should not die + numlist.erase(100); + ASSERT_EQ(numlist.size(), 0); + numlist.push_front(4); + ASSERT_EQ(numlist.size(), 1); + numlist.pop_back(); + ASSERT_EQ(numlist.size(), 0); + numlist.push_back(5); + ASSERT_EQ(numlist.size(), 1); + numlist.erase(0); + ASSERT_EQ(numlist.size(), 0); + numlist.push_back(5); + ASSERT_EQ(numlist.size(), 1); + numlist.clear(); + ASSERT_EQ(numlist.size(), 0); + numlist.push_back(3); + numlist.push_back(1); + numlist.push_back(2); + const LinkedList constlist = move(numlist); + ASSERT_EQ(constlist.front(), 3); + ASSERT_EQ(constlist.back(), 2); + ASSERT_EQ(constlist.size(), 3); +} + +TEST(list_tests, indexing_tests) { + LinkedList numlist; + numlist.push_front(1); + numlist.push_back(2); + numlist.push_front(3); // 3 1 2 + ASSERT_EQ(numlist.indexOf(3), 0); + ASSERT_EQ(numlist.indexOf(1), 1); + ASSERT_EQ(numlist.indexOf(2), 2); + ASSERT_EQ(numlist.indexOf(4), 3); + ASSERT_EQ(numlist.at(0), 3); + ASSERT_EQ(numlist[2], 2); + const LinkedList constlist = move(numlist); + ASSERT_EQ(constlist[0], 3); + ASSERT_EQ(constlist[1], 1); + ASSERT_EQ(constlist[2], 2); +} + +TEST(list_tests, iterator_tests) { + LinkedList numlist; + numlist.push_front(1); + numlist.push_back(2); + numlist.push_front(3); // 3 1 2 + LinkedListIterator it = numlist.begin(); + ASSERT_EQ(*it, 3); + ++it; + ASSERT_EQ(*it, 1); + it++; + ASSERT_NE(it, numlist.end()); + ASSERT_EQ(*it, 2); + ++it; + ASSERT_EQ(it, numlist.end()); + const LinkedList constlist = move(numlist); + LinkedListConstIterator it2 = constlist.begin(); + ASSERT_EQ(*it2, 3); + ++it2; + ASSERT_EQ(*it2, 1); + it2++; + ASSERT_NE(it2, constlist.end()); + ASSERT_EQ(*it2, 2); + ++it2; + ASSERT_EQ(it2, constlist.end()); +} + +TEST(list_tests, copy_move_constructors) { + LinkedList list; + auto newlist = move(list); + LinkedList list2; + auto movedlist = move(list2); + ASSERT_EQ(newlist.size(), 0); + ASSERT_EQ(movedlist.size(), 0); +} + +TEST(list_tests, dynamic_list_class) { + LinkedList* pList = new LinkedList; + ASSERT_EQ(pList->size(), 0); + delete pList; +} \ No newline at end of file diff --git a/tests/template_defs.h b/tests/template_defs.h index fc4fd50f..b8a4a055 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -8,6 +8,7 @@ #include "stl/ChainMap.h" #include "stl/OpenMap.h" #include "stl/ArrayHeap.h" +#include "stl/LinkedList.h" namespace wlp { template @@ -144,6 +145,9 @@ namespace wlp { template struct Comparator; + template + class LinkedList; + } #endif // TEMPLATE_DEFS_H diff --git a/wmake b/wmake index 054afbe9..2cd6d49f 100755 --- a/wmake +++ b/wmake @@ -227,7 +227,7 @@ _coverage(){ cd bin echo "Generating Coverage Report" lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info 'tests/*' '/include/*' 'examples/*' --output-file coverage.info + lcov --remove coverage.info '/usr/*' "$(pwd)/tests/*" "$(pwd)/include/*" "$(pwd)/examples/*" --output-file coverage.info lcov --list coverage.info mkdir -p coverage genhtml -no-branch-coverage -o coverage coverage.info From e442cc0c0a282e4cc40c57b75785c472b7ad6eca Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 20 Nov 2017 18:49:31 -0800 Subject: [PATCH 018/102] [Lib] State Machine + [HF] memory fixes (#56) * Created state machine class and defn * f * object size is stored to free them properly * Removed dynamic event data allocation * Updated with master * memory test fixed --- lib/wlib/CMakeLists.txt | 1 + lib/wlib/fsm/StateMachine.h | 621 ++++++++++++++++++++++++++++++++ lib/wlib/memory/Memory.cpp | 19 +- lib/wlib/memory/Memory.h | 31 +- lib/wlib/strings/StaticString.h | 2 +- lib/wlib/utility/Tmp.h | 56 ++- tests/CMakeLists.txt | 1 + tests/fsm/fsm_check.cpp | 129 +++++++ tests/memory/memory_check.cpp | 19 +- 9 files changed, 835 insertions(+), 44 deletions(-) create mode 100755 lib/wlib/fsm/StateMachine.h create mode 100644 tests/fsm/fsm_check.cpp diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index ae738d1a..3becf7b8 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -23,6 +23,7 @@ add_definitions(-DMAX_ALLOCATORS=10u -DNUM_BLOCKS=100u -DDYNAMIC_POOL) file(GLOB header_files "*.h" + "fsm/*.h" "strings/*.h" "stl/*.h" "memory/*.h" diff --git a/lib/wlib/fsm/StateMachine.h b/lib/wlib/fsm/StateMachine.h new file mode 100755 index 00000000..ce6a1b02 --- /dev/null +++ b/lib/wlib/fsm/StateMachine.h @@ -0,0 +1,621 @@ +#ifndef STATEMACHINE_H +#define STATEMACHINE_H + +#include "../Wlib.h" +#include "../Types.h" +#include "../memory/Memory.h" +#include "../utility/Tmp.h" + +namespace wlp { + + /** + * Unique state machine event data must + * inherit from this class. + */ + class EventData { + public: + virtual ~EventData() {} + }; + + typedef uint8_t state_type; + typedef EventData NoEventData; + + class StateMachine; + + /** + * Abstract state base class that all + * states inherit from. + */ + class StateBase { + public: + virtual ~StateBase() {} + + /** + * Called by the state machine engine to execute a + * state action. If a guard condition exists and it + * evaluates to false, the state action will not + * execute. + * + * @param sm a state machine instance + * @param data the event data + */ + virtual void invokeStateAction(StateMachine *sm, const EventData *data) const = 0; + }; + + /** + * This class represents the action that occurs when + * a new state is executed. + * + * @tparam SM state machine class + * @tparam Data state function event data type + * @tparam Func state machine member function pointer + */ + template + class StateAction : public StateBase { + public: + virtual ~StateAction() {} + + /** + * @see StateBase::InvokeStateAction + */ + virtual void invokeStateAction(StateMachine *sm, const EventData *data) const { + // Downcast the state machine and event data to the correct derived type + SM *derivedSM = static_cast(sm); + /* + * If the derived data dynamic cast returns a null pointer, then + * there is a mismatch between the event type in STATE_DECLARE and + * the event type passed to the fucntion. + */ + const Data *derivedData = dynamic_cast(data); + /* assert(derivedData != nullptr) */ + if (derivedData == nullptr) { + return; + } + // Call the state function + (derivedSM->*Func)(derivedData); + } + }; + + /** + * Abstract guard base class that all + * guards classes inherit from. + */ + class GuardBase { + public: + virtual ~GuardBase() {} + + /** + * Called by the state machine engine to execute + * a guard condition action. If guard condition + * evaluates to true, the state action is executed. + * If false, no state transition is performed. + * + * @param sm a state machine instance + * @param data the event data + * @return true if no guard condition or if the + * condition evaluates to true + */ + virtual bool invokeGuardAction(StateMachine *sm, const EventData *data) const = 0; + }; + + /** + * The class represents a guard condition that + * must be passed when transitioning to a new state. + * + * @tparam SM state machine class + * @tparam Data state function event data type + * @tparam Func state machine member function pointer + */ + template + class GuardCondition : public GuardBase { + public: + virtual ~GuardCondition() {} + + virtual bool invokeGuardAction(StateMachine *sm, const EventData *data) const { + SM *derivedSM = static_cast(sm); + const Data *derivedData = dynamic_cast(data); + /* assert(derivedData != nullptr) */ + if (derivedData == nullptr) { + return false; + } + // Call the guard function + return (derivedSM->*Func)(derivedData); + } + }; + + /** + * Abstract entry base class that all + * entry classes inherit from. + */ + class EntryBase { + public: + virtual ~EntryBase() {} + + /** + * Called by the state machine engine to execute + * a state entry action. Called when entering a state. + * + * @param sm a state machine instance + * @param data the event data + */ + virtual void invokeEntryAction(StateMachine *sm, const EventData *data) const = 0; + }; + + /** + * This class represents an action that is executed + * upon entry into a new state. + * + * @tparam SM state machine class + * @tparam Data state function event data type + * @tparam Func state machine member function pointer + */ + template + class EntryAction : public EntryBase { + public: + virtual ~EntryAction() {} + + virtual void invokeEntryAction(StateMachine *sm, const EventData *data) const { + SM *derivedSM = static_cast(sm); + const Data *derivedData = dynamic_cast(data); + /* assert(derivedData != nullptr) */ + if (derivedData == nullptr) { + return; + } + // Call the entry function + (derivedSM->*Func)(derivedData); + } + }; + + /** + * Abstract exit base class that all + * exit classes inherit from. + */ + class ExitBase { + public: + virtual ~ExitBase() {} + + /** + * Called by the state machine engine to exeucte a + * state exit action. Called when leaving a state. + * + * @param sm a state machine instance + */ + virtual void invokeExitAction(StateMachine *sm) const = 0; + }; + + /** + * This class represents an action that is executed + * upon exiting a state. + * + * @tparam SM state machine class + * @tparam Func state machine member function pointer + */ + template + class ExitAction : public ExitBase { + public: + virtual ~ExitAction() {} + + virtual void invokeExitAction(StateMachine *sm) const { + SM *derivedSM = static_cast(sm); + + // Call the exit function + (derivedSM->*Func)(); + } + }; + + /** + * A structure to hold a single row within the state map. + */ + struct StateMapRow { + const StateBase *const state; + }; + + /** + * A structure to hold a single row within the extended state map. + */ + struct StateMapRowEx { + const StateBase *const state; + const GuardBase *const guard; + const EntryBase *const entry; + const ExitBase *const exit; + }; + + /** + * StateMachine implements a software-based state machine. + */ + class StateMachine { + public: + enum { + EVENT_IGNORED = 0xfe, CANNOT_HAPPEN + }; + + /** + * Constructor for the state machine defines the + * maximum number of states the machine may occupy + * and the initial state of the machine + * + * There can be at most 254 states whose ordinal values + * range from 0 to 253 inclusive. If the number of states + * exceeds this range, behaviour is undefined. + * + * @param maxStates machine number of states + * @param initialState initial machine state + */ + StateMachine(state_type maxStates, state_type initialState = 0) + : m_max_states(maxStates), + m_current_state(initialState), + m_new_state(0), + m_event_generated(false), + m_event_data(nullptr) { + /* assert(m_max_states < EVENT_IGNORED) */ + } + + virtual ~StateMachine() {} + + /** + * @return the current state machine state + * as an ordinal value + */ + state_type getCurrentState() { return m_current_state; } + + /** + * @return the maximum ordinal value that + * a state may have + */ + state_type getMaxStates() { return m_max_states; } + + protected: + /** + * Trigger an external state machine event. + * + * @param newState the state machine state to + * which the machine should transition + * @param pData the event data to send + * to the new state + */ + template + void externalEvent(state_type newState, EventDataType *pData = nullptr) { + if (newState != EVENT_IGNORED && newState != CANNOT_HAPPEN) { + internalEvent(newState, pData); + stateEngine(); + } + } + + /** + * Trigger an interval state machine event. + * These events are geneated while executing a state + * machine state. + * + * @param newState the state machine state to + * which the machine should transition + * @param pData the event data to send + * to the new state + */ + template + void internalEvent(state_type newState, EventDataType *pData = nullptr) { + if (pData == nullptr) { + pData = static_cast(&m_dataless); + } + m_event_data = pData; + m_event_generated = true; + m_new_state = newState; + } + + private: + /** + * The maximum number of state machine states, + * which also corresponds to the strict upper + * bound on the machine state ordinal value. + */ + const state_type m_max_states; + + /** + * The current state machine state as an + * ordinal value. + */ + state_type m_current_state; + + /** + * The new state machine state to which the + * machine has yet to make the transition. + */ + state_type m_new_state; + + /** + * This value is set to true when an event + * is generated. + */ + bool m_event_generated; + + /** + * The state event data pointer. + */ + EventData *m_event_data; + + /** + * Class-level event data instance used to + * represent an event with no data. + */ + EventData m_dataless; + + /** + * Get the state map as defined in a derived class of State Machine. + * The @code BEGIN_STATE_MAP @endcode, @code STATE_MAP_ENTRY @endcode, and + * @code END_STATE_MAP @endcode macros are used to assist in constructing + * the map. Derived classes only need to implement one of @code getStateMap @endcode + * and @code getStateMapEx @endcode. + * + * @return an array of state map rows with an array size of + * @code MAX_STATES @endcode or nullptr if the state machine + * uses @code getStateMapEx @endcode + */ + virtual const StateMapRow *getStateMap() = 0; + + /** + * Get the extended state map as defined in the derived class of State Machine. + * The @code BEGIN_STATE_MAP_EX @endcode, @code STATE_MAP_ENTRY_EX @endcode, + * @code STATE_MAP_ENTRY_ALL_EX @endcode, and @code END_STATE_MAP_EX @endcode are + * used to assist in constructing the map. + * + * @return an array of extended state map rows of size @code MAX_STATES @endcode + * or nullptr if the state machine uses @code getStateMap @endcode + */ + virtual const StateMapRowEx *getStateMapEx() = 0; + + /** + * Set a new current state. + * + * @param newState the new state of the machine + */ + void setCurrentState(state_type newState) { m_current_state = newState; } + + /** + * The state machine engine that executes the external events and, optionally, + * all internal events generated during state execution. + * + * This function will pull the state map from the state + * map definition. If both the state map and the extended + * state map are undefined, no execution occurs. + */ + template + void stateEngine() { + const StateMapRow *pStateMap = getStateMap(); + if (pStateMap != nullptr) { + stateEngine(pStateMap); + } else { + const StateMapRowEx *pStateMapEx = getStateMapEx(); + if (pStateMapEx != nullptr) { + stateEngine(pStateMapEx); + } else { + /* fail() */ + } + } + } + + /** + * Execute the state transition as per the state map. + * + * If at any moment an invalid state is provided, that is + * its ordinal value is not strictly less than the + * maximum number of states, or a state in the map is + * undefined, results are undefined. + * + * @param pStateMap the state machine state map + */ + template + void stateEngine(const StateMapRow *const pStateMap); + + /** + * Execute the state transition as per the state map. + * This function also checks against guards and executes + * entry and exit actions. + * + * If at any moment an invalid state is provided, that is + * its ordinal value is not strictly less than the + * maximum number of states, or a state in the map is + * undefined, or an entry/exit action makes a call to + * interval event, results are undefined. + * + * @param pStateMapEx the state machine extended state map + */ + template + void stateEngine(const StateMapRowEx *const pStateMapEx); + }; + + template + void StateMachine::stateEngine(const StateMapRow *const pStateMap) { + EventDataType *pDataTemp = nullptr; + while (m_event_generated) { + /* assert(m_new_state < m_max_states) */ + if (m_new_state >= m_max_states) { + return; + } + const StateBase *state = pStateMap[m_new_state].state; + pDataTemp = static_cast(m_event_data); + m_event_data = nullptr; + m_event_generated = false; + setCurrentState(m_new_state); + /* assert(state != nullptr) */ + if (state == nullptr) { + return; + } + state->invokeStateAction(this, pDataTemp); + } + } + + template + void StateMachine::stateEngine(const StateMapRowEx *const pStateMapEx) { + EventDataType *pDataTemp = nullptr; + while (m_event_generated) { + /* assert(m_new_state < m_max_states) */ + if (m_new_state >= m_max_states) { + return; + } + const StateBase *state = pStateMapEx[m_new_state].state; + const GuardBase *guard = pStateMapEx[m_new_state].guard; + const EntryBase *entry = pStateMapEx[m_new_state].entry; + const ExitBase *exit = pStateMapEx[m_current_state].exit; + pDataTemp = static_cast(m_event_data); + m_event_data = nullptr; + m_event_generated = false; + bool guardResult = true; + if (guard != nullptr) { + guardResult = guard->invokeGuardAction(this, pDataTemp); + } + if (pDataTemp == nullptr) { + return; + } + if (guardResult == true) { + if (m_new_state != m_current_state) { + if (exit != nullptr) { + exit->invokeExitAction(this); + } + if (entry != nullptr) { + entry->invokeEntryAction(this, pDataTemp); + } + /* assert(m_event_generated == false) */ + if (m_event_generated) { + return; + } + } + setCurrentState(m_new_state); + /* assert(state != nullptr) */ + if (state == nullptr) { + return; + } + state->invokeStateAction(this, pDataTemp); + } + } + } + +} + + +/** + * Macros used to declare and define state machine + * states, guards, entries, and exits. + */ +#define STATE_DECLARE(...) VFUNC(STATE_DECLARE, __VA_ARGS__) +#define STATE_DEFINE(...) VFUNC(STATE_DEFINE, __VA_ARGS__) +#define STATE_DECLARE2(stateMachine, stateName) \ + void ST_##stateName(const NoEventData*); \ + StateAction stateName; +#define STATE_DECLARE3(stateMachine, stateName, eventData) \ + void ST_##stateName(const eventData*); \ + StateAction stateName; +#define STATE_DEFINE2(stateMachine, stateName) \ + void stateMachine::ST_##stateName(const NoEventData*) +#define STATE_DEFINE3(stateMachine, stateName, eventData) \ + void stateMachine::ST_##stateName(const eventData* data) + +#define GUARD_DECLARE(...) VFUNC(GUARD_DECLARE, __VA_ARGS__) +#define GUARD_DEFINE(...) VFUNC(GUARD_DEFINE, __VA_ARGS__) +#define GUARD_DECLARE2(stateMachine, guardName) \ + bool GD_##guardName(const NoEventData*); \ + GuardCondition guardName; +#define GUARD_DECLARE3(stateMachine, guardName, eventData) \ + bool GD_##guardName(const eventData*); \ + GuardCondition guardName; +#define GUARD_DEFINE2(stateMachine, guardName) \ + bool stateMachine::GD_##guardName(const NoEventData*) +#define GUARD_DEFINE3(stateMachine, guardName, eventData) \ + bool stateMachine::GD_##guardName(const eventData* data) + +#define ENTRY_DELCARE(...) VFUNC(ENTRY_DELCARE, __VA_ARGS__) +#define ENTRY_DEFINE(...) VFUNC(ENTRY_DEFINE, __VA_ARGS__) +#define ENTRY_DECLARE2(stateMachine, entryName) \ + void EN_##entryName(const NoEventData*); \ + EntryAction entryName; +#define ENTRY_DECLARE3(stateMachine, entryName, eventData) \ + void EN_##entryName(const eventData*); \ + EntryAction entryName; +#define ENTRY_DEFINE2(stateMachine, entryName) \ + void stateMachine::EN_##entryName(const NoEventData*) +#define ENTRY_DEFINE3(stateMachine, entryName, eventData) \ + void stateMachine::EN_##entryName(const eventData* data) + +#define EXIT_DECLARE2(stateMachine, exitName) \ + void EX_##exitName(void); \ + ExitAction exitName; +#define EXIT_DEFINE2(stateMachine, exitName) \ + void stateMachine::EX_##exitName(void) + + +/** + * Transition map definition macros, used to + * define the valid transitions between states. + * Upon ending the transition map, the current + * state is called and executed. + * + * A static assertion will fail if the number + * of transitions defined does not equal the + * number of states. + */ +#define BEGIN_TRANSITION_MAP \ + static const state_type TRANSITIONS[] = { +#define TRANSITION_MAP_ENTRY(entry) \ + entry, +#define END_TRANSITION_MAP(data, dataType) \ + }; \ + ASSERT_TRUE(getCurrentState() < ST_MAX_STATES); \ + externalEvent(TRANSITIONS[getCurrentState()], data); \ + static_assert((sizeof(TRANSITIONS) / sizeof(state_type)) == ST_MAX_STATES, "Invalid number of transitions"); + + +/** + * Transition in the parent StateMachine class, + * used to trigger that transition + */ +#define PARENT_TRANSITION(state) \ + if (getCurrentState() >= ST_MAX_STATES && getCurrentState() < getMaxStates()) { \ + externalEvent(state); \ + return; \ + } + + +/** + * State map macros, used to define a state + * map with its entries. + * + * A static assertion occurs if the number of + * states in the state map does not equal the + * number of defined states. + */ +#define BEGIN_STATE_MAP \ + private:\ + virtual const StateMapRowEx* getStateMapEx() { return nullptr; } \ + virtual const StateMapRow* getStateMap() { \ + static const StateMapRow STATE_MAP[] = { +#define STATE_MAP_ENTRY(stateName)\ + { stateName }, +#define END_STATE_MAP \ + }; \ + static_assert((sizeof(STATE_MAP) / sizeof(StateMapRow)) == ST_MAX_STATES, "Invalid state map size"); \ + return &STATE_MAP[0]; \ + } + + +/** + * Extended state map macros, used to support entries, + * exits, and guards in the state map + * + * A static assertion occurs if the number of + * states in the state map does not equal the + * number of defined states. + */ +#define BEGIN_STATE_MAP_EX \ + private: \ + virtual const StateMapRow* getStateMap() { return nullptr; } \ + virtual const StateMapRowEx* getStateMapEx() { \ + static const StateMapRowEx STATE_MAP[] = { +#define STATE_MAP_ENTRY_EX(stateName) \ + { stateName, 0, 0, 0 }, +#define STATE_MAP_ENTRY_ALL_EX(stateName, guardName, entryName, exitName) \ + { stateName, guardName, entryName, exitName }, +#define END_STATE_MAP_EX \ + }; \ + static_assert((sizeof(STATE_MAP) / sizeof(StateMapRowEx)) == ST_MAX_STATES, "Invalid state map size"); \ + return &STATE_MAP[0]; \ + } + +#endif // STATEMACHINE_H diff --git a/lib/wlib/memory/Memory.cpp b/lib/wlib/memory/Memory.cpp index 225b253f..a857ea53 100644 --- a/lib/wlib/memory/Memory.cpp +++ b/lib/wlib/memory/Memory.cpp @@ -18,6 +18,7 @@ using namespace wlp; +static constexpr uint8_t OBJECT_INFO_BUFFER = 2; // 2 bytes to store object info static constexpr size_type REQUIRED_EXTRA_BUFFER = sizeof(__Allocator *); /** @@ -222,9 +223,10 @@ T nextHigher(T k) { * If there is no such Allocator available, create a new one * * @param size client's requested block size + * @param anObject specify if the memory will be used object(s) or fundamental types * @return an allocator instance that handles the block size */ -__Allocator *memory_get_allocator(size32_type size) { +__Allocator *memory_get_allocator(size32_type size, bool anObject) { // Based on the size, find the next higher powers of two value. // Add REQUIRED_EXTRA_BUFFER to the requested block size to hold the size // of an Allocator* within the block memory region. Most blocks are powers of two, @@ -234,6 +236,10 @@ __Allocator *memory_get_allocator(size32_type size) { size32_type blockSize = size + REQUIRED_EXTRA_BUFFER; + if (anObject) + blockSize += OBJECT_INFO_BUFFER; + + #if !defined(DYNAMIC_POOL) && !defined(STATIC_POOL) // set custom blocks if pool is not used @@ -266,11 +272,12 @@ __Allocator *memory_get_allocator(size32_type size) { * the fixed block allocators * * @param size the client's requested size of the block + * @param anObject specify if the memory will be used object(s) or fundamental types * @return a pointer to the memory block */ -void *__memory_alloc(size32_type size) { +void *__memory_alloc(size32_type size, bool anObject) { // Allocate a raw memory block - __Allocator *allocator = memory_get_allocator(size); + __Allocator *allocator = memory_get_allocator(size, anObject); // if not enough sizes available if (allocator == nullptr) { @@ -285,7 +292,7 @@ void *__memory_alloc(size32_type size) { // give a block from them if available size32_type currBlockSize = allocator->getBlockSize(); if (currBlockSize < __allocators[MAX_ALLOCATORS - 1]->getBlockSize()) { - return __memory_alloc(currBlockSize + 1); + return __memory_alloc(currBlockSize + 1, anObject); } return nullptr; @@ -357,7 +364,7 @@ void __memory_free(void *ptr) { */ void *__memory_realloc(void *oldMem, size32_type size) { if (oldMem == nullptr) { - return __memory_alloc(size); + return __memory_alloc(size, false); } if (size == 0) { @@ -365,7 +372,7 @@ void *__memory_realloc(void *oldMem, size32_type size) { return nullptr; } else { // Create a new memory block - void *newMem = __memory_alloc(size); + void *newMem = __memory_alloc(size, false); if (newMem != nullptr) { // Get the original allocator instance from the old memory block __Allocator *oldAllocator = get_block_allocator(oldMem); diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index b9db1338..133ace1a 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -51,7 +51,7 @@ static MemoryInitDestroy __g_smemoryInitDestroy; * Used internally not for client's use * Use the @code malloc @endcode function */ -void *__memory_alloc(uint32_t size); +void *__memory_alloc(uint32_t size, bool anObject); /** * Used internally not for client's use @@ -84,17 +84,26 @@ void __memory_free(void *ptr); * @return address to memory allocated */ template -Type *malloc(wlp::size32_type num = 1) { - void *memory = __memory_alloc(static_cast(sizeof(Type)) * num); +Type *malloc(wlp::size_type num = 1) { + void *memory = nullptr; if (!wlp::is_fundamental::value) { - char *pointer = static_cast(memory); - for (wlp::size32_type i = 0; i < num; ++i) { + memory = __memory_alloc(static_cast(sizeof(Type)) * num, true); + + uint16_t *objInfo = static_cast(memory); + *objInfo = static_cast(num); + + char *pointer = reinterpret_cast(++objInfo); + for (wlp::size_type i = 0; i < num; ++i) { new(pointer) Type; pointer += sizeof(Type); } + + return reinterpret_cast(objInfo); } + memory = __memory_alloc(static_cast(sizeof(Type)) * num, false); + return static_cast(memory); } @@ -138,16 +147,19 @@ wlp::size32_type getFixedMemorySize(void *ptr); template void free(Type *ptr) { if (!wlp::is_fundamental::value) { - wlp::size32_type num = static_cast(getFixedMemorySize(ptr) / sizeof(Type)); + uint16_t *objInfo = reinterpret_cast(ptr); + wlp::size_type numObjects = *(--objInfo); Type *pointer = ptr; - for (wlp::size32_type i = 0; i < num; ++i) { + for (wlp::size_type i = 0; i < numObjects; ++i) { pointer->~Type(); ++pointer; } - } - __memory_free(ptr); + __memory_free(reinterpret_cast(objInfo)); + } else{ + __memory_free(ptr); + } } /** @@ -219,5 +231,4 @@ uint16_t getMaxAllocations(); */ wlp::size_type getSmallestBlockSize(); - #endif //FIXED_MEMORY_MEMORY_H diff --git a/lib/wlib/strings/StaticString.h b/lib/wlib/strings/StaticString.h index dacbcd69..af90ce34 100644 --- a/lib/wlib/strings/StaticString.h +++ b/lib/wlib/strings/StaticString.h @@ -260,7 +260,7 @@ namespace wlp { for (size_type i = bufferLength; i < bufferLength + otherLength && i < capacity(); i++) { m_buffer[i] = str[i - bufferLength]; } - m_len = MIN(tSize, bufferLength + otherLength); + m_len = static_cast(MIN(tSize, bufferLength + otherLength)); m_buffer[m_len] = '\0'; return *this; } diff --git a/lib/wlib/utility/Tmp.h b/lib/wlib/utility/Tmp.h index 2b4fed83..aac823c9 100644 --- a/lib/wlib/utility/Tmp.h +++ b/lib/wlib/utility/Tmp.h @@ -134,6 +134,22 @@ namespace wlp { typedef T type; }; + template + struct remove_volatile { + typedef _Tp type; + }; + + template + struct remove_volatile<_Tp volatile> { + typedef _Tp type; + }; + + template + struct remove_cv { + typedef typename + remove_const::type>::type type; + }; + /** * Base declaration for a boolean or. * @tparam ... ignored parameteres @@ -278,6 +294,24 @@ namespace wlp { : public or_, is_rvalue_reference>::type { }; + template + struct __remove_pointer__ { + typedef T type; + }; + + template + struct __remove_pointer__ { + typedef U type; + }; + + template + struct remove_pointer + : public __remove_pointer__::type> { + }; + + template + using remove_pointer_type = typename remove_pointer::type; + /** * Remove reference type. Base case for non-reference types. * @tparam T non-reference type @@ -709,22 +743,6 @@ namespace wlp { return __declval__::__delegate__(); } - template - struct remove_volatile { - typedef _Tp type; - }; - - template - struct remove_volatile<_Tp volatile> { - typedef _Tp type; - }; - - template - struct remove_cv { - typedef typename - remove_const::type>::type type; - }; - template struct __is_null_pointer_helper : public false_type { @@ -783,7 +801,8 @@ namespace wlp { #ifdef _GLIBCXX_USE_WCHAR_T template<> struct __is_integral_helper - : public true_type { }; + : public true_type { + }; #endif template<> @@ -869,7 +888,8 @@ namespace wlp { #if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) template<> struct __is_floating_point_helper<__float128> - : public true_type { }; + : public true_type { + }; #endif /** diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 544be407..b4fcd1d0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ file(GLOB files "template_defs.h" "strings/*.cpp" "stl/*.cpp" + "fsm/*.cpp" "memory/*.cpp") add_executable(tests ${files}) diff --git a/tests/fsm/fsm_check.cpp b/tests/fsm/fsm_check.cpp new file mode 100644 index 00000000..72ac933e --- /dev/null +++ b/tests/fsm/fsm_check.cpp @@ -0,0 +1,129 @@ +#include "gtest/gtest.h" +#include "fsm/StateMachine.h" +#include "stl/ArrayList.h" + +using namespace wlp; + +class TestData : public EventData { +public: + int value; +}; + +class TestMachine : public StateMachine { +public: + TestMachine() + : StateMachine(States::ST_MAX_STATES, States::ST_IDLE), + m_value(0) { + } + + void setValue(int value) { + TestData data; + data.value = value; + BEGIN_TRANSITION_MAP + TRANSITION_MAP_ENTRY(ST_START) // ST_IDLE + TRANSITION_MAP_ENTRY(CANNOT_HAPPEN) // ST_STOP + TRANSITION_MAP_ENTRY(ST_CHANGE_SPEED) // ST_START + TRANSITION_MAP_ENTRY(ST_CHANGE_SPEED) // ST_CHANGE_SPEED + END_TRANSITION_MAP(&data, TestData) + } + + void zero() { + BEGIN_TRANSITION_MAP + TRANSITION_MAP_ENTRY(EVENT_IGNORED) + TRANSITION_MAP_ENTRY(CANNOT_HAPPEN) + TRANSITION_MAP_ENTRY(ST_STOP) + TRANSITION_MAP_ENTRY(ST_STOP) + END_TRANSITION_MAP(nullptr, NoEventData) + } + + int m_value; + /** + * Used to trace the order of state transitions to + * verify validity. + */ + ArrayList state_trace{25}; + + enum States { + ST_IDLE, + ST_STOP, + ST_START, + ST_CHANGE_SPEED, + ST_MAX_STATES + }; + +private: + STATE_DECLARE(TestMachine, Idle) + STATE_DECLARE(TestMachine, Stop) + STATE_DECLARE(TestMachine, Start, TestData) + STATE_DECLARE(TestMachine, ChangeSpeed, TestData) + + BEGIN_STATE_MAP + STATE_MAP_ENTRY(&Idle) + STATE_MAP_ENTRY(&Stop) + STATE_MAP_ENTRY(&Start) + STATE_MAP_ENTRY(&ChangeSpeed) + END_STATE_MAP +}; + +STATE_DEFINE(TestMachine, Idle) { + state_trace.push_back((int) ST_IDLE); +} + +STATE_DEFINE(TestMachine, Stop) { + state_trace.push_back((int) ST_STOP); + m_value = 0; + internalEvent(ST_IDLE); +} + +STATE_DEFINE(TestMachine, Start, TestData) { + state_trace.push_back((int) ST_START); + m_value = data->value; +} + +STATE_DEFINE(TestMachine, ChangeSpeed, TestData) { + state_trace.push_back((int) ST_CHANGE_SPEED); + m_value = data->value; + if (m_value == 0) { + internalEvent(ST_IDLE); + } +} + +TEST(fsm_test, test_machine_transitions) { + TestMachine sm{}; + int expected = TestMachine::States::ST_IDLE; + int current = sm.getCurrentState(); + ASSERT_EQ(expected, current); + ASSERT_EQ(0, sm.state_trace.size()); + sm.zero(); + // Event is ignored + ASSERT_EQ(0, sm.state_trace.size()); + sm.setValue(10); + ASSERT_EQ(10, sm.m_value); + sm.zero(); + ASSERT_EQ(0, sm.m_value); + sm.setValue(15); + ASSERT_EQ(15, sm.m_value); + sm.setValue(20); + ASSERT_EQ(20, sm.m_value); + sm.zero(); + ASSERT_EQ(0, sm.m_value); + sm.zero(); + ASSERT_EQ(0, sm.m_value); + int idle = TestMachine::States::ST_IDLE; + int stop = TestMachine::States::ST_STOP; + int start = TestMachine::States::ST_START; + int changeSpeed = TestMachine::States::ST_CHANGE_SPEED; + int expected_state_traverse[] = { + start, + stop, + idle, + start, + changeSpeed, + stop, + idle + }; + ASSERT_EQ(7, sm.state_trace.size()); + for (int i = 0; i < sm.state_trace.size(); i++) { + ASSERT_EQ(expected_state_traverse[i], (int) sm.state_trace[(size_type) i]); + } +} diff --git a/tests/memory/memory_check.cpp b/tests/memory/memory_check.cpp index a8d39736..9836a2de 100644 --- a/tests/memory/memory_check.cpp +++ b/tests/memory/memory_check.cpp @@ -12,8 +12,8 @@ #include "memory/Memory.h" class Sample{ - int constr = 0; public: + static int constr; Sample(){ constr += 4; @@ -22,12 +22,10 @@ class Sample{ ~Sample(){ constr += 5; } - - int getConstr(){ - return constr; - } }; +int Sample::constr = 0; + TEST(memory_check, general_usability) { ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); ASSERT_TRUE(isSizeAvailable(16)); @@ -52,13 +50,14 @@ TEST(memory_check, general_usability) { character4 = realloc(character4, 8); // create an object + Sample::constr = 0; auto *test = malloc(); - ASSERT_EQ(4, test->getConstr()); + ASSERT_EQ(4, Sample::constr); free(character4); free(test); - ASSERT_EQ(9, test->getConstr()); + ASSERT_EQ(9, Sample::constr); ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); } @@ -85,11 +84,13 @@ TEST(memory_check, malloc_and_realloc){ } TEST(memory_check, array_allocation){ + Sample::constr = 0; + Sample *s = malloc(2); - ASSERT_EQ(8, s[0].getConstr() + s[1].getConstr()); + ASSERT_EQ(8, Sample::constr); free(s); - ASSERT_EQ(18, s[0].getConstr() + s[1].getConstr()); + ASSERT_EQ(18, Sample::constr); } TEST(memory_check, free){ From ac5f309970d747ecb3a5cbb0d5829b5f2eb20529 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 20 Nov 2017 19:25:22 -0800 Subject: [PATCH 019/102] [Lib] Red black tree, Tree Map, Tree Set (#50) * red black tree * Created tree map and set * Updated with new memory * Fixes include path --- lib/wlib/stl/ChainSet.h | 8 +- lib/wlib/stl/OpenSet.h | 6 +- lib/wlib/stl/RedBlackTree.h | 1253 ++++++++++++++++++++++++++++ lib/wlib/stl/TreeMap.h | 152 ++++ lib/wlib/stl/TreeSet.h | 126 +++ tests/CMakeLists.txt | 2 +- tests/stl/red_black_tree_check.cpp | 145 ++++ tests/test_helper.h | 18 + wmake | 12 + 9 files changed, 1714 insertions(+), 8 deletions(-) create mode 100644 lib/wlib/stl/RedBlackTree.h create mode 100644 lib/wlib/stl/TreeMap.h create mode 100644 lib/wlib/stl/TreeSet.h create mode 100644 tests/stl/red_black_tree_check.cpp create mode 100644 tests/test_helper.h diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index 9daacc6d..3d7b4598 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -35,9 +35,9 @@ namespace wlp { typedef ChainHashMap map_type; typedef ChainHashMapIterator iterator; typedef ChainHashMapConstIterator const_iterator; - typedef map_type::size_type size_type; - typedef map_type::percent_type percent_type; - typedef map_type::key_type key_type; + typedef typename map_type::size_type size_type; + typedef typename map_type::percent_type percent_type; + typedef typename map_type::key_type key_type; private: map_type m_hash_map; @@ -100,7 +100,7 @@ namespace wlp { /** * @return a pointer to the backing hash map */ - const map_type *get_backing_hash_map() const { + const map_type *get_backing_table() const { return &m_hash_map; } diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index 663138fb..8a8459f2 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -36,9 +36,9 @@ namespace wlp { typedef OpenHashMap map_type; typedef OpenHashMapIterator iterator; typedef OpenHashMapConstIterator const_iterator; - typedef map_type::size_type size_type; - typedef map_type::percent_type percent_type; - typedef map_type::key_type key_type; + typedef typename map_type::size_type size_type; + typedef typename map_type::percent_type percent_type; + typedef typename map_type::key_type key_type; private: /** diff --git a/lib/wlib/stl/RedBlackTree.h b/lib/wlib/stl/RedBlackTree.h new file mode 100644 index 00000000..41ed4fe4 --- /dev/null +++ b/lib/wlib/stl/RedBlackTree.h @@ -0,0 +1,1253 @@ +/** + * @file RedBlackTree.h + * @brief Red black tree implementation. + * + * Implements a red black tree structure for use in other + * data structures using non-recursive methods. + * + * @author Jeff Niu + * @date November 12, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_REDBLACKTREE_H +#define EMBEDDEDCPLUSPLUS_REDBLACKTREE_H + +#include "Comparator.h" +#include "Pair.h" + +#include "../Types.h" +#include "../utility/Utility.h" + +namespace wlp { + + /** + * Tree node color, either red or black. + */ + struct RedBlackTreeColor { + /** + * Color type. + */ + typedef bool type; + /** + * Red node. + */ + static constexpr type RED = false; + /** + * Black node. + */ + static constexpr type BLACK = true; + }; + + /** + * Tree node contains the node key and value. + * + * @tparam Key key type + * @tparam Val value type + */ + template + struct RedBlackTreeNode { + typedef RedBlackTreeNode node_type; + typedef Key key_type; + typedef Val val_type; + + private: + typedef RedBlackTreeColor::type color; + + + public: + /** + * The node color. + */ + color m_color; + + /** + * Node parent. + */ + node_type *m_parent; + /** + * Left child node. + */ + node_type *m_left; + /** + * Right child node. + */ + node_type *m_right; + + /** + * Node key, used for ordering and comparisons. + */ + key_type m_key; + /** + * Node value, accessed using the node key. + */ + val_type m_val; + + /** + * Obtain the minimum key node starting from the given node. + * + * @param node from which to find the minimum + * @return pointer to the node with the smallest key + */ + static node_type *find_minimum(node_type *node) { + while (node->m_left) { + node = node->m_left; + } + return node; + } + + /** + * Obtain the maximum key node starting from the given node. + * + * @param node from which to find the maximum + * @return pointer to the node with the largest key + */ + static node_type *find_maximum(node_type *node) { + while (node->m_right) { + node = node->m_right; + } + return node; + } + }; + + /** + * Tree iterator class, templated to enable constant and non-constant + * derived types. This class should not be used directly. + * + * @tparam Key the node key type + * @tparam Val the node value type + * @tparam Ref reference to value type, which may be a constant reference + * @tparam Ptr pointer to value type, which may be a constant pointer + */ + template + struct RedBlackTreeIterator { + typedef RedBlackTreeNode node_type; + typedef RedBlackTreeIterator iterator; + typedef RedBlackTreeIterator const_iterator; + typedef RedBlackTreeColor color; + typedef Ref reference; + typedef Ptr pointer; + typedef Key key_type; + typedef Val val_type; + + private: + typedef RedBlackTreeIterator self_type; + + public: + /** + * The tree node pointed to by this iterator. + */ + node_type *m_node; + + /** + * Constructor from node. + * + * @param node to point to + */ + RedBlackTreeIterator(node_type *node) + : m_node(node) { + } + + /** + * Constructor from constant reference. + * + * @param it iterator to copy + */ + RedBlackTreeIterator(const self_type &it) + : m_node(it.m_node) { + } + + /** + * Move the iterator to the next ordered node in the tree. + */ + void increment() { + if (m_node->m_right) { + m_node = m_node->m_right; + while (m_node->m_left) { + m_node = m_node->m_left; + } + } else { + node_type *parent = m_node->m_parent; + while (m_node == parent->m_right) { + m_node = parent; + parent = parent->m_parent; + } + if (m_node->m_right != parent) { + m_node = parent; + } + } + } + + /** + * Move the iterator to the previous ordered node in the tree. + */ + void decrement() { + if (m_node->m_color == color::RED && m_node->m_parent->m_parent == m_node) { + m_node = m_node->m_right; + } else if (m_node->m_left) { + node_type *child = m_node->m_left; + while (child->m_right) { + child = child->m_right; + } + m_node = child; + } else { + node_type *parent = m_node->m_parent; + while (m_node == parent->m_left) { + m_node = parent; + parent = parent->m_parent; + } + m_node = parent; + } + } + + /** + * Iterator equality operator. + * + * @param it iterator to compare + * @return true if they point to the same node + */ + bool operator==(const self_type &it) const { + return m_node == it.m_node; + } + + /** + * Iterator inequality operator. + * + * @param it iterator to compare + * @return true if they point to different nodes + */ + bool operator!=(const self_type &it) const { + return m_node != it.m_node; + } + + /** + * Deference operator. + * + * @return reference to the value of the node + * pointed to by the iterator + */ + reference operator*() const { + return m_node->m_val; + } + + /** + * Pointer operator. + * + * @return pointer to the value of the node + * pointer to by the iterator + */ + pointer operator->() const { + return &m_node->m_val; + } + + /** + * Prefix increment operator moves the iterator to the next + * ordered node in the tree, or pass-the-end if the + * iterator has reached the rightmost end of the tree. + * + * @return reference to this iterator + */ + self_type &operator++() { + increment(); + return *this; + } + + /** + * Postfix increment operator moves the iterator to the next + * ordered node in the tree, or pass-the-end if the + * iterator has reached the rightmost end of the tree. + * + * @return a copy of the iterator before the increment + */ + self_type operator++(int) { + iterator tmp = *this; + increment(); + return tmp; + } + + /** + * Prefix decrement operator moves the iterator to the previous + * ordered node in the tree. Iterator does not move past the begin. + * + * @return reference to this iterator + */ + self_type &operator--() { + decrement(); + return *this; + } + + /** + * Postfix decrement operator moves the iterator to the previous + * ordered node in the tree. Iterator does not move past the begin. + * + * @return a copy of the iterator before the increment + */ + self_type operator--(int) { + iterator tmp = *this; + decrement(); + return tmp; + } + + /** + * @return a reference to the key contained by the iterator node + */ + const key_type &key() const { + return m_node->m_key; + } + + /** + * Copy assignment operator. + * + * @param it iterator to assign + * @return reference to this iterator + */ + self_type &operator=(const self_type &it) { + m_node = it.m_node; + return *this; + } + + }; + + /** + * Red black tree implementation, designed for use in associative + * container implementation, e.g. @code Map @endcode and @code Set @endcode. + * The insertion and deletion operations are based on those in CLRS. + * + * @tparam Key node key type + * @tparam Val node value type + * @tparam Cmp key comparator type, which uses the default comparator + */ + template> + class RedBlackTree { + public: + typedef Key key_type; + typedef Val val_type; + typedef Cmp comparator; + typedef wlp::size_type size_type; + typedef RedBlackTreeNode node_type; + typedef RedBlackTree tree_type; + typedef RedBlackTreeIterator iterator; + typedef RedBlackTreeIterator const_iterator; + + protected: + typedef RedBlackTreeColor color; + + /** + * Header node, which maintains reference to the leftmost node, + * the rightmost node, and the root node. + */ + node_type *m_header; + /** + * The number of nodes currently in the tree. + */ + size_type m_size; + /** + * Class comparator instance. + */ + comparator m_cmp; + + /** + * Allocate a new node. + * + * @return pointer to the new node + */ + node_type *create_node() { + return malloc(); + } + + /** + * Copy the contents of a node except for its paremt. + * + * @param node the tree node to copy + * @return a copy of the node + */ + node_type *copy_node(node_type *node) { + node_type *copy = create_node(); + copy->m_key = node->m_key; + copy->m_val = node->m_val; + copy->m_color = node->m_color; + copy->m_left = node->m_left; + copy->m_right = node->m_right; + return copy; + } + + /** + * Deallocate the given node. + * + * @param node node to deallocate + */ + void destroy_node(node_type *node) { + free(node); + } + + /** + * Perform red-black tree left rotation of the specified + * node about the specified root. + * + * @param node the node to rotate + * @param root the rotate root node + */ + void rotateLeft(node_type *node, node_type *&root); + + /** + * Perform red-black tree right rotation of the specified + * node about the specified root. + * + * @param node the node to rotate + * @param root the rotate root node + */ + void rotateRight(node_type *node, node_type *&root); + + /** + * Perform red-black tree rebalance of a potentially + * erroneous node starting from the given root. + * + * @param node the node to rebalance + * @param root the rebalance root node + */ + void rebalance(node_type *node, node_type *&root); + + /** + * Rebalance for erasure the given node. The node is eliminated + * from the tree during the rebalance and is prepared for deletion. + * + * @param node the node to delete + * @param root the root node in the tree + * @param leftmost the leftmost node in the tree + * @param rightmost the right most node in the tree + * @return a pointer to the node that can be deleted + */ + node_type *eraseRebalance( + node_type *node, + node_type *&root, + node_type *&leftmost, + node_type *&rightmost + ); + + /** + * Insert a given node at the pivot position, which will become + * the parent node of the inserted node. + * + * @param node the node to insert + * @param piv the insertion pivot node + * @param key the key to insert + * @param val the value to insert + * @return iterator to the inserted node + */ + template + iterator insert(node_type *node, node_type *piv, K &&key, V &&val); + + /** + * Delete the supplied node from the tree and all + * nodes beneath it. + * + * @param root the node to delete + */ + void erase(node_type *root); + + /** + * Initialize the tree as empty, where the header + * node children are itself and the parent is null. + */ + void empty_initialize() { + m_header->m_color = color::RED; + m_header->m_parent = nullptr; + m_header->m_left = m_header; + m_header->m_right = m_header; + } + + public: + /** + * Create an empty red black tree. + * + * @param n reserved space for nodes + */ + explicit RedBlackTree() + : m_header(nullptr), + m_size(0), + m_cmp() { + m_header = create_node(); + empty_initialize(); + } + + /** + * Disable copy construction. + */ + RedBlackTree(const tree_type &) = delete; + + /** + * Move constructor. + * + * @param tree tree to move + */ + RedBlackTree(tree_type &&tree) + : m_header(move(tree.m_header)), + m_size(move(tree.m_size)), + m_cmp() { + tree.m_header = nullptr; + tree.m_size = 0; + } + + /** + * Destructor. + */ + ~RedBlackTree() { + clear(); + if (m_header) { + destroy_node(m_header); + } + } + + /** + * @return an iterator to the leftmost node in the tree + */ + iterator begin() { + return iterator(m_header->m_left); + } + + /** + * @return a const iterator to the leftmost node in the tree + */ + const_iterator begin() const { + return const_iterator(m_header->m_left); + } + + /** + * @return an iterator to the header node, which is the + * pass-the-end node after the rightmost node + */ + iterator end() { + return iterator(m_header); + } + + /** + * @return a const iterator to the header node, which is the + * pass-the-end node after the rightmost node + */ + const_iterator end() const { + return const_iterator(m_header); + } + + /** + * @return whether the tree has no nodes + */ + bool empty() const { + return m_size == 0; + } + + /** + * @return the number of nodes in the tree + */ + size_type size() const { + return m_size; + } + + /** + * The maximum number of nodes that can be held in the + * tree. The tree is not intrinsically limited by any limit + * except that its size cannot exceed the defined size type. + * + * @return the maximum value of size_type + */ + size_type capacity() const { + return static_cast(-1); + } + + /** + * Delete all the nodes in the tree such that it is now empty. + */ + void clear() noexcept { + if (m_size > 0) { + erase(m_header->m_parent); + m_header->m_parent = nullptr; + m_header->m_left = m_header; + m_header->m_right = m_header; + m_size = 0; + } + } + + /** + * Insert a value with a given key into the tree. This function + * will insert the value if its key does not exist and fail + * if the key already exists. + * + * @param key key to insert + * @param val value to insert + * @return a pair consisting of an iterator to the inserted node + * or the node that prevented insertion and a flag indicating + * whether insertion occurred + */ + template + Pair insert_unique(K &&key, V &&val); + + /** + * Insert a value with a given key into the tree. This function + * will always insert the value, allowing duplicate keys. + * + * @param key key to insert + * @param val value to insert + * @return iterator to the inserted node + */ + template + iterator insert_equal(K &&key, V &&val); + + /** + * Delete the node pointed to by the provided iterator. + * + * @param pos iterator whose node to delete + */ + void erase(const iterator &pos); + + /** + * Erase all nodes in the tree that have the provided key. + * For containers not allowing multiple keys, the returned value + * is never greater than 1. + * + * @param key the key all of whose associated nodes are to be deleted + * @return the number of deleted nodes + */ + size_type erase(const key_type &key); + + /** + * Erase all nodes starting from the first iterator to before the + * last iterator, such that the nodes @code [first, last) @endcode + * are deleted and the size of the tree is reduced by + * @code last - first @endcode. + * + * @param first iterator to the first nodes to delete + * @param last iterator to the last nodes to delete + * @return the number of deleted nodes + */ + size_type erase(const iterator &first, const iterator &last); + + /** + * Obtain an iterator to the first node in the tree + * whose key matches the provided key. Returns pass-the-end + * if no node in the tree has the provided key. + * + * @param key the key for which to obtain the first node + * @return iterator to the first node with the key or pass-the-end + */ + iterator find(const key_type &key); + + /** + * Obtain a const iterator to the first node in the tree + * whose key matches the provided key. Returns pass-the-end + * if no node in the tree has the provided key. + * + * @param key the key for which to obtain the first node + * @return const iterator to the first node with the key or pass-the-end + */ + const_iterator find(const key_type &key) const; + + /** + * Obtain the number of nodes in the tree that have + * the provided key as their keys. + * + * @param key the key whose nodes to count + * @return the number of nodes with the key + */ + size_type count(const key_type &key) const; + + /** + * Obtain an iterator to the first node in the tree by natural + * order that has the provided key. Returns pass-the-end if + * there are no nodes with the provided key. + * + * @pre The returned value is such that all nodes with the provided + * key are in the range @code [lower_bound(key), upper_bound(key)) @endcode. + * + * @param key the key whose first node to find + * @return iterator to the first node with the key + */ + iterator lower_bound(const key_type &key); + + /** + * Obtain an iterator to the node right after the last node in the + * tree by natural order that has the provided key. May return pass-the-end + * if the key is the largest key in the tree, or if the key is not found. + * + * @pre The returned value is such that all nodes with the provided + * key are in the range @code [lower_bound(key), upper_bound(key)) @endcode. + * + * @param key the key whose last node to find + * @return iterator to the node right after the last node + */ + iterator upper_bound(const key_type &key); + + /** + * Obtain a const iterator to the first node in the tree by natural + * order that has the provided key. Returns pass-the-end if + * there are no nodes with the provided key. + * + * @pre The returned value is such that all nodes with the provided + * key are in the range @code [lower_bound(key), upper_bound(key)) @endcode. + * + * @param key the key whose first node to find + * @return const iterator to the first node with the key + */ + const_iterator lower_bound(const key_type &key) const; + +/** + * Obtain a const iterator to the node right after the last node in the + * tree by natural order that has the provided key. May return pass-the-end + * if the key is the largest key in the tree, or if the key is not found. + * + * @pre The returned value is such that all nodes with the provided + * key are in the range @code [lower_bound(key), upper_bound(key)) @endcode. + * + * @param key the key whose last node to find + * @return const iterator to the node right after the last node + */ + const_iterator upper_bound(const key_type &key) const; + + /** + * Obtain the range of nodes whose keys are equal to the provided key + * as per @code lower_bound @endcode and @code upper_bound @endcode. + * + * @param key the key whose range to get + * @return a pair of iterators to the lower and upper bounds + */ + Pair equal_range(const key_type &key); + + /** + * Obtain the range of nodes whose keys are equal to the provided key + * as per @code lower_bound @endcode and @code upper_bound @endcode. + * + * @param key the key whose range to get + * @return a pair of const iterators to the lower and upper bounds + */ + Pair equal_range(const key_type &val) const; + + /** + * Disable copy assignemnt. + * + * @return reference to this tree + */ + tree_type &operator=(const tree_type &) = delete; + + /** + * Move assignment operator. Resources in this tree + * are freed and replaced by moving those from the + * assigned tree. The assigned tree is prepared for + * destrution. + * + * @param tree the tree to move + * @return reference to this tree + */ + tree_type &operator=(tree_type &&tree) { + clear(); + destroy_node(m_header); + m_size = move(tree.m_size); + m_header = move(tree.m_header); + tree.m_size = 0; + tree.m_header = 0; + return *this; + } + + }; + + template + inline void RedBlackTree::rotateLeft(node_type *node, node_type *&root) { + node_type *carry = node->m_right; + node->m_right = carry->m_left; + if (carry->m_left) { + carry->m_left->m_parent = node; + } + carry->m_parent = node->m_parent; + if (node == root) { + root = carry; + } else if (node == node->m_parent->m_left) { + node->m_parent->m_left = carry; + } else { + node->m_parent->m_right = carry; + } + carry->m_left = node; + node->m_parent = carry; + } + + template + inline void RedBlackTree::rotateRight(node_type *node, node_type *&root) { + node_type *carry = node->m_left; + node->m_left = carry->m_right; + if (carry->m_right) { + carry->m_right->m_parent = node; + } + carry->m_parent = node->m_parent; + if (node == root) { + root = carry; + } else if (node == node->m_parent->m_right) { + node->m_parent->m_right = carry; + } else { + node->m_parent->m_left = carry; + } + carry->m_right = node; + node->m_parent = carry; + } + + template + inline void RedBlackTree::rebalance(node_type *node, node_type *&root) { + node->m_color = color::RED; + while (node != root && node->m_parent->m_color == color::RED) { + if (node->m_parent == node->m_parent->m_parent->m_left) { + node_type *carry = node->m_parent->m_parent->m_right; + if (carry && carry->m_color == color::RED) { + node->m_parent->m_color = color::BLACK; + carry->m_color = color::BLACK; + node->m_parent->m_parent->m_color = color::RED; + node = node->m_parent->m_parent; + } else { + if (node == node->m_parent->m_right) { + node = node->m_parent; + rotateLeft(node, root); + } + node->m_parent->m_color = color::BLACK; + node->m_parent->m_parent->m_color = color::RED; + rotateRight(node->m_parent->m_parent, root); + } + } else { + node_type *carry = node->m_parent->m_parent->m_left; + if (carry && carry->m_color == color::RED) { + node->m_parent->m_color = color::BLACK; + carry->m_color = color::BLACK; + node->m_parent->m_parent->m_color = color::RED; + node = node->m_parent->m_parent; + } else { + if (node == node->m_parent->m_left) { + node = node->m_parent; + rotateRight(node, root); + } + node->m_parent->m_color = color::BLACK; + node->m_parent->m_parent->m_color = color::RED; + rotateLeft(node->m_parent->m_parent, root); + } + } + } + root->m_color = color::BLACK; + } + + template + inline typename RedBlackTree::node_type * + RedBlackTree::eraseRebalance( + node_type *node, + node_type *&root, + node_type *&leftmost, + node_type *&rightmost) { + node_type *carry = node; + node_type *cur = 0; + node_type *cur_parent = 0; + if (!carry->m_left) { + // node has at most one non-null child + // carry == node and cur might be null + cur = carry->m_right; + } else if (!carry->m_right) { + // node has exactly one non-null child + // carry == node and cur is not null + cur = carry->m_left; + } else { + // node has two non-null children + // set cur to node's successor and cur might be null + carry = carry->m_right; + while (carry->m_left) { + carry = carry->m_left; + } + cur = carry->m_right; + } + if (carry != node) { + // Relink cur in place of node + // cur is node's successor + node->m_left->m_parent = carry; + carry->m_left = node->m_left; + if (carry != node->m_right) { + cur_parent = carry->m_parent; + if (cur) { + // carry must be a child of m_left + cur->m_parent = carry->m_parent; + } + carry->m_parent->m_left = cur; + carry->m_right = node->m_right; + node->m_right->m_parent = carry; + } else { + cur_parent = carry; + } + if (root == node) { + root = carry; + } else if (node->m_parent->m_left == node) { + node->m_parent->m_left = carry; + } else { + node->m_parent->m_right = carry; + } + carry->m_parent = node->m_parent; + swap(carry->m_color, node->m_color); + // carry now points to node that is deleted + carry = node; + } else { + // here carry == node + cur_parent = carry->m_parent; + if (cur) { + cur->m_parent = carry->m_parent; + } + if (root == node) { + root = cur; + } else if (node->m_parent->m_left == node) { + node->m_parent->m_left = cur; + } else { + node->m_parent->m_right = cur; + } + if (leftmost == node) { + // node->m_left might also be null + if (!node->m_right) { + // makes leftmost == header if node == root + leftmost = node->m_parent; + } else { + leftmost = node_type::find_minimum(cur); + } + } + if (rightmost == node) { + // node->m_rught might also be null + if (!node->m_left) { + // makes rightmost == header if node == root + rightmost = node->m_parent; + } else { + // cur == node->m_left + rightmost = node_type::find_maximum(cur); + } + } + } + if (carry->m_color != color::RED) { + while (cur != root && (!cur || cur->m_color == color::BLACK)) { + if (cur == cur_parent->m_left) { + node_type *aux = cur_parent->m_right; + if (aux->m_color == color::RED) { + aux->m_color = color::BLACK; + cur_parent->m_color = color::RED; + rotateLeft(cur_parent, root); + aux = cur_parent->m_right; + } + if ((!aux->m_left || aux->m_left->m_color == color::BLACK) && + (!aux->m_right || aux->m_right->m_color == color::BLACK)) { + aux->m_color = color::RED; + cur = cur_parent; + cur_parent = cur_parent->m_parent; + } else { + if (!aux->m_right || aux->m_right->m_color == color::BLACK) { + if (aux->m_left) { + aux->m_left->m_color = color::BLACK; + } + aux->m_color = color::RED; + rotateRight(aux, root); + aux = cur_parent->m_right; + } + aux->m_color = cur_parent->m_color; + cur_parent->m_color = color::BLACK; + if (aux->m_right) { + aux->m_right->m_color = color::BLACK; + } + rotateLeft(cur_parent, root); + break; + } + } else { + // same as above but with left and right switched + node_type *aux = cur_parent->m_left; + if (aux->m_color == color::RED) { + aux->m_color = color::BLACK; + cur_parent->m_color = color::RED; + rotateRight(cur_parent, root); + aux = cur_parent->m_left; + } + if ((!aux->m_right || aux->m_right->m_color == color::BLACK) && + (!aux->m_left || aux->m_left->m_color == color::BLACK)) { + aux->m_color = color::RED; + cur = cur_parent; + cur_parent = cur_parent->m_parent; + } else { + if (!aux->m_left || aux->m_left->m_color == color::BLACK) { + if (aux->m_right) { + aux->m_right->m_color = color::BLACK; + } + aux->m_color = color::RED; + rotateLeft(aux, root); + aux = cur_parent->m_left; + } + aux->m_color = cur_parent->m_color; + cur_parent->m_color = color::BLACK; + if (aux->m_left) { + aux->m_left->m_color = color::BLACK; + } + rotateRight(cur_parent, root); + break; + } + } + } + if (cur) { + cur->m_color = color::BLACK; + } + } + return carry; + } + + template + template + typename RedBlackTree::iterator + RedBlackTree::insert(node_type *cur, node_type *carry, K &&key, V &&val) { + node_type *node = create_node(); + node->m_key = forward(key); + node->m_val = forward(val); + if (carry == m_header || cur || m_cmp.__lt__(key, carry->m_key)) { + carry->m_left = node; + if (carry == m_header) { + m_header->m_parent = node; + m_header->m_right = node; + } else if (carry == m_header->m_left) { + m_header->m_left = node; + } + } else { + carry->m_right = node; + if (carry == m_header->m_right) { + m_header->m_right = node; + } + } + node->m_parent = carry; + node->m_left = nullptr; + node->m_right = nullptr; + rebalance(node, m_header->m_parent); + ++m_size; + return iterator(node); + } + + template + template + Pair::iterator, bool> + RedBlackTree::insert_unique(K &&key, V &&val) { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + bool compare = true; + while (cur) { + carry = cur; + compare = m_cmp.__lt__(key, cur->m_key); + cur = compare ? cur->m_left : cur->m_right; + } + iterator tmp = iterator(carry); + if (compare) { + if (tmp == begin()) { + return Pair(insert(cur, carry, forward(key), forward(val)), true); + } else { + --tmp; + } + } + if (m_cmp.__lt__(tmp.m_node->m_key, key)) { + return Pair(insert(cur, carry, forward(key), forward(val)), true); + } + return Pair(tmp, false); + } + + template + template + typename RedBlackTree::iterator + RedBlackTree::insert_equal(K &&key, V &&val) { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + carry = cur; + cur = m_cmp.__lt__(key, cur->m_key) ? cur->m_left : cur->m_right; + } + return insert(cur, carry, forward(key), forward(val)); + } + + template + inline void RedBlackTree::erase(node_type *root) { + node_type *current; + node_type *pre; + node_type *tmp; + if (!root) { + return; + } + current = root; + while (current) { + if (!current->m_left) { + tmp = current; + current = current->m_right; + destroy_node(tmp); + } else { + pre = current->m_left; + while (pre->m_right && pre->m_right != current) { + pre = pre->m_right; + } + if (!pre->m_right) { + pre->m_right = current; + current = current->m_left; + } else { + pre->m_right = nullptr; + tmp = current; + current = current->m_right; + destroy_node(tmp); + } + } + } + } + + template + inline void RedBlackTree::erase(const iterator &pos) { + node_type *carry = eraseRebalance(pos.m_node, m_header->m_parent, m_header->m_left, m_header->m_right); + destroy_node(carry); + --m_size; + } + + template + inline typename RedBlackTree::size_type + RedBlackTree::erase(const key_type &cur) { + Pair res = equal_range(cur); + return erase(res.m_first, res.m_second); + } + + template + inline size_type RedBlackTree::erase(const iterator &first, const iterator &last) { + size_type count; + if (first == begin() && last == end()) { + count = m_size; + clear(); + } else { + count = 0; + iterator tmp = first; + while (tmp != last) { + erase(tmp++); + ++count; + } + } + return count; + } + + template + typename RedBlackTree::iterator + RedBlackTree::find(const key_type &key) { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (!m_cmp.__lt__(cur->m_key, key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + iterator tmp = iterator(carry); + return (tmp == end() || m_cmp.__lt__(key, tmp.m_node->m_key)) ? end() : tmp; + } + + template + typename RedBlackTree::const_iterator + RedBlackTree::find(const key_type &key) const { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (!m_cmp.__lt__(cur->m_key, key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + const_iterator tmp = const_iterator(carry); + return (tmp == end() || m_cmp.__lt__(key, tmp.m_node->m_key)) ? end() : tmp; + } + + template + typename RedBlackTree::size_type + RedBlackTree::count(const key_type &key) const { + Pair res = equal_range(key); + size_type count = 0; + while (res.m_first != res.m_second) { + ++res.m_first; + ++count; + } + return count; + } + + template + typename RedBlackTree::iterator + RedBlackTree::lower_bound(const key_type &key) { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (!m_cmp.__lt__(cur->m_key, key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + return iterator(carry); + } + + template + typename RedBlackTree::iterator + RedBlackTree::upper_bound(const key_type &key) { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (m_cmp.__lt__(key, cur->m_key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + + return iterator(carry); + } + + template + typename RedBlackTree::const_iterator + RedBlackTree::lower_bound(const key_type &key) const { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (!m_cmp.__lt__(cur->m_key, key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + return const_iterator(carry); + } + + template + typename RedBlackTree::const_iterator + RedBlackTree::upper_bound(const key_type &key) const { + node_type *carry = m_header; + node_type *cur = m_header->m_parent; + while (cur) { + if (m_cmp.__lt__(key, cur->m_key)) { + carry = cur; + cur = cur->m_left; + } else { + cur = cur->m_right; + } + } + + return const_iterator(carry); + } + + template + inline Pair< + typename RedBlackTree::iterator, + typename RedBlackTree::iterator + > + RedBlackTree::equal_range(const key_type &key) { + return Pair(lower_bound(key), upper_bound(key)); + } + + + template + inline Pair< + typename RedBlackTree::const_iterator, + typename RedBlackTree::const_iterator + > + RedBlackTree::equal_range(const key_type &key) const { + return Pair(lower_bound(key), upper_bound(key)); + } + +} + +#endif //EMBEDDEDCPLUSPLUS_REDBLACKTREE_H diff --git a/lib/wlib/stl/TreeMap.h b/lib/wlib/stl/TreeMap.h new file mode 100644 index 00000000..5f1fd27b --- /dev/null +++ b/lib/wlib/stl/TreeMap.h @@ -0,0 +1,152 @@ +/** + * @file TreeMap.h + * @brief Map implementation using red black tree. + * + * @author Jeff Niu + * @date November 14, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_TREEMAP_H +#define EMBEDDEDCPLUSPLUS_TREEMAP_H + +#include "../Types.h" +#include "RedBlackTree.h" + +namespace wlp { + + /** + * Map implementation using @code RedBlackTree @endcode as the + * backing data structure. + * + * @see wlp::ChainHashMap + * @see wlp::RedBlackTree + * + * @tparam Key key type + * @tparam Val value type + * @tparam Cmp key comparator type, which uses the default comparator + */ + template> + class TreeMap { + public: + typedef TreeMap map_type; + typedef RedBlackTree table_type; + typedef typename RedBlackTree::node_type node_type; + typedef typename RedBlackTree::iterator iterator; + typedef typename RedBlackTree::const_iterator const_iterator; + typedef typename RedBlackTree::size_type size_type; + + typedef Key key_type; + typedef Val val_type; + + private: + table_type m_tree; + + public: + explicit TreeMap(size_type n = 12) + : m_tree(n) { + } + + TreeMap(const map_type &) = delete; + + TreeMap(map_type &&map) + : m_tree(move(map.m_tree)) { + } + + size_type size() const { + return m_tree.size(); + } + + size_type capacity() const { + return m_tree.capacity(); + } + + bool empty() const { + return m_tree.empty(); + } + + const table_type *get_backing_table() const { + return &m_tree; + } + + iterator begin() { + return m_tree.begin(); + } + + const_iterator begin() const { + return m_tree.begin(); + } + + iterator end() { + return m_tree.end(); + } + + const_iterator end() const { + return m_tree.end(); + } + + void clear() noexcept { + m_tree.clear(); + } + + template + Pair insert(K &&key, V &&val) { + return m_tree.insert_unique(forward(key), forward(val)); + }; + + template + Pair insert_or_assign(K &&key, V &&val) { + Pair result = m_tree.insert_unique(forward(key), forward(val)); + if (!result.m_second) { + *result.m_first = forward(val); + } + return result; + }; + + iterator erase(const iterator &pos) { + iterator tmp = pos; + ++tmp; + m_tree.erase(pos); + return tmp; + } + + bool erase(const key_type &key) { + return m_tree.erase(key) > 0; + } + + val_type &at(const key_type &key) { + return *m_tree.find(key); + } + + const val_type &at(const key_type &key) const { + return *m_tree.find(key); + } + + bool contains(const key_type &key) const { + return m_tree.find(key) != m_tree.end(); + } + + iterator find(const key_type &key) { + return m_tree.find(key); + } + + const_iterator find(const key_type &key) const { + return m_tree.find(key); + } + + val_type &operator[](const key_type &key) { + Pair result = m_tree.insert_unique(key, val_type()); + return *result.m_first; + } + + map_type &operator=(const map_type &) = delete; + + map_type &operator=(map_type &&map) { + m_tree = move(map.m_tree); + return *this; + } + }; + +} + +#endif //EMBEDDEDCPLUSPLUS_TREEMAP_H diff --git a/lib/wlib/stl/TreeSet.h b/lib/wlib/stl/TreeSet.h new file mode 100644 index 00000000..61c7a9c1 --- /dev/null +++ b/lib/wlib/stl/TreeSet.h @@ -0,0 +1,126 @@ +/** + * @file TreeSet.h + * @brief Set implementation using red black tree. + * + * @author Jeff Niu + * @date November 14, 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_TREESET_H +#define EMBEDDEDCPLUSPLUS_TREESET_H + +#include "RedBlackTree.h" + +namespace wlp { + + /** + * Set implementation using @code RedBlackTree @endcode as the + * backing data structure. + * + * @see wlp::ChainHashSet + * @see wlp::RedBlackTree + * + * @tparam Key stored value type + * @tparam Cmp comparator for stored value, which uses the default comparator + */ + template> + class TreeSet { + public: + typedef TreeSet set_type; + typedef RedBlackTree table_type; + typedef typename RedBlackTree::iterator iterator; + typedef typename RedBlackTree::const_iterator const_iterator; + typedef typename RedBlackTree::size_type size_type; + + typedef Key key_type; + + private: + table_type m_tree; + + public: + explicit TreeSet(size_type n = 12) + : m_tree(n) { + } + + TreeSet(const set_type &) = delete; + + TreeSet(set_type &&set) + : m_tree(move(set.m_tree)) { + } + + size_type size() const { + return m_tree.size(); + } + + size_type capacity() const { + return m_tree.capacity(); + } + + bool empty() const { + return m_tree.empty(); + } + + const table_type *get_backing_table() const { + return &m_tree; + } + + iterator begin() { + return m_tree.begin(); + } + + const_iterator begin() const { + return m_tree.begin(); + } + + iterator end() { + return m_tree.end(); + } + + const_iterator end() const { + return m_tree.end(); + } + + void clear() noexcept { + m_tree.clear(); + } + + template + Pair insert(K &&key) { + return m_tree.insert_unique(forward(key), forward(key)); + }; + + bool contains(const key_type &key) const { + return m_tree.find(key) != m_tree.end(); + } + + iterator find(const key_type &key) { + return m_tree.find(key); + } + + const_iterator find(const key_type &key) const { + return m_tree.find(key); + } + + iterator &erase(iterator &pos) { + iterator tmp = pos++; + m_tree.erase(tmp); + return pos; + } + + bool erase(const key_type &key) { + return m_tree.erase(key) > 0; + } + + set_type &operator=(const set_type &) = delete; + + set_type &operator=(set_type &&set) { + m_tree = move(set.m_tree); + return *this; + } + + }; + +} + +#endif //EMBEDDEDCPLUSPLUS_TREESET_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b4fcd1d0..d909efdf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,7 +12,7 @@ include_directories(${WLIB_INCLUDE_DIR}) file(GLOB files "test.cpp" - "template_defs.h" + "*.h" "strings/*.cpp" "stl/*.cpp" "fsm/*.cpp" diff --git a/tests/stl/red_black_tree_check.cpp b/tests/stl/red_black_tree_check.cpp new file mode 100644 index 00000000..a4df6486 --- /dev/null +++ b/tests/stl/red_black_tree_check.cpp @@ -0,0 +1,145 @@ +#include +#include +#include "gtest/gtest.h" + +#include "stl/ArrayList.h" +#include "stl/ArrayHeap.h" +#include "stl/RedBlackTree.h" + +#include "../test_helper.h" + +using namespace wlp; + +typedef RedBlackTree::iterator rbi; +typedef RedBlackTree rb_tree; + +TEST(rb_tree_test, test_insert_iterator_order) { + char keys[] = {'g', 'h', 'j', 'k', 'y', 'c', 'd', 'q', 'w'}; + int vals[] = {5, 1, 0, 9, -1, -4, 12, 10, -66}; + OpenHashMap val_map(20); + RedBlackTree tree; + for (size_type i = 0; i < 9; i++) { + val_map.insert(keys[i], vals[i]); + Pair res = tree.insert_unique(keys[i], vals[i]); + ASSERT_TRUE(res.second()); + ASSERT_EQ(vals[i], *res.first()); + } + ASSERT_EQ(9, tree.size()); + ArrayList key_list(keys, 9); + heap_sort(key_list); + rbi it = tree.begin(); + for (size_type i = 0; i < key_list.size(); i++) { + char expected_key = key_list[i]; + int expected_val = val_map[expected_key]; + char key = it.key(); + int val = *it; + ASSERT_EQ(expected_key, key); + ASSERT_EQ(expected_val, val); + ++it; + } + ASSERT_TRUE(tree.end() == it); +} + +TEST(rb_tree_test, test_insert_unique_find) { + rb_tree tree; + char keys[] = { + 'o', 'y', '8', 'D', 'B', '9', 'e', 'B', '2', '8', + 'P', 'p', 'k', 'j', 'd', 'M', 'm', 'c', 'Z', 'h', + 'd', 'T', 'p', 'o', 'H', 's', 'Y', 'p', 'd', 'L', + 'I', '3', '6', '6', 'L', 'o', '3', 'd', 's', 'G' + }; + int vals[40]; + OpenHashMap val_map(80); + OpenHashSet key_set(80); + for (int i = 0; i < 40; i++) { + vals[i] = random_int(); + Pair res = tree.insert_unique(keys[i], vals[i]); + if (key_set.contains(keys[i])) { + ASSERT_FALSE(res.second()); + } else { + ASSERT_TRUE(res.second()); + } + key_set.insert(keys[i]); + val_map.insert(keys[i], vals[i]); + ASSERT_EQ(val_map[keys[i]], *res.first()); + } + ArrayList key_list(key_set.size()); + for (OpenHashSet::iterator it = key_set.begin(); it != key_set.end(); ++it) { + key_list.push_back(*it); + } + ReverseComparator cmp; + heap_sort(key_list, cmp); + for (int i = 0; i < 40; i++) { + Pair res = tree.insert_unique(keys[i], vals[i]); + ASSERT_FALSE(res.second()); + ASSERT_EQ(val_map[keys[i]], *res.first()); + ASSERT_EQ(keys[i], res.first().key()); + } + ASSERT_EQ(key_set.size(), tree.size()); + int count = 0; + ArrayList::iterator kit = key_list.begin(); + for (rbi it = --tree.end();; --it) { + ASSERT_EQ(*kit, it.key()); + ASSERT_EQ(val_map[*kit], *it); + ++kit; + if (it == tree.begin()) { + break; + } + count++; + if (count >= 40) { + FAIL(); + } + } + for (int i = 0; i < 40; i++) { + ASSERT_EQ(val_map[keys[i]], *tree.find(keys[i])); + } + for (OpenHashSet::iterator it = key_set.begin(); it != key_set.end(); ++it) { + ASSERT_EQ(1, tree.erase(*it)); + } + ASSERT_EQ(0, tree.size()); +} + +TEST(rb_tree_test, test_insert_equal_and_range) { + char keys[] = {'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'd'}; + int values[] = {5, 6, 7, 8, 9, 10, 10, 11, 12, 13}; + ChainHashSet val_set(20); + size_type cnt = 10; + rb_tree tree; + for (int i = 0; i < cnt; i++) { + rbi it = tree.insert_equal(keys[i], values[i]); + ASSERT_EQ(values[i], *it); + ASSERT_EQ(keys[i], it.key()); + val_set.insert(values[i]); + } + char ukeys[] = {'a', 'b', 'c', 'd'}; + int counts[] = {3, 2, 4, 1}; + for (int i = 0; i < 4; i++) { + ASSERT_EQ(counts[i], tree.count(ukeys[i])); + } + bool at_repeat = false; + for (int i = 0; i < 4; i++) { + char ukey = ukeys[i]; + Pair eq_range = tree.equal_range(ukey); + for (rbi it = eq_range.first(); it != eq_range.second(); ++it) { + int val = *it; + if (val == 10) { + if (at_repeat) { + continue; + } + at_repeat = true; + } + ASSERT_TRUE(val_set.contains(val)); + ASSERT_TRUE(val_set.erase(val)); + } + } + ASSERT_TRUE(val_set.empty()); + for (int i = 0; i < 4; i++) { + char ukey = ukeys[i]; + size_type erased = tree.erase(ukey); + ASSERT_EQ(counts[i], erased); + } + ASSERT_EQ(0, tree.size()); + ASSERT_TRUE(tree.empty()); + ASSERT_TRUE(tree.begin() == tree.end()); +} + diff --git a/tests/test_helper.h b/tests/test_helper.h new file mode 100644 index 00000000..23883f34 --- /dev/null +++ b/tests/test_helper.h @@ -0,0 +1,18 @@ +#ifndef EMBEDDEDCPLUSPLUS_TEST_HELPER_H +#define EMBEDDEDCPLUSPLUS_TEST_HELPER_H + +#include + +namespace wlp { + + char random_char() { + return static_cast(rand() % 0x100); + } + + int random_int() { + return rand() % 0x10000; + } + +} + +#endif //EMBEDDEDCPLUSPLUS_TEST_HELPER_H diff --git a/wmake b/wmake index 2cd6d49f..dbf59c7c 100755 --- a/wmake +++ b/wmake @@ -196,6 +196,9 @@ Options: clean Cleans the project and deletes every file from the bin folder run Execute the Examples binary test Execute the Tests binary + rebuild Clean, build, and test + clcov Clean and build, then run coverage + cltest Cleans coverage data, builds, and then test HEREDOC } @@ -245,6 +248,12 @@ _run(){ echo "Execution Finished" } +_cltest() { + find ./bin/tests/CMakeFiles/tests.dir/ -name '*.gcda' -delete + _build + ./bin/tests/tests +} + _test(){ find ./bin/tests/CMakeFiles/tests.dir/ -name '*.gcda' -delete ./bin/tests/tests @@ -282,6 +291,9 @@ _simple() { echo "Rebuilding and coverage" _clean _coverage + elif [ "$1" == 'cltest' ]; then + echo "Fresh testing" + _cltest else _print_help fi From 4a6c9c1ca78e0a48b8109b90bb2fa63b071535f8 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Tue, 21 Nov 2017 07:12:49 -0800 Subject: [PATCH 020/102] Added extra wmake commands (#59) --- wmake | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/wmake b/wmake index dbf59c7c..0a18c5ff 100755 --- a/wmake +++ b/wmake @@ -196,9 +196,9 @@ Options: clean Cleans the project and deletes every file from the bin folder run Execute the Examples binary test Execute the Tests binary - rebuild Clean, build, and test - clcov Clean and build, then run coverage - cltest Cleans coverage data, builds, and then test + rebuild Cleans, builds, and tests the project, add 'notest' to skip tests + clcov Cleans, builds, and runs coverage + cltest Builds and runs tests HEREDOC } @@ -248,12 +248,6 @@ _run(){ echo "Execution Finished" } -_cltest() { - find ./bin/tests/CMakeFiles/tests.dir/ -name '*.gcda' -delete - _build - ./bin/tests/tests -} - _test(){ find ./bin/tests/CMakeFiles/tests.dir/ -name '*.gcda' -delete ./bin/tests/tests @@ -291,9 +285,10 @@ _simple() { echo "Rebuilding and coverage" _clean _coverage - elif [ "$1" == 'cltest' ]; then - echo "Fresh testing" - _cltest + elif [ "$1" == "cltest" ]; then + echo "Building and testing" + _build + _test else _print_help fi From b69d8e3cc0930356abcd9f289ac84805528ab406 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Tue, 21 Nov 2017 07:24:20 -0800 Subject: [PATCH 021/102] Change iterator template parameters to take ref and ptr type (#58) --- lib/wlib/stl/ArrayList.h | 185 ++++------------------- lib/wlib/stl/ChainMap.h | 251 ++++++++++---------------------- lib/wlib/stl/ChainSet.h | 4 +- lib/wlib/stl/LinkedList.h | 123 +++------------- lib/wlib/stl/OpenMap.h | 208 +++++++------------------- lib/wlib/stl/OpenSet.h | 4 +- tests/stl/linked_list_check.cpp | 7 +- tests/template_defs.h | 82 +++++++---- 8 files changed, 234 insertions(+), 630 deletions(-) diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index 343fbaa4..f9ce865c 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -26,15 +26,18 @@ namespace wlp { /** * Array list forward iterator type. + * * @tparam T list element type + * @tparam Ref reference type, which may be const + * @tparam Ptr pointer type, which may be const */ - template + template class ArrayListIterator { public: typedef wlp::size_type size_type; typedef T val_type; typedef ArrayList array_list; - typedef ArrayListIterator iterator; + typedef ArrayListIterator self_type; private: /** @@ -44,7 +47,7 @@ namespace wlp { /** * Pointer to the backing array list. */ - array_list *m_list; + const array_list *m_list; friend class ArrayList; @@ -62,7 +65,7 @@ namespace wlp { * * @param it iterator to copy */ - ArrayListIterator(const iterator &it) + ArrayListIterator(const self_type &it) : m_i(it.m_i), m_list(it.m_list) { check_bounds(); @@ -75,7 +78,7 @@ namespace wlp { * @param i array index * @param list backing array list */ - explicit ArrayListIterator(const size_type &i, array_list *list) + explicit ArrayListIterator(const size_type &i, const array_list *list) : m_i(i), m_list(list) { check_bounds(); @@ -117,7 +120,7 @@ namespace wlp { * * @return reference to this iterator */ - iterator &operator++() { + self_type &operator++() { if (m_i == m_list->m_size) { return *this; } @@ -131,8 +134,8 @@ namespace wlp { * * @return copy of this iterator before increment */ - iterator operator++(int) { - iterator tmp = *this; + self_type operator++(int) { + self_type tmp = *this; ++*this; return tmp; } @@ -145,7 +148,7 @@ namespace wlp { * @param d the number of positions to increment * @return reference to this iterator */ - iterator &operator+=(const size_type &d) { + self_type &operator+=(const size_type &d) { m_i = static_cast(m_i + d); if (m_i > m_list->m_size) { m_i = m_list->m_size; @@ -160,7 +163,7 @@ namespace wlp { * * @return reference to this iterator */ - iterator &operator--() { + self_type &operator--() { if (m_i == 0) { return *this; } @@ -173,8 +176,8 @@ namespace wlp { * * @return a copy of the iterator before moving */ - iterator operator--(int) { - iterator tmp = *this; + self_type operator--(int) { + self_type tmp = *this; --*this; return tmp; } @@ -186,7 +189,7 @@ namespace wlp { * @param d the number of elements to move back * @return reference to this iterator */ - iterator &operator-=(const size_type &d) { + self_type &operator-=(const size_type &d) { if (d >= m_i) { m_i = 0; } else { @@ -199,7 +202,7 @@ namespace wlp { * @param it iterator to compare * @return true if they point to the same element */ - bool operator==(const iterator &it) const { + bool operator==(const self_type &it) const { return m_i == it.m_i; } @@ -207,7 +210,7 @@ namespace wlp { * @param it iterator to compare * @return true if they point to different elements */ - bool operator!=(const iterator &it) const { + bool operator!=(const self_type &it) const { return m_i != it.m_i; } @@ -217,7 +220,7 @@ namespace wlp { * @param it iterator to copy * @return reference to this iterator */ - iterator &operator=(const iterator &it) { + self_type &operator=(const self_type &it) { m_i = it.m_i; m_list = it.m_list; return *this; @@ -230,8 +233,8 @@ namespace wlp { * @param d number of positions to increment * @return */ - iterator operator+(const size_type &d) const { - return iterator(static_cast(m_i + d), m_list); + self_type operator+(const size_type &d) const { + return self_type(static_cast(m_i + d), m_list); } /** @@ -241,8 +244,8 @@ namespace wlp { * @param d number of positions to decrement * @return a new iterator */ - iterator operator-(const size_type &d) const { - return iterator(static_cast(m_i - d), m_list); + self_type operator-(const size_type &d) const { + return self_type(static_cast(m_i - d), m_list); } /** @@ -252,138 +255,7 @@ namespace wlp { * @param it iterator to subtract * @return the integer distance */ - size_type operator-(const iterator &it) const { - if (m_i < it.m_i) { - return static_cast(it.m_i - m_i); - } - return static_cast(m_i - it.m_i); - } - - }; - - /** - * Const iterator for array list. - * - * @see ArrayListIterator - * @tparam T iterator value type - */ - template - class ArrayListConstIterator { - public: - typedef wlp::size_type size_type; - typedef T val_type; - typedef ArrayList array_list; - typedef ArrayListConstIterator const_iterator; - - private: - size_type m_i; - const array_list *m_list; - - friend class ArrayList; - - public: - ArrayListConstIterator() - : m_i(static_cast(-1)), - m_list(nullptr) { - } - - ArrayListConstIterator(const const_iterator &it) - : m_i(it.m_i), - m_list(it.m_list) { - check_bounds(); - } - - explicit ArrayListConstIterator(const size_type &i, const array_list *list) - : m_i(i), - m_list(list) { - check_bounds(); - } - - private: - void check_bounds() { - if (m_i > m_list->m_size) { - m_i = m_list->m_size; - } - } - - public: - - val_type &operator*() const { - return m_list->m_data[m_i]; - } - - val_type *operator->() const { - return &(operator*()); - } - - const_iterator &operator++() { - if (m_i == m_list->m_size) { - return *this; - } - ++m_i; - return *this; - } - - const_iterator operator++(int) { - const_iterator tmp = *this; - ++*this; - return tmp; - } - - const_iterator &operator+=(const size_type &d) { - m_i = static_cast(m_i + d); - if (m_i > m_list->m_size) { - m_i = m_list->m_size; - } - return *this; - } - - const_iterator &operator--() { - if (m_i == 0) { - return *this; - } - --m_i; - return *this; - } - - const_iterator operator--(int) { - const_iterator tmp = *this; - --*this; - return tmp; - } - - const_iterator &operator-=(const size_type &d) { - if (d >= m_i) { - m_i = 0; - } else { - m_i = static_cast(m_i - d); - } - return *this; - } - - bool operator==(const const_iterator &it) const { - return m_i == it.m_i; - } - - bool operator!=(const const_iterator &it) const { - return m_i != it.m_i; - } - - const_iterator &operator=(const const_iterator &it) { - m_i = it.m_i; - m_list = it.m_list; - return *this; - } - - const_iterator operator+(const size_type &d) const { - return const_iterator(static_cast(m_i + d), m_list); - } - - const_iterator operator-(const size_type &d) const { - return const_iterator(static_cast(m_i - d), m_list); - } - - size_type operator-(const const_iterator &it) const { + size_type operator-(const self_type &it) const { if (m_i < it.m_i) { return static_cast(it.m_i - m_i); } @@ -404,8 +276,8 @@ namespace wlp { typedef wlp::size_type size_type; typedef T val_type; typedef ArrayList array_list; - typedef ArrayListIterator iterator; - typedef ArrayListConstIterator const_iterator; + typedef ArrayListIterator iterator; + typedef ArrayListIterator const_iterator; private: /** @@ -421,9 +293,8 @@ namespace wlp { */ size_type m_capacity; - friend class ArrayListIterator; - - friend class ArrayListConstIterator; + friend class ArrayListIterator; + friend class ArrayListIterator; public: /** diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index 1919db63..3be6a28f 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -23,26 +23,12 @@ namespace wlp { // Forward declaration of ChainHashMap - template + typename Hasher, + typename Equals> class ChainHashMap; - // Forward declaration of ChainHashMap iterator - template - struct ChainHashMapIterator; - - // Forward declaration of const ChainHashMap iterator - template - struct ChainHashMapConstIterator; - /** * Hasher map node comprise the elements of a hash map's * backing array, containing an element key and corresponding value. @@ -50,7 +36,7 @@ namespace wlp { * @tparam Key key type * @tparam Val value type */ - template + template struct ChainHashMapNode { typedef ChainHashMapNode node_type; typedef Key key_type; @@ -87,14 +73,16 @@ namespace wlp { * @tparam Hasher hash function * @tparam Equals key equality function */ - template + template struct ChainHashMapIterator { typedef ChainHashMap map_type; - typedef ChainHashMapIterator iterator; typedef ChainHashMapNode node_type; + typedef ChainHashMapIterator self_type; typedef Val val_type; @@ -107,7 +95,7 @@ namespace wlp { /** * Pointer to the iterated ChainHashMap. */ - map_type *m_hash_map; + const map_type *m_hash_map; /** * Default constructor. @@ -122,7 +110,7 @@ namespace wlp { * @param node hash map node * @param map parent hash map */ - ChainHashMapIterator(node_type *node, map_type *map) + ChainHashMapIterator(node_type *node, const map_type *map) : m_current(node), m_hash_map(map) { } @@ -131,7 +119,7 @@ namespace wlp { * Copy constructor for const. * @param it iterator copy */ - ChainHashMapIterator(const iterator &it) + ChainHashMapIterator(const self_type &it) : m_current(it.m_current), m_hash_map(it.m_hash_map) { } @@ -158,20 +146,20 @@ namespace wlp { * iterator. This is pre-fix unary operator. * @return this iterator */ - iterator &operator++(); + self_type &operator++(); /** * Post-fix unary operator. * @return this iterator */ - iterator operator++(int); + self_type operator++(int); /** * Equality operator for const. * @param it iterator to compare * @return true if they are equal */ - bool operator==(const iterator &it) const { + bool operator==(const self_type &it) const { return m_current == it.m_current; } @@ -181,7 +169,7 @@ namespace wlp { * @param it iterator to compare * @return true if they point to different nodes */ - bool operator!=(const iterator &it) const { + bool operator!=(const self_type &it) const { return m_current != it.m_current; } @@ -191,77 +179,7 @@ namespace wlp { * @param it iterator to copy * @return reference to this iterator */ - iterator &operator=(const iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; - return *this; - } - - }; - - /** - * Constant iterator over a ChainHashMap. Values iterated by - * this class cannot be modified. - * - * @see ChainHashMapIterator - * - * @tparam Key key type - * @tparam Val value type - * @tparam Hasher hash function - * @tparam Equals key equality function - */ - template - struct ChainHashMapConstIterator { - typedef ChainHashMap map_type; - typedef ChainHashMapConstIterator const_iterator; - typedef ChainHashMapNode node_type; - - typedef Val val_type; - - typedef wlp::size_type size_type; - - const node_type *m_current; - const map_type *m_hash_map; - - ChainHashMapConstIterator() - : m_current(nullptr), - m_hash_map(nullptr) { - } - - ChainHashMapConstIterator(node_type *node, const map_type *map) - : m_current(node), - m_hash_map(map) { - } - - ChainHashMapConstIterator(const const_iterator &it) - : m_current(it.m_current), - m_hash_map(it.m_hash_map) { - } - - const val_type &operator*() const { - return m_current->m_val; - } - - const val_type *operator->() const { - return &(operator*()); - } - - const_iterator &operator++(); - - const_iterator operator++(int); - - bool operator==(const const_iterator &it) const { - return m_current == it.m_current; - } - - bool operator!=(const const_iterator &it) const { - return m_current != it.m_current; - } - - const_iterator &operator=(const const_iterator &it) { + self_type &operator=(const self_type &it) { m_current = it.m_current; m_hash_map = it.m_hash_map; return *this; @@ -277,15 +195,15 @@ namespace wlp { * @tparam Hasher hash function * @tparam Equals key equality function */ - template, - class Equals = Equal> + template, + typename Equals = Equal> class ChainHashMap { public: typedef ChainHashMap map_type; - typedef ChainHashMapIterator iterator; - typedef ChainHashMapConstIterator const_iterator; + typedef ChainHashMapIterator iterator; + typedef ChainHashMapIterator const_iterator; typedef ChainHashMapNode node_type; typedef Key key_type; @@ -294,8 +212,8 @@ namespace wlp { typedef wlp::size_type size_type; typedef uint8_t percent_type; - friend struct ChainHashMapIterator; - friend struct ChainHashMapConstIterator; + friend struct ChainHashMapIterator; + friend struct ChainHashMapIterator; private: /** @@ -486,7 +404,7 @@ namespace wlp { } /** - * @see ChainHashMap::begin() + * @see ChainHashMap::begin() * @return a constant iterator to the first element */ const_iterator begin() const { @@ -502,7 +420,7 @@ namespace wlp { } /** - * @see ChainHashMap::end() + * @see ChainHashMap::end() * @return a constant pass-the-end iterator */ const_iterator end() const { @@ -570,7 +488,7 @@ namespace wlp { iterator at(const key_type &key); /** - * @see ChainHashMap::at() + * @see ChainHashMap::at() * @param key key for which to find the value * @return the mapped value * @throws KeyException if the key does not exist @@ -594,7 +512,7 @@ namespace wlp { iterator find(const key_type &key); /** - * @see ChainHashMap::find() + * @see ChainHashMap::find() * @param key the key to map * @return a const iterator to the element mapped by the key */ @@ -631,16 +549,16 @@ namespace wlp { map_type &operator=(map_type &&map); }; - template - void ChainHashMap::init_buckets(ChainHashMap::size_type n) { + template + void ChainHashMap::init_buckets(ChainHashMap::size_type n) { m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } } - template - void ChainHashMap::ensure_capacity() { + template + void ChainHashMap::ensure_capacity() { if (m_num_elements * 100 < m_max_load * m_capacity) { return; } @@ -668,8 +586,8 @@ namespace wlp { m_capacity = new_capacity; } - template - void ChainHashMap::clear() noexcept { + template + void ChainHashMap::clear() noexcept { for (size_type i = 0; i < m_capacity; ++i) { node_type *cur = m_buckets[i]; node_type *next; @@ -683,7 +601,7 @@ namespace wlp { m_num_elements = 0; } - template + template template Pair::iterator, bool> ChainHashMap::insert(K &&key, V &&val) { @@ -704,7 +622,7 @@ namespace wlp { return Pair(iterator(tmp, this), true); }; - template + template template Pair::iterator, bool> ChainHashMap::insert_or_assign(K &&key, V &&val) { @@ -726,9 +644,9 @@ namespace wlp { return Pair(iterator(tmp, this), true); }; - template - typename ChainHashMap::iterator - ChainHashMap::erase(const iterator &pos) { + template + typename ChainHashMap::iterator + ChainHashMap::erase(const iterator &pos) { node_type *p_node = pos.m_current; if (p_node) { node_type *n_node = p_node->next; @@ -771,8 +689,8 @@ namespace wlp { return end(); } - template - bool ChainHashMap::erase(const key_type &key) { + template + bool ChainHashMap::erase(const key_type &key) { size_type i = hash(key); node_type *first = m_buckets[i]; if (first) { @@ -811,9 +729,9 @@ namespace wlp { return false; } - template - typename ChainHashMap::iterator - ChainHashMap::at(const key_type &key) { + template + typename ChainHashMap::iterator + ChainHashMap::at(const key_type &key) { size_type i = hash(key); node_type *cur = m_buckets[i]; if (!cur) { @@ -828,9 +746,9 @@ namespace wlp { return iterator(cur, this); } - template - typename ChainHashMap::const_iterator - ChainHashMap::at(const key_type &key) const { + template + typename ChainHashMap::const_iterator + ChainHashMap::at(const key_type &key) const { size_type i = hash(key); node_type *cur = m_buckets[i]; if (!cur) { @@ -845,8 +763,8 @@ namespace wlp { return const_iterator(cur, this); } - template - bool ChainHashMap::contains(const key_type &key) const { + template + bool ChainHashMap::contains(const key_type &key) const { size_type i = hash(key); node_type *cur = m_buckets[i]; if (!cur) { @@ -858,10 +776,10 @@ namespace wlp { return cur != nullptr; } - template + template template - typename ChainHashMap::val_type & - ChainHashMap::operator[](K &&key) { + typename ChainHashMap::val_type & + ChainHashMap::operator[](K &&key) { ensure_capacity(); size_type i = hash(key); node_type *first = m_buckets[i]; @@ -891,9 +809,9 @@ namespace wlp { return cur->m_val; } - template - typename ChainHashMap::iterator - ChainHashMap::find(const key_type &key) { + template + typename ChainHashMap::iterator + ChainHashMap::find(const key_type &key) { size_type i = hash(key); node_type *cur = m_buckets[i]; if (!cur) { @@ -908,9 +826,9 @@ namespace wlp { return iterator(cur, this); } - template - typename ChainHashMap::const_iterator - ChainHashMap::find(const key_type &key) const { + template + typename ChainHashMap::const_iterator + ChainHashMap::find(const key_type &key) const { size_type i = hash(key); node_type *cur = m_buckets[i]; if (!cur) { @@ -925,8 +843,8 @@ namespace wlp { return const_iterator(cur, this); } - template - ChainHashMap::~ChainHashMap() { + template + ChainHashMap::~ChainHashMap() { if (!m_buckets) { return; } @@ -944,7 +862,7 @@ namespace wlp { m_buckets = nullptr; } - template + template ChainHashMap & ChainHashMap::operator=(ChainHashMap &&map) { clear(); @@ -959,34 +877,10 @@ namespace wlp { return *this; } - template - ChainHashMapIterator & - ChainHashMapIterator::operator++() { - const node_type *old = m_current; - m_current = m_current->next; - if (!m_current) { - size_type i = m_hash_map->hash(old->m_key); - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} - if (i == m_hash_map->m_capacity) { - m_current = nullptr; - } else { - m_current = m_hash_map->m_buckets[i]; - } - } - return *this; - } - - template - inline ChainHashMapIterator - ChainHashMapIterator::operator++(int) { - iterator tmp = *this; - ++*this; - return tmp; - } - - template - ChainHashMapConstIterator & - ChainHashMapConstIterator::operator++() { + template + typename ChainHashMapIterator::self_type & + ChainHashMapIterator::operator++() { const node_type *old = m_current; m_current = m_current->next; if (!m_current) { @@ -1001,10 +895,11 @@ namespace wlp { return *this; } - template - inline ChainHashMapConstIterator - ChainHashMapConstIterator::operator++(int) { - const_iterator tmp = *this; + template + inline typename ChainHashMapIterator::self_type + ChainHashMapIterator::operator++(int) { + self_type tmp = *this; ++*this; return tmp; } diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index 3d7b4598..0f19bea9 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -33,8 +33,8 @@ namespace wlp { public: typedef ChainHashSet set_type; typedef ChainHashMap map_type; - typedef ChainHashMapIterator iterator; - typedef ChainHashMapConstIterator const_iterator; + typedef typename ChainHashMap::iterator iterator; + typedef typename ChainHashMap::const_iterator const_iterator; typedef typename map_type::size_type size_type; typedef typename map_type::percent_type percent_type; typedef typename map_type::key_type key_type; diff --git a/lib/wlib/stl/LinkedList.h b/lib/wlib/stl/LinkedList.h index c8304798..1048f9f2 100644 --- a/lib/wlib/stl/LinkedList.h +++ b/lib/wlib/stl/LinkedList.h @@ -26,7 +26,8 @@ namespace wlp { typedef LinkedListNode node_type; val_type m_val; - node_type *m_next, *m_prev; + node_type *m_next; + node_type *m_prev; }; // Forward Declaration of List class @@ -34,17 +35,17 @@ namespace wlp { class LinkedList; /** - * Iterator class over the elements of a List. + * Iterator class over the elements of a @code LinkedList @endcode. * - * @tparam T value type + * @tparam T value type */ - template + template struct LinkedListIterator { typedef T val_type; typedef wlp::size_type size_type; typedef LinkedListNode node_type; - typedef LinkedListIterator iterator; typedef LinkedList list_type; + typedef LinkedListIterator self_type; /** * Pointer to the node referenced by this iterator. @@ -53,7 +54,7 @@ namespace wlp { /** * Pointer to the iterated List. */ - list_type *m_list; + const list_type *m_list; /** * Default constructor. @@ -68,7 +69,7 @@ namespace wlp { * @param node linked list node * @param list parent linked list */ - LinkedListIterator(node_type *node, list_type *list) + LinkedListIterator(node_type *node, const list_type *list) : m_current(node), m_list(list) {} @@ -77,7 +78,7 @@ namespace wlp { * * @param it iterator copy */ - LinkedListIterator(const iterator &it) + LinkedListIterator(const self_type &it) : m_current(it.m_current), m_list(it.m_list) {} @@ -104,7 +105,7 @@ namespace wlp { * * @return this iterator */ - iterator &operator++() { + self_type &operator++() { if (m_current) { m_current = m_current->m_next; } @@ -116,8 +117,8 @@ namespace wlp { * * @return this iterator */ - iterator operator++(int) { - iterator clone(*this); + self_type operator++(int) { + self_type clone(*this); ++*this; return clone; } @@ -130,7 +131,7 @@ namespace wlp { * * @return reference to this iterator */ - iterator &operator--() { + self_type &operator--() { if (m_current && m_current != m_list->m_head) { m_current = m_current->m_prev; } @@ -142,8 +143,8 @@ namespace wlp { * * @return reference to this iterator */ - iterator operator--(int) { - iterator clone(*this); + self_type operator--(int) { + self_type clone(*this); --*this; return *this; } @@ -154,7 +155,7 @@ namespace wlp { * @param it iterator to compare * @return true if they are equal */ - bool operator==(const iterator &it) const { + bool operator==(const self_type &it) const { return m_current == it.m_current; } @@ -165,7 +166,7 @@ namespace wlp { * @param it iterator to compare * @return true if they point to different nodes */ - bool operator!=(const iterator &it) const { + bool operator!=(const self_type &it) const { return m_current != it.m_current; } @@ -176,86 +177,7 @@ namespace wlp { * @param it iterator to copy * @return reference to this iterator */ - iterator &operator=(const iterator &it) { - m_current = it.m_current; - m_list = it.m_list; - return *this; - } - }; - - /** - * Constant iterator over a List. Values iterated by - * this class cannot be modified. - * - * @see ListIterator - * @tparam T value type - */ - template - struct LinkedListConstIterator { - typedef T val_type; - typedef wlp::size_type size_type; - typedef LinkedListNode node_type; - typedef LinkedListConstIterator const_iterator; - typedef LinkedList list_type; - - const node_type *m_current; - const list_type *m_list; - - LinkedListConstIterator() - : m_current(nullptr), - m_list(nullptr) {} - - LinkedListConstIterator(const node_type *node, const list_type *list) - : m_current(node), - m_list(list) {} - - LinkedListConstIterator(const const_iterator &it) - : m_current(it.m_current), - m_list(it.m_list) {} - - const val_type &operator*() const { - return m_current->m_val; - } - - const val_type *operator->() const { - return &(operator*()); - } - - const_iterator &operator++() { - if (m_current) { - m_current = m_current->m_next; - } - return *this; - } - - const_iterator operator++(int) { - const_iterator clone(*this); - ++*this; - return clone; - } - - const_iterator &operator--() { - if (m_current && m_current != m_list->m_head) { - m_current = m_current->m_prev; - } - return *this; - } - - const_iterator operator--(int) { - const_iterator clone(*this); - --*this; - return *this; - } - - bool operator==(const const_iterator &it) const { - return m_current == it.m_current; - } - - bool operator!=(const const_iterator &it) const { - return m_current != it.m_current; - } - - const_iterator &operator=(const const_iterator &it) { + self_type &operator=(const self_type &it) { m_current = it.m_current; m_list = it.m_list; return *this; @@ -274,8 +196,8 @@ namespace wlp { typedef wlp::size_type size_type; typedef LinkedList list_type; typedef LinkedListNode node_type; - typedef LinkedListIterator iterator; - typedef LinkedListConstIterator const_iterator; + typedef LinkedListIterator iterator; + typedef LinkedListIterator const_iterator; private: /** @@ -291,9 +213,8 @@ namespace wlp { */ node_type *m_tail; - friend struct LinkedListIterator; - - friend struct LinkedListConstIterator; + friend struct LinkedListIterator; + friend struct LinkedListIterator; public: /** diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index 0bfcc4be..bffae48b 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -25,33 +25,19 @@ namespace wlp { // Forward declaration of OpenHashMap - template + template class OpenHashMap; - // Forward declaration of OpenHashMap iterator - template - struct OpenHashMapIterator; - - // Forward declaration of const OpenHashMap iterator - template - struct OpenHashMapConstIterator; - /** * Hasher map node comprise the elements of a hash map's * backing array, containing an element key and corresponding value. * @tparam Key key type * @tparam Val value type */ - template + template struct OpenHashMapNode { typedef OpenHashMapNode node_type; typedef Key key_type; @@ -84,14 +70,16 @@ namespace wlp { * @tparam Hasher hash function * @tparam Equals key equality function */ - template + template struct OpenHashMapIterator { typedef OpenHashMap map_type; - typedef OpenHashMapIterator iterator; typedef OpenHashMapNode node_type; + typedef OpenHashMapIterator self_type; typedef Val val_type; @@ -104,7 +92,7 @@ namespace wlp { /** * Pointer to the iterated OpenHashMap. */ - map_type *m_hash_map; + const map_type *m_hash_map; /** * Default constructor. @@ -119,7 +107,7 @@ namespace wlp { * @param node hash map node * @param map parent hash map */ - OpenHashMapIterator(node_type *node, map_type *map) + OpenHashMapIterator(node_type *node, const map_type *map) : m_current(node), m_hash_map(map) { } @@ -128,7 +116,7 @@ namespace wlp { * Copy constructor for const. * @param it iterator to copy */ - OpenHashMapIterator(const iterator &it) + OpenHashMapIterator(const self_type &it) : m_current(it.m_current), m_hash_map(it.m_hash_map) { } @@ -155,13 +143,13 @@ namespace wlp { * iterator. This is pre-fix unary operator. * @return this iterator */ - iterator &operator++(); + self_type &operator++(); /** * Post-fix unary operator. * @return this iterator */ - iterator operator++(int); + self_type operator++(int); /** * Compare two iterators, equal of they point to the @@ -169,7 +157,7 @@ namespace wlp { * @param it iterator to compare * @return true if both point to the same node */ - bool operator==(const iterator &it) const { + bool operator==(const self_type &it) const { return m_current == it.m_current; } @@ -179,7 +167,7 @@ namespace wlp { * @param it iterator to compare * @return true if they point to different nodes */ - bool operator!=(const iterator &it) const { + bool operator!=(const self_type &it) const { return m_current != it.m_current; } @@ -189,77 +177,7 @@ namespace wlp { * @param it iterator to copy * @return a reference to this iterator */ - iterator &operator=(const iterator &it) { - m_current = it.m_current; - m_hash_map = it.m_hash_map; - return *this; - } - - }; - - /** - * Constant iterator over a OpenHashMap. Values iterated by - * this class cannot be modified. - * - * @see OpenHashMapIterator - * - * @tparam Key key type - * @tparam Val value type - * @tparam Hasher hash function - * @tparam Equals key equality function - */ - template - struct OpenHashMapConstIterator { - typedef OpenHashMap map_type; - typedef OpenHashMapConstIterator const_iterator; - typedef OpenHashMapNode node_type; - - typedef Val val_type; - - typedef wlp::size_type size_type; - - const node_type *m_current; - const map_type *m_hash_map; - - OpenHashMapConstIterator() - : m_current(nullptr), - m_hash_map(nullptr) { - } - - OpenHashMapConstIterator(node_type *node, const map_type *map) - : m_current(node), - m_hash_map(map) { - } - - OpenHashMapConstIterator(const const_iterator &it) - : m_current(it.m_current), - m_hash_map(it.m_hash_map) { - } - - const val_type &operator*() const { - return m_current->m_val; - } - - const val_type *operator->() const { - return &(operator*()); - } - - const_iterator &operator++(); - - const_iterator operator++(int); - - bool operator==(const const_iterator &it) const { - return m_current == it.m_current; - } - - bool operator!=(const const_iterator &it) const { - return m_current != it.m_current; - } - - const_iterator &operator=(const const_iterator &it) { + self_type &operator=(const self_type &it) { m_current = it.m_current; m_hash_map = it.m_hash_map; return *this; @@ -275,16 +193,16 @@ namespace wlp { * @tparam Hasher hash function * @tparam Equals key equality function */ - template, - class Equals = Equal > + template, + typename Equals = Equal > class OpenHashMap { public: typedef OpenHashMap map_type; - typedef OpenHashMapIterator iterator; - typedef OpenHashMapConstIterator const_iterator; typedef OpenHashMapNode node_type; + typedef OpenHashMapIterator iterator; + typedef OpenHashMapIterator const_iterator; typedef Key key_type; typedef Val val_type; @@ -292,8 +210,8 @@ namespace wlp { typedef wlp::size_type size_type; typedef uint8_t percent_type; - friend struct OpenHashMapIterator; - friend struct OpenHashMapConstIterator; + friend struct OpenHashMapIterator; + friend struct OpenHashMapIterator; private: /** @@ -634,7 +552,7 @@ namespace wlp { map_type &operator=(map_type &&map); }; - template + template void OpenHashMap::init_buckets(OpenHashMap::size_type n) { m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { @@ -642,7 +560,7 @@ namespace wlp { } } - template + template void OpenHashMap::ensure_capacity() { if (m_num_elements * 100 < m_max_load * m_capacity) { return; @@ -670,7 +588,7 @@ namespace wlp { m_capacity = new_capacity; } - template + template void OpenHashMap::clear() noexcept { for (size_type i = 0; i < m_capacity; ++i) { if (m_buckets[i]) { @@ -681,7 +599,7 @@ namespace wlp { m_num_elements = 0; } - template + template template Pair::iterator, bool> OpenHashMap::insert(K &&key, V &&val) { @@ -704,7 +622,7 @@ namespace wlp { } }; - template + template template Pair::iterator, bool> OpenHashMap::insert_or_assign(K &&key, V &&val) { @@ -728,7 +646,7 @@ namespace wlp { } }; - template + template typename OpenHashMap::iterator OpenHashMap::erase(const iterator &pos) { const node_type *cur_node = pos.m_current; @@ -771,7 +689,7 @@ namespace wlp { return iterator(next_node, this); } - template + template bool OpenHashMap::erase(const key_type &key) { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { @@ -807,7 +725,7 @@ namespace wlp { return true; } - template + template typename OpenHashMap::iterator OpenHashMap::at(const key_type &key) { size_type i = hash(key); @@ -823,7 +741,7 @@ namespace wlp { } } - template + template typename OpenHashMap::const_iterator OpenHashMap::at(const key_type &key) const { size_type i = hash(key); @@ -839,7 +757,7 @@ namespace wlp { } } - template + template bool OpenHashMap::contains(const key_type &key) const { size_type i = hash(key); while (m_buckets[i]) { @@ -853,7 +771,7 @@ namespace wlp { return false; } - template + template template typename OpenHashMap::val_type & OpenHashMap::operator[](K &&key) { @@ -876,7 +794,7 @@ namespace wlp { } } - template + template typename OpenHashMap::iterator OpenHashMap::find(const key_type &key) { size_type i = hash(key); @@ -892,7 +810,7 @@ namespace wlp { } } - template + template typename OpenHashMap::const_iterator OpenHashMap::find(const key_type &key) const { size_type i = hash(key); @@ -908,7 +826,7 @@ namespace wlp { } } - template + template OpenHashMap::~OpenHashMap() { if (!m_buckets) { return; @@ -923,7 +841,7 @@ namespace wlp { m_buckets = nullptr; } - template + template OpenHashMap & OpenHashMap::operator=(OpenHashMap &&map) { clear(); @@ -938,35 +856,9 @@ namespace wlp { return *this; } - template - OpenHashMapIterator & - OpenHashMapIterator::operator++() { - size_type i = m_hash_map->hash(m_current->m_key); - while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { - if (++i >= m_hash_map->m_capacity) { - i = 0; - } - } - while (++i < m_hash_map->m_capacity && !m_hash_map->m_buckets[i]) {} - if (i == m_hash_map->m_capacity) { - m_current = nullptr; - } else { - m_current = m_hash_map->m_buckets[i]; - } - return *this; - } - - template - inline OpenHashMapIterator - OpenHashMapIterator::operator++(int) { - iterator tmp = *this; - ++*this; - return tmp; - } - - template - OpenHashMapConstIterator & - OpenHashMapConstIterator::operator++() { + template + OpenHashMapIterator & + OpenHashMapIterator::operator++() { size_type i = m_hash_map->hash(m_current->m_key); while (m_hash_map->m_buckets[i] && !m_hash_map->m_equal(m_current->m_key, m_hash_map->m_buckets[i]->m_key)) { if (++i >= m_hash_map->m_capacity) { @@ -982,10 +874,10 @@ namespace wlp { return *this; } - template - inline OpenHashMapConstIterator - OpenHashMapConstIterator::operator++(int) { - const_iterator tmp = *this; + template + inline OpenHashMapIterator + OpenHashMapIterator::operator++(int) { + self_type tmp = *this; ++*this; return tmp; } diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index 8a8459f2..2dec3856 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -34,8 +34,8 @@ namespace wlp { public: typedef OpenHashSet hash_set; typedef OpenHashMap map_type; - typedef OpenHashMapIterator iterator; - typedef OpenHashMapConstIterator const_iterator; + typedef typename OpenHashMap::iterator iterator; + typedef typename OpenHashMap::const_iterator const_iterator; typedef typename map_type::size_type size_type; typedef typename map_type::percent_type percent_type; typedef typename map_type::key_type key_type; diff --git a/tests/stl/linked_list_check.cpp b/tests/stl/linked_list_check.cpp index 93e5db30..5d1c2cef 100644 --- a/tests/stl/linked_list_check.cpp +++ b/tests/stl/linked_list_check.cpp @@ -5,6 +5,9 @@ using namespace wlp; +typedef LinkedList::iterator lli_it; +typedef LinkedList::const_iterator lli_cit; + TEST(list_tests, constructor_tests) { LinkedList numlist; ASSERT_EQ(numlist.size(), 0); @@ -76,7 +79,7 @@ TEST(list_tests, iterator_tests) { numlist.push_front(1); numlist.push_back(2); numlist.push_front(3); // 3 1 2 - LinkedListIterator it = numlist.begin(); + lli_it it = numlist.begin(); ASSERT_EQ(*it, 3); ++it; ASSERT_EQ(*it, 1); @@ -86,7 +89,7 @@ TEST(list_tests, iterator_tests) { ++it; ASSERT_EQ(it, numlist.end()); const LinkedList constlist = move(numlist); - LinkedListConstIterator it2 = constlist.begin(); + lli_cit it2 = constlist.begin(); ASSERT_EQ(*it2, 3); ++it2; ASSERT_EQ(*it2, 1); diff --git a/tests/template_defs.h b/tests/template_defs.h index b8a4a055..a97937d5 100644 --- a/tests/template_defs.h +++ b/tests/template_defs.h @@ -15,7 +15,7 @@ namespace wlp { struct Pair; template - class ChainHashMap, StaticString<16>>; + class ChainHashMap; template class ChainHashMap; @@ -24,44 +24,52 @@ namespace wlp { struct Pair::iterator, bool>; template - struct Pair, StaticString<16>>::iterator, bool>; + struct Pair::iterator, bool>; template struct ChainHashMapIterator< - StaticString<16>, - StaticString<16>, - Hash, uint16_t>, - Equal>>; + String16, + String16, + String16 &, + String16 *, + Hash, + Equal>; template struct ChainHashMapIterator< uint16_t, uint16_t, + uint16_t &, + uint16_t *, Hash, Equal>; template - struct ChainHashMapConstIterator< - StaticString<16>, - StaticString<16>, - Hash, uint16_t>, - Equal>>; + struct ChainHashMapIterator< + String16, + String16, + const String16 &, + const String16 *, + Hash, + Equal>; template - struct ChainHashMapConstIterator< + struct ChainHashMapIterator< uint16_t, uint16_t, + const uint16_t &, + const uint16_t *, Hash, Equal>; template - struct Equal>; + struct Equal; template struct Equal; template - struct Hash, uint16_t>; + struct Hash; template struct Hash; @@ -70,7 +78,7 @@ namespace wlp { struct Hash; template - class OpenHashMap, StaticString<16>>; + class OpenHashMap; template class OpenHashMap; @@ -79,33 +87,41 @@ namespace wlp { struct Pair::iterator, bool>; template - struct Pair, StaticString<16>>::iterator, bool>; + struct Pair::iterator, bool>; template struct OpenHashMapIterator< - StaticString<16>, - StaticString<16>, - Hash, uint16_t>, - Equal>>; + String16, + String16, + String16 &, + String16 *, + Hash, + Equal>; template struct OpenHashMapIterator< uint16_t, uint16_t, + uint16_t &, + uint16_t *, Hash, Equal>; template - struct OpenHashMapConstIterator< - StaticString<16>, - StaticString<16>, - Hash, uint16_t>, - Equal>>; + struct OpenHashMapIterator< + String16, + String16, + const String16 &, + const String16 *, + Hash, + Equal>; template - struct OpenHashMapConstIterator< + struct OpenHashMapIterator< uint16_t, uint16_t, + const uint16_t &, + const uint16_t *, Hash, Equal>; @@ -125,16 +141,16 @@ namespace wlp { class StaticString<16>; template - class ArrayListIterator; + class ArrayListIterator; template - class ArrayListIterator; + class ArrayListIterator; template - class ArrayListConstIterator; + class ArrayListIterator; template - class ArrayListConstIterator; + class ArrayListIterator; template struct Comparator; @@ -148,6 +164,12 @@ namespace wlp { template class LinkedList; + template + struct LinkedListIterator; + + template + struct LinkedListIterator; + } #endif // TEMPLATE_DEFS_H From f8bbf1feb71acd1133b731939db51a7b6b445d11 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Tue, 21 Nov 2017 17:16:35 -0800 Subject: [PATCH 022/102] [Enhancement] Synced LinkedList and ArrayList interface, List concept (#62) * synced linkedlist and arraylist interfaces * unit tests --- lib/wlib/stl/ArrayHeap.h | 2 +- lib/wlib/stl/ArrayList.h | 116 ++++++--- lib/wlib/stl/Concept.h | 65 +++++ lib/wlib/stl/LinkedList.h | 423 +++++++++++++++++++++----------- lib/wlib/stl/RedBlackTree.h | 1 + tests/stl/array_list_check.cpp | 149 ++++++++--- tests/stl/concept_check.cpp | 11 + tests/stl/linked_list_check.cpp | 117 +++++++-- 8 files changed, 654 insertions(+), 230 deletions(-) diff --git a/lib/wlib/stl/ArrayHeap.h b/lib/wlib/stl/ArrayHeap.h index 352ef98a..b06adb38 100644 --- a/lib/wlib/stl/ArrayHeap.h +++ b/lib/wlib/stl/ArrayHeap.h @@ -487,7 +487,7 @@ namespace wlp { typedef ArrayHeap array_heap; typedef typename ArrayList::val_type val_type; typedef typename ArrayList::size_type size_type; - typedef typename ArrayList::array_list array_list; + typedef typename ArrayList::list_type array_list; typedef typename ArrayList::iterator iterator; typedef typename ArrayList::const_iterator const_iterator; diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index f9ce865c..12cbfe26 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -140,22 +140,6 @@ namespace wlp { return tmp; } - /** - * Addition assignment operator moves the - * iterator by the specified number of - * positions. - * - * @param d the number of positions to increment - * @return reference to this iterator - */ - self_type &operator+=(const size_type &d) { - m_i = static_cast(m_i + d); - if (m_i > m_list->m_size) { - m_i = m_list->m_size; - } - return *this; - } - /** * Decrement operator moves the iterator backwards * one element. If the iterator points to the first @@ -182,6 +166,22 @@ namespace wlp { return tmp; } + /** + * Addition assignment operator moves the + * iterator by the specified number of + * positions. + * + * @param d the number of positions to increment + * @return reference to this iterator + */ + self_type &operator+=(const size_type &d) { + m_i = static_cast(m_i + d); + if (m_i > m_list->m_size) { + m_i = m_list->m_size; + } + return *this; + } + /** * Subtraction assignment operator moves the iterator * backwards a certain number of elements. @@ -273,9 +273,9 @@ namespace wlp { template class ArrayList { public: - typedef wlp::size_type size_type; typedef T val_type; - typedef ArrayList array_list; + typedef wlp::size_type size_type; + typedef ArrayList list_type; typedef ArrayListIterator iterator; typedef ArrayListIterator const_iterator; @@ -294,6 +294,7 @@ namespace wlp { size_type m_capacity; friend class ArrayListIterator; + friend class ArrayListIterator; public: @@ -312,14 +313,14 @@ namespace wlp { /** * Disable copy constructor. */ - ArrayList(const array_list &) = delete; + ArrayList(const list_type &) = delete; /** * Move constructor. * * @param list array list whose resources to transfer */ - ArrayList(array_list &&list) + ArrayList(list_type &&list) : m_data(move(list.m_data)), m_size(move(list.m_size)), m_capacity(move(list.m_capacity)) { @@ -521,7 +522,7 @@ namespace wlp { /** * @return reference to the first element in the list */ - val_type const &front() const { + const val_type &front() const { return m_data[0]; } @@ -538,7 +539,7 @@ namespace wlp { /** * @return reference to the last element in the list */ - val_type const &back() const { + const val_type &back() const { if (m_size == 0) { return m_data[0]; } @@ -563,7 +564,7 @@ namespace wlp { * Clear the contents of the array list * such that it is empty. */ - void clear() { + void clear() noexcept { m_size = 0; } @@ -665,7 +666,7 @@ namespace wlp { /** * Insert an element to the back of the list. * - * @param t element to insert + * @param val element to insert */ template void push_back(V &&val) { @@ -674,6 +675,19 @@ namespace wlp { ++m_size; } + /** + * Insert an element at the front of the list. + * + * @param val element to insert + */ + template + void push_front(V &&val) { + ensure_capacity(); + shift_right(0); + m_data[0] = forward(val); + ++m_size; + } + /** * Remove the last element from the list. */ @@ -684,20 +698,42 @@ namespace wlp { } /** - * Swap the contents of two array lists. - * - * @param list array list with which to swap + * Remove the first element from the list. + */ + void pop_front() { + if (m_size > 0) { + shift_left(0); + --m_size; + } + } + + /** + * @param val the value to find + * @return the index of the value, or the size of the list + * if the value is not found + */ + size_type index_of(const val_type &val) const { + size_type i = 0; + for (; i < m_size; ++i) { + if (val == m_data[i]) { return i; } + } + return i; + } + + /** + * @param val the value to find + * @return iterator to the value, or pass-the-end if not found + */ + iterator find(const val_type &val) { + return iterator(index_of(val), this); + } + + /** + * @param val the value to find + * @return iterator to the value, or pass-the-end if not found */ - void swap(array_list &list) { - val_type *tmp = m_data; - m_data = list.m_data; - list.m_data = tmp; - size_type tmp_size = m_size; - m_size = list.m_size; - list.m_size = tmp_size; - size_type tmp_cap = m_capacity; - m_capacity = list.m_capacity; - list.m_capacity = tmp_cap; + const_iterator find(const val_type &val) const { + return const_iterator(index_of(val), this); } /** @@ -705,7 +741,7 @@ namespace wlp { * * @return reference to this list */ - array_list &operator=(const array_list &) = delete; + list_type &operator=(const list_type &) = delete; /** * Move assignment operator. @@ -713,7 +749,7 @@ namespace wlp { * @param list array list to transfer * @return reference to this list */ - array_list &operator=(array_list &&list) { + list_type &operator=(list_type &&list) { free(m_data); m_data = move(list.m_data); m_size = move(list.m_size); @@ -731,7 +767,7 @@ namespace wlp { if (m_size < m_capacity) { return; } - size_type new_capacity = static_cast(2 * m_capacity); + size_type new_capacity = static_cast(2 * m_capacity); val_type *new_data = malloc(new_capacity); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; diff --git a/lib/wlib/stl/Concept.h b/lib/wlib/stl/Concept.h index 577971ed..3338c1c3 100644 --- a/lib/wlib/stl/Concept.h +++ b/lib/wlib/stl/Concept.h @@ -316,6 +316,71 @@ namespace wlp { return map_concept::value; } + template::value && + has_size_type::value && + has_iterator::value && + has_const_iterator::value + > + struct list_concept { + static constexpr bool value = false; + }; + + template + struct list_concept { + private: + typedef typename C::val_type val_type; + typedef typename C::size_type size_type; + typedef typename C::iterator iterator; + typedef typename C::const_iterator const_iterator; + typedef C list_type; + + template + static constexpr auto check(T *) -> typename and_< + __HAS_FCN(const T, size, size_type), + __HAS_FCN(const T, capacity, size_type), + __HAS_FCN(const T, empty, bool), + __HAS_FCN(T, at, size_type, val_type &), + __HAS_FCN(const T, at, size_type, const val_type &), + __HAS_FCN(T, operator[], size_type, val_type &), + __HAS_FCN(const T, operator[], size_type, const val_type &), + __HAS_FCN(T, front, val_type &), + __HAS_FCN(const T, front, const val_type &), + __HAS_FCN(T, back, val_type &), + __HAS_FCN(const T, back, const val_type &), + __HAS_FCN(T, clear, void), + __HAS_FCN(T, begin, iterator), + __HAS_FCN(const T, begin, const_iterator), + __HAS_FCN(T, end, iterator), + __HAS_FCN(const T, end, const_iterator), + __HAS_FCN(T, insert, size_type, const val_type &, iterator), + __HAS_FCN(T, insert, const iterator &, const val_type &, iterator), + __HAS_FCN(T, erase, size_type, iterator), + __HAS_FCN(T, erase, const iterator &, iterator), + __HAS_FCN(T, push_back, const val_type &, void), + __HAS_FCN(T, push_front, const val_type &, void), + __HAS_FCN(T, pop_back, void), + __HAS_FCN(T, pop_front, void), + __HAS_FCN(const T, index_of, const val_type &, size_type), + __HAS_FCN(T, find, const val_type &, iterator), + __HAS_FCN(const T, find, const val_type &, const_iterator), + __HAS_FCN(T, operator=, list_type &&, list_type &) + >::type; + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + template + static constexpr bool is_list() { + return list_concept::value; + } + } #endif //EMBEDDEDCPLUSPLUS_CONCEPTCHECKS_H diff --git a/lib/wlib/stl/LinkedList.h b/lib/wlib/stl/LinkedList.h index 1048f9f2..2c847020 100644 --- a/lib/wlib/stl/LinkedList.h +++ b/lib/wlib/stl/LinkedList.h @@ -249,79 +249,67 @@ namespace wlp { /** * Default Destructor deallocates all the nodes. */ - ~LinkedList(); + ~LinkedList() { + clear(); + } /** - * Creates a new node and pushes it to the back of the list. - * - * @param value the value to store at the new node + * @return whether the list has no elements */ - template - void push_back(V &&val) { - node_type *node = malloc(); - node->m_val = forward(val); - node->m_next = nullptr; - if (m_head == nullptr) { - m_head = node; - node->m_prev = nullptr; - } else { - m_tail->m_next = node; - node->m_prev = m_tail; - } - m_tail = node; - ++m_size; + bool empty() const { + return m_size == 0; + }; + + /** + * @return the length of the list + */ + size_type size() const { + return m_size; } /** - * Creates a new node and pushes it to the front of the list. + * @return the maximum number of elements storable in the list + */ + size_type capacity() const { + return static_cast(-1); + } + + /** + * Return a reference to the value stored at the `index` * - * @param value the value to store at the new node + * @param i to get + * @return reference to the value at that index */ - template - void push_front(V &&val) { - node_type *node = malloc(); - node->m_val = forward(val); - node->m_prev = nullptr; + val_type &at(size_type i); - if (m_tail == nullptr) { - m_tail = node; - node->m_next = nullptr; - } else { - m_head->m_prev = node; - node->m_next = m_head; - } - m_head = node; - m_size++; - } + /** + * Return a reference to the value stored at the `index` (const variant) + * + * @param i to get + * @return reference to the value at that index + */ + const val_type &at(size_type i) const; - void pop_back() { - if (!m_tail) { - return; - } - node_type *pTmp = m_tail; - m_tail = m_tail->m_prev; - if (m_tail != nullptr) { - m_tail->m_next = nullptr; - } else { - m_head = nullptr; - } - free(pTmp); - m_size--; + /** + * Array indexing operator + * `at` behind the scenes + * + * @param index to get + * @return reference to the value at that index + */ + val_type &operator[](size_type index) { + return at(index); } - void pop_front() { - if (!m_head) { - return; - } - node_type *pTmp = m_head; - m_head = m_head->m_next; - if (m_head != nullptr) { - m_head->m_prev = nullptr; - } else { - m_tail = nullptr; - } - free(pTmp); - m_size--; + /** + * Array indexing operator const variant + * `at` behind the scenes + * + * @param index to get + * @return reference to the value at that index + */ + const val_type &operator[](size_type index) const { + return at(index); } /** @@ -353,103 +341,260 @@ namespace wlp { } /** - * Returns the length of the List + * Removes all the elements in the list. + */ + void clear() noexcept; + + /** + * Obtain an iterator to the first element in the list. + * Returns pass-the-end iterator (nullptr) if + * there are no elements (m_pStart == nullptr) * - * @return the length of the list + * @return iterator the first element */ - size_type size() const { - return m_size; + iterator begin() { + return iterator(m_head, this); } - void clear() noexcept; + /** + * @return a pass-the-end iterator for this map + */ + iterator end() { + return iterator(nullptr, this); + } /** - * Removes the value stored at the given index + * @see List::begin() + * @return a constant iterator to the first element in the list + */ + const_iterator begin() const { + return const_iterator(m_head, this); + } + + /** + * @see List::end() + * @return a constant pass-the-end iterator + */ + const_iterator end() const { + return const_iterator(nullptr, this); + } + + /** + * Insert a value at the given index. * - * @param index the index to remove at + * @param i the index of the node to insert + * @param val the value to insert + * @return iterator to the inserted element */ - void erase(size_type index); + template + iterator insert(size_type i, V &&val) { + if (!m_size) { i = 0; } + else { i %= m_size; } + node_type *node = malloc(); + node->m_val = forward(val); + if (m_head == nullptr) { + node->m_next = nullptr; + node->m_prev = nullptr; + m_head = node; + m_tail = node; + ++m_size; + return iterator(m_head, this); + } + node_type *pTmp = m_head; + while(i-- > 0) { + pTmp = pTmp->m_next; + } + node->m_next = pTmp; + node->m_prev = pTmp->m_prev; + node->m_next->m_prev = node; + if (node->m_prev) { node->m_prev->m_next = node; } + else { m_head = node; } + ++m_size; + return iterator(node, this); + } /** - * Return a reference to the value stored at the `index` + * Insert a value at the given iterator. * - * @param index to get - * @return reference to the value at that index + * @param it the iterator to the node to insert + * @param val the value to insert + * @return iterator to the inserted value */ - val_type &at(size_type index); + template + iterator insert(const iterator &it, V &&val) { + if (it == end()) { + push_back(forward(val)); + return iterator(m_tail, this); + } + node_type *node = malloc(); + node->m_val = forward(val); + node->m_next = it.m_current; + node->m_prev = it.m_current->m_prev; + node->m_next->m_prev = node; + if (node->m_prev) { node->m_prev->m_next = node; } + else { m_head = node; } + ++m_size; + return iterator(node, this); + } /** - * Return a reference to the value stored at the `index` (const variant) + * Removes the value stored at the given index * - * @param index to get - * @return reference to the value at that index + * @param i the index to remove at + * @return iterator to the next element, or pass-the-end */ - const val_type &at(size_type index) const; + iterator erase(size_type i); /** - * Array indexing operator - * `at` behind the scenes + * Removes the value pointed to by an iterator. * - * @param index to get - * @return reference to the value at that index + * @param it the iterator whose value to remove + * @return iterator to the next element, or pass-the-end */ - val_type &operator[](size_type index) { - return at(index); + iterator erase(const iterator &it) { + if (m_size == 0 || !it.m_current) { + return end(); + } + node_type *pTmp = it.m_current; + if (pTmp->m_prev != nullptr) { + pTmp->m_prev->m_next = pTmp->m_next; + } else { + m_head = pTmp->m_next; + } + if (pTmp->m_next != nullptr) { + pTmp->m_next->m_prev = pTmp->m_prev; + } else { + m_tail = pTmp->m_prev; + } + node_type *next = pTmp->m_next; + free(pTmp); + --m_size; + return iterator(next, this); } /** - * Array indexing operator const variant - * `at` behind the scenes + * Creates a new node and pushes it to the back of the list. * - * @param index to get - * @return reference to the value at that index + * @param value the value to store at the new node */ - const val_type &operator[](size_type index) const { - return at(index); + template + void push_back(V &&val) { + node_type *node = malloc(); + node->m_val = forward(val); + node->m_next = nullptr; + if (m_head == nullptr) { + m_head = node; + node->m_prev = nullptr; + } else { + m_tail->m_next = node; + node->m_prev = m_tail; + } + m_tail = node; + ++m_size; } /** - * indexOf from Javascript land that finds the index of the - * first element from the beginning of the List that equals `value` - * but returns the length of the array instead of -1 on failure + * Creates a new node and pushes it to the front of the list. * - * @param value value to search for - * @return reference to the value at that index + * @param value the value to store at the new node */ - size_type indexOf(const T &value); + template + void push_front(V &&val) { + node_type *node = malloc(); + node->m_val = forward(val); + node->m_prev = nullptr; + + if (m_tail == nullptr) { + m_tail = node; + node->m_next = nullptr; + } else { + m_head->m_prev = node; + node->m_next = m_head; + } + m_head = node; + m_size++; + } /** - * Obtain an iterator to the first element in the list. - * Returns pass-the-end iterator (nullptr) if - * there are no elements (m_pStart == nullptr) - * - * @return iterator the first element + * Remove the last element from the list. */ - iterator begin() { - return iterator(m_head, this); + void pop_back() { + if (!m_tail) { + return; + } + node_type *pTmp = m_tail; + m_tail = m_tail->m_prev; + if (m_tail != nullptr) { + m_tail->m_next = nullptr; + } else { + m_head = nullptr; + } + free(pTmp); + m_size--; } /** - * @return a pass-the-end iterator for this map + * Remove the first element from the list. */ - iterator end() { - return iterator(nullptr, this); + void pop_front() { + if (!m_head) { + return; + } + node_type *pTmp = m_head; + m_head = m_head->m_next; + if (m_head != nullptr) { + m_head->m_prev = nullptr; + } else { + m_tail = nullptr; + } + free(pTmp); + m_size--; } /** - * @see List::begin() - * @return a constant iterator to the first element in the list + * Find the index of the first element from the beginning of + * the List that equals @code val @endcode. Returns the size + * of the list if not found. + * + * @param val value to search for + * @return the index of the first occurrence of the element */ - const_iterator begin() const { - return const_iterator(m_head, this); + size_type index_of(const val_type &val) const; + + /** + * Find the first occurrence of a value in the list. + * + * @param val the value to find + * @return iterator to the first occurrence of the element + * or pass-the-end if not found + */ + iterator find(const val_type &val) { + node_type *pTmp = m_head; + while(pTmp) { + if (pTmp->m_val == val) { + return iterator(pTmp, this); + } + pTmp = pTmp->m_next; + } + return end(); } /** - * @see List::end() - * @return a constant pass-the-end iterator + * Find the first occurrence of a value in the list. + * + * @param val the value to find + * @return iterator to the first occurrence of the element + * or pass-the-end if not found */ - const_iterator end() const { - return const_iterator(nullptr, this); + const_iterator find(const val_type &val) const { + node_type *pTmp = m_head; + while(pTmp) { + if (pTmp->m_val == val) { + return const_iterator(pTmp, this); + } + pTmp = pTmp->m_next; + } + return end(); } /** @@ -466,6 +611,7 @@ namespace wlp { * @return a reference to this list */ list_type &operator=(list_type &&list) { + clear(); m_size = list.m_size; m_head = list.m_head; m_tail = list.m_tail; @@ -477,12 +623,7 @@ namespace wlp { }; template - LinkedList::~LinkedList() { - clear(); - } - - template - void LinkedList::clear() noexcept { + inline void LinkedList::clear() noexcept { node_type *pTmp; while (m_head != nullptr) { pTmp = m_head; @@ -491,18 +632,20 @@ namespace wlp { } m_size = 0; m_tail = nullptr; + m_head = nullptr; } template - void LinkedList::erase(size_type index) { + typename LinkedList::iterator + LinkedList::erase(size_type i) { if (!m_size) { - return; + return end(); } - if (index >= m_size) { - index %= m_size; + if (i >= m_size) { + i %= m_size; } node_type *pTmp = m_head; - while (index-- > 0) { + while (i-- > 0) { pTmp = pTmp->m_next; } if (pTmp->m_prev != nullptr) { @@ -515,44 +658,46 @@ namespace wlp { } else { m_tail = pTmp->m_prev; } + node_type *next = pTmp->m_next; free(pTmp); m_size--; + return iterator(next, this); } template - typename LinkedList::val_type & - LinkedList::at(size_type index) { - if (index >= m_size) { - if (m_size) { index %= m_size; } - else { index = 0; } + inline typename LinkedList::val_type & + LinkedList::at(size_type i) { + if (i >= m_size) { + if (m_size) { i %= m_size; } + else { i = 0; } } node_type *pTmp = m_head; - while (index-- > 0) { + while (i-- > 0) { pTmp = pTmp->m_next; } return pTmp->m_val; } template - const typename LinkedList::val_type & - LinkedList::at(size_type index) const { - if (index >= m_size) { - if (m_size) { index %= m_size; } - else { index = 0; } + inline const typename LinkedList::val_type & + LinkedList::at(size_type i) const { + if (i >= m_size) { + if (m_size) { i %= m_size; } + else { i = 0; } } node_type *pTmp = m_head; - while (index-- > 0) { + while (i-- > 0) { pTmp = pTmp->m_next; } return pTmp->m_val; } template - typename LinkedList::size_type - LinkedList::indexOf(const T &value) { + inline typename LinkedList::size_type + LinkedList::index_of(const val_type &val) const { node_type *pTmp = m_head; for (size_type i = 0; i < m_size; i++) { - if (pTmp->m_val == value) { + if (pTmp->m_val == val) { return i; } pTmp = pTmp->m_next; diff --git a/lib/wlib/stl/RedBlackTree.h b/lib/wlib/stl/RedBlackTree.h index 41ed4fe4..e1c29867 100644 --- a/lib/wlib/stl/RedBlackTree.h +++ b/lib/wlib/stl/RedBlackTree.h @@ -17,6 +17,7 @@ #include "Pair.h" #include "../Types.h" +#include "../memory/Memory.h" #include "../utility/Utility.h" namespace wlp { diff --git a/tests/stl/array_list_check.cpp b/tests/stl/array_list_check.cpp index d01e76ec..b99932fa 100644 --- a/tests/stl/array_list_check.cpp +++ b/tests/stl/array_list_check.cpp @@ -8,7 +8,7 @@ using namespace wlp; typedef ArrayList::const_iterator cit; -TEST(list_test, test_constructors) { +TEST(array_list_test, test_constructors) { int values[] = {1, 2, 3, 4, 5}; ArrayList list(values, 5, 2); ASSERT_EQ(5, list.capacity()); @@ -22,7 +22,7 @@ TEST(list_test, test_constructors) { } } -TEST(list_test, test_at) { +TEST(array_list_test, test_at) { int values[] = {2, 3, 5, 7, 11, 13}; ArrayList list(values, 6); ASSERT_EQ(2, list.at(0)); @@ -41,7 +41,7 @@ TEST(list_test, test_at) { ASSERT_EQ(111, const_list.data()[0]); } -TEST(list_test, test_const_list_back_front_when_empty) { +TEST(array_list_test, test_const_list_back_front_when_empty) { int values[] = {1, 2, 3}; ArrayList list(values, 3); list.clear(); @@ -51,7 +51,7 @@ TEST(list_test, test_const_list_back_front_when_empty) { ASSERT_EQ(1, const_list.front()); } -TEST(list_test, test_clear) { +TEST(array_list_test, test_clear) { int values[] = {2, 3, 5, 7}; ArrayList list(values, 4); list.clear(); @@ -63,7 +63,7 @@ TEST(list_test, test_clear) { ASSERT_EQ(2, list.at(100)); } -TEST(list_test, test_list_begin_end) { +TEST(array_list_test, test_list_begin_end) { ArrayList list(5); ASSERT_EQ(list.begin(), list.end()); list.push_back(1); @@ -74,7 +74,7 @@ TEST(list_test, test_list_begin_end) { ASSERT_EQ(list.end(), it); } -TEST(list_test, test_const_list_begin_end) { +TEST(array_list_test, test_const_list_begin_end) { int values[] = {1, 2, 3, 4}; const ArrayList const_list(values, 4); const ArrayList empty_const_list(5); @@ -91,7 +91,7 @@ TEST(list_test, test_const_list_begin_end) { ASSERT_EQ(const_list.end(), it); } -TEST(list_test, test_insert_index_lvalue) { +TEST(array_list_test, test_insert_index_lvalue) { int values[] = {1, 2, 3, 4}; ArrayList list(values, 4, 5); ASSERT_EQ(4, list.size()); @@ -105,7 +105,7 @@ TEST(list_test, test_insert_index_lvalue) { } } -TEST(list_test, test_insert_index_rvalue) { +TEST(array_list_test, test_insert_index_rvalue) { int values[] = {1, 10}; ArrayList list(values, 2, 3); ASSERT_EQ(2, list.size()); @@ -118,7 +118,7 @@ TEST(list_test, test_insert_index_rvalue) { } } -TEST(list_test, test_insert_iterator_lvalue) { +TEST(array_list_test, test_insert_iterator_lvalue) { int values[] = {1, 10}; ArrayList list(values, 2, 3); ArrayList::iterator it = list.end(); @@ -130,7 +130,7 @@ TEST(list_test, test_insert_iterator_lvalue) { ASSERT_EQ(it, list.end()); } -TEST(list_test, test_insert_iterator_rvalue) { +TEST(array_list_test, test_insert_iterator_rvalue) { int values[] = {1, 10}; ArrayList list(values, 2, 2); ArrayList::iterator it = list.begin(); @@ -145,7 +145,7 @@ TEST(list_test, test_insert_iterator_rvalue) { ASSERT_EQ(list.end(), it); } -TEST(list_test, test_insert_when_full) { +TEST(array_list_test, test_insert_when_full) { int values[] = {1, 10}; ArrayList list(values, 2); list.insert(1, 15); @@ -156,7 +156,7 @@ TEST(list_test, test_insert_when_full) { ASSERT_EQ(10, list.at(2)); } -TEST(list_test, test_insert_when_empty) { +TEST(array_list_test, test_insert_when_empty) { ArrayList list(5); list.insert(0, 10); ASSERT_EQ(1, list.size()); @@ -164,7 +164,7 @@ TEST(list_test, test_insert_when_empty) { ASSERT_EQ(10, list.at(0)); } -TEST(list_test, test_insert_iterator_when_empty) { +TEST(array_list_test, test_insert_iterator_when_empty) { ArrayList list1(5); ArrayList::iterator it1 = list1.begin(); it1 = list1.insert(it1, 10); @@ -179,7 +179,102 @@ TEST(list_test, test_insert_iterator_when_empty) { ASSERT_EQ(10, *it2); } -TEST(list_test, test_push_back_when_full) { +TEST(array_list_test, test_insert_iterator) { + int values[] = {1, 2, 3, 4, 5}; + ArrayList list(values, 5, 5); + int traverse1[] = {1, 2, 10, 3, 4, 5}; + ArrayList::iterator it = list.insert(2, 10); + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(list[i], traverse1[i]); + } + ++it; + ++it; + it = list.insert(it, 15); + ASSERT_EQ(15, *it); + int traverse2[] = {1, 2, 10, 3, 15, 4, 5}; + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(list[i], traverse2[i]); + } +} + +TEST(array_list_test, test_insert_iterator_begin_end) { + int values[] = {1, 2, 3, 4, 5}; + ArrayList list(values, 5, 5); + list.insert(list.begin(), 15); + list.insert(list.end(), 20); + int traverse[] = {15, 1, 2, 3, 4, 5, 20}; + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(traverse[i], list[i]); + } +} + +TEST(array_list_test, test_push_pop_back) { + ArrayList list; + list.push_back(10); + list.push_back(15); + list.push_back(20); + int traverse[] = {10, 15, 20}; + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(traverse[i], list[i]); + } + list.pop_back(); + list.pop_back(); + ASSERT_EQ(1, list.size()); + ASSERT_EQ(list[0], 10); +} + +TEST(array_list_test, test_push_pop_front) { + ArrayList list; + list.push_front(0); + list.push_front(10); + list.push_front(15); + int traverse[] = {15, 10, 0}; + for (size_type i = 0; i < list.size(); i++) { + ASSERT_EQ(traverse[i], list[i]); + } + list.pop_front(); + list.pop_front(); + ASSERT_EQ(1, list.size()); + ASSERT_EQ(list[0], 0); +} + +TEST(array_list_test, test_index_of_empty_list) { + ArrayList empty_list; + ASSERT_EQ(0, empty_list.index_of(1234)); +} + +TEST(array_list_test, test_index_of) { + int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ArrayList list(values, 10); + for (size_type i = 0; i < 9; i++) { + ASSERT_EQ(i, list.index_of(i + 1)); + } +} + +TEST(array_list_test, test_index_of_repeats) { + int values[] = {1, 2, 3, 4, 5, 6, 5, 7, 5, 3}; + ArrayList list(values, 10); + ASSERT_EQ(4, list.index_of(5)); +} + +TEST(array_list_test, test_index_of_not_found) { + int values[] = {1, 2, 3, 4, 5, 6, 7, 10}; + ArrayList list(values, 8); + ASSERT_EQ(8, list.size()); + ASSERT_EQ(8, list.index_of(22)); + ASSERT_EQ(8, list.index_of(8)); +} + +TEST(array_list_test, test_find) { + int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 10}; + size_type size = 9; + ArrayList list(values, size); + ASSERT_EQ(list.begin(), list.find(1)); + ASSERT_EQ(list.end(), list.find(1000)); + ASSERT_EQ(5, *list.find(5)); +} + +TEST(array_list_test, test_push_back_when_full) { int values[] = {1, 2}; ArrayList list(values, 2); ASSERT_EQ(2, list.size()); @@ -190,7 +285,7 @@ TEST(list_test, test_push_back_when_full) { ASSERT_EQ(3, list.at(2)); } -TEST(list_test, test_erase_index) { +TEST(array_list_test, test_erase_index) { int values[] = {1, 2, 3}; ArrayList list(values, 3); ASSERT_EQ(3, list.size()); @@ -205,7 +300,7 @@ TEST(list_test, test_erase_index) { ASSERT_EQ(list.end(), list.erase(100)); } -TEST(list_test, test_erase_iterator) { +TEST(array_list_test, test_erase_iterator) { int values[] = {1, 2, 3}; ArrayList list(values, 3); ArrayList::iterator it = list.end(); @@ -223,25 +318,7 @@ TEST(list_test, test_erase_iterator) { ASSERT_EQ(list.end(), list.erase(it)); } -TEST(list_test, test_swap_lists) { - int values1[] = {1, 2, 3}; - int values2[] = {11, 22, 33, 44, 55}; - ArrayList list1(values1, 3, 5); - ArrayList list2(values2, 5, 10); - list1.swap(list2); - ASSERT_EQ(5, list1.size()); - ASSERT_EQ(10, list1.capacity()); - ASSERT_EQ(3, list2.size()); - ASSERT_EQ(5, list2.capacity()); - for (size_type i = 0; i < list1.size(); i++) { - ASSERT_EQ(values2[i], list1[i]); - } - for (size_type i = 0; i < list2.size(); i++) { - ASSERT_EQ(values1[i], list2[i]); - } -} - -TEST(list_test, test_reserve) { +TEST(array_list_test, test_reserve) { ArrayList list(10); ASSERT_EQ(10, list.capacity()); list.reserve(5); @@ -254,7 +331,7 @@ TEST(list_test, test_reserve) { ASSERT_EQ(5, list.back()); } -TEST(list_test, test_shrink) { +TEST(array_list_test, test_shrink) { int values[] = {1, 2, 3}; ArrayList list(values, 3); list.shrink(); diff --git a/tests/stl/concept_check.cpp b/tests/stl/concept_check.cpp index 54db1067..cac09d05 100644 --- a/tests/stl/concept_check.cpp +++ b/tests/stl/concept_check.cpp @@ -1,3 +1,4 @@ +#include #include "gtest/gtest.h" #include "stl/Concept.h" @@ -5,6 +6,7 @@ #include "stl/ChainMap.h" #include "stl/OpenMap.h" #include "stl/ArrayList.h" +#include "stl/LinkedList.h" using namespace wlp; @@ -83,3 +85,12 @@ TEST(concept_checks, check_map_concept) { ASSERT_FALSE((is_map())); ASSERT_FALSE((is_map>())); } + +TEST(concept_checks, check_list_concept) { + ASSERT_FALSE((is_list>())); + ASSERT_FALSE((is_list())); + ASSERT_FALSE((is_list>())); + + ASSERT_TRUE((is_list>())); + ASSERT_TRUE((is_list>())); +} diff --git a/tests/stl/linked_list_check.cpp b/tests/stl/linked_list_check.cpp index 5d1c2cef..58ff5c15 100644 --- a/tests/stl/linked_list_check.cpp +++ b/tests/stl/linked_list_check.cpp @@ -8,12 +8,12 @@ using namespace wlp; typedef LinkedList::iterator lli_it; typedef LinkedList::const_iterator lli_cit; -TEST(list_tests, constructor_tests) { +TEST(linked_list_test, constructor_tests) { LinkedList numlist; ASSERT_EQ(numlist.size(), 0); } -TEST(list_tests, push_pop_remove_tests) { +TEST(linked_list_test, push_pop_remove_tests) { LinkedList numlist; numlist.push_back(1); numlist.push_back(2); @@ -57,15 +57,15 @@ TEST(list_tests, push_pop_remove_tests) { ASSERT_EQ(constlist.size(), 3); } -TEST(list_tests, indexing_tests) { +TEST(linked_list_test, indexing_tests) { LinkedList numlist; numlist.push_front(1); numlist.push_back(2); numlist.push_front(3); // 3 1 2 - ASSERT_EQ(numlist.indexOf(3), 0); - ASSERT_EQ(numlist.indexOf(1), 1); - ASSERT_EQ(numlist.indexOf(2), 2); - ASSERT_EQ(numlist.indexOf(4), 3); + ASSERT_EQ(numlist.index_of(3), 0); + ASSERT_EQ(numlist.index_of(1), 1); + ASSERT_EQ(numlist.index_of(2), 2); + ASSERT_EQ(numlist.index_of(4), 3); ASSERT_EQ(numlist.at(0), 3); ASSERT_EQ(numlist[2], 2); const LinkedList constlist = move(numlist); @@ -74,7 +74,7 @@ TEST(list_tests, indexing_tests) { ASSERT_EQ(constlist[2], 2); } -TEST(list_tests, iterator_tests) { +TEST(linked_list_test, iterator_tests) { LinkedList numlist; numlist.push_front(1); numlist.push_back(2); @@ -100,7 +100,7 @@ TEST(list_tests, iterator_tests) { ASSERT_EQ(it2, constlist.end()); } -TEST(list_tests, copy_move_constructors) { +TEST(linked_list_test, copy_move_constructors) { LinkedList list; auto newlist = move(list); LinkedList list2; @@ -109,8 +109,97 @@ TEST(list_tests, copy_move_constructors) { ASSERT_EQ(movedlist.size(), 0); } -TEST(list_tests, dynamic_list_class) { - LinkedList* pList = new LinkedList; - ASSERT_EQ(pList->size(), 0); - delete pList; -} \ No newline at end of file +TEST(linked_list_test, test_insert_index) { + LinkedList list; + list.insert(0, 10); + list.insert(0, 15); + list.insert(1, 20); + list.insert(1, 25); + list.insert(2, 40); + ASSERT_EQ(5, list.size()); + int traverse[] = {15, 25, 40, 20, 10}; + LinkedList::iterator it = list.begin(); + for (int i = 0; i < list.size(); i++) { + ASSERT_EQ(*it, traverse[i]); + ++it; + } + ASSERT_EQ(it, list.end()); +} + +TEST(linked_list_test, test_insert_iterator) { + LinkedList list; + ASSERT_EQ(list.begin(), list.end()); + LinkedList::iterator it = list.begin(); + it = list.insert(it, 15); + ASSERT_EQ(it, list.begin()); + ASSERT_NE(list.begin(), list.end()); + list.insert(it, 20); + ASSERT_EQ(list.begin(), list.find(20)); + list.insert(it, 25); + ASSERT_EQ(15, *it); + --it; + ASSERT_EQ(25, *it); + it = list.insert(it, 30); + ++it; + list.insert(it, 45); + int traverse[] = {20, 30, 45, 25, 15}; + it = list.begin(); + ASSERT_EQ(5, list.size()); + for (int i = 0; i < list.size(); i++) { + ASSERT_EQ(traverse[i], *it); + ++it; + } + ASSERT_EQ(it, list.end()); +} + +TEST(linked_list_test, test_erase_index) { + LinkedList list; + int values[] = {1, 2, 3, 4, 5, 6, 7}; + for (size_type i = 0; i < 7; i++) { + list.push_back(values[i]); + } + LinkedList::iterator it = list.erase(1); + ASSERT_EQ(3, *it); + --it; + ASSERT_EQ(1, *it); + ASSERT_EQ(list.begin(), it); + it = list.erase(5); + ASSERT_EQ(it, list.end()); + it = list.erase(0); + ASSERT_EQ(3, *it); + ASSERT_EQ(4, list.size()); + LinkedList empty_list; + ASSERT_EQ(empty_list.erase(0), empty_list.end()); +} + +TEST(linked_list_test, test_erase_iterator) { + LinkedList list; + int values[] = {1, 2, 3, 4, 5, 6, 7}; + for (size_type i = 0; i < 7; i++) { + list.push_back(values[i]); + } + LinkedList::iterator it = list.find(5); + ASSERT_EQ(5, *it); + it = list.erase(it); + ASSERT_EQ(6, *it); + ++it; + ASSERT_EQ(7, *it); + it = list.erase(it); + ASSERT_EQ(it, list.end()); + ASSERT_EQ(list.end(), list.erase(it)); + it = list.erase(list.begin()); + ASSERT_EQ(it, list.begin()); + ASSERT_EQ(2, *it); +} + +TEST(linked_list_test, test_find) { + LinkedList list; + int values[] = {1, 2, 3, 4, 5, 6, 7}; + for (size_type i = 0; i < 7; i++) { + list.push_back(values[i]); + } + ASSERT_EQ(list.find(123), list.end()); + ASSERT_EQ(7, *list.find(7)); + ASSERT_EQ(1, *list.find(1)); + ASSERT_EQ(list.begin(), list.find(1)); +} From 6c583e4d173ceba660472f7591a2e10237eb4841 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Thu, 23 Nov 2017 15:14:05 -0800 Subject: [PATCH 023/102] Array tmp functions for sized and unsized arrays (#65) --- lib/wlib/utility/Tmp.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/wlib/utility/Tmp.h b/lib/wlib/utility/Tmp.h index aac823c9..99403d41 100644 --- a/lib/wlib/utility/Tmp.h +++ b/lib/wlib/utility/Tmp.h @@ -466,6 +466,45 @@ namespace wlp { : public true_type { }; + template + struct is_sized_array + : public false_type { + }; + + template + struct is_sized_array + : public false_type { + }; + + template + struct is_sized_array + : public true_type { + }; + + template + struct is_unsized_array + : public false_type { + }; + + template + struct is_unsized_array + : public true_type { + }; + + template + struct is_unsized_array + : public false_type { + }; + + template + struct get_array_size { + }; + + template + struct get_array_size { + static constexpr size_type value = size; + }; + /** * Decay metafunction strips pointers and references * from a type, allowing comparisons of the From d6010e1c4307775ab0c03f0ab958a55b27b4ecd5 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Thu, 23 Nov 2017 15:26:27 -0800 Subject: [PATCH 024/102] Changed iterators to return the correct reference and pointer types (#63) --- lib/wlib/stl/ArrayList.h | 6 ++++-- lib/wlib/stl/ChainMap.h | 6 ++++-- lib/wlib/stl/LinkedList.h | 6 ++++-- lib/wlib/stl/OpenMap.h | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index 12cbfe26..6c0b2180 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -36,6 +36,8 @@ namespace wlp { public: typedef wlp::size_type size_type; typedef T val_type; + typedef Ref reference; + typedef Ptr pointer; typedef ArrayList array_list; typedef ArrayListIterator self_type; @@ -100,7 +102,7 @@ namespace wlp { * @return a reference to the value pointed to * by this iterator */ - val_type &operator*() const { + reference operator*() const { return m_list->m_data[m_i]; } @@ -108,7 +110,7 @@ namespace wlp { * @return a pointer to the value pointer to * by this iterator */ - val_type *operator->() const { + pointer operator->() const { return &(operator*()); } diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index 3be6a28f..0ff93f9a 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -85,6 +85,8 @@ namespace wlp { typedef ChainHashMapIterator self_type; typedef Val val_type; + typedef Ref reference; + typedef Ptr pointer; typedef wlp::size_type size_type; @@ -128,7 +130,7 @@ namespace wlp { * @return reference to the value of the node * pointed to by the iterator */ - val_type &operator*() const { + reference operator*() const { return m_current->m_val; } @@ -136,7 +138,7 @@ namespace wlp { * @return pointer to the value of the node * pointed to by the iterator */ - val_type *operator->() const { + pointer operator->() const { return &(operator*()); } diff --git a/lib/wlib/stl/LinkedList.h b/lib/wlib/stl/LinkedList.h index 2c847020..4b4965e7 100644 --- a/lib/wlib/stl/LinkedList.h +++ b/lib/wlib/stl/LinkedList.h @@ -42,6 +42,8 @@ namespace wlp { template struct LinkedListIterator { typedef T val_type; + typedef Ref reference; + typedef Ptr pointer; typedef wlp::size_type size_type; typedef LinkedListNode node_type; typedef LinkedList list_type; @@ -86,7 +88,7 @@ namespace wlp { * @return reference to the value of the node * pointed to by the iterator */ - val_type &operator*() const { + reference operator*() const { return m_current->m_val; } @@ -94,7 +96,7 @@ namespace wlp { * @return pointer to the value of the node * pointed to by the iterator */ - val_type *operator->() const { + pointer operator->() const { return &(operator*()); } diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index bffae48b..68846d16 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -82,6 +82,8 @@ namespace wlp { typedef OpenHashMapIterator self_type; typedef Val val_type; + typedef Ref reference; + typedef Ptr pointer; typedef wlp::size_type size_type; @@ -125,7 +127,7 @@ namespace wlp { * @return reference to the value of the node * pointed to by the iterator */ - val_type &operator*() const { + reference operator*() const { return m_current->m_val; } @@ -133,7 +135,7 @@ namespace wlp { * @return pointer to the value of the node * pointed to by the iterator */ - val_type *operator->() const { + pointer operator->() const { return &(operator*()); } From d01febab12409aa2433bc0d1bd26d92cba5b98de Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Thu, 23 Nov 2017 23:54:24 -0500 Subject: [PATCH 025/102] [HF] memory-improvements (#66) * object size is stored to free them properly * memory test fixed * malloc changed to allow multi param object creation * build files removed * [HF] arg_array_malloc template condition fixed --- lib/wlib/memory/Memory.cpp | 43 +----- lib/wlib/memory/Memory.h | 246 +++++++++++++++++++++++++++------- lib/wlib/stl/ArrayList.h | 4 +- lib/wlib/stl/ChainMap.h | 4 +- lib/wlib/stl/OpenMap.h | 8 +- lib/wlib/utility/Tmp.h | 18 +++ tests/memory/memory_check.cpp | 70 +++++++--- tests/test.cpp | 18 ++- wmake | 3 +- 9 files changed, 299 insertions(+), 115 deletions(-) diff --git a/lib/wlib/memory/Memory.cpp b/lib/wlib/memory/Memory.cpp index a857ea53..77182bb8 100644 --- a/lib/wlib/memory/Memory.cpp +++ b/lib/wlib/memory/Memory.cpp @@ -355,42 +355,6 @@ void __memory_free(void *ptr) { allocator->deallocate(blockPtr); } -/** - * Reallocates a memory block previously allocated with @code __memory_alloc @endcode - * - * @param oldMem a pointer to a block created with @code __memory_alloc @endcode - * @param size the client requested block size - * @return pointer to new memory block - */ -void *__memory_realloc(void *oldMem, size32_type size) { - if (oldMem == nullptr) { - return __memory_alloc(size, false); - } - - if (size == 0) { - __memory_free(oldMem); - return nullptr; - } else { - // Create a new memory block - void *newMem = __memory_alloc(size, false); - if (newMem != nullptr) { - // Get the original allocator instance from the old memory block - __Allocator *oldAllocator = get_block_allocator(oldMem); - size_type oldSize = oldAllocator->getBlockSize() - sizeof(__Allocator *); - - // Copy the bytes from the old memory block into the new (as much as will fit) - memcpy(newMem, oldMem, (oldSize < size) ? oldSize : size); - - // Free the old memory block - __memory_free(oldMem); - - // Return the client pointer to the new memory block - return newMem; - } - return nullptr; - } -} - size32_type getTotalMemoryUsed() { size32_type totalMemory = 0; @@ -401,6 +365,10 @@ size32_type getTotalMemoryUsed() { return totalMemory; } +wlp::size32_type getTotalMemoryFree(){ + return getTotalMemoryAvailable() - getTotalMemoryUsed(); +} + size32_type getTotalMemoryAvailable() { size32_type totalMemory = 0; @@ -460,6 +428,9 @@ size_type getSmallestBlockSize() { } size32_type getFixedMemorySize(void *ptr) { + if (ptr == nullptr) + return 0; + __Allocator *allocator = get_block_allocator(ptr); return allocator->getBlockSize(); } diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 133ace1a..8d227bcd 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -17,9 +17,11 @@ #ifndef FIXED_MEMORY_MEMORY_H #define FIXED_MEMORY_MEMORY_H +#include "../utility/Utility.h" #include "../Types.h" #include "../utility/Tmp.h" +#include /** * @brief Helper for initializing and destroying memory management @@ -53,12 +55,6 @@ static MemoryInitDestroy __g_smemoryInitDestroy; */ void *__memory_alloc(uint32_t size, bool anObject); -/** - * Used internally not for client's use - * Use the @code realloc @endcode function - */ -void *__memory_realloc(void *ptr, uint32_t size); - /** * Used internally not for client's use * Use the @code free @endcode function @@ -66,72 +62,164 @@ void *__memory_realloc(void *ptr, uint32_t size); void __memory_free(void *ptr); /** - * This allocates memory of the size provided. Memory allocated could be greater than what has been - * asked in order to accommodate fixed memory allocations. If there is not a sufficient memory + * This allocates memory of the size of the type provided. Memory allocated could be greater + * than what has been asked in order to accommodate fixed memory allocations. If there is not a sufficient memory * available, it returns a @code nullptr @endcode * - * If an array of Objects is need then provide malloc with a number to specify how many objects to - * create and it will create that many objects. + * This is only used for creating single block of memory and not for array * - * @pre this can also act a @code new @endcode keyword to create objects so there is no need to use - * new keyword to create an object - * - * @pre malloc creates number of blocks of given type and it does not allocate memory by proving it + * @pre malloc creates number of blocks of given type and it does not allocate memory by providing it * number of bytes * - * @tparam Type pointer type - * @param num number of blocks of size @p Type + * @tparam T pointer type + * @tparam Args Argument types for non-fundamental Types + * @param args the arguments for @code Args @end types * @return address to memory allocated */ -template -Type *malloc(wlp::size_type num = 1) { - void *memory = nullptr; +template< + typename T, + typename... Args, + typename = typename wlp::enable_if::value, bool>::type> +T *malloc(Args... args) { + if (wlp::is_fundamental::type>::value){ + void *memory = __memory_alloc(static_cast(sizeof(T)), false); + return static_cast(memory); + } - if (!wlp::is_fundamental::value) { - memory = __memory_alloc(static_cast(sizeof(Type)) * num, true); + void *memory = __memory_alloc(static_cast(sizeof(T)), true); - uint16_t *objInfo = static_cast(memory); - *objInfo = static_cast(num); + uint16_t *objInfo = static_cast(memory); + *objInfo = static_cast(1); - char *pointer = reinterpret_cast(++objInfo); - for (wlp::size_type i = 0; i < num; ++i) { - new(pointer) Type; - pointer += sizeof(Type); - } + return new(reinterpret_cast(++objInfo)) T(wlp::forward(args)...); +} - return reinterpret_cast(objInfo); +/** + * This allocates memory of the size of the type provided. Memory allocated could be greater + * than what has been asked in order to accommodate fixed memory allocations. If there is not a sufficient memory + * available, it returns a @code nullptr @endcode + * + * This is only used for creating multiple block of memory and hence should be used for arrays. This + * only supports default Ctors for objects + * + * @pre malloc creates number of blocks of given type and it does not allocate memory by providing it + * number of bytes + * + * @tparam T pointer array type + * @tparam NonArrayType pointer non array type + * @param num number of elements needed + * @return address to memory allocated + */ +template< + typename T, + typename NonArrayType = typename wlp::remove_extent::type, + typename = typename wlp::enable_if::value, bool>::type> +NonArrayType *malloc(wlp::size_type num){ + if (wlp::is_fundamental::type>::value){ + void *memory = __memory_alloc(static_cast(sizeof(NonArrayType)) * num, false); + return static_cast(memory); } - memory = __memory_alloc(static_cast(sizeof(Type)) * num, false); + void *memory = __memory_alloc(static_cast(sizeof(NonArrayType)) * num, true); - return static_cast(memory); -} + uint16_t *objInfo = static_cast(memory); + *objInfo = static_cast(num); + + char *pointer = reinterpret_cast(++objInfo); + for (wlp::size_type i = 0; i < num; ++i) { + new(pointer) NonArrayType(); + pointer += sizeof(NonArrayType); + } + + return reinterpret_cast(objInfo); +}; /** - * This reallocates the memory to accommodate the new size provided. The memory address has to be - * allocation from Memory otherwise results are undefined. If there is not a sufficient memory + * This allocates memory of the size of the type provided. Memory allocated could be greater + * than what has been asked in order to accommodate fixed memory allocations. If there is not a sufficient memory * available, it returns a @code nullptr @endcode * - * @pre realloc creates number of blocks of given type and it does not allocate memory by proving it + * This is only used for creating multiple block of memory and hence should be used for arrays. This + * is a special case of @code malloc @endcode which supports creation of an array of objects where you can + * use non default ctor + * + * @pre this creates number of blocks of given type and it does not allocate memory by providing it * number of bytes * + * @warning should be avoided and used only where this is must + * + * @tparam T pointer array type + * @tparam Args Argument types for non-fundamental Types + * @param args the arguments for @code Args @end types + * @tparam NonArrayType pointer non array type + * @param num number of elements needed + * @return address to memory allocated + */ +template< + typename T, + typename... Args, + typename NonArrayType = typename wlp::remove_extent::type, + typename = typename wlp::enable_if::value, bool>::type> +NonArrayType *arg_array_malloc(wlp::size_type num, Args... args){ + void *memory = __memory_alloc(static_cast(sizeof(NonArrayType)) * num, true); + + uint16_t *objInfo = static_cast(memory); + *objInfo = static_cast(num); + + char *pointer = reinterpret_cast(++objInfo); + for (wlp::size_type i = 0; i < num; ++i) { + new(pointer) NonArrayType(wlp::forward(args)...); + pointer += sizeof(NonArrayType); + } + + return reinterpret_cast(objInfo); +}; + +/** + * Works exactly like malloc but initializes the memory by filling it with 0. This is the non + * array version of @code calloc @endcode + * * @tparam Type pointer type - * @param ptr address to memory to be reallocated - * @param size number of blocks of size @p Type - * @return address to new memory address + * @param num number of blocks of size @p Type + * @return address to memory allocated */ -template -Type *realloc(Type *ptr, wlp::size32_type num = 1) { - return static_cast(__memory_realloc(ptr, static_cast(sizeof(Type)) * num)); -} +template< + typename T, + typename = typename wlp::enable_if::value, bool>::type, + typename = typename wlp::enable_if::value, bool>::type> +T *calloc(){ + T *memory = malloc(); + + for (wlp::size32_type i = 0; i < sizeof(T); ++i) { + memory[i] = 0; + } + + return memory; +}; /** - * Returns the size of fixed sized block that was provided for @p ptr + * Works exactly like malloc but initializes the memory by filling it with 0. This is the + * array version of @code calloc @endcode * - * @param ptr memory address for which memory block is being searched - * @return the size of fixed size block + * @tparam Type pointer type + * @param num number of blocks of size @p Type + * @return address to memory allocated */ -wlp::size32_type getFixedMemorySize(void *ptr); +template< + typename T, + typename NonArrayType = typename wlp::remove_extent::type, + typename = typename wlp::enable_if::value, bool>::type, + typename = typename wlp::enable_if::value, bool>::type, + typename = typename wlp::enable_if::value, bool>::type> +NonArrayType *calloc(wlp::size_type num = 1){ + NonArrayType *memory = malloc(num); + + for (wlp::size32_type i = 0; i < num; ++i) { + memory[i] = 0; + } + + return memory; +}; /** * This frees the memory allocated. Only memory allocated using Memory will be freed and if another @@ -145,7 +233,7 @@ wlp::size32_type getFixedMemorySize(void *ptr); */ template -void free(Type *ptr) { +void free(Type *&ptr) { if (!wlp::is_fundamental::value) { uint16_t *objInfo = reinterpret_cast(ptr); wlp::size_type numObjects = *(--objInfo); @@ -160,6 +248,63 @@ void free(Type *ptr) { } else{ __memory_free(ptr); } + + ptr = nullptr; +} + +/** + * Returns the size of fixed sized block that was provided for @p ptr + * + * @param ptr memory address for which memory block is being searched + * @return the size of fixed size block + */ +wlp::size32_type getFixedMemorySize(void *ptr); + + +/** + * This reallocates the memory to accommodate the new size provided. The memory address has to be + * allocation from Memory otherwise results are undefined. If there is not a sufficient memory + * available, it returns a @code nullptr @endcode + * + * @pre realloc creates number of blocks of given type and it does not allocate memory by proving it + * number of bytes + * + * @tparam Type pointer type + * @param ptr address to memory to be reallocated + * @param size number of blocks of size @p Type + * @return address to new memory address + */ +template< + typename Type, + typename = typename wlp::enable_if::value, bool>::type> +Type *realloc(Type *ptr, wlp::size_type num = 1) { + if (num == 0) { + free(ptr); + return ptr; + } + + wlp::size32_type oldMemSize = getFixedMemorySize(ptr); + wlp::size32_type newMemSize = static_cast(sizeof(Type)) * num; + + if (oldMemSize == newMemSize) { + return ptr; + } + + Type *newPtr = malloc(num); + + // Typecast old and dest addresses to (char *) + char *cnew = reinterpret_cast(newPtr); + char *cold = reinterpret_cast(ptr); + + wlp::size32_type copySize = (oldMemSize < newMemSize) ? oldMemSize : newMemSize; + + // Copy contents of src[] to dest[] + for (wlp::size32_type i=0; i < copySize; i++) + cnew[i] = cold[i]; + + free(ptr); + + return newPtr; } /** @@ -169,6 +314,13 @@ void free(Type *ptr) { */ wlp::size32_type getTotalMemoryUsed(); +/** + * Returns the total memory that is free for use(in bytes) + * + * @return the total memory usage + */ +wlp::size32_type getTotalMemoryFree(); + /** * Returns the total memory available to use (in bytes). If no pool is * being used, this number can grow as more memory is borrowed otherwise diff --git a/lib/wlib/stl/ArrayList.h b/lib/wlib/stl/ArrayList.h index 6c0b2180..747e81a9 100644 --- a/lib/wlib/stl/ArrayList.h +++ b/lib/wlib/stl/ArrayList.h @@ -385,7 +385,7 @@ namespace wlp { * @param initial_size the initial capacity for the backing array */ void init_array(size_type initial_size) { - m_data = malloc(initial_size); + m_data = malloc(initial_size); } /** @@ -770,7 +770,7 @@ namespace wlp { return; } size_type new_capacity = static_cast(2 * m_capacity); - val_type *new_data = malloc(new_capacity); + val_type *new_data = malloc(new_capacity); for (size_type i = 0; i < m_size; i++) { new_data[i] = m_data[i]; } diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index 0ff93f9a..659179d3 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -553,7 +553,7 @@ namespace wlp { template void ChainHashMap::init_buckets(ChainHashMap::size_type n) { - m_buckets = malloc(n); + m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } @@ -565,7 +565,7 @@ namespace wlp { return; } size_type new_capacity = static_cast(m_capacity * 2); - node_type **new_buckets = malloc(new_capacity); + node_type **new_buckets = malloc(new_capacity); for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index 68846d16..c7ba9798 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -556,7 +556,7 @@ namespace wlp { template void OpenHashMap::init_buckets(OpenHashMap::size_type n) { - m_buckets = malloc(n); + m_buckets = malloc(n); for (size_type i = 0; i < n; ++i) { m_buckets[i] = nullptr; } @@ -568,7 +568,7 @@ namespace wlp { return; } size_type new_capacity = static_cast(m_capacity * 2); - node_type **new_buckets = malloc(new_capacity); + node_type **new_buckets = malloc(new_capacity); for (size_type i = 0; i < new_capacity; ++i) { new_buckets[i] = nullptr; } @@ -669,7 +669,7 @@ namespace wlp { m_buckets[i] = nullptr; while (++i < m_capacity && !m_buckets[i]) {} node_type *next_node = i >= m_capacity ? nullptr : m_buckets[i]; - node_type **new_buckets = malloc(m_capacity); + node_type **new_buckets = malloc(m_capacity); for (size_type k = 0; k < m_capacity; k++) { new_buckets[k] = nullptr; } @@ -705,7 +705,7 @@ namespace wlp { --m_num_elements; free(m_buckets[i]); m_buckets[i] = nullptr; - node_type **new_buckets = malloc(m_capacity); + node_type **new_buckets = malloc(m_capacity); for (size_type k = 0; k < m_capacity; k++) { new_buckets[k] = nullptr; } diff --git a/lib/wlib/utility/Tmp.h b/lib/wlib/utility/Tmp.h index 99403d41..025f5254 100644 --- a/lib/wlib/utility/Tmp.h +++ b/lib/wlib/utility/Tmp.h @@ -931,6 +931,24 @@ namespace wlp { }; #endif + template + struct __is_pointer_helper + : public false_type { }; + + template + struct __is_pointer_helper<_Tp*> + : public true_type { }; + + /* + * checks if @p _Tp type is a pointer type + * + * @tparam _Tp type being verified + */ + template + struct is_pointer + : public __is_pointer_helper::type>::type + { }; + /** * checks if @p _Tp type is a floating point * diff --git a/tests/memory/memory_check.cpp b/tests/memory/memory_check.cpp index 9836a2de..f5cc5e23 100644 --- a/tests/memory/memory_check.cpp +++ b/tests/memory/memory_check.cpp @@ -19,6 +19,10 @@ class Sample{ constr += 4; } + Sample(const char*){ + constr += 2; + } + ~Sample(){ constr += 5; } @@ -37,14 +41,14 @@ TEST(memory_check, general_usability) { ASSERT_NE(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); // allocate 2 characters - auto *character2 = malloc(2); + auto *character2 = malloc(2); // free all of them free(character); free(character2); // allocate 4 characters - auto *character4 = malloc(4); + auto *character4 = malloc(4); // reallocate character4 = realloc(character4, 8); @@ -61,45 +65,67 @@ TEST(memory_check, general_usability) { ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); } -TEST(memory_check, malloc_and_realloc){ - int *v = malloc(75); - *v = 75; - int *v2 = malloc(); - *v2 = 68; +TEST(memory_check, malloc_realloc_and_calloc){ + int *v = malloc(75); + v[0] = 75; + v[1] = 175; + v[2] = 375; - v2 = realloc(v2); - ASSERT_EQ(68, *v2); + int *v2 = malloc(); + v2[0] = 68; - v2 = realloc(v2, 15); - ASSERT_EQ(68, *v2); + v = realloc(v, 2); + ASSERT_EQ(75, v[0]); + ASSERT_EQ(175, v[1]); - v2 = realloc(v, 15); - ASSERT_EQ(75, *v2); + v2 = realloc(v2, 4); + ASSERT_EQ(68, v2[0]); v2 = realloc(v2, 0); ASSERT_EQ(nullptr, v2); + char *v3 = calloc(2); + ASSERT_EQ('\0', v3[0]); + ASSERT_EQ('\0', v3[1]); + + uint16_t *v4 = calloc(2); + ASSERT_EQ(0u, v4[0]); + ASSERT_EQ(0u, v4[1]); + + uint32_t *v5 = calloc(); + ASSERT_EQ(0u, v5[0]); + + char *v6 = calloc(); + ASSERT_EQ('\0', v6[0]); + free(v); free(v2); + free(v3); + free(v4); + free(v5); + free(v6); } TEST(memory_check, array_allocation){ Sample::constr = 0; - Sample *s = malloc(2); + Sample *s = malloc(2); ASSERT_EQ(8, Sample::constr); + Sample *d = arg_array_malloc(3, "hello"); + ASSERT_EQ(14, Sample::constr); + + free(d); + ASSERT_EQ(29, Sample::constr); free(s); - ASSERT_EQ(18, Sample::constr); + ASSERT_EQ(39, Sample::constr); } TEST(memory_check, free){ - free(nullptr); - int *g = malloc(7); - free(g); - int *l = malloc(7); - ASSERT_EQ(l, g); - free(g); -} + free(g); + ASSERT_EQ(nullptr, g); + free(g); + ASSERT_EQ(nullptr, g); +} diff --git a/tests/test.cpp b/tests/test.cpp index a04e5df2..21736f44 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -10,8 +10,24 @@ */ #include +#include "memory/Memory.h" int main(int argc, char *argv[]) { + wlp::size32_type startingFreeMemory = getTotalMemoryFree(); + ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + int testStatusCode = RUN_ALL_TESTS(); + + wlp::size32_type endingMemory = getTotalMemoryFree(); + + int memoryStatusCode = 0; + if (endingMemory - startingFreeMemory != 0 || startingFreeMemory != getTotalMemoryAvailable()) + memoryStatusCode = 1; + + int finalCode = 0; + + if (testStatusCode != memoryStatusCode) + finalCode = 1; + + return finalCode; } diff --git a/wmake b/wmake index 0a18c5ff..e7fdcbff 100755 --- a/wmake +++ b/wmake @@ -218,6 +218,7 @@ _build(){ } _coverage(){ + dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) mkdir -p bin cd bin echo "Running CMake" @@ -230,7 +231,7 @@ _coverage(){ cd bin echo "Generating Coverage Report" lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info '/usr/*' "$(pwd)/tests/*" "$(pwd)/include/*" "$(pwd)/examples/*" --output-file coverage.info + lcov --remove coverage.info '/usr/*' "$dir/tests/*" "$dir/include/*" "$dir/examples/*" --output-file coverage.info lcov --list coverage.info mkdir -p coverage genhtml -no-branch-coverage -o coverage coverage.info From 36bf34c9c640f36ee523f5ec1f41e5439a803fb9 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Fri, 24 Nov 2017 05:41:23 -0800 Subject: [PATCH 026/102] Added rvalue overload for (#67) --- lib/wlib/memory/Memory.h | 49 ++++++++++++++++++++------- tests/memory/memory_check.cpp | 62 ++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 20 deletions(-) diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 8d227bcd..06ed7a03 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -81,7 +81,7 @@ template< typename... Args, typename = typename wlp::enable_if::value, bool>::type> T *malloc(Args... args) { - if (wlp::is_fundamental::type>::value){ + if (wlp::is_fundamental::type>::value) { void *memory = __memory_alloc(static_cast(sizeof(T)), false); return static_cast(memory); } @@ -114,8 +114,8 @@ template< typename T, typename NonArrayType = typename wlp::remove_extent::type, typename = typename wlp::enable_if::value, bool>::type> -NonArrayType *malloc(wlp::size_type num){ - if (wlp::is_fundamental::type>::value){ +NonArrayType *malloc(wlp::size_type num) { + if (wlp::is_fundamental::type>::value) { void *memory = __memory_alloc(static_cast(sizeof(NonArrayType)) * num, false); return static_cast(memory); } @@ -160,7 +160,7 @@ template< typename... Args, typename NonArrayType = typename wlp::remove_extent::type, typename = typename wlp::enable_if::value, bool>::type> -NonArrayType *arg_array_malloc(wlp::size_type num, Args... args){ +NonArrayType *arg_array_malloc(wlp::size_type num, Args... args) { void *memory = __memory_alloc(static_cast(sizeof(NonArrayType)) * num, true); uint16_t *objInfo = static_cast(memory); @@ -187,7 +187,7 @@ template< typename T, typename = typename wlp::enable_if::value, bool>::type, typename = typename wlp::enable_if::value, bool>::type> -T *calloc(){ +T *calloc() { T *memory = malloc(); for (wlp::size32_type i = 0; i < sizeof(T); ++i) { @@ -211,7 +211,7 @@ template< typename = typename wlp::enable_if::value, bool>::type, typename = typename wlp::enable_if::value, bool>::type, typename = typename wlp::enable_if::value, bool>::type> -NonArrayType *calloc(wlp::size_type num = 1){ +NonArrayType *calloc(wlp::size_type num = 1) { NonArrayType *memory = malloc(num); for (wlp::size32_type i = 0; i < num; ++i) { @@ -231,11 +231,10 @@ NonArrayType *calloc(wlp::size_type num = 1){ * @tparam Type pointer type * @param ptr address to memory that will be freed */ - template void free(Type *&ptr) { if (!wlp::is_fundamental::value) { - uint16_t *objInfo = reinterpret_cast(ptr); + uint16_t *objInfo = reinterpret_cast(ptr); wlp::size_type numObjects = *(--objInfo); Type *pointer = ptr; @@ -245,13 +244,38 @@ void free(Type *&ptr) { } __memory_free(reinterpret_cast(objInfo)); - } else{ + } else { __memory_free(ptr); } ptr = nullptr; } +/** + * Overload for rvalue pointers. + * + * @see free + * @tparam Type + * @param ptr + */ +template +void free(Type *&&ptr) { + if (!wlp::is_fundamental::value) { + uint16_t *objInfo = reinterpret_cast(ptr); + wlp::size_type numObjects = *(--objInfo); + + Type *pointer = ptr; + for (wlp::size_type i = 0; i < numObjects; ++i) { + pointer->~Type(); + ++pointer; + } + + __memory_free(reinterpret_cast(objInfo)); + } else { + __memory_free(ptr); + } +} + /** * Returns the size of fixed sized block that was provided for @p ptr * @@ -293,14 +317,15 @@ Type *realloc(Type *ptr, wlp::size_type num = 1) { Type *newPtr = malloc(num); // Typecast old and dest addresses to (char *) - char *cnew = reinterpret_cast(newPtr); - char *cold = reinterpret_cast(ptr); + char *cnew = reinterpret_cast(newPtr); + char *cold = reinterpret_cast(ptr); wlp::size32_type copySize = (oldMemSize < newMemSize) ? oldMemSize : newMemSize; // Copy contents of src[] to dest[] - for (wlp::size32_type i=0; i < copySize; i++) + for (wlp::size32_type i = 0; i < copySize; i++) { cnew[i] = cold[i]; + } free(ptr); diff --git a/tests/memory/memory_check.cpp b/tests/memory/memory_check.cpp index f5cc5e23..bd4ba625 100644 --- a/tests/memory/memory_check.cpp +++ b/tests/memory/memory_check.cpp @@ -11,23 +11,46 @@ #include "memory/Memory.h" -class Sample{ +class Sample { public: static int constr; - Sample(){ + Sample() { constr += 4; } - Sample(const char*){ + Sample(const char *) { constr += 2; } - ~Sample(){ + ~Sample() { constr += 5; } }; +class SamplePtrContainer { +public: + Sample *simp; + + SamplePtrContainer() + : simp(malloc()) { + } + + ~SamplePtrContainer() { + if (get() != nullptr) { + free(get()); // calls rvalue overload + } + } + + void destroy() { + free(simp); + } + + Sample *get() { + return simp; + } +}; + int Sample::constr = 0; TEST(memory_check, general_usability) { @@ -65,7 +88,7 @@ TEST(memory_check, general_usability) { ASSERT_EQ(getTotalMemoryAvailable(), getTotalMemoryAvailable() - getTotalMemoryUsed()); } -TEST(memory_check, malloc_realloc_and_calloc){ +TEST(memory_check, malloc_realloc_and_calloc) { int *v = malloc(75); v[0] = 75; v[1] = 175; @@ -88,7 +111,7 @@ TEST(memory_check, malloc_realloc_and_calloc){ ASSERT_EQ('\0', v3[0]); ASSERT_EQ('\0', v3[1]); - uint16_t *v4 = calloc(2); + uint16_t *v4 = calloc(2); ASSERT_EQ(0u, v4[0]); ASSERT_EQ(0u, v4[1]); @@ -106,7 +129,7 @@ TEST(memory_check, malloc_realloc_and_calloc){ free(v6); } -TEST(memory_check, array_allocation){ +TEST(memory_check, array_allocation) { Sample::constr = 0; Sample *s = malloc(2); @@ -121,7 +144,7 @@ TEST(memory_check, array_allocation){ ASSERT_EQ(39, Sample::constr); } -TEST(memory_check, free){ +TEST(memory_check, free) { int *g = malloc(7); free(g); ASSERT_EQ(nullptr, g); @@ -129,3 +152,26 @@ TEST(memory_check, free){ free(g); ASSERT_EQ(nullptr, g); } + +TEST(memory_check, free_rvalue) { + Sample::constr = 0; + SamplePtrContainer *pSpc = malloc(); + ASSERT_EQ(4, Sample::constr); + ASSERT_NE(nullptr, pSpc->simp); + ASSERT_NE(nullptr, pSpc->get()); + free(pSpc); + ASSERT_EQ(9, Sample::constr); + ASSERT_EQ(nullptr, pSpc); + Sample::constr = 0; + SamplePtrContainer spc; + ASSERT_EQ(4, Sample::constr); + spc.destroy(); + ASSERT_EQ(9, Sample::constr); + ASSERT_EQ(nullptr, spc.simp); + Sample::constr = 0; + { + SamplePtrContainer local_spc; + ASSERT_EQ(4, Sample::constr); + } // ~SamplePtrContainer called on local_spc + ASSERT_EQ(9, Sample::constr); +} From b432039087c4efc221d9879d68dcfe1e2d5b9be2 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Fri, 24 Nov 2017 05:50:06 -0800 Subject: [PATCH 027/102] Modified treemap to fit map concept, created set concept (#60) --- lib/wlib/stl/ChainMap.h | 52 ++------ lib/wlib/stl/ChainSet.h | 12 +- lib/wlib/stl/Concept.h | 232 +++++++++++++++++++++------------- lib/wlib/stl/OpenMap.h | 44 ++----- lib/wlib/stl/OpenSet.h | 22 ++-- lib/wlib/stl/TreeMap.h | 9 +- lib/wlib/stl/TreeSet.h | 13 +- tests/stl/chain_map_check.cpp | 23 ++-- tests/stl/concept_check.cpp | 34 +++-- tests/stl/open_map_check.cpp | 42 +++--- 10 files changed, 245 insertions(+), 238 deletions(-) diff --git a/lib/wlib/stl/ChainMap.h b/lib/wlib/stl/ChainMap.h index 659179d3..6a9ccb4a 100644 --- a/lib/wlib/stl/ChainMap.h +++ b/lib/wlib/stl/ChainMap.h @@ -24,7 +24,7 @@ namespace wlp { // Forward declaration of ChainHashMap template class ChainHashMap; @@ -36,7 +36,7 @@ namespace wlp { * @tparam Key key type * @tparam Val value type */ - template + template struct ChainHashMapNode { typedef ChainHashMapNode node_type; typedef Key key_type; @@ -487,7 +487,9 @@ namespace wlp { * @return the value mapped to by the key * @throws KeyException if the key does not map to a value */ - iterator at(const key_type &key); + val_type &at(const key_type &key) { + return *find(key); + } /** * @see ChainHashMap::at() @@ -495,7 +497,9 @@ namespace wlp { * @return the mapped value * @throws KeyException if the key does not exist */ - const_iterator at(const key_type &key) const; + const val_type &at(const key_type &key) const { + return *find(key); + } /** * @param key key for which to check existence of a value @@ -603,7 +607,7 @@ namespace wlp { m_num_elements = 0; } - template + template template Pair::iterator, bool> ChainHashMap::insert(K &&key, V &&val) { @@ -624,7 +628,7 @@ namespace wlp { return Pair(iterator(tmp, this), true); }; - template + template template Pair::iterator, bool> ChainHashMap::insert_or_assign(K &&key, V &&val) { @@ -731,40 +735,6 @@ namespace wlp { return false; } - template - typename ChainHashMap::iterator - ChainHashMap::at(const key_type &key) { - size_type i = hash(key); - node_type *cur = m_buckets[i]; - if (!cur) { - return end(); - } - while (cur && !m_equal(key, cur->m_key)) { - cur = cur->next; - } - if (!cur) { - return end(); - } - return iterator(cur, this); - } - - template - typename ChainHashMap::const_iterator - ChainHashMap::at(const key_type &key) const { - size_type i = hash(key); - node_type *cur = m_buckets[i]; - if (!cur) { - return end(); - } - while (cur && !m_equal(key, cur->m_key)) { - cur = cur->next; - } - if (!cur) { - return end(); - } - return const_iterator(cur, this); - } - template bool ChainHashMap::contains(const key_type &key) const { size_type i = hash(key); @@ -864,7 +834,7 @@ namespace wlp { m_buckets = nullptr; } - template + template ChainHashMap & ChainHashMap::operator=(ChainHashMap &&map) { clear(); diff --git a/lib/wlib/stl/ChainSet.h b/lib/wlib/stl/ChainSet.h index 0f19bea9..7b1240ea 100644 --- a/lib/wlib/stl/ChainSet.h +++ b/lib/wlib/stl/ChainSet.h @@ -32,15 +32,15 @@ namespace wlp { class ChainHashSet { public: typedef ChainHashSet set_type; - typedef ChainHashMap map_type; + typedef ChainHashMap table_type; typedef typename ChainHashMap::iterator iterator; typedef typename ChainHashMap::const_iterator const_iterator; - typedef typename map_type::size_type size_type; - typedef typename map_type::percent_type percent_type; - typedef typename map_type::key_type key_type; + typedef typename table_type::size_type size_type; + typedef typename table_type::percent_type percent_type; + typedef typename table_type::key_type key_type; private: - map_type m_hash_map; + table_type m_hash_map; public: /** @@ -100,7 +100,7 @@ namespace wlp { /** * @return a pointer to the backing hash map */ - const map_type *get_backing_table() const { + const table_type *get_backing_table() const { return &m_hash_map; } diff --git a/lib/wlib/stl/Concept.h b/lib/wlib/stl/Concept.h index 3338c1c3..bd5f5090 100644 --- a/lib/wlib/stl/Concept.h +++ b/lib/wlib/stl/Concept.h @@ -26,33 +26,33 @@ * function with a function name, return type, and * argument types. */ -#define __HAS_FCN(...) VFUNC(__HAS_FCN, __VA_ARGS__) -#define __HAS_FCN3(TypeName, FcnName, RetType) \ +#define HAS_FCN(...) VFUNC(HAS_FCN, __VA_ARGS__) +#define HAS_FCN3(TypeName, FcnName, RetType) \ is_same().FcnName( \ )), RetType> -#define __HAS_FCN4(TypeName, FcnName, ArgType1, RetType) \ +#define HAS_FCN4(TypeName, FcnName, ArgType1, RetType) \ is_same().FcnName( \ declval() \ )), RetType> -#define __HAS_FCN5(TypeName, FcnName, ArgType1, ArgType2, RetType) \ +#define HAS_FCN5(TypeName, FcnName, ArgType1, ArgType2, RetType) \ is_same().FcnName( \ declval(), \ declval() \ )), RetType> -#define __HAS_FCN6(TypeName, FcnName, ArgType1, ArgType2, ArgType3, RetType) \ +#define HAS_FCN6(TypeName, FcnName, ArgType1, ArgType2, ArgType3, RetType) \ is_same().FcnName( \ declval(), \ declval(), \ declval() \ )), RetType> -#define __HAS_FCN7(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, RetType) \ +#define HAS_FCN7(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, RetType) \ is_same().FcnName( \ declval(), \ declval(), \ declval(), \ declval() \ )), RetType> -#define __HAS_FCN8(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, RetType) \ +#define HAS_FCN8(TypeName, FcnName, ArgType1, ArgType2, ArgType3, ArgType4, ArgType5, RetType) \ is_same().FcnName( \ declval(), \ declval(), \ @@ -75,12 +75,12 @@ namespace wlp { private: template static constexpr auto check(T *) -> typename and_< - __HAS_FCN(const T, __lt__, const Q &, const Q &, bool), - __HAS_FCN(const T, __le__, const Q &, const Q &, bool), - __HAS_FCN(const T, __eq__, const Q &, const Q &, bool), - __HAS_FCN(const T, __ne__, const Q &, const Q &, bool), - __HAS_FCN(const T, __gt__, const Q &, const Q &, bool), - __HAS_FCN(const T, __ge__, const Q &, const Q &, bool) + HAS_FCN(const T, __lt__, const Q &, const Q &, bool), + HAS_FCN(const T, __le__, const Q &, const Q &, bool), + HAS_FCN(const T, __eq__, const Q &, const Q &, bool), + HAS_FCN(const T, __ne__, const Q &, const Q &, bool), + HAS_FCN(const T, __gt__, const Q &, const Q &, bool), + HAS_FCN(const T, __ge__, const Q &, const Q &, bool) >::type; template @@ -111,7 +111,7 @@ namespace wlp { * @tparam C candidate forward iterator type */ template::value && has_val_type::value> - struct forward_iterator_concept { + struct iterator_concept { static constexpr bool value = false; }; @@ -123,7 +123,7 @@ namespace wlp { * @tparam C forward iterator type */ template - struct forward_iterator_concept { + struct iterator_concept { private: typedef typename C::val_type val_type; typedef typename C::size_type size_type; @@ -132,18 +132,18 @@ namespace wlp { template static constexpr auto check(T *) -> typename and_< typename or_< - __HAS_FCN(const T, operator*, val_type &), - __HAS_FCN(const T, operator*, const val_type &) + HAS_FCN(const T, operator*, val_type &), + HAS_FCN(const T, operator*, const val_type &) >::type, typename or_< - __HAS_FCN(T, operator->, val_type *), - __HAS_FCN(T, operator->, const val_type *) + HAS_FCN(T, operator->, val_type *), + HAS_FCN(T, operator->, const val_type *) >::type, - __HAS_FCN(T, operator++, iterator &), - __HAS_FCN(T, operator++, int, iterator), - __HAS_FCN(const T, operator==, const iterator &, bool), - __HAS_FCN(const T, operator!=, const iterator &, bool), - __HAS_FCN(T, operator=, const iterator &, iterator &) + HAS_FCN(T, operator++, iterator &), + HAS_FCN(T, operator++, int, iterator), + HAS_FCN(const T, operator==, const iterator &, bool), + HAS_FCN(const T, operator!=, const iterator &, bool), + HAS_FCN(T, operator=, const iterator &, iterator &) >::type; @@ -163,8 +163,8 @@ namespace wlp { * @return true if the class is a forward iterator */ template - static constexpr bool is_forward_iterator() { - return forward_iterator_concept::value; + static constexpr bool is_iterator() { + return iterator_concept::value; } /** @@ -195,25 +195,25 @@ namespace wlp { template static constexpr auto check(T *) -> typename and_< typename or_< - __HAS_FCN(const T, operator*, val_type &), - __HAS_FCN(const T, operator*, const val_type &) + HAS_FCN(const T, operator*, val_type &), + HAS_FCN(const T, operator*, const val_type &) >::type, typename or_< - __HAS_FCN(const T, operator->, val_type *), - __HAS_FCN(const T, operator->, const val_type *) + HAS_FCN(const T, operator->, val_type *), + HAS_FCN(const T, operator->, const val_type *) >::type, - __HAS_FCN(T, operator++, iterator &), - __HAS_FCN(T, operator++, int, iterator), - __HAS_FCN(T, operator--, iterator &), - __HAS_FCN(T, operator--, int, iterator), - __HAS_FCN(T, operator==, const iterator &, bool), - __HAS_FCN(T, operator!=, const iterator &, bool), - __HAS_FCN(T, operator=, const iterator &, iterator &), - __HAS_FCN(const T, operator+, const size_type &, iterator), - __HAS_FCN(const T, operator-, const size_type &, iterator), - __HAS_FCN(const T, operator-, const iterator &, size_type), - __HAS_FCN(T, operator-=, const size_type &, iterator &), - __HAS_FCN(T, operator+=, const size_type &, iterator &) + HAS_FCN(T, operator++, iterator &), + HAS_FCN(T, operator++, int, iterator), + HAS_FCN(T, operator--, iterator &), + HAS_FCN(T, operator--, int, iterator), + HAS_FCN(T, operator==, const iterator &, bool), + HAS_FCN(T, operator!=, const iterator &, bool), + HAS_FCN(T, operator=, const iterator &, iterator &), + HAS_FCN(const T, operator+, const size_type &, iterator), + HAS_FCN(const T, operator-, const size_type &, iterator), + HAS_FCN(const T, operator-, const iterator &, size_type), + HAS_FCN(T, operator-=, const size_type &, iterator &), + HAS_FCN(T, operator+=, const size_type &, iterator &) >::type; template @@ -275,25 +275,25 @@ namespace wlp { template static constexpr auto check(T *) -> typename and_< - __HAS_FCN(const T, size, size_type), - __HAS_FCN(const T, capacity, size_type), - __HAS_FCN(const T, empty, bool), - __HAS_FCN(T, begin, iterator), - __HAS_FCN(T, end, iterator), - __HAS_FCN(const T, begin, const_iterator), - __HAS_FCN(const T, end, const_iterator), - __HAS_FCN(T, clear, void), - __HAS_FCN(T, insert, const key_type &, const val_type &, insert_ret_type), - __HAS_FCN(T, insert_or_assign, const key_type &, const val_type &, insert_ret_type), - __HAS_FCN(T, erase, const key_type &, bool), - __HAS_FCN(T, erase, const iterator &, iterator), - __HAS_FCN(T, at, const key_type &, iterator), - __HAS_FCN(const T, at, const key_type &, const_iterator), - __HAS_FCN(const T, contains, const key_type &, bool), - __HAS_FCN(T, find, const key_type &, iterator), - __HAS_FCN(const T, find, const key_type &, const_iterator), - __HAS_FCN(T, operator[], const key_type &, val_type &), - __HAS_FCN(T, operator=, map_type &&, map_type &) + HAS_FCN(const T, size, size_type), + HAS_FCN(const T, capacity, size_type), + HAS_FCN(const T, empty, bool), + HAS_FCN(T, begin, iterator), + HAS_FCN(T, end, iterator), + HAS_FCN(const T, begin, const_iterator), + HAS_FCN(const T, end, const_iterator), + HAS_FCN(T, clear, void), + HAS_FCN(T, insert, const key_type &, const val_type &, insert_ret_type), + HAS_FCN(T, insert_or_assign, const key_type &, const val_type &, insert_ret_type), + HAS_FCN(T, erase, const key_type &, bool), + HAS_FCN(T, erase, const iterator &, iterator), + HAS_FCN(T, at, const key_type &, val_type &), + HAS_FCN(const T, at, const key_type &, const val_type &), + HAS_FCN(const T, contains, const key_type &, bool), + HAS_FCN(T, find, const key_type &, iterator), + HAS_FCN(const T, find, const key_type &, const_iterator), + HAS_FCN(T, operator[], const key_type &, val_type &), + HAS_FCN(T, operator=, map_type &&, map_type &) >::type; template @@ -316,6 +316,60 @@ namespace wlp { return map_concept::value; } + template::value && + has_size_type::value && + has_iterator::value && + has_const_iterator::value + > + struct set_concept { + static constexpr bool value = false; + }; + + template + struct set_concept { + private: + typedef typename C::key_type key_type; + typedef typename C::size_type size_type; + typedef typename C::iterator iterator; + typedef typename C::const_iterator const_iterator; + typedef C set_type; + + typedef Pair insert_ret_type; + + template + static constexpr auto check(T *) -> typename and_< + HAS_FCN(const T, size, size_type), + HAS_FCN(const T, capacity, size_type), + HAS_FCN(const T, empty, bool), + HAS_FCN(T, begin, iterator), + HAS_FCN(T, end, iterator), + HAS_FCN(const T, begin, const_iterator), + HAS_FCN(const T, end, const_iterator), + HAS_FCN(T, clear, void), + HAS_FCN(T, insert, const key_type &, insert_ret_type), + HAS_FCN(const T, contains, const key_type &, bool), + HAS_FCN(T, find, const key_type &, iterator), + HAS_FCN(const T, find, const key_type &, const_iterator), + HAS_FCN(T, erase, const iterator &, iterator), + HAS_FCN(T, erase, const key_type &, bool), + HAS_FCN(T, operator=, set_type &&, set_type &) + >::type; + + template + static constexpr false_type check(...); + + typedef decltype(check(nullptr)) type; + + public: + static constexpr bool value = type::value; + }; + + template + static constexpr bool is_set() { + return set_concept::value; + } + template::value && has_size_type::value && @@ -337,34 +391,34 @@ namespace wlp { template static constexpr auto check(T *) -> typename and_< - __HAS_FCN(const T, size, size_type), - __HAS_FCN(const T, capacity, size_type), - __HAS_FCN(const T, empty, bool), - __HAS_FCN(T, at, size_type, val_type &), - __HAS_FCN(const T, at, size_type, const val_type &), - __HAS_FCN(T, operator[], size_type, val_type &), - __HAS_FCN(const T, operator[], size_type, const val_type &), - __HAS_FCN(T, front, val_type &), - __HAS_FCN(const T, front, const val_type &), - __HAS_FCN(T, back, val_type &), - __HAS_FCN(const T, back, const val_type &), - __HAS_FCN(T, clear, void), - __HAS_FCN(T, begin, iterator), - __HAS_FCN(const T, begin, const_iterator), - __HAS_FCN(T, end, iterator), - __HAS_FCN(const T, end, const_iterator), - __HAS_FCN(T, insert, size_type, const val_type &, iterator), - __HAS_FCN(T, insert, const iterator &, const val_type &, iterator), - __HAS_FCN(T, erase, size_type, iterator), - __HAS_FCN(T, erase, const iterator &, iterator), - __HAS_FCN(T, push_back, const val_type &, void), - __HAS_FCN(T, push_front, const val_type &, void), - __HAS_FCN(T, pop_back, void), - __HAS_FCN(T, pop_front, void), - __HAS_FCN(const T, index_of, const val_type &, size_type), - __HAS_FCN(T, find, const val_type &, iterator), - __HAS_FCN(const T, find, const val_type &, const_iterator), - __HAS_FCN(T, operator=, list_type &&, list_type &) + HAS_FCN(const T, size, size_type), + HAS_FCN(const T, capacity, size_type), + HAS_FCN(const T, empty, bool), + HAS_FCN(T, at, size_type, val_type &), + HAS_FCN(const T, at, size_type, const val_type &), + HAS_FCN(T, operator[], size_type, val_type &), + HAS_FCN(const T, operator[], size_type, const val_type &), + HAS_FCN(T, front, val_type &), + HAS_FCN(const T, front, const val_type &), + HAS_FCN(T, back, val_type &), + HAS_FCN(const T, back, const val_type &), + HAS_FCN(T, clear, void), + HAS_FCN(T, begin, iterator), + HAS_FCN(const T, begin, const_iterator), + HAS_FCN(T, end, iterator), + HAS_FCN(const T, end, const_iterator), + HAS_FCN(T, insert, size_type, const val_type &, iterator), + HAS_FCN(T, insert, const iterator &, const val_type &, iterator), + HAS_FCN(T, erase, size_type, iterator), + HAS_FCN(T, erase, const iterator &, iterator), + HAS_FCN(T, push_back, const val_type &, void), + HAS_FCN(T, push_front, const val_type &, void), + HAS_FCN(T, pop_back, void), + HAS_FCN(T, pop_front, void), + HAS_FCN(const T, index_of, const val_type &, size_type), + HAS_FCN(T, find, const val_type &, iterator), + HAS_FCN(const T, find, const val_type &, const_iterator), + HAS_FCN(T, operator=, list_type &&, list_type &) >::type; template diff --git a/lib/wlib/stl/OpenMap.h b/lib/wlib/stl/OpenMap.h index c7ba9798..61508b1b 100644 --- a/lib/wlib/stl/OpenMap.h +++ b/lib/wlib/stl/OpenMap.h @@ -491,7 +491,9 @@ namespace wlp { * @return the value mapped to by the key * @throws KeyException if the key does not map to a value */ - iterator at(const key_type &key); + val_type &at(const key_type &key) { + return *find(key); + } /** * @see OpenHashMap::at() @@ -499,7 +501,9 @@ namespace wlp { * @return the mapped value * @throws KeyException if the key does not exist */ - const_iterator at(const key_type &key) const; + const val_type &at(const key_type &key) const { + return *find(key); + } /** * @param key key for which to check existence of a value @@ -727,38 +731,6 @@ namespace wlp { return true; } - template - typename OpenHashMap::iterator - OpenHashMap::at(const key_type &key) { - size_type i = hash(key); - while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_capacity) { - i = 0; - } - } - if (m_buckets[i]) { - return iterator(m_buckets[i], this); - } else { - return end(); - } - } - - template - typename OpenHashMap::const_iterator - OpenHashMap::at(const key_type &key) const { - size_type i = hash(key); - while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { - if (++i >= m_capacity) { - i = 0; - } - } - if (m_buckets[i]) { - return const_iterator(m_buckets[i], this); - } else { - return end(); - } - } - template bool OpenHashMap::contains(const key_type &key) const { size_type i = hash(key); @@ -797,7 +769,7 @@ namespace wlp { } template - typename OpenHashMap::iterator + inline typename OpenHashMap::iterator OpenHashMap::find(const key_type &key) { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { @@ -813,7 +785,7 @@ namespace wlp { } template - typename OpenHashMap::const_iterator + inline typename OpenHashMap::const_iterator OpenHashMap::find(const key_type &key) const { size_type i = hash(key); while (m_buckets[i] && !m_equal(key, m_buckets[i]->m_key)) { diff --git a/lib/wlib/stl/OpenSet.h b/lib/wlib/stl/OpenSet.h index 2dec3856..6574806f 100644 --- a/lib/wlib/stl/OpenSet.h +++ b/lib/wlib/stl/OpenSet.h @@ -32,19 +32,19 @@ namespace wlp { class Equal = Equal> class OpenHashSet { public: - typedef OpenHashSet hash_set; - typedef OpenHashMap map_type; + typedef OpenHashSet set_type; + typedef OpenHashMap table_type; typedef typename OpenHashMap::iterator iterator; typedef typename OpenHashMap::const_iterator const_iterator; - typedef typename map_type::size_type size_type; - typedef typename map_type::percent_type percent_type; - typedef typename map_type::key_type key_type; + typedef typename table_type::size_type size_type; + typedef typename table_type::percent_type percent_type; + typedef typename table_type::key_type key_type; private: /** * The backing hash map. */ - map_type m_hash_map; + table_type m_hash_map; public: /** @@ -64,14 +64,14 @@ namespace wlp { /** * Disable copy constructor. */ - OpenHashSet(const hash_set &) = delete; + OpenHashSet(const set_type &) = delete; /** * Move constructor. * * @param set hash set to move */ - OpenHashSet(hash_set &&set) + OpenHashSet(set_type &&set) : m_hash_map(move(set.m_hash_map)) { } @@ -106,7 +106,7 @@ namespace wlp { /** * @return a pointer to the backing hash map */ - const map_type *get_backing_hash_map() const { + const table_type *get_backing_hash_map() const { return &m_hash_map; } @@ -222,7 +222,7 @@ namespace wlp { * * @return reference to this set */ - hash_set &operator=(const hash_set &) = delete; + set_type &operator=(const set_type &) = delete; /** * Move assignment operator. @@ -230,7 +230,7 @@ namespace wlp { * @param set hash set to move * @return reference to this set */ - hash_set &operator=(hash_set &&set) { + set_type &operator=(set_type &&set) { m_hash_map = move(set.m_hash_map); return *this; } diff --git a/lib/wlib/stl/TreeMap.h b/lib/wlib/stl/TreeMap.h index 5f1fd27b..93ca9839 100644 --- a/lib/wlib/stl/TreeMap.h +++ b/lib/wlib/stl/TreeMap.h @@ -43,8 +43,8 @@ namespace wlp { table_type m_tree; public: - explicit TreeMap(size_type n = 12) - : m_tree(n) { + explicit TreeMap() + : m_tree() { } TreeMap(const map_type &) = delete; @@ -134,8 +134,9 @@ namespace wlp { return m_tree.find(key); } - val_type &operator[](const key_type &key) { - Pair result = m_tree.insert_unique(key, val_type()); + template + val_type &operator[](K &&key) { + Pair result = m_tree.insert_unique(forward(key), val_type()); return *result.m_first; } diff --git a/lib/wlib/stl/TreeSet.h b/lib/wlib/stl/TreeSet.h index 61c7a9c1..fe82e252 100644 --- a/lib/wlib/stl/TreeSet.h +++ b/lib/wlib/stl/TreeSet.h @@ -39,8 +39,8 @@ namespace wlp { table_type m_tree; public: - explicit TreeSet(size_type n = 12) - : m_tree(n) { + explicit TreeSet() + : m_tree() { } TreeSet(const set_type &) = delete; @@ -102,10 +102,11 @@ namespace wlp { return m_tree.find(key); } - iterator &erase(iterator &pos) { - iterator tmp = pos++; - m_tree.erase(tmp); - return pos; + iterator erase(const iterator &pos) { + iterator tmp = pos; + ++tmp; + m_tree.erase(pos); + return tmp; } bool erase(const key_type &key) { diff --git a/tests/stl/chain_map_check.cpp b/tests/stl/chain_map_check.cpp index d50bfaba..bf2b6006 100644 --- a/tests/stl/chain_map_check.cpp +++ b/tests/stl/chain_map_check.cpp @@ -149,7 +149,7 @@ TEST(chain_map_test, test_insert_at_iterator_no_collision) { for (ui16 i = 0; i < 5; i++) { ASSERT_TRUE(r[i].second()); ASSERT_EQ(values[i], *r[i].first()); - ASSERT_EQ(values[i], *map.at(keys[i])); + ASSERT_EQ(values[i], map.at(keys[i])); } P_imi_b failed = map.insert(0, 10); ASSERT_FALSE(failed.second()); @@ -228,13 +228,13 @@ TEST(chain_map_test, test_insert_or_assign) { ASSERT_EQ(2, map.size()); ASSERT_TRUE(r1.second()); ASSERT_TRUE(r2.second()); - ASSERT_EQ(v1, *map.at(a1)); - ASSERT_EQ(v2, *map.at(a2)); + ASSERT_EQ(v1, map.at(a1)); + ASSERT_EQ(v2, map.at(a2)); P_smi_b r3 = map.insert_or_assign(a1, v3); ASSERT_EQ(2, map.size()); ASSERT_FALSE(r3.second()); ASSERT_EQ(v3, *r3.first()); - ASSERT_EQ(v3, *map.at(a1)); + ASSERT_EQ(v3, map.at(a1)); } TEST(chain_map_test, test_erase_key_nothing) { @@ -280,12 +280,9 @@ TEST(chain_map_test, test_erase_iterator) { it = map.erase(it); ASSERT_EQ(3, map.size()); ASSERT_EQ(map.end(), it); - ASSERT_EQ(40, *map.at(40)); - ASSERT_EQ(20, *map.at(20)); - ASSERT_EQ(0, *map.at(0)); - ASSERT_EQ(map.end(), map.at(1)); - ASSERT_EQ(map.end(), map.at(3)); - ASSERT_EQ(map.end(), map.at(33)); + ASSERT_EQ(40, map.at(40)); + ASSERT_EQ(20, map.at(20)); + ASSERT_EQ(0, map.at(0)); it = r20.first(); it = map.erase(it); ASSERT_EQ(2, map.size()); @@ -308,10 +305,10 @@ TEST(chain_map_test, test_contains_access_operator) { ASSERT_EQ(5, map.size()); map.insert(3, 30); ASSERT_EQ(6, map.size()); - ASSERT_EQ(30, *map.at(3)); + ASSERT_EQ(30, map.at(3)); map[3] = 33; ASSERT_EQ(6, map.size()); - ASSERT_EQ(33, *map.at(3)); + ASSERT_EQ(33, map.at(3)); ASSERT_EQ(50, map[5]); ASSERT_EQ(150, map[15]); ASSERT_EQ(200, map[20]); @@ -401,7 +398,7 @@ TEST(chain_map_test, test_at_const) { map.insert(3, 15); const int_map const_map(move(map)); const int v = 3; - ASSERT_EQ(15, *const_map.at(v)); + ASSERT_EQ(15, const_map.at(v)); ASSERT_EQ(15, *const_map.find(v)); } diff --git a/tests/stl/concept_check.cpp b/tests/stl/concept_check.cpp index cac09d05..1fb9b5ec 100644 --- a/tests/stl/concept_check.cpp +++ b/tests/stl/concept_check.cpp @@ -1,11 +1,14 @@ -#include #include "gtest/gtest.h" #include "stl/Concept.h" #include "stl/Comparator.h" #include "stl/ChainMap.h" #include "stl/OpenMap.h" +#include "stl/TreeMap.h" #include "stl/ArrayList.h" +#include "stl/ChainSet.h" +#include "stl/OpenSet.h" +#include "stl/TreeSet.h" #include "stl/LinkedList.h" using namespace wlp; @@ -68,24 +71,35 @@ TEST(concept_checks, check_random_access_iterator_concept) { } TEST(concept_checks, check_forward_iterator_concept) { - ASSERT_TRUE((is_forward_iterator::iterator>())); - ASSERT_TRUE((is_forward_iterator::const_iterator>())); - ASSERT_TRUE((is_forward_iterator::iterator>())); - ASSERT_TRUE((is_forward_iterator::const_iterator>())); - ASSERT_TRUE((is_forward_iterator::iterator>())); - ASSERT_TRUE((is_forward_iterator::const_iterator>())); - - ASSERT_FALSE((is_forward_iterator>())); - ASSERT_FALSE((is_forward_iterator>())); + ASSERT_TRUE((is_iterator::iterator>())); + ASSERT_TRUE((is_iterator::const_iterator>())); + ASSERT_TRUE((is_iterator::iterator>())); + ASSERT_TRUE((is_iterator::const_iterator>())); + ASSERT_TRUE((is_iterator::iterator>())); + ASSERT_TRUE((is_iterator::const_iterator>())); + + ASSERT_FALSE((is_iterator>())); + ASSERT_FALSE((is_iterator>())); } TEST(concept_checks, check_map_concept) { ASSERT_TRUE((is_map>())); ASSERT_TRUE((is_map>())); + ASSERT_TRUE((is_map>())); + ASSERT_FALSE((is_map())); ASSERT_FALSE((is_map>())); } +TEST(concept_checks, check_set_concept) { + ASSERT_FALSE((is_set>())); + ASSERT_FALSE((is_set())); + + ASSERT_TRUE((is_set>())); + ASSERT_TRUE((is_set>())); + ASSERT_TRUE((is_set>())); +} + TEST(concept_checks, check_list_concept) { ASSERT_FALSE((is_list>())); ASSERT_FALSE((is_list())); diff --git a/tests/stl/open_map_check.cpp b/tests/stl/open_map_check.cpp index f65eaad9..5a8354f4 100644 --- a/tests/stl/open_map_check.cpp +++ b/tests/stl/open_map_check.cpp @@ -57,14 +57,12 @@ TEST(open_map_test, test_at_const) { map[9] = 9; map[17] = 17; const int_map const_map(move(map)); - ASSERT_EQ(const_map.end(), const_map.at(10)); - ASSERT_EQ(7, *const_map.at(7)); - ASSERT_EQ(8, *const_map.at(8)); - ASSERT_EQ(9, *const_map.at(9)); - ASSERT_EQ(17, *const_map.at(17)); - ASSERT_EQ(const_map.at(7), const_map.find(7)); - ASSERT_EQ(const_map.at(10), const_map.find(10)); - ASSERT_EQ(const_map.at(9), const_map.find(9)); + ASSERT_EQ(7, const_map.at(7)); + ASSERT_EQ(8, const_map.at(8)); + ASSERT_EQ(9, const_map.at(9)); + ASSERT_EQ(17, const_map.at(17)); + ASSERT_EQ(const_map.at(7), *const_map.find(7)); + ASSERT_EQ(const_map.at(9), *const_map.find(9)); int_map::const_iterator it = const_map.begin(); ASSERT_EQ(17, *it); ++it; @@ -156,29 +154,29 @@ TEST(open_map_test, test_at_returns_value) { map.insert(20, 19); map.insert(4, 16); ASSERT_EQ(4, map.size()); - ASSERT_EQ(12, *map.at(10)); - ASSERT_EQ(15, *map.at(16)); - ASSERT_EQ(19, *map.at(20)); - ASSERT_EQ(16, *map.at(4)); + ASSERT_EQ(12, map.at(10)); + ASSERT_EQ(15, map.at(16)); + ASSERT_EQ(19, map.at(20)); + ASSERT_EQ(16, map.at(4)); } TEST(open_map_test, test_at_is_assignable) { int_map map(10, 75); map.insert(10, 12); map.insert(16, 15); - ASSERT_EQ(15, *map.at(16)); - ASSERT_EQ(12, *map.at(10)); + ASSERT_EQ(15, map.at(16)); + ASSERT_EQ(12, map.at(10)); ASSERT_EQ(2, map.size()); - *map.at(16) = 100; - *map.at(10) = 101; - ASSERT_EQ(100, *map.at(16)); - ASSERT_EQ(101, *map.at(10)); + map.at(16) = 100; + map.at(10) = 101; + ASSERT_EQ(100, map.at(16)); + ASSERT_EQ(101, map.at(10)); ASSERT_EQ(2, map.size()); } TEST(open_map_test, test_at_returns_pass_the_end) { int_map map(10, 75); - ASSERT_EQ(map.end(), map.at(4)); + ASSERT_EQ(map.end(), map.find(4)); } TEST(open_map_test, test_contains_key) { @@ -195,9 +193,9 @@ TEST(open_map_test, test_contains_key) { ASSERT_TRUE(map.contains(key1)); ASSERT_TRUE(map.contains(key2)); ASSERT_TRUE(map.contains(key3)); - ASSERT_EQ(val1, *map.at(key1)); - ASSERT_EQ(val2, *map.at(key2)); - ASSERT_EQ(val3, *map.at(key3)); + ASSERT_EQ(val1, map.at(key1)); + ASSERT_EQ(val2, map.at(key2)); + ASSERT_EQ(val3, map.at(key3)); } TEST(open_map_test, test_find) { From 8ad6ee4aa827c90558d6372646d2b78eee2083c9 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Fri, 24 Nov 2017 13:37:42 -0800 Subject: [PATCH 028/102] allow creation of primitive types with value (#69) --- lib/wlib/memory/Memory.h | 2 +- tests/memory/memory_check.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 06ed7a03..381cc8e5 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -83,7 +83,7 @@ template< T *malloc(Args... args) { if (wlp::is_fundamental::type>::value) { void *memory = __memory_alloc(static_cast(sizeof(T)), false); - return static_cast(memory); + return new(memory) T(wlp::forward(args)...); } void *memory = __memory_alloc(static_cast(sizeof(T)), true); diff --git a/tests/memory/memory_check.cpp b/tests/memory/memory_check.cpp index bd4ba625..39ef2437 100644 --- a/tests/memory/memory_check.cpp +++ b/tests/memory/memory_check.cpp @@ -175,3 +175,12 @@ TEST(memory_check, free_rvalue) { } // ~SamplePtrContainer called on local_spc ASSERT_EQ(9, Sample::constr); } + +TEST(memory_check, placement_fundamental) { + int *i = malloc(5); + ASSERT_EQ(5, *i); + free(i); + char *l = malloc('c'); + ASSERT_EQ('c', *l); + free(l); +} From 6b8a06f5f2a4342393249a96d5f1b861e4c7aef7 Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 26 Nov 2017 13:24:34 -0500 Subject: [PATCH 029/102] [IMP] Mem imporv (#74) * imporved dynamic string and added realloc improvement * realloc imporv * dynamic string removed * memcpy use instead of a for loop * unused chars removed --- lib/wlib/memory/Memory.h | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/wlib/memory/Memory.h b/lib/wlib/memory/Memory.h index 381cc8e5..fbb8b14d 100644 --- a/lib/wlib/memory/Memory.h +++ b/lib/wlib/memory/Memory.h @@ -284,6 +284,12 @@ void free(Type *&&ptr) { */ wlp::size32_type getFixedMemorySize(void *ptr); +/** + * Returns the smallest block of memory that is given + * + * @return the smallest block of memory + */ +wlp::size_type getSmallestBlockSize(); /** * This reallocates the memory to accommodate the new size provided. The memory address has to be @@ -310,22 +316,14 @@ Type *realloc(Type *ptr, wlp::size_type num = 1) { wlp::size32_type oldMemSize = getFixedMemorySize(ptr); wlp::size32_type newMemSize = static_cast(sizeof(Type)) * num; - if (oldMemSize == newMemSize) { + if (oldMemSize >= newMemSize + getSmallestBlockSize()) { return ptr; } Type *newPtr = malloc(num); - // Typecast old and dest addresses to (char *) - char *cnew = reinterpret_cast(newPtr); - char *cold = reinterpret_cast(ptr); - wlp::size32_type copySize = (oldMemSize < newMemSize) ? oldMemSize : newMemSize; - - // Copy contents of src[] to dest[] - for (wlp::size32_type i = 0; i < copySize; i++) { - cnew[i] = cold[i]; - } + memcpy(newPtr, ptr, copySize); free(ptr); @@ -401,11 +399,5 @@ uint16_t getNumBlocks(); */ uint16_t getMaxAllocations(); -/** - * Returns the smallest block of memory that is given - * - * @return the smallest block of memory - */ -wlp::size_type getSmallestBlockSize(); #endif //FIXED_MEMORY_MEMORY_H From 822f3a0c05133abce387d295e50922baf4002aa0 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Sun, 26 Nov 2017 11:26:35 -0800 Subject: [PATCH 030/102] Create LICENSE (#75) --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e3bdbe69 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Waterloop + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 5e078e215cbfab8d95f2f65dca9f3bb92bf0b761 Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Sun, 26 Nov 2017 11:53:10 -0800 Subject: [PATCH 031/102] Fixes conversion warnings (#71) --- lib/wlib/stl/Bitset.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/wlib/stl/Bitset.h b/lib/wlib/stl/Bitset.h index cca3074f..65c5c6b5 100644 --- a/lib/wlib/stl/Bitset.h +++ b/lib/wlib/stl/Bitset.h @@ -28,7 +28,7 @@ namespace wlp { */ template struct pow_mask { - static const uint32_t value = (uint32_t) ((1 << exp) - 1); + static const uint32_t value = static_cast((1 << exp) - 1); }; /** @@ -47,7 +47,7 @@ namespace wlp { */ template struct ceil_bits { - static const uint32_t value = (nBits + INT32_SIZE - 1) / INT32_SIZE; + static const uint32_t value = static_cast((nBits + INT32_SIZE - 1) / INT32_SIZE); }; template @@ -99,14 +99,14 @@ namespace wlp { */ void setFromNumber(uint64_t n) { memset(m_array, 0, sizeof(m_array)); - constexpr uint32_t end = nBits / INT32_SIZE; - constexpr uint32_t extra = nBits - end * INT32_SIZE; + constexpr uint32_t end = static_cast(nBits / INT32_SIZE); + constexpr uint32_t extra = static_cast(nBits - end * INT32_SIZE); for (size_type i = 0; i < end; ++i) { - m_array[i] = (uint32_t) n; + m_array[i] = static_cast(n); n >>= INT32_SIZE; } if (extra) { - m_array[end] = ((uint32_t) n) & pow_mask::value; + m_array[end] = (static_cast(n)) & pow_mask::value; } } From d736ff1761f996a8671179efc8fbc119886ee080 Mon Sep 17 00:00:00 2001 From: Bob Wei Date: Sun, 26 Nov 2017 19:56:26 +0000 Subject: [PATCH 032/102] EMB#3-dynamic-strings created (#73) * imporved dynamic string and added realloc improvement * Changes to dynamic string * Changes to dynamic string * Updated Dynamic String * all pr fixes added to imporve dynamic strings --- lib/wlib/CMakeLists.txt | 3 +- lib/wlib/strings/DynamicString.cpp | 471 +++++++++++++++++++++++++ lib/wlib/strings/DynamicString.h | 375 ++++++++++++++++++++ tests/CMakeLists.txt | 2 +- tests/strings/dynamic_string_check.cpp | 116 ++++++ 5 files changed, 965 insertions(+), 2 deletions(-) create mode 100644 lib/wlib/strings/DynamicString.cpp create mode 100644 lib/wlib/strings/DynamicString.h create mode 100644 tests/strings/dynamic_string_check.cpp diff --git a/lib/wlib/CMakeLists.txt b/lib/wlib/CMakeLists.txt index 3becf7b8..3b21775a 100644 --- a/lib/wlib/CMakeLists.txt +++ b/lib/wlib/CMakeLists.txt @@ -30,7 +30,8 @@ file(GLOB header_files "utility/*.h") file(GLOB source_files - "memory/*.cpp") + "memory/*.cpp" + "strings/*.cpp") set(HEADER_FILES ${header_files}) set(SOURCE_FILES ${source_files}) diff --git a/lib/wlib/strings/DynamicString.cpp b/lib/wlib/strings/DynamicString.cpp new file mode 100644 index 00000000..1787ba40 --- /dev/null +++ b/lib/wlib/strings/DynamicString.cpp @@ -0,0 +1,471 @@ +/** + * @file DynamicString.cpp + * @brief DynamicString is a class that provides dynamic strings and functions for dynamic strings + * + * @author Bob Wei + * @date November 25, 2017 + * @bug No known bugs + */ + +#include "DynamicString.h" + +namespace wlp { + + /** + * Default constructor creates string with no characters + */ + DynamicString::DynamicString() : DynamicString(nullptr, nullptr, 0, 0) {} + + /** + * Constructor creates string using character array + * + * @param str char string + */ + DynamicString::DynamicString(const char *str) + : DynamicString(str, nullptr, static_cast(strlen(str)), 0) {} + + /** + * Constructor creates string using DynamicString object + * + * @param str @code DynamicString object + */ + DynamicString::DynamicString(const DynamicString &str) : DynamicString(str.c_str()) {} + + DynamicString::DynamicString(const char *str1, const char *str2, size_type len1, size_type len2) { + m_len = len1 + len2; + m_buffer = malloc(static_cast(m_len + 1)); + + memcpy(m_buffer, str1, len1); + memcpy(m_buffer + len1, str2, len2); + + m_buffer[m_len] = '\0'; + } + + /** + * Destructor for DynamicString object + */ + DynamicString::~DynamicString() { + if (m_buffer) { + free(m_buffer); + } + } + + /** + * Assign operator assigns current object to given object + * + * @param str @code DynamicString object + * @return current object + */ + DynamicString &DynamicString::operator=(const DynamicString &str) { + return operator=(str.c_str()); + } + + /** + * Assign operator assigns current object to given character string + * @param str + * @return current object + */ + DynamicString &DynamicString::operator=(const char *str) { + auto size = static_cast(strlen(str)); + m_buffer = realloc(m_buffer, static_cast(size + 1)); + strcpy(m_buffer, str); + m_buffer[size] = '\0'; + m_len = size; + + return *this; + } + + /** + * Provides current m_length of string + * + * @return string m_length + */ + size_type DynamicString::length() const { + return m_len; + } + + /** + * Clears the string such that there are no characters left in it + */ + void DynamicString::clear() { + m_buffer[0] = '\0'; + m_len = 0; + } + + /** + * Element access operator gives access to character at @code pos + * + * @param pos the position of the character + * @return character at @code position + */ + char &DynamicString::operator[](size_type pos) { + return m_buffer[pos]; + } + + /** + * Element access operator gives access to character at @code pos. + * Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &DynamicString::operator[](size_type pos) const { + return m_buffer[pos]; + } + + /** + * Provides access to character at @code pos with bounds checking + * + * @param pos the position of the character + * @return character at @code position + */ + char &DynamicString::at(size_type pos) { + return pos < m_len ? m_buffer[pos] : m_buffer[m_len]; + } + + /** + * Provides access to character at @code pos with bounds checking. Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &DynamicString::at(size_type pos) const { + return pos < m_len ? m_buffer[pos] : m_buffer[m_len]; + } + + /** + * Checks if string is empty or not + * + * @return if string is empty or not + */ + bool DynamicString::empty() const { + return m_len == 0; + } + + /** + * Provides access to the first character in the string + * + * @return the first character + */ + char &DynamicString::front() { + return m_buffer[0]; + } + + /** + * Provides access to the first character in the string. Character is constant + * + * @return the first character + */ + const char &DynamicString::front() const { + return m_buffer[0]; + } + + /** + * Provides access to the last character in the string + * + * @return the last character + */ + char &DynamicString::end() { + return empty() ? m_buffer[0] : m_buffer[m_len - 1]; + } + + /** + * Provides access to the last character in the string. Character is constant + * + * @return the last character + */ + const char &DynamicString::end() const { + return empty() ? m_buffer[0] : m_buffer[m_len - 1]; + } + + /** + * Modifier operator adds character to the current string. + * + * @param c character to add + * @return the current string + */ + DynamicString &DynamicString::operator+=(char c) { + const char array[2] = {c, '\0'}; + return append(array); + } + + /** + * Modifier operator adds char string to the current string. + * + * @param val char string to add + * @return the current string + */ + DynamicString &DynamicString::operator+=(const char *val) { + return append(val, static_cast(strlen(val))); + } + + /** + * Modifier operator adds @code DynamicString object to the current string. + * + * @param other @code DynamicString string to add + * @return the current string + */ + DynamicString &DynamicString::operator+=(DynamicString &other) { + return append(other.c_str(), other.length()); + } + + DynamicString &DynamicString::append(const char *cstr, size_type len) { + auto newLength = static_cast(m_len + len); + m_buffer = realloc(m_buffer, static_cast(newLength + 1)); + + memcpy(m_buffer + m_len, cstr, newLength); + + m_buffer[newLength] = '\0'; + m_len = newLength; + + return *this; + } + + /** + * Appends a character string to the current string. + * + * @param str character string to add + * @return the current string + */ + DynamicString &DynamicString::append(const char *str) { + return append(str, static_cast(strlen(str))); + } + + /** + * Appends a DynamicString string to the current string. + * + * @param str DynamicString string to add + * @return the current string + */ + DynamicString &DynamicString::append(const DynamicString &str) { + return append(str.c_str(), str.length()); + } + + /** + * Appends a character to the current string. + * + * @param c character to add + * @return the current string + */ + DynamicString &DynamicString::push_back(const char c) { + const char array[2] = {c, '\0'}; + return append(array, 1); + } + + /** + * Deletes the element @p pos from the String + * + * @param pos position of the element to be deleted + * @return the modified String + */ + DynamicString &DynamicString::erase(size_type pos) { + if (m_len == 0 || pos >= m_len) return *this; + + m_len--; + + for (size_type i = pos; i < m_len; i++) { + m_buffer[i] = m_buffer[i + 1]; + } + + m_buffer[m_len] = '\0'; + return *this; + } + + /** + * Deletes the last character in the String + */ + void DynamicString::pop_back() { + if (m_len != 0) { + m_buffer[m_len - 1] = '\0'; + m_len--; + } + } + + /** + * Provides access to character array that string uses behind the screen + * + * @return character array + */ + const char *DynamicString::c_str() const { + return m_buffer; + } + + /** + * Makes substring of the current string + * + * @param pos starting position + * @param m_length m_length of the new string + * @return new string which is a substring of current string + */ + DynamicString DynamicString::substr(size_type pos, size_type m_length) const { + char newBuffer[m_length + 1]; + + for (size_type i = pos; i < pos + m_length; i++) { + newBuffer[i - pos] = m_buffer[i]; + } + + newBuffer[m_length] = '\0'; + + DynamicString s{newBuffer}; + + return s; + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str @code DynamicString string to compare against current string + * @return a signed number based on how strings compare + */ + diff_type DynamicString::compare(const DynamicString &str) const { + return compare(str.c_str()); + } + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str character string to compare against current string + * @return a signed number based on how strings compare + */ + diff_type DynamicString::compare(const char *str) const { + return static_cast(strcmp(c_str(), str)); + } + + /** + * Compares a string and character and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param c character to compare against current string + * @return a signed number based on how strings compare + */ + diff_type DynamicString::compare(char c) const { + const char array[2] = {c, '\0'}; + return static_cast(strcmp(c_str(), array)); + } + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return true or false based on if two strings are equal + */ + + bool operator==(const DynamicString &lhs, const DynamicString &rhs) { + return lhs.compare(rhs) == 0; + } + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs character string as left hand side string + * @param rhs @code DynamicString @endcode string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(const char *lhs, const DynamicString &rhs) { + return rhs.compare(lhs) == 0; + } + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs @code DynamicString @endcode string as left hand side string + * @param rhs character string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(const DynamicString &lhs, const char *rhs) { + return lhs.compare(rhs) == 0; + } + + /** + * Comparative operator compares if string and single character are equal or not + * + * @param lhs character as left hand side + * @param rhs @code DynamicString string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(char lhs, const DynamicString &rhs) { + return rhs.compare(lhs) == 0; + } + + /** + * Comparative operator compares if string and single character are equal or not + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character as right hand side + * @return true or false based on if two strings are equal + */ + bool operator==(const DynamicString &lhs, char rhs) { + return lhs.compare(rhs) == 0; + } + + /** + * Additive operator adds two given strings + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, const DynamicString &rhs) { + DynamicString newStr(lhs.c_str(), rhs.c_str(), static_cast(strlen(lhs.c_str())), + static_cast(strlen(rhs.c_str()))); + return newStr; + } + + /** + * Additive operator adds two given strings + * + * @param lhs character string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const char *lhs, const DynamicString &rhs) { + DynamicString newStr(lhs, rhs.c_str(), static_cast(strlen(lhs)), + static_cast(strlen(rhs.c_str()))); + return newStr; + } + + /** + * Additive operator adds two given strings + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, const char *rhs) { + DynamicString newStr(lhs.c_str(), rhs, static_cast(strlen(lhs.c_str())), + static_cast(strlen(rhs))); + return newStr; + } + + /** + * Additive operator single character to string + * + * @param lhs character as left hand side + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(char lhs, const DynamicString &rhs) { + const char temp[2] = {lhs, '\0'}; + DynamicString newStr(temp, rhs.c_str(), 1, static_cast(strlen(rhs.c_str()))); + return newStr; + } + + /** + * Additive operator adds string to single character + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character as right hand side + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, char rhs) { + const char temp[2] = {rhs, '\0'}; + DynamicString newStr(lhs.c_str(), temp, static_cast(strlen(lhs.c_str())), 1); + return newStr; + } +} diff --git a/lib/wlib/strings/DynamicString.h b/lib/wlib/strings/DynamicString.h new file mode 100644 index 00000000..54d83ea8 --- /dev/null +++ b/lib/wlib/strings/DynamicString.h @@ -0,0 +1,375 @@ +/** + * @file DynamicString.h + * @brief DynamicString is a class that provides dynamic strings and functions for dynamic strings + * + * @author Bob Wei + * @date November , 2017 + * @bug No known bugs + */ + +#ifndef EMBEDDEDCPLUSPLUS_DYNAMICSTRING_H +#define EMBEDDEDCPLUSPLUS_DYNAMICSTRING_H + +#include + +#include "../memory/Memory.h" +#include "../Types.h" + +namespace wlp { + class DynamicString { + public: + /** + * Default constructor creates string with no characters + */ + DynamicString(); + + /** + * Constructor creates string using character array + * + * @param str char string + */ + explicit DynamicString(const char *str); + + /** + * Constructor creates string using DynamicString object + * + * @param str @code DynamicString object + */ + DynamicString(const DynamicString &str); + + /** + * Destructor for DynamicString object + */ + ~DynamicString(); + + /** + * Assign operator assigns current object to given object + * + * @param str @code DynamicString object + * @return current object + */ + DynamicString &operator=(const DynamicString &str); + + /** + * Assign operator assigns current object to given character string + * @param str + * @return current object + */ + DynamicString &operator=(const char *str); + + /** + * Provides current length of string + * + * @return string length + */ + size_type length() const; + + /** + * Clears the string such that there are no characters left in it + */ + void clear(); + + /** + * Element access operator gives access to character at @code pos + * + * @param pos the position of the character + * @return character at @code position + */ + char &operator[](size_type pos); + + /** + * Element access operator gives access to character at @code pos. + * Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &operator[](size_type pos) const; + + /** + * Provides access to character at @code pos with bounds checking + * + * @param pos the position of the character + * @return character at @code position + */ + char &at(size_type pos); + + /** + * Provides access to character at @code pos with bounds checking. Character is constant + * + * @param pos the position of the character + * @return character at @code position + */ + const char &at(size_type pos) const; + + /** + * Checks if string is empty or not + * + * @return if string is empty or not + */ + bool empty() const; + + /** + * Provides access to the first character in the string + * + * @return the first character + */ + char &front(); + + /** + * Provides access to the first character in the string. Character is constant + * + * @return the first character + */ + const char &front() const; + + /** + * Provides access to the last character in the string + * + * @return the last character + */ + char &end(); + + /** + * Provides access to the last character in the string. Character is constant + * + * @return the last character + */ + const char &end() const; + + /** + * Modifier operator adds character to the current string. + * + * @param c character to add + * @return the current string + */ + DynamicString &operator+=(char c); + + /** + * Modifier operator adds char string to the current string. + * + * @param val char string to add + * @return the current string + */ + DynamicString &operator+=(const char *val); + + /** + * Modifier operator adds @code DynamicString object to the current string. + * + * @param other @code DynamicString string to add + * @return the current string + */ + DynamicString &operator+=(DynamicString &other); + + /** + * Appends a character string to the current string. + * + * @param str character string to add + * @return the current string + */ + DynamicString &append(const char *str); + + /** + * Appends a DynamicString string to the current string. + * + * @param str DynamicString string to add + * @return the current string + */ + DynamicString &append(const DynamicString &str); + + /** + * Appends a character to the current string. + * + * @param c character to add + * @return the current string + */ + DynamicString &push_back(const char c); + + /** + * Deletes the element @p pos from the String + * + * @param pos position of the element to be deleted + * @return the modified String + */ + DynamicString &erase(size_type pos = 0); + + /** + * Deletes the last character in the String + */ + void pop_back(); + + /** + * Provides access to character array that string uses behind the screen + * + * @return character array + */ + const char *c_str() const; + + /** + * Makes substring of the current string + * + * @param pos starting position + * @param length length of the new string + * @return new string which is a substring of current string + */ + DynamicString substr(size_type pos, size_type length) const; + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str @code DynamicString string to compare against current string + * @return a signed number based on how strings compare + */ + diff_type compare(const DynamicString &str) const; + + /** + * Compares two strings and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param str character string to compare against current string + * @return a signed number based on how strings compare + */ + diff_type compare(const char *str) const; + + /** + * Compares a string and character and return 0 if they are equal, less than 0 if + * given string is less than current string and greater than 0 if + * given string is greater than current string + * + * @param c character to compare against current string + * @return a signed number based on how strings compare + */ + diff_type compare(const char c) const; + + private: + char *m_buffer; + size_type m_len; + + /** + * Constructor used by other String constructors to create @code DynamicString @endcode + * + * @param str1 first string to use in making + * @param str2 second string to use in making + * @param len1 length of first string + * @param len2 length of second string + */ + DynamicString(const char *str1, const char *str2, size_type len1, size_type len2); + + /** + * Append method used by other public append methods + * + * @param cstr c style string to append + * @param len length of @p cstr + * @return the @code DynamicString @endcode with @p cstr append to it + */ + DynamicString &append(const char *cstr, size_type len); + + friend DynamicString operator+(const DynamicString &lhs, const DynamicString &rhs); + + friend DynamicString operator+(const char *lhs, const DynamicString &rhs); + + friend DynamicString operator+(const DynamicString &lhs, const char *rhs); + + friend DynamicString operator+(const DynamicString &lhs, const DynamicString &rhs); + + friend DynamicString operator+(char lhs, const DynamicString &rhs); + + friend DynamicString operator+(const DynamicString &lhs, char rhs); + }; + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return true or false based on if two strings are equal + */ + + bool operator==(const DynamicString &lhs, const DynamicString &rhs); + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs character string as left hand side string + * @param rhs @code DynamicString @endcode string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(const char *lhs, const DynamicString &rhs); + + /** + * Comparative operator compares if two strings are equal or not + * + * @param lhs @code DynamicString @endcode string as left hand side string + * @param rhs character string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(const DynamicString &lhs, const char *rhs); + + /** + * Comparative operator compares if string and single character are equal or not + * + * @param lhs character as left hand side + * @param rhs @code DynamicString string as right hand side string + * @return true or false based on if two strings are equal + */ + bool operator==(char lhs, const DynamicString &rhs); + + /** + * Comparative operator compares if string and single character are equal or not + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character as right hand side + * @return true or false based on if two strings are equal + */ + bool operator==(const DynamicString &lhs, char rhs); + + /** + * Additive operator adds two given strings + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, const DynamicString &rhs); + + /** + * Additive operator adds two given strings + * + * @param lhs character string as left hand side string + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const char *lhs, const DynamicString &rhs); + + /** + * Additive operator adds two given strings + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, const char *rhs); + + /** + * Additive operator single character to string + * + * @param lhs character as left hand side + * @param rhs @code DynamicString string as right hand side string + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(char lhs, const DynamicString &rhs); + + /** + * Additive operator adds string to single character + * + * @param lhs @code DynamicString string as left hand side string + * @param rhs character as right hand side + * @return a @code DynamicString that is build from left hand string and right hand string + */ + DynamicString operator+(const DynamicString &lhs, char rhs); +} + +#endif //EMBEDDEDCPLUSPLUS_DYNAMICSTRING_H \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d909efdf..8ef88e21 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,8 +11,8 @@ include_directories(${GTEST_INCLUDE_DIR}) include_directories(${WLIB_INCLUDE_DIR}) file(GLOB files - "test.cpp" "*.h" + "test.cpp" "strings/*.cpp" "stl/*.cpp" "fsm/*.cpp" diff --git a/tests/strings/dynamic_string_check.cpp b/tests/strings/dynamic_string_check.cpp new file mode 100644 index 00000000..3a5f23a8 --- /dev/null +++ b/tests/strings/dynamic_string_check.cpp @@ -0,0 +1,116 @@ +#include "gtest/gtest.h" +#include "strings/DynamicString.h" + +using namespace wlp; + + +TEST(dynamic_string_tests, constructor_tests) { + DynamicString string1; + DynamicString string2("HELLo WORld!"); + DynamicString string3(string1); + ASSERT_EQ(string2, "HELLo WORld!"); + ASSERT_TRUE(string1.empty()); + ASSERT_EQ(12, string2.length()); + ASSERT_EQ(0, string3.length()); //This assert fails + + string2.clear(); + + ASSERT_TRUE(string2.empty()); +} + +TEST(dynamic_string_tests, assignment_tests) { + DynamicString string1; + DynamicString string2("Waterloop"); + DynamicString string3("is awesome"); + + string3 = string2; + string2 = string1; + + ASSERT_EQ(string3, "Waterloop"); + ASSERT_EQ(string2, ""); + ASSERT_EQ(string1, ""); + + ASSERT_EQ(string3.length(), 9); + ASSERT_EQ(string2.length(), 0); +} + +TEST(dynamic_string_tests, character_access_tests) { + DynamicString string1("Hello my name is BOB"); + + EXPECT_TRUE(string1[4] == 'o'); + EXPECT_TRUE(string1.at(3) == 'l'); + EXPECT_TRUE(string1.front() == 'H'); + EXPECT_TRUE(string1.end() == 'B'); +} + +TEST(dynamic_string_tests, append_operator_tests) { + DynamicString string1("Hey"); + DynamicString string2("Water"); + DynamicString string3("Loo"); + + char array1[] = {'y', 'o', 'o', 'o', '\0'}; + + ASSERT_STREQ((string1 += "Water").c_str(), "HeyWater"); + ASSERT_STREQ((string1 += "!").c_str(), "HeyWater!"); + ASSERT_STREQ((string1 += array1).c_str(), "HeyWater!yooo"); + ASSERT_STREQ((string2 += string3).c_str(), "WaterLoo"); +} + +TEST(dynamic_string_tests, append_tests) { + DynamicString string1("Hey"); + DynamicString string2("Water"); + DynamicString string3("Loo"); + + char array1[] = {'y', 'o', 'o', 'o', '\0'}; + + ASSERT_STREQ((string1.append("Water")).c_str(), "HeyWater"); + ASSERT_STREQ((string1.append("!")).c_str(), "HeyWater!"); + ASSERT_STREQ((string1.append(array1)).c_str(), "HeyWater!yooo"); + ASSERT_STREQ((string2.append(string3)).c_str(), "WaterLoo"); + ASSERT_STREQ((string3.push_back('k')).c_str(), "Look"); + ASSERT_STREQ((string2.push_back('x')).c_str(), "WaterLoox"); +} + +TEST(dynamic_string_tests, substring_tests) { + DynamicString string1("Heeelllloooo"); + DynamicString string2; + + ASSERT_STREQ("Heee", (string1.substr(0, 4)).c_str()); + ASSERT_STREQ("el", (string1.substr(3, 2)).c_str()); + ASSERT_STREQ("", (string2.substr(0, 3)).c_str()); +} + +TEST(dynamic_string_tests, addition_operator_tests) { + DynamicString string1("boiii"); + DynamicString string2("mannns"); + + ASSERT_STREQ("boiiimannns", (string1 + string2).c_str()); + ASSERT_STREQ("boiii!", (string1 + '!').c_str()); + ASSERT_STREQ("!mannns", ('!' + string2).c_str()); + ASSERT_STREQ("mannnsnothot", (string2 + "nothot").c_str()); + ASSERT_STREQ("!!!!boiii", ("!!!!" + string1).c_str()); +} + +TEST(dynamic_string_tests, equality_operator_tests) { + DynamicString string1("boiii"); + DynamicString string2("mannns"); + DynamicString string3("x"); + + ASSERT_TRUE(string1 == string1); + ASSERT_FALSE(string2 == string1); + ASSERT_TRUE(string1 == "boiii"); + ASSERT_TRUE("mannns" == string2); + ASSERT_TRUE('x' == string3); + ASSERT_TRUE(string3 == 'x'); +} + +TEST(dynamic_string_tests, erase_popback_tests) { + DynamicString string1("lastone,soclosetofinished"); + + ASSERT_STREQ("astone,soclosetofinished", (string1.erase(0)).c_str()); + ASSERT_STREQ("astonesoclosetofinished", (string1.erase(6)).c_str()); + + string1.pop_back(); + + ASSERT_STREQ("astonesoclosetofinishe", string1.c_str()); +} From 89ed3a6141c2c5dd2147944a10e6d80dc603d13b Mon Sep 17 00:00:00 2001 From: Deep Dhillon Date: Sun, 26 Nov 2017 18:09:39 -0500 Subject: [PATCH 033/102] doxygen docs added for c++ (#78) --- .gitignore | 1 + deploy.sh | 62 + deploy_key.enc | Bin 0 -> 3248 bytes doxygen.conf | 2310 +++++++++++++++++ include/gtest-1.8.0/docs/AdvancedGuide.md | 2182 ---------------- include/gtest-1.8.0/docs/DevGuide.md | 126 - include/gtest-1.8.0/docs/Documentation.md | 14 - include/gtest-1.8.0/docs/FAQ.md | 1087 -------- include/gtest-1.8.0/docs/Primer.md | 502 ---- include/gtest-1.8.0/docs/PumpManual.md | 177 -- include/gtest-1.8.0/docs/Samples.md | 14 - .../gtest-1.8.0/docs/V1_5_AdvancedGuide.md | 2096 --------------- .../gtest-1.8.0/docs/V1_5_Documentation.md | 12 - include/gtest-1.8.0/docs/V1_5_FAQ.md | 886 ------- include/gtest-1.8.0/docs/V1_5_Primer.md | 497 ---- include/gtest-1.8.0/docs/V1_5_PumpManual.md | 177 -- include/gtest-1.8.0/docs/V1_5_XcodeGuide.md | 93 - .../gtest-1.8.0/docs/V1_6_AdvancedGuide.md | 2178 ---------------- .../gtest-1.8.0/docs/V1_6_Documentation.md | 14 - include/gtest-1.8.0/docs/V1_6_FAQ.md | 1038 -------- include/gtest-1.8.0/docs/V1_6_Primer.md | 501 ---- include/gtest-1.8.0/docs/V1_6_PumpManual.md | 177 -- include/gtest-1.8.0/docs/V1_6_Samples.md | 14 - include/gtest-1.8.0/docs/V1_6_XcodeGuide.md | 93 - .../gtest-1.8.0/docs/V1_7_AdvancedGuide.md | 2181 ---------------- .../gtest-1.8.0/docs/V1_7_Documentation.md | 14 - include/gtest-1.8.0/docs/V1_7_FAQ.md | 1082 -------- include/gtest-1.8.0/docs/V1_7_Primer.md | 501 ---- include/gtest-1.8.0/docs/V1_7_PumpManual.md | 177 -- include/gtest-1.8.0/docs/V1_7_Samples.md | 14 - include/gtest-1.8.0/docs/V1_7_XcodeGuide.md | 93 - include/gtest-1.8.0/docs/XcodeGuide.md | 93 - lib/wlib/fsm/StateMachine.h | 0 wmake | 0 34 files changed, 2373 insertions(+), 16033 deletions(-) create mode 100644 deploy.sh create mode 100644 deploy_key.enc create mode 100644 doxygen.conf delete mode 100644 include/gtest-1.8.0/docs/AdvancedGuide.md delete mode 100644 include/gtest-1.8.0/docs/DevGuide.md delete mode 100644 include/gtest-1.8.0/docs/Documentation.md delete mode 100644 include/gtest-1.8.0/docs/FAQ.md delete mode 100644 include/gtest-1.8.0/docs/Primer.md delete mode 100644 include/gtest-1.8.0/docs/PumpManual.md delete mode 100644 include/gtest-1.8.0/docs/Samples.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_AdvancedGuide.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_Documentation.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_FAQ.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_Primer.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_PumpManual.md delete mode 100644 include/gtest-1.8.0/docs/V1_5_XcodeGuide.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_AdvancedGuide.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_Documentation.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_FAQ.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_Primer.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_PumpManual.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_Samples.md delete mode 100644 include/gtest-1.8.0/docs/V1_6_XcodeGuide.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_AdvancedGuide.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_Documentation.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_FAQ.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_Primer.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_PumpManual.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_Samples.md delete mode 100644 include/gtest-1.8.0/docs/V1_7_XcodeGuide.md delete mode 100644 include/gtest-1.8.0/docs/XcodeGuide.md mode change 100755 => 100644 lib/wlib/fsm/StateMachine.h mode change 100755 => 100644 wmake diff --git a/.gitignore b/.gitignore index 9f7d707d..08051001 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ CMakeListsPrivate.txt src/main.cpp bin/ +docs/ # Created by https://www.gitignore.io/api/clion ### CLion ### diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 00000000..056d0261 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -e # Exit with nonzero exit code if anything fails + +SOURCE_BRANCH="master" +TARGET_BRANCH="gh-pages" + +# Pull requests and commits to other branches shouldn't try to deploy, just build to verify +if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then + echo "Skipping deploy" + exit 0 +fi + +# Save some useful information +REPO=`git config remote.origin.url` +SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:} +SHA=`git rev-parse --verify HEAD` + +# Clone the existing gh-pages for this repo into out/ +# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply) +git clone $REPO out +cd out +git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH +cd .. + +# Clean out existing contents +rm -rf out/**/* || exit 0 + +# Run our compile script +doxygen doxygen.conf + +# Move content from html folder +cp -r docs/html/* out/ + +# Now let's go have some fun with the cloned repo +cd out +git config user.name "Travis CI" +git config user.email "deep.dhill6@gmail.com" + +# If there are no changes (e.g. this is a README update) then just bail. +if [ -z `git diff --exit-code` ]; then + echo "No changes to the spec on this push; exiting." + exit 0 +fi + +# Commit the "changes", i.e. the new version. +# The delta will show diffs between new and old versions. +git add . +git commit -m "Deploy to GitHub Pages: ${SHA}" + +# Get the deploy key by using Travis's stored variables to decrypt deploy_key.enc +ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" +ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" +ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} +ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} +openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in ../deploy_key.enc -out deploy_key -d +chmod 600 deploy_key +eval `ssh-agent -s` +ssh-add deploy_key +rm deploy_key + +# Now that we're all set up, we can push. +git push $SSH_REPO $TARGET_BRANCH diff --git a/deploy_key.enc b/deploy_key.enc new file mode 100644 index 0000000000000000000000000000000000000000..0cfbf215e4d4f712ba52c66207359488cdece226 GIT binary patch literal 3248 zcmV;h3{Ug4H0`pyAs-=I9>dI*uQu#+B)c{tY*+%1pyj{FQYv%zu?O6uMwP97EaAVv zJU^#oT%S^jgPCW;tEZ`Qx?hN3^8k4V;_K2mdHUWMnnAh5kmXNeFzHalMR@KX;C7;CZG-2`N*!zw;4?5_eZLDUgxu}EIJC(QbKdyuqKMs)&I3PF=mYgUiE$jh zI<+RnKRWa>80+}MZ2LD!4)Rv>7}}rFEgg^GZE3-Z0d(y2=BgKf%OmWH8tyoP_zcZ+EmY#vJ;wJ~j6!bQLR)FqU{PC(T1*IH>Bm99Qrh^(zPJ;*%hs3=w zy!%0QlTj`H0~??F=py@vBO?7htZF2UESljuF_GBCA`y#AZ1=(yO&E)3zFKbW_&z~t zTaT4k-{WVkdu9&`+md~es6|@29kQt`sz2}fP&@j|hoyLcbx|EKmyxImRdSywuq5k)Fr+oH0KRPiADJd0Xy;ScUk7cz7OGHpxzS}+h(EY7m z1$4C;45E>YRAkikTKRq}%kq^Px&o+3O1~7V7j_+hD~z^}5Mkrqp~68-hvH$>wCzYh zij+@vmbE&L%9x_s?XR`(`e%x5dYo*7c`!d4!x{lWU%1uMR3F~fmCM8hdgGp2pdaMB(5t-O*HNH$IiEVEappE$XX66}U7r~OM_}DA6(+70 z>GC{r;YqQ*;&Z0Z?!mYMV3>x;6ppOgurQ@GW8RRaK+{YeoOCL4%Jyw`GSEGOL~hSu zM31=2h3Q&EvwqXlSGDsqQajzajOhzpK+4+*#US72t|mluu7!OfS5nQ7!Tb;mSn=V$ zdgSTk%LTViw3P9@acspYT;k-^V-2pRktbpuTa%FKvsJSvng?iEy{1vo1I&bTU$q!+PucVsGXPT3V# z{g&x830pjlV^IdFy>db)1M_v&i$5;Y&l8%H#TTXmuChr#k-yF`pHk>-xreMAE@Jd{ z*&t*58KV(AD+hD5ckgV-0*U9^9&nVRi#f124A5%^xn@7&R%bG-eOQdHr$J|+fIml; z+sw%ByZ-!nj|_Co>-K^KUmymxpkXoi7ZJC3gMWSM(i$yPQf^rO+85udODKuXdXC03 z^YJ+}=>1s4v)3}Ivu2Ns4Wv?+Xx!S8_%@n7Td;C2dlNI2YUk4*J>D$`><@$j&YJq; zD8@0m!i#sm63}Od_$7!6Y+cAbNSoV0Ih7Uk9)86Xe^mvy6?|zbti;z@Lf~KQ=YU=( zwXJ5=QCPnX_kHBM>)2h4S^(dW{1f>3|9wK!L`?`98q@8=k%jZdP9bxjZ-1yF|}X#^X(Bhi-r zf&WCqE<=lYxV26#oE=o7yByB4I(UAvj+Zb7drMj7tN>p;W~3(4{R=O&4pmJ4I|h=V zQNW6eWR@#tL5Y83;eTrU*jCRz)>-rXVB}uB5>K^K>Z8Vf`WGVq2_G9zm{<7vn4aP@ zb?-TK!Wb6?KNwQb9GP}dzS#CQ_P@mJ#J3RQJw*Yh2gJ${sGE1qwq88diDh zVjeK3kjIXMo3`c7PC2drP}I#m0}&c{x>ZD^GBBQ;1}pR5JtllE8Qd}=qcdSmDQ@f; zP#hWnXf#$w+8!pPXep>?#zM#2!9;+2R^eSZq33o5ee8YpAe;;zf~iF9nBJN%7YhEa}@?0qS*Jk~4VwEA_ms`gl+4WS< z2X#DZ8V6;>w`r&b4qs#CUGa3s2O)3XR0RpX$&xYto zsEy9x*hZFyv6+}pYTI~2x!GsrwB`fg+*OE57Q{dGhw5zELPhdBU9smz#s3K3oN1-Y zzZ=fuh=<-H8rY@%bmszH9va|D&dT)%bW1`yv*YlHR^sb6OT*1F9yVDKUt^Pow)x4AGO(bp@-tmsXW=D$g`07p z%>P-~&I?67wxxbR=Pn08y47L0 z`FF+0gTy@%;7CF$ZZib99;xVy&>^H}lzaU7YM?dn4jw@J2d}=Ck;rJE3dr#^xEToh z2egsKgz?`Alw=$}Lt-2%l(|>fonjZE6Qq3c+6xf?0O7*7Q_~D+9ReCoOLK`$@Crd~ zXn3T)#OZkY>woVD;J5;@OI!mL?NJSBVzZRJgx{h077lkwI!@WJ;PsVOBPmoO`XZee zsD2YUf;m!uAv2bfB55e*)MfTEgCD&rS2x*XuT(h_A)Wa3lXLyK2fv^QxyJhzni|W;hyIR)|WSQVH>*xKh;Zv6E8i-eYmw*A^aephtdVD=Py!No(_IQ%@5_x6oxJ%(gZIJiN=AcICp4HEijG2i4O~ zyLDtIkx~#0(pzTXXcLxAv)LWIKLcReX;OS!C6ik3aco*}NXmrAOPDMqHv4+DVc<(t zp&P$wn|FZ@E<}nlqDeQvix7(OX9j<=V)M4;mK@3_P}4l)G92CxtVl1Z5h4uU(lXPK zpW%SMqM1HoKRmsd&yZJ1BvEmtbck+r;;0Y*AUlL!NSMwq&?5oTqDbD%6*}#`Qxt3x z@m!sPYHs#HhiO}PkA+9m@d|w@IgigS{a?Oq``8|EcULa5L^&zmV9z)cTdO{NZ9|FD z1)OlQ8CE0#ZQWR?TgXADBzC5F848t-nUfmhlu|KPP@$JE z-^+6~ZvKUiT9XS7QV4xO#%}gq)0D#uRljV^B@i3J-t4R{+b5lw%2LT?SpIOZKTBHo zy%c$*o-NkQrRCfnnhR4xn4z@8T&}z!TlR9;RbK010*71ptLIL%j@{nu#L_F_#`kzt z31gO%VQ!v{$MkCDY^oN+jVBuGqL*7U((k)~>qI&yhw6h-KNf9zMC6$tJt2XzUvRM%%l>_ZvsM8e+yz@$0$TQZ)y zSp7y|F*}_a-mI4dTmjKE!>YO=2RC?SA+$p!TTvrIyn^Uutf-)jS2*SV_B{Gj)Un)I iC);UB1Rg&I?w``PS!MS{n!ty_sIkh~Ey`hGz21fTy-IWd literal 0 HcmV?d00001 diff --git a/doxygen.conf b/doxygen.conf new file mode 100644 index 00000000..95fa4166 --- /dev/null +++ b/doxygen.conf @@ -0,0 +1,2310 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "C++ Wlib" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = README.md lib/wlib + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /