From d7e063558b4493b6a60557cf218834e3abc2f8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20Horva=CC=81t?= Date: Sun, 28 Jul 2024 19:11:17 +0300 Subject: [PATCH] feat: StrVec --- examples/CMakeLists.txt | 3 +- examples/ex_strvec.cpp | 18 ++++ include/igraph.hpp | 3 + include/strvec.hpp | 220 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 examples/ex_strvec.cpp create mode 100644 include/strvec.hpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 03e8ec9..30ed8d9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,8 +6,9 @@ function(make_test NAME) endfunction() make_test(ex_basic) -make_test(ex_complex) make_test(ex_matrix) +make_test(ex_strvec) +make_test(ex_complex) make_test(ex_graph) make_test(ex_list) make_test(ex_decompose) diff --git a/examples/ex_strvec.cpp b/examples/ex_strvec.cpp new file mode 100644 index 0000000..4731072 --- /dev/null +++ b/examples/ex_strvec.cpp @@ -0,0 +1,18 @@ + +#include +#include + +using namespace ig; + +int main() { + StrVec sv = {"foo", "bar"}; + + sv.push_back("baz"); + sv.resize(5); + sv[4] = "xyz"; + + for (auto el : sv) + std::cout << '"' << el << '"' << '\n'; + + return 0; +} diff --git a/include/igraph.hpp b/include/igraph.hpp index fe2907b..eb97701 100644 --- a/include/igraph.hpp +++ b/include/igraph.hpp @@ -129,6 +129,9 @@ using BoolMat = Mat; using ComplexVec = Vec>; using ComplexMat = Mat>; +// StrVec +#include "strvec.hpp" + #include "rng_scope.hpp" class GraphList; diff --git a/include/strvec.hpp b/include/strvec.hpp new file mode 100644 index 0000000..8f8c58a --- /dev/null +++ b/include/strvec.hpp @@ -0,0 +1,220 @@ + +class StrVec { + using igraph_type = igraph_strvector_t; + + igraph_type vec; + igraph_type *ptr = &vec; + + bool is_alias() const { return ptr != &vec; } + +public: + using value_type = const char *; + using difference_type = igraph_integer_t; + using size_type = igraph_integer_t; + + class reference { + friend class StrVec; + StrVec::igraph_type *ptr; + StrVec::size_type index; + + reference(StrVec::igraph_type *ptr_,StrVec::size_type index_) : ptr(ptr_), index(index_) { } + + public: + + operator StrVec::value_type () const { return igraph_strvector_get(ptr, index); } + + // See https://stackoverflow.com/a/66931919/695132 for why the ref-qualifier is used. + reference & operator = (const char *chr) && { + check(igraph_strvector_set(ptr, index, chr)); + return *this; + } + }; + + using const_reference = const reference; + + class iterator; + using const_iterator = iterator; + + explicit StrVec(CaptureType v) : vec(v.obj) { } + explicit StrVec(AliasType v) : ptr(&v.obj) { } + + explicit StrVec(size_type n = 0) { + check(igraph_strvector_init(ptr, n)); + } + + StrVec(StrVec &&other) noexcept { + if (other.is_alias()) { + ptr = other.ptr; + } else { + vec = other.vec; + } + other.ptr = nullptr; + } + + StrVec(const StrVec &other) { + check(igraph_strvector_init_copy(ptr, other.ptr)); + } + + StrVec(const igraph_type *v) { + check(igraph_strvector_init_copy(ptr, v)); + } + + StrVec(std::initializer_list list) { + check(igraph_strvector_init(ptr, 0)); + check(igraph_strvector_reserve(ptr, list.size())); + for (auto el : list) { + check(igraph_strvector_push_back(ptr, el)); + } + } + + StrVec & operator = (const StrVec &other) = delete; // TODO 1.0 + StrVec & operator = (StrVec &&other) noexcept = delete; + + ~StrVec() { + if (! is_alias()) + igraph_strvector_destroy(ptr); + } + + operator igraph_type *() { return ptr; } + operator const igraph_type *() const { return ptr; } + + iterator begin(); + iterator end(); + + const_iterator begin() const; + const_iterator end() const; + + const_iterator cbegin() const; + const_iterator cend() const; + + reference operator [] (size_type i) { return {ptr, i}; } + const_reference operator [] (size_type i) const { return {ptr, i}; } + + void clear() { igraph_strvector_clear(ptr); } + void resize(size_type size) { check(igraph_strvector_resize(ptr, size)); } + void reserve(size_type capacity) { check(igraph_strvector_reserve(ptr, capacity)); } + // void shrink_to_fit() { igraph_strvector_resize_min(ptr); } // TODO 1.0 + + void push_back(value_type elem) { check(igraph_strvector_push_back(ptr, elem)); } + void push_back(value_type elem, igraph_integer_t len) { check(igraph_strvector_push_back_len(ptr, elem, len)); } + + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + // There is no igraph_strvector_pop_back(), so we skip it here as well. + + // TODO swap() 1.0 +}; + +class StrVec::iterator { +public: + using value_type = StrVec::value_type; + using difference_type = StrVec::difference_type; + using pointer = void; + using reference = StrVec::reference; + using iterator_category = std::random_access_iterator_tag; + + friend class StrVec; + +private: + igraph_strvector_t *ptr; + igraph_integer_t index; + + iterator(igraph_strvector_t *ptr_, igraph_integer_t index_) : ptr(ptr_), index(index_) { } + +public: + + iterator() = default; + iterator(const iterator &) = default; + iterator(iterator &&) = default; + iterator & operator = (const iterator &) = default; + iterator & operator = (iterator &&) = default; + + reference operator * () { return {ptr, index}; } + reference operator * () const { return {ptr, index}; } + reference operator [] (difference_type i) const { return {ptr, index}; } + + iterator & operator ++ () { ++index; return *this; } + iterator operator ++ (int) { ++index; return *this; } + iterator & operator -- () { --index; return *this; } + iterator operator -- (int) { --index; return *this; } + + iterator & operator += (difference_type n) { index += n; return *this; } + iterator & operator -= (difference_type n) { index -= n; return *this; } + + friend bool operator == (const iterator &lhs, const iterator &rhs) { + return lhs.index == rhs.index; + } + + friend bool operator != (const iterator &lhs, const iterator &rhs) { + return ! (lhs == rhs); + } + + friend bool operator < (const iterator &lhs, const iterator &rhs) { + return lhs.index < rhs.index; + } + + friend bool operator > (const iterator &lhs, const iterator &rhs) { + return lhs.index > rhs.index; + } + + friend bool operator <= (const iterator &lhs, const iterator &rhs) { + return lhs.index <= rhs.index; + } + + friend bool operator >= (const iterator &lhs, const iterator &rhs) { + return lhs.index >= rhs.index; + } + + friend iterator operator + (const iterator &it, difference_type n) { + return iterator(it.ptr, it.index + n); + } + + friend iterator operator + (difference_type n, const iterator &it) { + return iterator(it.ptr, it.index + n); + } + + friend iterator operator - (const iterator &it, difference_type n) { + return iterator(it.ptr, it.index - n); + } + + friend difference_type operator - (const iterator &lhs, const iterator &rhs) { + return lhs.index - rhs.index; + } + + // TODO iter_swap() 1.0 +}; + +StrVec::iterator StrVec::begin() { + return iterator(ptr, 0); +} + +StrVec::iterator StrVec::end() { + return iterator(ptr, ptr->end - ptr->stor_begin); +} + +StrVec::const_iterator StrVec::begin() const { + return iterator(ptr, 0); +} + +StrVec::const_iterator StrVec::end() const { + return iterator(ptr, ptr->end - ptr->stor_begin); +} + +StrVec::const_iterator StrVec::cbegin() const { + return begin(); +} + +StrVec::const_iterator StrVec::cend() const { + return end(); +} + +StrVec::iterator StrVec::erase(const_iterator first, const_iterator last) { + igraph_strvector_remove_section(ptr, first.index, last.index); + return first; +} + +StrVec::iterator StrVec::erase(const_iterator pos) { + igraph_strvector_remove(ptr, pos.index); + return pos; +}