diff --git a/tstl/include/bit_field.hpp b/tstl/include/bit_field.hpp index ecb83cfc..3779dcbe 100644 --- a/tstl/include/bit_field.hpp +++ b/tstl/include/bit_field.hpp @@ -12,16 +12,37 @@ namespace std { +/*! + * \brief Helper to handle a value as a bit field. + * \param S The type of the source value + * \param T The type of the bit value + * \param Position The starting position from the right (LSB) + * \param Size The number of bits + */ template struct bit_field { - S* value; - + /*! + * \brief Construct a bit field around the given value + */ bit_field(S* value) : value(value) {} - T operator*() const { + /*! + * \brief Extract the value of the bit field + */ + T get() const { return (*value >> Position) & ((1ULL << Size) - 1); } + /*! + * \brief Extract the value of the bit field + */ + T operator*() const { + return get(); + } + + /*! + * \brief Assign a new value to the bit field + */ bit_field& operator=(T new_value_real){ S new_value(new_value_real); @@ -29,6 +50,9 @@ struct bit_field { *value = (*value & ~mask) | ((new_value << Position) & mask); return *this; } + +private: + S* value; ///< Pointer to the source value }; } //end of namespace std diff --git a/tstl/include/queue.hpp b/tstl/include/queue.hpp index e2b191a5..f9059ec3 100644 --- a/tstl/include/queue.hpp +++ b/tstl/include/queue.hpp @@ -13,35 +13,55 @@ namespace std { +/*! + * \brief Container adapter to provide a queue (FIFO) + */ template> struct queue { -private: - C container; - -public: + /*! + * \brief Indicates if the queue is empty + */ bool empty() const { return size() == 0; } + /*! + * \brief Returns the size of the queue + */ size_t size() const { return container.size(); } + /*! + * \brief Push a new element onto the queue + */ void push(const T& value){ container.push_back(value); } + /*! + * \brief Pop the top element from the queue + */ void pop(){ container.pop_front(); } + /*! + * \brief Returns a reference to the top element + */ T& top(){ return container.front(); } + /*! + * \brief Returns a const reference to the top element + */ const T& top() const { return container.front(); } + +private: + C container; ///< The underlying container }; } //end of namespace std diff --git a/tstl/include/stack.hpp b/tstl/include/stack.hpp index a20c688e..f3d3c081 100644 --- a/tstl/include/stack.hpp +++ b/tstl/include/stack.hpp @@ -14,7 +14,7 @@ namespace std { /*! - * \brief Container adapter to provide a stack + * \brief Container adapter to provide a stack (LIFO) */ template> struct stack { diff --git a/tstl/include/string.hpp b/tstl/include/string.hpp index 6adff9eb..b8c65537 100644 --- a/tstl/include/string.hpp +++ b/tstl/include/string.hpp @@ -87,11 +87,15 @@ static_assert(min_capacity == sizeof(base_short), "base_short must be the static_assert(min_capacity == sizeof(base_long), "base_long must be the correct SSO size"); static_assert(min_capacity == sizeof(base_raw), "base_raw must be the correct SSO size"); +/*! + * \brief A string of the given character type. + * + * This implementation uses SSO to not allocate any dynamic memory on short strings (<16 chars) + */ template struct basic_string { -public: - typedef CharT* iterator; - typedef const CharT* const_iterator; + using iterator = CharT*; ///< The iterator type + using const_iterator = const CharT*; ///< The const iterator type static constexpr const size_t npos = -1; @@ -137,12 +141,18 @@ private: public: //Constructors + /*! + * \brief Construct an empty string + */ basic_string() : _size(0){ set_small(true); (*this)[0] = '\0'; } + /*! + * \brief Construct a new string from the given raw string + */ basic_string(const CharT* s) : _size(str_len(s)) { auto capacity = size() + 1; @@ -155,6 +165,9 @@ public: std::copy_n(s, capacity, begin()); } + /*! + * \brief Construct a new string of the given capacity. + */ explicit basic_string(size_t __capacity) : _size(0) { set_small(__capacity <= 16); @@ -165,6 +178,9 @@ public: (*this)[0] = '\0'; } + /*! + * \brief Construct a new string from the given range of characters + */ template basic_string(It it, It end) { _size = std::distance(it, end); @@ -262,6 +278,9 @@ public: //Destructors + /*! + * \brief Destructs the string and releases all its associated memory + */ ~basic_string(){ if(is_long()){ storage.big.~base_long(); @@ -274,20 +293,32 @@ public: set_size(size); } + /*! + * \brief Clear the string + */ void clear(){ set_size(0); (*this)[0] = '\0'; } + /*! + * \brief Pop the last character of the string. + */ void pop_back(){ set_size(size() - 1); (*this)[size()] = '\0'; } + /*! + * \brief Ensures a capacity of at least new_capacity + */ void reserve(size_t new_capacity){ ensure_capacity(new_capacity); } + /*! + * \brief Creates a string resulting of the concatenation of this string the given char + */ basic_string operator+(CharT c) const { basic_string copy(*this); @@ -296,6 +327,9 @@ public: return move(copy); } + /*! + * \brief Concatenates the given char to the current string + */ basic_string& operator+=(CharT c){ ensure_capacity(size() + 2); @@ -307,29 +341,6 @@ public: return *this; } - void ensure_capacity(size_t new_capacity){ - if(new_capacity > 0 && (capacity() < new_capacity)){ - auto new_cap = capacity() * 2; - - if(new_cap < new_capacity){ - new_cap = new_capacity; - } - - auto new_data = new CharT[new_cap]; - - std::copy_n(begin(), size() + 1, new_data); - - if(is_small()){ - new (&storage.big) base_long(new_cap, new_data); - - set_small(false); - } else { - storage.big.data.reset(new_data); - storage.big.capacity = new_cap; - } - } - } - basic_string& operator+=(const char* rhs){ auto len = str_len(rhs); @@ -358,10 +369,16 @@ public: //Accessors + /*! + * \brief Returns the size of the string + */ size_t size() const { return _size & ~(1UL << 63); } + /*! + * \brief Returns the capacity of the string + */ size_t capacity() const { if(is_small()){ return 16; @@ -370,6 +387,9 @@ public: } } + /* + * \brief Indicates if the string is empty + */ bool empty() const { return size() == 0; } @@ -390,18 +410,30 @@ public: } } + /*! + * \return the raw string + */ CharT* c_str(){ return data_ptr(); } + /*! + * \return the raw string + */ const CharT* c_str() const { return data_ptr(); } + /*! + * \brief Returns a reference to the ith character + */ CharT& operator[](size_t i){ return *(data_ptr() + i); } + /*! + * \brief Returns a const reference to the ith character + */ const CharT& operator[](size_t i) const { return *(data_ptr() + i); } @@ -456,21 +488,57 @@ public: //Iterators + /*! + * \brief Returns an iterator to the first character of the string + */ iterator begin(){ return iterator(data_ptr()); } - iterator end(){ - return iterator(data_ptr() + size()); - } - + /*! + * \brief Returns a const iterator to the first character of the string + */ const_iterator begin() const { return const_iterator(data_ptr()); } + /*! + * \brief Returns an iterator the past-the-end character of the string + */ + iterator end(){ + return iterator(data_ptr() + size()); + } + + /*! + * \brief Returns a const iterator the past-the-end character of the string + */ const_iterator end() const { return const_iterator(data_ptr() + size()); } + +private: + void ensure_capacity(size_t new_capacity){ + if(new_capacity > 0 && (capacity() < new_capacity)){ + auto new_cap = capacity() * 2; + + if(new_cap < new_capacity){ + new_cap = new_capacity; + } + + auto new_data = new CharT[new_cap]; + + std::copy_n(begin(), size() + 1, new_data); + + if(is_small()){ + new (&storage.big) base_long(new_cap, new_data); + + set_small(false); + } else { + storage.big.data.reset(new_data); + storage.big.capacity = new_cap; + } + } + } }; template diff --git a/tstl/include/types.hpp b/tstl/include/types.hpp index 6c73c279..61bfd34a 100644 --- a/tstl/include/types.hpp +++ b/tstl/include/types.hpp @@ -8,15 +8,15 @@ #ifndef TYPES_H #define TYPES_H -typedef unsigned int uint8_t __attribute__((__mode__(__QI__))); -typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__))); -typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); -typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__))); +typedef unsigned int uint8_t __attribute__((__mode__(__QI__))); ///< An unsigned 8-bit number +typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__))); ///< An unsigned 16-bit number +typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); ///< An unsigned 32-bit number +typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__))); ///< An unsigned 64-bit number -typedef int int8_t __attribute__((__mode__(__QI__))); -typedef int int16_t __attribute__ ((__mode__ (__HI__))); -typedef int int32_t __attribute__ ((__mode__ (__SI__))); -typedef int int64_t __attribute__ ((__mode__ (__DI__))); +typedef int int8_t __attribute__((__mode__(__QI__))); ///< A signed 8-bit number +typedef int int16_t __attribute__ ((__mode__ (__HI__))); ///< A signed 16-bit number +typedef int int32_t __attribute__ ((__mode__ (__SI__))); ///< A signed 32-bit number +typedef int int64_t __attribute__ ((__mode__ (__DI__))); ///< A signed 64-bit number typedef uint64_t uintptr_t; typedef uint64_t size_t; diff --git a/tstl/include/unique_ptr.hpp b/tstl/include/unique_ptr.hpp index be566417..66d0a0cc 100644 --- a/tstl/include/unique_ptr.hpp +++ b/tstl/include/unique_ptr.hpp @@ -38,22 +38,30 @@ struct default_delete { } }; +/*! + * \brief An unique ptr of type T. + * + * An unique ptr represents unique ownership of dynamically allocated data. + */ template > -class unique_ptr { -public: - using pointer_type = T*; - using element_type = T; - using deleter_type = D; +struct unique_ptr { + using pointer_type = T*; ///< The pointer type + using element_type = T; ///< The element type + using deleter_type = D; ///< The deleter type -private: - using data_impl = tuple; - - data_impl _data; - -public: + /*! + * \brief Construct an empty (nullptr) unique_ptr + */ unique_ptr() : _data() {} + + /*! + * \brief Construct an empty (nullptr) unique_ptr + */ unique_ptr(decltype(nullptr)) : unique_ptr() {} + /*! + * \brief Construct a new unique_ptr from the given pointer + */ explicit unique_ptr(pointer_type p) : _data(make_tuple(p, deleter_type())) {} unique_ptr(unique_ptr&& u) : _data(make_tuple(u.unlock(), u.get_deleter())) {} @@ -63,6 +71,9 @@ public: return *this; } + /*! + * \brief Destructs the object and releases its memory if it still references any + */ ~unique_ptr(){ reset(); } @@ -71,6 +82,9 @@ public: unique_ptr(const unique_ptr& rhs) = delete; unique_ptr& operator=(const unique_ptr& rhs) = delete; + /*! + * \brief Assign nullptr to the unique ptr (reset it) + */ unique_ptr& operator=(decltype(nullptr)){ reset(); return *this; @@ -78,36 +92,63 @@ public: //Access + /*! + * \brief Returns a reference to the owned object + */ element_type& operator*() const { return *get(); } + /*! + * \brief Returns a pointer to the owned object + */ pointer_type operator->() const { return get(); } + /*! + * \brief Returns a pointer to the owned object + */ pointer_type get() const { return std::get<0>(_data); } + /*! + * \brief Returns a reference to the deleter + */ deleter_type& get_deleter(){ return std::get<1>(_data); } + /*! + * \brief Returns a const reference to the deleter + */ const deleter_type& get_deleter() const { return std::get<1>(_data); } + /*! + * \brief Converts the unique ptr to a boolean, indicating if it points to something or not + */ explicit operator bool() const { return get() == pointer_type() ? false : true; } + /*! + * \brief Extract the owned object out of the unique ptr. + * + * After this, the unique ptr will not own the objet anymore. + */ pointer_type unlock(){ pointer_type p = get(); std::get<0>(_data) = pointer_type(); return p; } + /*! + * \brief Resets the unique pointer to a new state + * \param p The new pointer value + */ void reset(pointer_type p = pointer_type()){ if(get() != pointer_type()){ get_deleter()(get()); @@ -117,23 +158,30 @@ public: } }; -//Partial specialization for array +/*! + * \brief Unique pointer implementation for an array. + * + * This has the same semantics, but allow random accesss as an array. + */ template -class unique_ptr { -public: - using pointer_type = T*; - using element_type = T; - using deleter_type = D; +struct unique_ptr { + using pointer_type = T*; ///< The pointer type + using element_type = T; ///< The element type + using deleter_type = D; ///< The deleter type -private: - using data_impl = tuple; - - data_impl _data; - -public: + /*! + * \brief Construct an empty (nullptr) unique_ptr + */ unique_ptr() : _data() {} + + /*! + * \brief Construct an empty (nullptr) unique_ptr + */ unique_ptr(decltype(nullptr)) : unique_ptr() {} + /*! + * \brief Construct a new unique_ptr from the given pointer + */ explicit unique_ptr(pointer_type p) : _data(make_tuple(p, deleter_type())) {} unique_ptr(unique_ptr&& u) : _data(make_tuple(u.unlock(), u.get_deleter())) {} @@ -143,6 +191,9 @@ public: return *this; } + /*! + * \brief Destructs the object and releases its memory if it still references any + */ ~unique_ptr(){ reset(); } @@ -156,36 +207,64 @@ public: return *this; } + /*! + * \brief Returns a pointer to the owned object + */ pointer_type get() const { return std::get<0>(_data); } + /*! + * \brief Returns a reference to the deleter + */ deleter_type& get_deleter(){ return std::get<1>(_data); } + /*! + * \brief Returns a const reference to the deleter + */ const deleter_type& get_deleter() const { return std::get<1>(_data); } + /*! + * \brief Returns a reference to an element of the array + * \param i The index inside the array + */ element_type& operator[](size_t i) const { return get()[i]; } + /*! + * \brief Converts the unique ptr to a boolean, indicating if it points to something or not + */ explicit operator bool() const { return get() == pointer_type() ? false : true; } + /*! + * \brief Extract the owned object out of the unique ptr. + * + * After this, the unique ptr will not own the objet anymore. + */ pointer_type unlock(){ pointer_type p = get(); std::get<0>(_data) = pointer_type(); return p; } + /*! + * \brief Resets the unique pointer to an empty state + */ void reset(){ reset(pointer_type()); } + /*! + * \brief Resets the unique pointer to a new state + * \param p The new pointer value + */ void reset(pointer_type p){ auto tmp = get(); std::get<0>(_data) = p; @@ -193,11 +272,19 @@ public: get_deleter()(tmp); } } + +private: + using data_impl = tuple; ///< The type of internal data + + data_impl _data; ///< The internal data storage }; static_assert(sizeof(unique_ptr) == sizeof(long), "unique_ptr must have zero overhead with default deleter"); static_assert(sizeof(unique_ptr) == sizeof(long), "unique_ptr must have zero overhead with default deleter"); +/*! + * \brief Helper to create an unique_ptr from the args + */ template std::unique_ptr make_unique(Args&&... args){ return std::unique_ptr(new T(std::forward(args)...));