diff --git a/api/include/opentelemetry/nostd/list.h b/api/include/opentelemetry/nostd/list.h new file mode 100644 index 0000000000..770a9dc335 --- /dev/null +++ b/api/include/opentelemetry/nostd/list.h @@ -0,0 +1,254 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "opentelemetry/nostd/utility.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace nostd +{ +// Non-standard implementation of the list data structure. +template +class list +{ +public: + typedef T value_type; + + // Custom iterator class + class iterator + { + public: + iterator operator++() + { + ptr_++; + return ptr_; + } + + T &operator*() { return *ptr_; } + + T *operator->() { return ptr_; } + + bool operator==(const iterator &other) { return ptr_ == other.ptr_; } + + bool operator!=(const iterator &other) { return ptr_ != other.ptr_; } + + private: + friend class list; + + iterator(T *ptr) : ptr_(ptr) {} + + T *ptr_; + }; + + list() + { + size_ = 0; + data_ = nullptr; + }; + + // Constructs class with passed in element. + list(T element) + { + size_ = 1; + + data_ = new T[size_]; + + std::memcpy(data_, &element, sizeof(T)); + }; + + // Constructs class with the passed in initializer_list. + list(std::initializer_list init_list) + { + size_ = init_list.size(); + + data_ = new T[size_]; + + std::memcpy(data_, std::begin(init_list), init_list.size() * sizeof(T)); + } + + // Returns the element at the front of the list. + T &front() { return data_[0]; } + + // Returns the element at the back of the list. + T &back() + { + if (size_ == 0) + { + return data_[0]; + } + + return data_[size_ - 1]; + } + + // Returns an iterator pointing at the front of the list. + iterator begin() { return iterator(data_); } + + // Returns an iterator pointing at the back of the list. + iterator end() { return iterator(data_ + size_); } + + // Inserts the passed in element at the passed in + // iterator position. + iterator insert(iterator position, const T &element) + { + int previous_size = size_; + size_++; + + T *temp = new T[size_]; + + // Counter tracks the index of the passed in iterator position. + int counter = position.ptr_ - data_; + + int insert_index = counter; + int next_index = counter + 1; + int remaining_elements = previous_size - counter; + + // Copy the original data that comes before the insertion. + std::memcpy(temp, data_, insert_index * sizeof(T)); + // Copy the inserted data. + std::memcpy(temp + insert_index, &element, sizeof(T)); + // Copy the original data that comes after the insertion. + std::memcpy(temp + next_index, data_ + counter, remaining_elements * sizeof(T)); + + delete[] data_; + + data_ = temp; + + // Return an iterator at the inserted element. + return iterator(data_ + counter); + } + + // Insert an element at the end of the list. + void push_back(T element) + { + + int previous_size = size_; + size_++; + + T *temp = new T[size_]; + + // Copy the original data into the new array. + for (int i = 0; i < previous_size; i++) + { + temp[i] = data_[i]; + } + + // Deallocate memory used by previous array. + delete[] data_; + + data_ = temp; + + data_[previous_size] = element; + }; + + // Insert an element at the front of the list. + void push_front(T element) + { + size_++; + + T *temp = new T[size_]; + + // Copy the original data into the new array leaving space + // for the new element at the front. + for (unsigned int i = 1; i < size_; i++) + { + temp[i] = data_[i - 1]; + } + + // Deallocate memory used by previous array. + delete[] data_; + + data_ = temp; + data_[0] = element; + }; + + // Returns the last element and removes it from the list. + T pop_back() + { + T back_elem = data_[size_ - 1]; + size_--; + + T *temp = new T[size_]; + + // Copy the original data. + std::memcpy(temp, data_, size_ * sizeof(T)); + + // Deallocate memory used by previous array. + delete[] data_; + + data_ = temp; + + return back_elem; + } + + // Returns the first element and removes it from the list. + T pop_front() + { + T front_elem = front(); + size_--; + + T *temp = new T[size_]; + + // Copy the original data. + std::memcpy(temp, data_ + 1, size_ * sizeof(T)); + + // Deallocate memory used by previous array. + delete[] data_; + + data_ = temp; + + return front_elem; + } + + // Returns the number of elements in the list. // + int size() { return size_; } + + list &operator=(const list &other_list) + { + delete[] data_; + + data_ = new T[other_list.size_]; + + memcpy(data_, other_list.data_, other_list.size_ * sizeof(T)); + + size_ = other_list.size_; + + return *this; + } + + list(const list &other_list) + { + size_ = other_list.size_; + + data_ = new T[size_]; + + memcpy(data_, other_list.data_, other_list.size_ * sizeof(T)); + } + + // Returns true if the list contents are the same, false if they are not + bool operator==(const list &other_list) + { + if (size_ != other_list.size_) + { + return false; + } + + return (memcmp(data_, other_list.data_, size_*sizeof(T)) == 0); + } + + T &operator[](int index) { return data_[index]; } + + ~list() { delete[] data_; } + +private: + size_t size_; + + T *data_; +}; +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/nostd/pair.h b/api/include/opentelemetry/nostd/pair.h new file mode 100644 index 0000000000..87dd6f03f2 --- /dev/null +++ b/api/include/opentelemetry/nostd/pair.h @@ -0,0 +1,52 @@ +#pragma once + +#include "opentelemetry/nostd/utility.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace nostd +{ + +// The nostd::pair class provides a data structure capable of hold +// two values of different or the same types, and provides access to each. + +template +class pair +{ +public: + pair() + { + first_ = T1(); + second_ = T2(); + } + + // Constructs a pair object with the passed in first and second values. + pair(T1 first, T2 second) + { + first_ = first; + second_ = second; + } + + void operator=(const pair &other_pair) + { + first_ = other_pair.first_; + second_ = other_pair.second_; + } + + bool operator==(const pair &other_pair) + { + return (first_ == other_pair.first_ && second_ == other_pair.second_); + } + + // Returns the first element. + T1 &first() { return first_; } + + // Returns the second element. + T2 &second() { return second_; } + +private: + T1 first_; + T2 second_; +}; +} // namespace nostd +OPENTELEMETRY_END_NAMESPACE diff --git a/api/test/nostd/BUILD b/api/test/nostd/BUILD index 35306e6a3c..e816b63dba 100644 --- a/api/test/nostd/BUILD +++ b/api/test/nostd/BUILD @@ -74,3 +74,25 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "list_test", + srcs = [ + "list_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "pair_test", + srcs = [ + "pair_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/nostd/list_test.cc b/api/test/nostd/list_test.cc new file mode 100644 index 0000000000..41cf8739df --- /dev/null +++ b/api/test/nostd/list_test.cc @@ -0,0 +1,180 @@ +#include "opentelemetry/nostd/list.h" +#include "opentelemetry/nostd/pair.h" + +#include +#include + +using opentelemetry::nostd::list; +using opentelemetry::nostd::pair; + +// Tests that front() returns the first element and back() +// returns the last element. +TEST(ListTest, FrontBackReturnsProperElements) +{ + list int_list; + + int_list.push_back(9); + int_list.push_back(8); + int_list.push_back(7); + int_list.push_back(6); + + EXPECT_EQ(int_list.front(), 9); + EXPECT_EQ(int_list.back(), 6); +} + +// Tests that the list object can handle data types of a size +// other than an int. +TEST(ListTest, ListAcceptsPairDatatype) +{ + list> pair_list; + + pair_list.push_back(pair(1, 2)); + pair_list.push_back(pair(2, 3)); + pair_list.push_back(pair(4, 5)); + + EXPECT_EQ(pair_list.front().first(), 1); + EXPECT_EQ(pair_list.front().second(), 2); + EXPECT_EQ(pair_list.back().first(), 4); + EXPECT_EQ(pair_list.back().second(), 5); +} + +// Tests that a list object can be initialized with an initalizer list. +TEST(ListTest, ListConstructorAcceptsInitializerList) +{ + list int_list = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + EXPECT_EQ(int_list.front(), 1); + EXPECT_EQ(int_list.back(), 10); +} + +// Tests that the list object can handle an insert_iterator. +TEST(ListTest, InsertIteratorAddsToList) +{ + list int_list = {1, 2, 3, 4}; + list insert_list = {5, 6, 7, 8}; + + std::insert_iterator> back(int_list, std::end(int_list)); + + for (auto iter = std::begin(insert_list); iter != std::end(insert_list); ++iter) + { + back = *iter; + } + + int counter = 1; + + for (auto iter = std::begin(int_list); iter != std::end(int_list); ++iter) + { + EXPECT_EQ(*iter, counter); + counter++; + } +} + +// Tests that the push_front method added elements to the front of the list. +TEST(ListTest, PushFrontAddsDataAtFront) +{ + list> list_list; + list inner_list = {0, 1, 2, 3, 4}; + list mid_list = {5, 6, 7, 8, 9}; + list end_list = {10, 11, 12, 13, 14}; + + list_list.push_front(end_list); + list_list.push_front(mid_list); + list_list.push_front(inner_list); + + EXPECT_EQ(list_list.front().front(), 0); + EXPECT_EQ(list_list.front().back(), 4); + EXPECT_EQ(list_list.back().front(), 10); + EXPECT_EQ(list_list.back().back(), 14); +} + +// Tests that the push_back method added elements at the back of the list. +TEST(ListTest, PushBackAddsDataAtBack) +{ + list> list_list; + list inner_list = {0, 1, 2, 3, 4}; + list mid_list = {5, 6, 7, 8, 9}; + list end_list = {10, 11, 12, 13, 14}; + + list_list.push_back(inner_list); + list_list.push_back(mid_list); + list_list.push_back(end_list); + + EXPECT_EQ(list_list.front().front(), 0); + EXPECT_EQ(list_list.front().back(), 4); + EXPECT_EQ(list_list.back().front(), 10); + EXPECT_EQ(list_list.back().back(), 14); +} + +// Tests that you can modify elements via the subscript operator. +TEST(ListTest, SubscriptOperatorAllowsForValueModification) +{ + list int_list = {0, 1, 2, 3, 4}; + + EXPECT_EQ(int_list[2], 2); + int_list[2] = 9; + EXPECT_EQ(int_list[2], 9); +} + +// Tests that the pop_back method returns and removes the back element +// from the list. +TEST(ListTest, PopBackReturnsAndRemovesFromBack) +{ + list int_list = {0, 1, 2, 3, 4}; + int previous_size = int_list.size(); + + EXPECT_EQ(int_list.back(), 4); + EXPECT_EQ(int_list.pop_back(), 4); + EXPECT_EQ(int_list.size(), previous_size - 1); + EXPECT_EQ(int_list.back(), 3); +} + +// Tests that the pop_front method returns and removes the front element +// from the list. +TEST(ListTest, PopFrontReturnsAndRemovesFromFront) +{ + list int_list = {0, 1, 2, 3, 4}; + int previous_size = int_list.size(); + + EXPECT_EQ(int_list.front(), 0); + EXPECT_EQ(int_list.pop_front(), 0); + EXPECT_EQ(int_list.size(), previous_size - 1); + EXPECT_EQ(int_list.front(), 1); +} + +// Tests that after using the assignment operator, changing the new +// doesn't change the original +TEST(ListTest, AssignmentOperatorDoesNotChangeOriginal) +{ + + list first_list = {0, 1, 2, 3, 4}; + list first_list_copy = {0, 1, 2, 3, 4}; + list second_list = first_list; + + second_list.pop_back(); + second_list.pop_back(); + second_list.pop_back(); + + EXPECT_TRUE(first_list == first_list_copy); + EXPECT_FALSE(first_list == second_list); +} + +// Tests that two lists with the same contents return true when compared +// using the comparison operator +TEST(ListTest, ComparisonOperatureReturnsTrueWithSameContents) +{ + list first_list = {0, 1, 2, 3, 4}; + list second_list = {0, 1, 2, 3, 4}; + list third_list = {0, 1, 2, 3, 5}; + + EXPECT_TRUE(first_list == second_list); + EXPECT_FALSE(first_list == third_list); +} + +// Tests that constructing a list with one element populates the list object +// with that element +TEST(ListTest, SingleElementConstruction) +{ + list single_list = list(5); + + EXPECT_EQ(single_list[0], 5); +} diff --git a/api/test/nostd/pair_test.cc b/api/test/nostd/pair_test.cc new file mode 100644 index 0000000000..342900a30e --- /dev/null +++ b/api/test/nostd/pair_test.cc @@ -0,0 +1,96 @@ +#include "opentelemetry/nostd/pair.h" +#include "opentelemetry/nostd/list.h" + +#include + +#include + +using opentelemetry::nostd::list; +using opentelemetry::nostd::pair; + +// Tests constructing a pair object. +TEST(PairTest, BasicConstruction) +{ + int val_1 = 1; + int val_2 = 9; + pair temp_pair = pair(val_1, val_2); + + EXPECT_EQ(temp_pair.first(), val_1); + EXPECT_EQ(temp_pair.second(), val_2); +} + +// Tests that the comparison operator returns true when pair values +// are the same and returns false when different. +TEST(PairTest, ComparisonSameValuesReturnTrue) +{ + + int val_1 = 1; + int val_2 = 2; + pair pair_1 = pair(val_1, val_2); + pair pair_2 = pair(val_1, val_2); + + EXPECT_EQ(pair_1 == pair_2, true); + + pair_1.first() = 8; + + EXPECT_EQ(pair_1 == pair_2, false); +} + +// Tests that the assignment operator sets the values as one would expect. +TEST(PairTest, AssignmentBasic) +{ + + int val_1 = 1; + int val_2 = 2; + pair pair_1 = pair(val_1, val_2); + + int val_3 = 3; + int val_4 = 4; + pair pair_2 = pair(val_3, val_4); + + // EXPECT_EQ(pair_1 == pair_2, false); + EXPECT_EQ(pair_1, pair_2); + + pair_1 = pair_2; + + EXPECT_EQ(pair_1 == pair_2, true); + EXPECT_EQ(pair_1.first(), val_3); + EXPECT_EQ(pair_1.second(), val_4); +} + +// Tests that after using the assignment operator, changing values of one +// object does not change both. +TEST(PairTest, AssignmentOtherObjectImmutable) +{ + + int val_1 = 1; + int val_2 = 2; + pair pair_1 = pair(val_1, val_2); + + int val_3 = 3; + int val_4 = 4; + pair pair_2 = pair(val_3, val_4); + + pair_1 = pair_2; + + pair_1.first() = 8; + pair_1.second() = 7; + + EXPECT_EQ(pair_1.first(), 8); + EXPECT_EQ(pair_1.second(), 7); + EXPECT_EQ(pair_2.first(), val_3); + EXPECT_EQ(pair_2.second(), val_4); +} + +// Tests that the pair class can accept containers +TEST(PairTest, PairAcceptContainers) +{ + list int_list = {1, 2, 3, 4}; + std::string test_string = "test"; + + pair, std::string> container_pair = pair, std::string>(int_list, test_string); + + EXPECT_EQ(container_pair.second(), test_string); + EXPECT_EQ(container_pair.first().front(), int_list.front()); + EXPECT_EQ(container_pair.first().back(), int_list.back()); +}