The container types (modules list, set, oset, map, omap) can be used in C++, with casts. It is customary in C++ to use template classes in order to avoid casts in user code. I'm doing this here:
Data type C++ class Module Include file Sequential list gl_List list-c++ "gl_list.hh" Set gl_Set set-c++ "gl_set.hh" Ordered set gl_OSet oset-c++ "gl_oset.hh" Map gl_Map map-c++ "gl_map.hh" Ordered map gl_OMap omap-c++ "gl_omap.hh" This is not perfect yet: - It would be possible to put these classes into a namespace. - It would probably be possible (with some work) to make the iterators implement the usual C++ idioms, without reducing the efficiency of the iterators. But it should be usable.
>From bd0908412877c65f675202a3a88ee4cc42e3c8b6 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 18:59:00 +0100 Subject: [PATCH 01/11] list-c++: New module. * lib/gl_list.hh: New file, based on lib/gl_list.h. * modules/list-c++: New file. --- ChangeLog | 6 + lib/gl_list.hh | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/list-c++ | 22 ++++ 3 files changed, 393 insertions(+) create mode 100644 lib/gl_list.hh create mode 100644 modules/list-c++ diff --git a/ChangeLog b/ChangeLog index 1923883..a9350ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + list-c++: New module. + * lib/gl_list.hh: New file, based on lib/gl_list.h. + * modules/list-c++: New file. + +2020-02-02 Bruno Haible <br...@clisp.org> + xalloc: Fix compilation error in C++ mode on FreeBSD 12. * lib/xalloc.h (xalloc_die): Comment out 'extern' keyword before '_Noreturn'. diff --git a/lib/gl_list.hh b/lib/gl_list.hh new file mode 100644 index 0000000..f67c214 --- /dev/null +++ b/lib/gl_list.hh @@ -0,0 +1,365 @@ +/* Abstract sequential list data type as a C++ class. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2006. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#ifndef _GL_LIST_HH +#define _GL_LIST_HH + +#include "gl_list.h" +#include "gl_xlist.h" +#include "gl_sublist.h" +#include "gl_xsublist.h" + +/* gl_List is a C++ wrapper around the gl_list data type. + Its element type is 'ELTYPE *'. + + It is merely a pointer, not a smart pointer. In other words: + it does NOT do reference-counting, and the destructor does nothing. */ + +template <class T> class gl_List; + +template <class ELTYPE> +class gl_List<ELTYPE *> +{ +public: + // ------------------------------ Constructors ------------------------------ + + gl_List () + : _ptr (NULL) + {} + + /* Creates an empty list. + IMPLEMENTATION is one of GL_ARRAY_LIST, GL_CARRAY_LIST, GL_LINKED_LIST, + GL_AVLTREE_LIST, GL_RBTREE_LIST, GL_LINKEDHASH_LIST, GL_AVLTREEHASH_LIST, + GL_RBTREEHASH_LIST. + EQUALS_FN is an element comparison function or NULL. + HASHCODE_FN is an element hash code function or NULL. + DISPOSE_FN is an element disposal function or NULL. + ALLOW_DUPLICATES is false if duplicate elements shall not be allowed in + the list. The implementation may verify this at runtime. */ + gl_List (gl_list_implementation_t implementation, + bool (*equals_fn) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + size_t (*hashcode_fn) (ELTYPE *), + void (*dispose_fn) (ELTYPE *), + bool allow_duplicates) + : _ptr (gl_list_create_empty (implementation, + reinterpret_cast<gl_listelement_equals_fn>(equals_fn), + reinterpret_cast<gl_listelement_hashcode_fn>(hashcode_fn), + reinterpret_cast<gl_listelement_dispose_fn>(dispose_fn), + allow_duplicates)) + {} + + /* Creates a list with given contents. + IMPLEMENTATION is one of GL_ARRAY_LIST, GL_CARRAY_LIST, GL_LINKED_LIST, + GL_AVLTREE_LIST, GL_RBTREE_LIST, GL_LINKEDHASH_LIST, GL_AVLTREEHASH_LIST, + GL_RBTREEHASH_LIST. + EQUALS_FN is an element comparison function or NULL. + HASHCODE_FN is an element hash code function or NULL. + DISPOSE_FN is an element disposal function or NULL. + ALLOW_DUPLICATES is false if duplicate elements shall not be allowed in + the list. The implementation may verify this at runtime. + COUNT is the number of initial elements. + CONTENTS[0..COUNT-1] is the initial contents. */ + gl_List (gl_list_implementation_t implementation, + bool (*equals_fn) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + size_t (*hashcode_fn) (ELTYPE *), + void (*dispose_fn) (ELTYPE *), + bool allow_duplicates, + size_t count, ELTYPE **contents) + : _ptr (gl_list_create (implementation, + reinterpret_cast<gl_listelement_equals_fn>(equals_fn), + reinterpret_cast<gl_listelement_hashcode_fn>(hashcode_fn), + reinterpret_cast<gl_listelement_dispose_fn>(dispose_fn), + allow_duplicates, + count, contents)) + {} + + /* Creates a sublist of a given list. + This is the list of elements with indices i, start_index <= i < end_index. + The sublist is backed by the given list, which means: + - Modifications to the sublist affect the whole list. + - Modifications to the whole list are immediately visible in the sublist. + - The sublist is only valid as long as the whole list is valid. + - The sublist must not be passed to the gl_list_sortedlist_add() function. + */ + gl_List (const gl_List& whole_list, size_t start_index, size_t end_index) + : _ptr (gl_sublist_create (whole_list._ptr, start_index, end_index)) + {} + + /* Copy constructor. */ + gl_List (const gl_List& x) + { _ptr = x._ptr; } + + /* Assignment operator. */ + gl_List& operator= (const gl_List& x) + { _ptr = x._ptr; return *this; } + + // ------------------------------- Destructor ------------------------------- + + ~gl_List () + { _ptr = NULL; } + + // ----------------------- Read-only member functions ----------------------- + + /* Returns the current number of elements in the list. */ + size_t size () const + { return gl_list_size (_ptr); } + + /* Returns the element value represented by a list node. */ + ELTYPE * node_value (gl_list_node_t node) const + { return static_cast<ELTYPE *>(gl_list_node_value (_ptr, node)); } + + /* Returns the node immediately after the given node in the list, or NULL + if the given node is the last (rightmost) one in the list. */ + gl_list_node_t next_node (gl_list_node_t node) const + { return gl_list_next_node (_ptr, node); } + + /* Returns the node immediately before the given node in the list, or NULL + if the given node is the first (leftmost) one in the list. */ + gl_list_node_t previous_node (gl_list_node_t node) const + { return gl_list_previous_node (_ptr, node); } + + /* Returns the element at a given position in the list. + POSITION must be >= 0 and < gl_list_size (list). */ + ELTYPE * get_at (size_t position) const + { return static_cast<ELTYPE *>(gl_list_get_at (_ptr, position)); } + + /* Searches whether an element is already in the list. + Returns its node if found, or NULL if not present in the list. */ + gl_list_node_t search (ELTYPE * elt) const + { return gl_list_search (_ptr, elt); } + + /* Searches whether an element is already in the list, + at a position >= START_INDEX. + Returns its node if found, or NULL if not present in the list. */ + gl_list_node_t search_from (size_t start_index, ELTYPE * elt) const + { return gl_list_search_from (_ptr, start_index, elt); } + + /* Searches whether an element is already in the list, + at a position >= START_INDEX and < END_INDEX. + Returns its node if found, or NULL if not present in the list. */ + gl_list_node_t search_from_to (size_t start_index, size_t end_index, ELTYPE * elt) const + { return gl_list_search_from_to (_ptr, start_index, end_index, elt); } + + /* Searches whether an element is already in the list. + Returns its position if found, or (size_t)(-1) if not present in the list. */ + size_t indexof (ELTYPE * elt) const + { return gl_list_indexof (_ptr, elt); } + + /* Searches whether an element is already in the list, + at a position >= START_INDEX. + Returns its position if found, or (size_t)(-1) if not present in the list. */ + size_t indexof_from (size_t start_index, ELTYPE * elt) const + { return gl_list_indexof_from (_ptr, start_index, elt); } + + /* Searches whether an element is already in the list, + at a position >= START_INDEX and < END_INDEX. + Returns its position if found, or (size_t)(-1) if not present in the list. */ + size_t indexof_from_to (size_t start_index, size_t end_index, ELTYPE * elt) const + { return gl_list_indexof_from_to (_ptr, start_index, end_index, elt); } + + // ----------------------- Modifying member functions ----------------------- + + /* Replaces the element value represented by a list node. */ + void node_set_value (gl_list_node_t node, ELTYPE * elt) + { gl_list_node_set_value (_ptr, node, elt); } + + /* Replaces the element at a given position in the list. + POSITION must be >= 0 and < gl_list_size (list). + Returns its node. */ + gl_list_node_t set_at (size_t position, ELTYPE * elt) + { return gl_list_set_at (_ptr, position, elt); } + + /* Adds an element as the first element of the list. + Returns its node. */ + gl_list_node_t add_first (ELTYPE * elt) + { return gl_list_add_first (_ptr, elt); } + + /* Adds an element as the last element of the list. + Returns its node. */ + gl_list_node_t add_last (ELTYPE * elt) + { return gl_list_add_last (_ptr, elt); } + + /* Adds an element before a given element node of the list. + Returns its node. */ + gl_list_node_t add_before (gl_list_node_t node, ELTYPE * elt) + { return gl_list_add_before (_ptr, node, elt); } + + /* Adds an element after a given element node of the list. + Return its node. */ + gl_list_node_t add_after (gl_list_node_t node, ELTYPE * elt) + { return gl_list_add_after (_ptr, node, elt); } + + /* Adds an element at a given position in the list. + POSITION must be >= 0 and <= gl_list_size (list). */ + gl_list_node_t add_at (size_t position, ELTYPE * elt) + { return gl_list_add_at (_ptr, position, elt); } + + /* Removes an element from the list. + Returns true. */ + bool remove_node (gl_list_node_t node) + { return gl_list_remove_node (_ptr, node); } + + /* Removes an element at a given position from the list. + POSITION must be >= 0 and < gl_list_size (list). + Returns true. */ + bool remove_at (size_t position) + { return gl_list_remove_at (_ptr, position); } + + /* Searches and removes an element from the list. + Returns true if it was found and removed. */ + bool remove (ELTYPE * elt) + { return gl_list_remove (_ptr, elt); } + + /* Frees the entire list. + (But this call does not free the elements of the list. It only invokes + the DISPOSE_FN on each of the elements of the list, and only if the list + is not a sublist.) */ + void free () + { gl_list_free (_ptr); _ptr = NULL; } + + // -------------------- Member functions for sorted lists -------------------- + + /* The following functions are for lists without duplicates where the + order is given by a sort criterion. */ + + /* Searches whether an element is already in the list. + The list is assumed to be sorted with COMPAR. + Returns its node if found, or NULL if not present in the list. + If the list contains several copies of ELT, the node of the leftmost one is + returned. */ + gl_list_node_t sortedlist_search (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + ELTYPE * elt) + { return gl_sortedlist_search (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), elt); } + + /* Searches whether an element is already in the list. + The list is assumed to be sorted with COMPAR. + Only list elements with indices >= START_INDEX and < END_INDEX are + considered; the implementation uses these bounds to minimize the number + of COMPAR invocations. + Returns its node if found, or NULL if not present in the list. + If the list contains several copies of ELT, the node of the leftmost one is + returned. */ + gl_list_node_t sortedlist_search_from_to (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + size_t start_index, + size_t end_index, + ELTYPE * elt) + { return gl_sortedlist_search_from_to (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), start_index, end_index, elt); } + + /* Searches whether an element is already in the list. + The list is assumed to be sorted with COMPAR. + Returns its position if found, or (size_t)(-1) if not present in the list. + If the list contains several copies of ELT, the position of the leftmost one + is returned. */ + size_t sortedlist_indexof (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + ELTYPE * elt) + { return gl_sortedlist_indexof (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), elt); } + + /* Searches whether an element is already in the list. + The list is assumed to be sorted with COMPAR. + Only list elements with indices >= START_INDEX and < END_INDEX are + considered; the implementation uses these bounds to minimize the number + of COMPAR invocations. + Returns its position if found, or (size_t)(-1) if not present in the list. + If the list contains several copies of ELT, the position of the leftmost one + is returned. */ + size_t sortedlist_indexof_from_to (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + size_t start_index, + size_t end_index, + ELTYPE * elt) + { return gl_sortedlist_indexof_from_to (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), start_index, end_index, elt); } + + /* Adds an element at the appropriate position in the list. + The list is assumed to be sorted with COMPAR. + Returns its node. */ + gl_list_node_t sortedlist_add (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + ELTYPE * elt) + { return gl_sortedlist_add (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), elt); } + + /* Searches and removes an element from the list. + The list is assumed to be sorted with COMPAR. + Returns true if it was found and removed. + If the list contains several copies of ELT, only the leftmost one is + removed. */ + bool sortedlist_remove (int (*compar) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + ELTYPE * elt) + { return gl_sortedlist_remove (_ptr, reinterpret_cast<gl_listelement_compar_fn>(compar), elt); } + + // ------------------------------ Private stuff ------------------------------ + +private: + gl_list_t _ptr; + +public: + // -------------------------------- Iterators -------------------------------- + // Only a forward iterator. + // Does not implement the STL operations (++, *, and != .end()), but a simpler + // interface that needs only one virtual function call per iteration instead + // of three. + + class iterator { + public: + + /* If there is a next element, stores the next element in ELT, advances + the iterator and returns true. + Otherwise, returns false. */ + bool next (ELTYPE *& elt) + { return gl_list_iterator_next (&_state, reinterpret_cast<const void **>(&elt), NULL); } + + /* If there is a next element, stores the next element in ELT, stores its + node in *NODEP if NODEP is non-NULL, advances the iterator and returns true. + Otherwise, returns false. */ + bool next (ELTYPE *& elt, gl_list_node_t *nodep) + { return gl_list_iterator_next (&_state, reinterpret_cast<const void **>(&elt), nodep); } + + ~iterator () + { gl_list_iterator_free (&_state); } + + #if defined __xlC__ || defined __HP_aCC || defined __SUNPRO_CC + public: + #else + private: + friend iterator gl_List::begin (); + #endif + + iterator (gl_list_t ptr) + : _state (gl_list_iterator (ptr)) + {} + + iterator (gl_list_t ptr, size_t start_index, size_t end_index) + : _state (gl_list_iterator_from_to (ptr, start_index, end_index)) + {} + + private: + + gl_list_iterator_t _state; + }; + + /* Creates an iterator traversing the list. + The list contents must not be modified while the iterator is in use, + except for replacing or removing the last returned element. */ + iterator begin () + { return iterator (_ptr); } + + /* Creates an iterator traversing the element with indices i, + start_index <= i < end_index, of a list. + The list contents must not be modified while the iterator is in use, + except for replacing or removing the last returned element. */ + iterator begin (size_t start_index, size_t end_index) + { return iterator (_ptr, start_index, end_index); } +}; + +#endif /* _GL_LIST_HH */ diff --git a/modules/list-c++ b/modules/list-c++ new file mode 100644 index 0000000..a3c8b0a --- /dev/null +++ b/modules/list-c++ @@ -0,0 +1,22 @@ +Description: +Abstract sequential list data type as a C++ class. + +Files: +lib/gl_list.hh + +Depends-on: +xlist +xsublist + +configure.ac: + +Makefile.am: + +Include: +"gl_list.hh" + +License: +GPL + +Maintainer: +all -- 2.7.4
>From 770219943d9e9d76daffbc427937b792acf25737 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:00:11 +0100 Subject: [PATCH 02/11] list-c++: Add tests. * tests/test-list-c++.cc: New file. * modules/list-c++-tests: New file. --- ChangeLog | 4 +++ modules/list-c++-tests | 17 +++++++++++ tests/test-list-c++.cc | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 modules/list-c++-tests create mode 100644 tests/test-list-c++.cc diff --git a/ChangeLog b/ChangeLog index a9350ec..9d28f86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + list-c++: Add tests. + * tests/test-list-c++.cc: New file. + * modules/list-c++-tests: New file. + list-c++: New module. * lib/gl_list.hh: New file, based on lib/gl_list.h. * modules/list-c++: New file. diff --git a/modules/list-c++-tests b/modules/list-c++-tests new file mode 100644 index 0000000..e1d74a6 --- /dev/null +++ b/modules/list-c++-tests @@ -0,0 +1,17 @@ +Files: +tests/test-list-c++.cc +tests/macros.h + +Depends-on: +ansi-c++-opt +array-list + +configure.ac: + +Makefile.am: +if ANSICXX +TESTS += test-list-c++ +check_PROGRAMS += test-list-c++ +test_list_c___SOURCES = test-list-c++.cc +test_list_c___LDADD = $(LDADD) @LIBINTL@ +endif diff --git a/tests/test-list-c++.cc b/tests/test-list-c++.cc new file mode 100644 index 0000000..d0be7ba --- /dev/null +++ b/tests/test-list-c++.cc @@ -0,0 +1,79 @@ +/* Test of list data type implementation as a C++ class. + Copyright (C) 2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2020. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "gl_list.hh" +#include "gl_array_list.h" + +#include <string.h> + +#include "macros.h" + +static const char A[] = "A"; +static const char C[] = "C"; +static const char D[] = "D"; + +int +main (int argc, char *argv[]) +{ + gl_List<const char *> list1; + + list1 = gl_List<const char *> (GL_ARRAY_LIST, NULL, NULL, NULL, true); + list1.add_last (A); + list1.add_last (C); + list1.add_last (D); + list1.add_last (C); + ASSERT (list1.size () == 4); + + gl_List<const char *>::iterator iter1 = list1.begin (); + { + const char *elt; + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "A") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "C") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "D") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "C") == 0); + ASSERT (!iter1.next (elt)); + } + + gl_List<const char *> list2 = gl_List<const char *> (list1, 1, 3); + + gl_List<const char *>::iterator iter2 = list2.begin (); + { + const char *elt; + ASSERT (iter2.next (elt)); + ASSERT (strcmp (elt, "C") == 0); + ASSERT (iter2.next (elt)); + ASSERT (strcmp (elt, "D") == 0); + ASSERT (!iter1.next (elt)); + } + + ASSERT (list2.indexof (A) == (size_t)(-1)); + ASSERT (list2.indexof (D) == 1); + + ASSERT (list2.sortedlist_indexof (strcmp, "A") == (size_t)(-1)); + ASSERT (list2.sortedlist_indexof (strcmp, "D") == 1); + + list2.free (); + list1.free (); + + return 0; +} -- 2.7.4
>From adb365b99317e888cdb89dacdfcb16708a47b672 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:01:38 +0100 Subject: [PATCH 03/11] set-c++: New module. * lib/gl_set.hh: New file, based on lib/gl_set.h. * modules/set-c++: New file. --- ChangeLog | 6 +++ lib/gl_set.hh | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/set-c++ | 21 ++++++++ 3 files changed, 172 insertions(+) create mode 100644 lib/gl_set.hh create mode 100644 modules/set-c++ diff --git a/ChangeLog b/ChangeLog index 9d28f86..fbcc0c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + set-c++: New module. + * lib/gl_set.hh: New file, based on lib/gl_set.h. + * modules/set-c++: New file. + +2020-02-02 Bruno Haible <br...@clisp.org> + list-c++: Add tests. * tests/test-list-c++.cc: New file. * modules/list-c++-tests: New file. diff --git a/lib/gl_set.hh b/lib/gl_set.hh new file mode 100644 index 0000000..357e141 --- /dev/null +++ b/lib/gl_set.hh @@ -0,0 +1,145 @@ +/* Abstract set data type as a C++ class. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2018. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#ifndef _GL_SET_HH +#define _GL_SET_HH + +#include "gl_set.h" +#include "gl_xset.h" + +/* gl_Set is a C++ wrapper around the gl_set data type. + Its element type is 'ELTYPE *'. + + It is merely a pointer, not a smart pointer. In other words: + it does NOT do reference-counting, and the destructor does nothing. */ + +template <class T> class gl_Set; + +template <class ELTYPE> +class gl_Set<ELTYPE *> +{ +public: + // ------------------------------ Constructors ------------------------------ + + gl_Set () + : _ptr (NULL) + {} + + /* Creates an empty set. + IMPLEMENTATION is one of GL_ARRAY_SET, GL_LINKEDHASH_SET, GL_HASH_SET. + EQUALS_FN is an element comparison function or NULL. + HASHCODE_FN is an element hash code function or NULL. + DISPOSE_FN is an element disposal function or NULL. */ + gl_Set (gl_set_implementation_t implementation, + bool (*equals_fn) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + size_t (*hashcode_fn) (ELTYPE *), + void (*dispose_fn) (ELTYPE *)) + : _ptr (gl_set_create_empty (implementation, + reinterpret_cast<gl_setelement_equals_fn>(equals_fn), + reinterpret_cast<gl_setelement_hashcode_fn>(hashcode_fn), + reinterpret_cast<gl_setelement_dispose_fn>(dispose_fn))) + {} + + /* Copy constructor. */ + gl_Set (const gl_Set& x) + { _ptr = x._ptr; } + + /* Assignment operator. */ + gl_Set& operator= (const gl_Set& x) + { _ptr = x._ptr; return *this; } + + // ------------------------------- Destructor ------------------------------- + + ~gl_Set () + { _ptr = NULL; } + + // ----------------------- Read-only member functions ----------------------- + + /* Returns the current number of elements in the set. */ + size_t size () const + { return gl_set_size (_ptr); } + + /* Searches whether an element is already in the set. + Returns true if found, or false if not present in the set. */ + bool search (ELTYPE * elt) const + { return gl_set_search (_ptr, elt); } + + // ----------------------- Modifying member functions ----------------------- + + /* Adds an element to the set. + Returns true if it was not already in the set and added, false otherwise. */ + bool add (ELTYPE * elt) + { return gl_set_add (_ptr, elt); } + + /* Removes an element from the set. + Returns true if it was found and removed. */ + bool remove (ELTYPE * elt) + { return gl_set_remove (_ptr, elt); } + + /* Frees the entire set. + (But this call does not free the elements of the set. It only invokes + the DISPOSE_FN on each of the elements of the set.) */ + void free () + { gl_set_free (_ptr); _ptr = NULL; } + + // ------------------------------ Private stuff ------------------------------ + +private: + gl_set_t _ptr; + +public: + // -------------------------------- Iterators -------------------------------- + // Only a forward iterator. + // Does not implement the STL operations (++, *, and != .end()), but a simpler + // interface that needs only one virtual function call per iteration instead + // of three. + + class iterator { + public: + + /* If there is a next element, stores the next element in ELT, advances the + iterator and returns true. Otherwise, returns false. */ + bool next (ELTYPE *& elt) + { return gl_set_iterator_next (&_state, reinterpret_cast<const void **>(&elt)); } + + ~iterator () + { gl_set_iterator_free (&_state); } + + #if defined __xlC__ || defined __HP_aCC || defined __SUNPRO_CC + public: + #else + private: + friend iterator gl_Set::begin (); + #endif + + iterator (gl_set_t ptr) + : _state (gl_set_iterator (ptr)) + {} + + private: + + gl_set_iterator_t _state; + }; + + /* Creates an iterator traversing the set. + The set's contents must not be modified while the iterator is in use, + except for removing the last returned element. */ + iterator begin () + { return iterator (_ptr); } +}; + +#endif /* _GL_SET_HH */ diff --git a/modules/set-c++ b/modules/set-c++ new file mode 100644 index 0000000..7b999f6 --- /dev/null +++ b/modules/set-c++ @@ -0,0 +1,21 @@ +Description: +Abstract set data type as a C++ class. + +Files: +lib/gl_set.hh + +Depends-on: +xset + +configure.ac: + +Makefile.am: + +Include: +"gl_set.hh" + +License: +GPL + +Maintainer: +all -- 2.7.4
>From 3b52e55775d60e7da7e2e8677f01c4cd11bdbc4f Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:02:10 +0100 Subject: [PATCH 04/11] set-c++: Add tests. * tests/test-set-c++.cc: New file. * modules/set-c++-tests: New file. --- ChangeLog | 4 ++++ modules/set-c++-tests | 17 ++++++++++++++++ tests/test-set-c++.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 modules/set-c++-tests create mode 100644 tests/test-set-c++.cc diff --git a/ChangeLog b/ChangeLog index fbcc0c1..2d53bde 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + set-c++: Add tests. + * tests/test-set-c++.cc: New file. + * modules/set-c++-tests: New file. + set-c++: New module. * lib/gl_set.hh: New file, based on lib/gl_set.h. * modules/set-c++: New file. diff --git a/modules/set-c++-tests b/modules/set-c++-tests new file mode 100644 index 0000000..9acef66 --- /dev/null +++ b/modules/set-c++-tests @@ -0,0 +1,17 @@ +Files: +tests/test-set-c++.cc +tests/macros.h + +Depends-on: +ansi-c++-opt +array-set + +configure.ac: + +Makefile.am: +if ANSICXX +TESTS += test-set-c++ +check_PROGRAMS += test-set-c++ +test_set_c___SOURCES = test-set-c++.cc +test_set_c___LDADD = $(LDADD) @LIBINTL@ +endif diff --git a/tests/test-set-c++.cc b/tests/test-set-c++.cc new file mode 100644 index 0000000..8846be9 --- /dev/null +++ b/tests/test-set-c++.cc @@ -0,0 +1,56 @@ +/* Test of set data type implementation as a C++ class. + Copyright (C) 2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2020. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "gl_set.hh" +#include "gl_array_set.h" + +#include <string.h> + +#include "macros.h" + +static const char A[] = "A"; +static const char C[] = "C"; +static const char D[] = "D"; + +int +main (int argc, char *argv[]) +{ + gl_Set<const char *> set1; + + set1 = gl_Set<const char *> (GL_ARRAY_SET, NULL, NULL, NULL); + set1.add (A); + set1.add (C); + set1.add (D); + set1.add (C); + ASSERT (set1.size () == 3); + + gl_Set<const char *>::iterator iter1 = set1.begin (); + const char *elt; + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "A") == 0 || strcmp (elt, "D") == 0 || strcmp (elt, "C") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "A") == 0 || strcmp (elt, "D") == 0 || strcmp (elt, "C") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "A") == 0 || strcmp (elt, "D") == 0 || strcmp (elt, "C") == 0); + ASSERT (!iter1.next (elt)); + + set1.free (); + + return 0; +} -- 2.7.4
>From ba3d925c185958eaeddf67945c1f4a107de4ecff Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:03:39 +0100 Subject: [PATCH 05/11] oset-c++: New module. * lib/gl_oset.hh: New file, based on lib/gl_oset.h. * modules/oset-c++: New file. --- ChangeLog | 6 +++ lib/gl_oset.hh | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/oset-c++ | 21 ++++++++ 3 files changed, 179 insertions(+) create mode 100644 lib/gl_oset.hh create mode 100644 modules/oset-c++ diff --git a/ChangeLog b/ChangeLog index 2d53bde..d219e03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + oset-c++: New module. + * lib/gl_oset.hh: New file, based on lib/gl_oset.h. + * modules/oset-c++: New file. + +2020-02-02 Bruno Haible <br...@clisp.org> + set-c++: Add tests. * tests/test-set-c++.cc: New file. * modules/set-c++-tests: New file. diff --git a/lib/gl_oset.hh b/lib/gl_oset.hh new file mode 100644 index 0000000..16da0dd --- /dev/null +++ b/lib/gl_oset.hh @@ -0,0 +1,152 @@ +/* Abstract ordered set data type as a C++ class. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2006. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#ifndef _GL_OSET_HH +#define _GL_OSET_HH + +#include "gl_oset.h" +#include "gl_xoset.h" + +/* gl_OSet is a C++ wrapper around the gl_oset data type. + Its element type is 'ELTYPE *'. + + It is merely a pointer, not a smart pointer. In other words: + it does NOT do reference-counting, and the destructor does nothing. */ + +template <class T> class gl_OSet; + +template <class ELTYPE> +class gl_OSet<ELTYPE *> +{ +public: + // ------------------------------ Constructors ------------------------------ + + gl_OSet () + : _ptr (NULL) + {} + + /* Creates an empty set. + IMPLEMENTATION is one of GL_ARRAY_OSET, GL_AVLTREE_OSET, GL_RBTREE_OSET. + COMPAR_FN is an element comparison function or NULL. + DISPOSE_FN is an element disposal function or NULL. */ + gl_OSet (gl_oset_implementation_t implementation, + int (*compar_fn) (ELTYPE * /*elt1*/, ELTYPE * /*elt2*/), + void (*dispose_fn) (ELTYPE *)) + : _ptr (gl_oset_create_empty (implementation, + reinterpret_cast<gl_setelement_compar_fn>(compar_fn), + reinterpret_cast<gl_setelement_dispose_fn>(dispose_fn))) + {} + + /* Copy constructor. */ + gl_OSet (const gl_OSet& x) + { _ptr = x._ptr; } + + /* Assignment operator. */ + gl_OSet& operator= (const gl_OSet& x) + { _ptr = x._ptr; return *this; } + + // ------------------------------- Destructor ------------------------------- + + ~gl_OSet () + { _ptr = NULL; } + + // ----------------------- Read-only member functions ----------------------- + + /* Returns the current number of elements in the ordered set. */ + size_t size () const + { return gl_oset_size (_ptr); } + + /* Searches whether an element is already in the ordered set. + Returns true if found, or false if not present in the set. */ + bool search (ELTYPE * elt) const + { return gl_oset_search (_ptr, elt); } + + /* Searches the least element in the ordered set that compares greater or equal + to the given THRESHOLD. The representation of the THRESHOLD is defined + by the THRESHOLD_FN. + Returns true and store the found element in ELT if found, otherwise returns + false. */ + bool search_atleast (bool (*threshold_fn) (ELTYPE * /*elt*/, ELTYPE * /*threshold*/), + ELTYPE * threshold, + ELTYPE *& elt) const + { return gl_oset_search_atleast (_ptr, reinterpret_cast<gl_setelement_threshold_fn>(threshold_fn), threshold, &elt); } + + // ----------------------- Modifying member functions ----------------------- + + /* Adds an element to the ordered set. + Returns true if it was not already in the set and added, false otherwise. */ + bool add (ELTYPE * elt) + { return gl_oset_add (_ptr, elt); } + + /* Removes an element from the ordered set. + Returns true if it was found and removed. */ + bool remove (ELTYPE * elt) + { return gl_oset_remove (_ptr, elt); } + + /* Frees the entire ordered set. + (But this call does not free the elements of the set. It only invokes + the DISPOSE_FN on each of the elements of the set.) */ + void free () + { gl_oset_free (_ptr); } + + // ------------------------------ Private stuff ------------------------------ + +private: + gl_oset_t _ptr; + +public: + // -------------------------------- Iterators -------------------------------- + // Only a forward iterator. + // Does not implement the STL operations (++, *, and != .end()), but a simpler + // interface that needs only one virtual function call per iteration instead + // of three. + + class iterator { + public: + + /* If there is a next element, stores the next element in ELT, advances the + iterator and returns true. Otherwise, returns false. */ + bool next (ELTYPE *& elt) + { return gl_oset_iterator_next (&_state, reinterpret_cast<const void **>(&elt)); } + + ~iterator () + { gl_oset_iterator_free (&_state); } + + #if defined __xlC__ || defined __HP_aCC || defined __SUNPRO_CC + public: + #else + private: + friend iterator gl_OSet::begin (); + #endif + + iterator (gl_oset_t ptr) + : _state (gl_oset_iterator (ptr)) + {} + + private: + + gl_oset_iterator_t _state; + }; + + /* Creates an iterator traversing the ordered set. + The set's contents must not be modified while the iterator is in use, + except for removing the last returned element. */ + iterator begin () + { return iterator (_ptr); } +}; + +#endif /* _GL_OSET_HH */ diff --git a/modules/oset-c++ b/modules/oset-c++ new file mode 100644 index 0000000..18dce2f --- /dev/null +++ b/modules/oset-c++ @@ -0,0 +1,21 @@ +Description: +Abstract ordered set data type as a C++ class. + +Files: +lib/gl_oset.hh + +Depends-on: +xoset + +configure.ac: + +Makefile.am: + +Include: +"gl_oset.hh" + +License: +GPL + +Maintainer: +all -- 2.7.4
>From e67b6a3a29eaf926b9715d7d4f81d2f436974856 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:04:19 +0100 Subject: [PATCH 06/11] oset-c++: Add tests. * tests/test-oset-c++.cc: New file. * modules/oset-c++-tests: New file. --- ChangeLog | 4 ++++ modules/oset-c++-tests | 17 +++++++++++++++ tests/test-oset-c++.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 modules/oset-c++-tests create mode 100644 tests/test-oset-c++.cc diff --git a/ChangeLog b/ChangeLog index d219e03..1529ebd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + oset-c++: Add tests. + * tests/test-oset-c++.cc: New file. + * modules/oset-c++-tests: New file. + oset-c++: New module. * lib/gl_oset.hh: New file, based on lib/gl_oset.h. * modules/oset-c++: New file. diff --git a/modules/oset-c++-tests b/modules/oset-c++-tests new file mode 100644 index 0000000..d86d973 --- /dev/null +++ b/modules/oset-c++-tests @@ -0,0 +1,17 @@ +Files: +tests/test-oset-c++.cc +tests/macros.h + +Depends-on: +ansi-c++-opt +array-oset + +configure.ac: + +Makefile.am: +if ANSICXX +TESTS += test-oset-c++ +check_PROGRAMS += test-oset-c++ +test_oset_c___SOURCES = test-oset-c++.cc +test_oset_c___LDADD = $(LDADD) @LIBINTL@ +endif diff --git a/tests/test-oset-c++.cc b/tests/test-oset-c++.cc new file mode 100644 index 0000000..c737675 --- /dev/null +++ b/tests/test-oset-c++.cc @@ -0,0 +1,59 @@ +/* Test of ordered set data type implementation as a C++ class. + Copyright (C) 2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2020. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "gl_oset.hh" +#include "gl_array_oset.h" + +#include <string.h> + +#include "macros.h" + +static int +reverse_strcmp (const char *str1, const char *str2) +{ + int cmp = strcmp (str1, str2); + return (cmp > 0 ? -1 : cmp < 0 ? 1 : 0); +} + +int +main (int argc, char *argv[]) +{ + gl_OSet<const char *> set1; + + set1 = gl_OSet<const char *> (GL_ARRAY_OSET, reverse_strcmp, NULL); + set1.add ("A"); + set1.add ("C"); + set1.add ("D"); + set1.add ("C"); + ASSERT (set1.size () == 3); + + gl_OSet<const char *>::iterator iter1 = set1.begin (); + const char *elt; + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "D") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "C") == 0); + ASSERT (iter1.next (elt)); + ASSERT (strcmp (elt, "A") == 0); + ASSERT (!iter1.next (elt)); + + set1.free (); + + return 0; +} -- 2.7.4
>From 4105a91334fd9f88115d0776cdb6d5ec54cf19d6 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:05:19 +0100 Subject: [PATCH 07/11] map-c++: New module. * lib/gl_map.hh: New file, based on lib/gl_map.h. * modules/map-c++: New file. --- ChangeLog | 6 ++ lib/gl_map.hh | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/map-c++ | 21 +++++++ 3 files changed, 202 insertions(+) create mode 100644 lib/gl_map.hh create mode 100644 modules/map-c++ diff --git a/ChangeLog b/ChangeLog index 1529ebd..15e36fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + map-c++: New module. + * lib/gl_map.hh: New file, based on lib/gl_map.h. + * modules/map-c++: New file. + +2020-02-02 Bruno Haible <br...@clisp.org> + oset-c++: Add tests. * tests/test-oset-c++.cc: New file. * modules/oset-c++-tests: New file. diff --git a/lib/gl_map.hh b/lib/gl_map.hh new file mode 100644 index 0000000..f3d0a46 --- /dev/null +++ b/lib/gl_map.hh @@ -0,0 +1,175 @@ +/* Abstract map data type as a C++ class. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2018. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#ifndef _GL_MAP_HH +#define _GL_MAP_HH + +#include "gl_map.h" +#include "gl_xmap.h" + +/* gl_Map is a C++ wrapper around the gl_map data type. + Its key type is 'KEYTYPE *'. Its value type is 'VALUETYPE *'. + + It is merely a pointer, not a smart pointer. In other words: + it does NOT do reference-counting, and the destructor does nothing. */ + +template <class K, class V> class gl_Map; + +template <class KEYTYPE, class VALUETYPE> +class gl_Map<KEYTYPE *, VALUETYPE *> +{ +public: + // ------------------------------ Constructors ------------------------------ + + gl_Map () + : _ptr (NULL) + {} + + /* Creates an empty map. + IMPLEMENTATION is one of GL_ARRAY_MAP, GL_LINKEDHASH_MAP, GL_HASH_MAP. + EQUALS_FN is a key comparison function or NULL. + HASHCODE_FN is a key hash code function or NULL. + KDISPOSE_FN is a key disposal function or NULL. + VDISPOSE_FN is a value disposal function or NULL. */ + gl_Map (gl_map_implementation_t implementation, + bool (*equals_fn) (KEYTYPE * /*key1*/, KEYTYPE * /*key2*/), + size_t (*hashcode_fn) (KEYTYPE *), + void (*kdispose_fn) (KEYTYPE *), + void (*vdispose_fn) (VALUETYPE *)) + : _ptr (gl_map_create_empty (implementation, + reinterpret_cast<gl_mapkey_equals_fn>(equals_fn), + reinterpret_cast<gl_mapkey_hashcode_fn>(hashcode_fn), + reinterpret_cast<gl_mapkey_dispose_fn>(kdispose_fn), + reinterpret_cast<gl_mapvalue_dispose_fn>(vdispose_fn))) + {} + + /* Copy constructor. */ + gl_Map (const gl_Map& x) + { _ptr = x._ptr; } + + /* Assignment operator. */ + gl_Map& operator= (const gl_Map& x) + { _ptr = x._ptr; return *this; } + + // ------------------------------- Destructor ------------------------------- + + ~gl_Map () + { _ptr = NULL; } + + // ----------------------- Read-only member functions ----------------------- + + /* Returns the current number of pairs in the map. */ + size_t size () const + { return gl_map_size (_ptr); } + + /* Searches whether a pair with the given key is already in the map. + Returns the value if found, or NULL if not present in the map. */ + VALUETYPE * get (KEYTYPE * key) const + { return static_cast<VALUETYPE *>(gl_map_get (_ptr, key)); } + + /* Searches whether a pair with the given key is already in the map. + Returns true and sets VALUE to the value if found. + Returns false if not present in the map. */ + bool search (KEYTYPE * key, VALUETYPE *& value) const + { return gl_map_search (_ptr, key, &value); } + + // ----------------------- Modifying member functions ----------------------- + + /* Adds a pair to the map. + Returns true if a pair with the given key was not already in the map and so + this pair was added. + Returns false if a pair with the given key was already in the map and only + its value was replaced. */ + bool put (KEYTYPE * key, VALUETYPE * value) + { return gl_map_put (_ptr, key, value); } + + /* Adds a pair to the map and retrieves the previous value. + Returns true if a pair with the given key was not already in the map and so + this pair was added. + Returns false and sets OLDVALUE to the previous value, if a pair with the + given key was already in the map and only its value was replaced. */ + bool getput (KEYTYPE * key, VALUETYPE * value, VALUETYPE *& oldvalue) + { return gl_map_getput (_ptr, key, value, &oldvalue); } + + /* Removes a pair from the map. + Returns true if the key was found and its pair removed. + Returns false otherwise. */ + bool remove (KEYTYPE * key) + { return gl_map_remove (_ptr, key); } + + /* Removes a pair from the map and retrieves the previous value. + Returns true and sets OLDVALUE to the previous value, if the key was found + and its pair removed. + Returns false otherwise. */ + bool getremove (KEYTYPE * key, VALUETYPE *& oldvalue) + { return gl_map_getremove (_ptr, key, &oldvalue); } + + /* Frees the entire map. + (But this call does not free the keys and values of the pairs in the map. + It only invokes the KDISPOSE_FN on each key and the VDISPOSE_FN on each value + of the pairs in the map.) */ + void free () + { gl_map_free (_ptr); _ptr = NULL; } + + // ------------------------------ Private stuff ------------------------------ + +private: + gl_map_t _ptr; + +public: + // -------------------------------- Iterators -------------------------------- + // Only a forward iterator. + // Does not implement the STL operations (++, *, and != .end()), but a simpler + // interface that needs only one virtual function call per iteration instead + // of three. + + class iterator { + public: + + /* If there is a next pair, stores the next pair in KEY and VALUE, advance + the iterator, and returns true. Otherwise, returns false. */ + bool next (KEYTYPE *& key, VALUETYPE *& value) + { return gl_map_iterator_next (&_state, reinterpret_cast<const void **>(&key), reinterpret_cast<const void **>(&value)); } + + ~iterator () + { gl_map_iterator_free (&_state); } + + #if defined __xlC__ || defined __HP_aCC || defined __SUNPRO_CC + public: + #else + private: + friend iterator gl_Map::begin (); + #endif + + iterator (gl_map_t ptr) + : _state (gl_map_iterator (ptr)) + {} + + private: + + gl_map_iterator_t _state; + }; + + /* Creates an iterator traversing the map. + The map's contents must not be modified while the iterator is in use, + except for modifying the value of the last returned key or removing the + last returned pair. */ + iterator begin () + { return iterator (_ptr); } +}; + +#endif /* _GL_MAP_HH */ diff --git a/modules/map-c++ b/modules/map-c++ new file mode 100644 index 0000000..e9a7058 --- /dev/null +++ b/modules/map-c++ @@ -0,0 +1,21 @@ +Description: +Abstract map data type as a C++ class. + +Files: +lib/gl_map.hh + +Depends-on: +xmap + +configure.ac: + +Makefile.am: + +Include: +"gl_map.hh" + +License: +GPL + +Maintainer: +all -- 2.7.4
>From 27008822a5e0c47e8217eae171a3b8ead59b8394 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:06:33 +0100 Subject: [PATCH 08/11] map-c++: Add tests. * tests/test-map-c++.cc: New file. * modules/map-c++-tests: New file. --- ChangeLog | 4 +++ modules/map-c++-tests | 17 ++++++++++++ tests/test-map-c++.cc | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 modules/map-c++-tests create mode 100644 tests/test-map-c++.cc diff --git a/ChangeLog b/ChangeLog index 15e36fe..a894f10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + map-c++: Add tests. + * tests/test-map-c++.cc: New file. + * modules/map-c++-tests: New file. + map-c++: New module. * lib/gl_map.hh: New file, based on lib/gl_map.h. * modules/map-c++: New file. diff --git a/modules/map-c++-tests b/modules/map-c++-tests new file mode 100644 index 0000000..edfbf28 --- /dev/null +++ b/modules/map-c++-tests @@ -0,0 +1,17 @@ +Files: +tests/test-map-c++.cc +tests/macros.h + +Depends-on: +ansi-c++-opt +array-map + +configure.ac: + +Makefile.am: +if ANSICXX +TESTS += test-map-c++ +check_PROGRAMS += test-map-c++ +test_map_c___SOURCES = test-map-c++.cc +test_map_c___LDADD = $(LDADD) @LIBINTL@ +endif diff --git a/tests/test-map-c++.cc b/tests/test-map-c++.cc new file mode 100644 index 0000000..2750155 --- /dev/null +++ b/tests/test-map-c++.cc @@ -0,0 +1,74 @@ +/* Test of map data type implementation as a C++ class. + Copyright (C) 2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2020. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "gl_map.hh" +#include "gl_array_map.h" + +#include <string.h> + +#include "macros.h" + +static const int integers[6] = { 0, 1, 2, 3, 4, 5 }; + +static bool +streq (const char *str1, const char *str2) +{ + return strcmp (str1, str2) == 0; +} + +int +main (int argc, char *argv[]) +{ + gl_Map<const char *, const int *> map1; + + map1 = gl_Map<const char *, const int *> (GL_ARRAY_MAP, streq, NULL, NULL, NULL); + map1.put ("five", integers); + map1.put ("one", integers + 1); + map1.put ("two", integers + 2); + map1.put ("three", integers + 3); + map1.put ("four", integers + 4); + map1.put ("five", integers + 5); + ASSERT (map1.size () == 5); + + ASSERT (map1.get ("two")[0] == 2); + + gl_Map<const char *, const int *>::iterator iter1 = map1.begin (); + const char *key; + const int *val; + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "five") == 0); + ASSERT (*val == 5); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "one") == 0); + ASSERT (*val == 1); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "two") == 0); + ASSERT (*val == 2); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "three") == 0); + ASSERT (*val == 3); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "four") == 0); + ASSERT (*val == 4); + ASSERT (!iter1.next (key, val)); + + map1.free (); + + return 0; +} -- 2.7.4
>From 0314e51d0fcfb9d96d4b0868f085d5f811300b46 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:07:17 +0100 Subject: [PATCH 09/11] omap-c++: New module. * lib/gl_omap.hh: New file, based on lib/gl_omap.h. * modules/omap-c++: New file. --- ChangeLog | 6 ++ lib/gl_omap.hh | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules/omap-c++ | 21 +++++++ 3 files changed, 209 insertions(+) create mode 100644 lib/gl_omap.hh create mode 100644 modules/omap-c++ diff --git a/ChangeLog b/ChangeLog index a894f10..3b2616e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + omap-c++: New module. + * lib/gl_omap.hh: New file, based on lib/gl_omap.h. + * modules/omap-c++: New file. + +2020-02-02 Bruno Haible <br...@clisp.org> + map-c++: Add tests. * tests/test-map-c++.cc: New file. * modules/map-c++-tests: New file. diff --git a/lib/gl_omap.hh b/lib/gl_omap.hh new file mode 100644 index 0000000..15d8104 --- /dev/null +++ b/lib/gl_omap.hh @@ -0,0 +1,182 @@ +/* Abstract ordered map data type as a C++ class. + Copyright (C) 2006-2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2018. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#ifndef _GL_OMAP_HH +#define _GL_OMAP_HH + +#include "gl_omap.h" +#include "gl_xomap.h" + +/* gl_OMap is a C++ wrapper around the gl_omap data type. + Its key type is 'KEYTYPE *'. Its value type is 'VALUETYPE *'. + + It is merely a pointer, not a smart pointer. In other words: + it does NOT do reference-counting, and the destructor does nothing. */ + +template <class K, class V> class gl_OMap; + +template <class KEYTYPE, class VALUETYPE> +class gl_OMap<KEYTYPE *, VALUETYPE *> +{ +public: + // ------------------------------ Constructors ------------------------------ + + gl_OMap () + : _ptr (NULL) + {} + + /* Creates an empty map. + IMPLEMENTATION is one of GL_ARRAY_OMAP, GL_AVLTREE_OMAP, GL_RBTREE_OMAP. + COMPAR_FN is a key comparison function or NULL. + KDISPOSE_FN is a key disposal function or NULL. + VDISPOSE_FN is a value disposal function or NULL. */ + gl_OMap (gl_omap_implementation_t implementation, + int (*compar_fn) (KEYTYPE * /*key1*/, KEYTYPE * /*key2*/), + void (*kdispose_fn) (KEYTYPE *), + void (*vdispose_fn) (VALUETYPE *)) + : _ptr (gl_omap_create_empty (implementation, + reinterpret_cast<gl_mapkey_compar_fn>(compar_fn), + reinterpret_cast<gl_mapkey_dispose_fn>(kdispose_fn), + reinterpret_cast<gl_mapvalue_dispose_fn>(vdispose_fn))) + {} + + /* Copy constructor. */ + gl_OMap (const gl_OMap& x) + { _ptr = x._ptr; } + + /* Assignment operator. */ + gl_OMap& operator= (const gl_OMap& x) + { _ptr = x._ptr; return *this; } + + // ------------------------------- Destructor ------------------------------- + + ~gl_OMap () + { _ptr = NULL; } + + // ----------------------- Read-only member functions ----------------------- + + /* Returns the current number of pairs in the ordered map. */ + size_t size () const + { return gl_omap_size (_ptr); } + + /* Searches whether a pair with the given key is already in the ordered map. + Returns the value if found, or NULL if not present in the map. */ + VALUETYPE * get (KEYTYPE * key) const + { return static_cast<VALUETYPE *>(gl_omap_get (_ptr, key)); } + + /* Searches whether a pair with the given key is already in the ordered map. + Returns true and sets VALUE to the value if found. + Returns false if not present in the map. */ + bool search (KEYTYPE * key, VALUETYPE *& value) const + { return gl_omap_search (_ptr, key, &value); } + + /* Searches the pair with the least key in the ordered map that compares + greater or equal to the given THRESHOLD. The representation of the + THRESHOLD is defined by the THRESHOLD_FN. + Returns true and stores the found pair in KEY and VALUE if found. + Otherwise returns false. */ + bool search_atleast (bool (*threshold_fn) (KEYTYPE * /*key*/, KEYTYPE * /*threshold*/), + KEYTYPE * threshold, + KEYTYPE *& key, VALUETYPE *& value) const + { return gl_omap_search_atleast (_ptr, reinterpret_cast<gl_mapkey_threshold_fn>(threshold_fn), threshold, &key, &value); } + + // ----------------------- Modifying member functions ----------------------- + + /* Adds a pair to the ordered map. + Returns true if a pair with the given key was not already in the map and so + this pair was added. + Returns false if a pair with the given key was already in the map and only + its value was replaced. */ + bool put (KEYTYPE * key, VALUETYPE * value) + { return gl_omap_put (_ptr, key, value); } + + /* Adds a pair to the ordered map and retrieves the previous value. + Returns true if a pair with the given key was not already in the map and so + this pair was added. + Returns false and sets OLDVALUE to the previous value, if a pair with the + given key was already in the map and only its value was replaced. */ + bool getput (KEYTYPE * key, VALUETYPE * value, VALUETYPE *& oldvalue) + { return gl_omap_getput (_ptr, key, value, &oldvalue); } + + /* Removes a pair from the ordered map. + Returns true if the key was found and its pair removed. + Returns false otherwise. */ + bool remove (KEYTYPE * key) + { return gl_omap_remove (_ptr, key); } + + /* Removes a pair from the ordered map and retrieves the previous value. + Returns true and sets OLDVALUE to the previous value, if the key was found + and its pair removed. + Returns false otherwise. */ + bool getremove (KEYTYPE * key, VALUETYPE *& oldvalue) + { return gl_omap_getremove (_ptr, key, &oldvalue); } + + /* Frees the entire ordered map. + (But this call does not free the keys and values of the pairs in the map. + It only invokes the KDISPOSE_FN on each key and the VDISPOSE_FN on each value + of the pairs in the map.) */ + void free () + { gl_omap_free (_ptr); _ptr = NULL; } + + // ------------------------------ Private stuff ------------------------------ + +private: + gl_omap_t _ptr; + +public: + // -------------------------------- Iterators -------------------------------- + // Only a forward iterator. + // Does not implement the STL operations (++, *, and != .end()), but a simpler + // interface that needs only one virtual function call per iteration instead + // of three. + + class iterator { + public: + + /* If there is a next pair, stores the next pair in KEY and VALUE, advances + the iterator, and returns true. Otherwise, returns false. */ + bool next (KEYTYPE *& key, VALUETYPE *& value) + { return gl_omap_iterator_next (&_state, reinterpret_cast<const void **>(&key), reinterpret_cast<const void **>(&value)); } + + ~iterator () + { gl_omap_iterator_free (&_state); } + + #if defined __xlC__ || defined __HP_aCC || defined __SUNPRO_CC + public: + #else + private: + friend iterator gl_OMap::begin (); + #endif + + iterator (gl_omap_t ptr) + : _state (gl_omap_iterator (ptr)) + {} + + private: + + gl_omap_iterator_t _state; + }; + + /* Creates an iterator traversing the ordered map. + The map's contents must not be modified while the iterator is in use, + except for modifying the value of the last returned key or removing the + last returned pair. */ + iterator begin () + { return iterator (_ptr); } +}; + +#endif /* _GL_OMAP_HH */ diff --git a/modules/omap-c++ b/modules/omap-c++ new file mode 100644 index 0000000..ce1609a --- /dev/null +++ b/modules/omap-c++ @@ -0,0 +1,21 @@ +Description: +Abstract ordered map data type as a C++ class. + +Files: +lib/gl_omap.hh + +Depends-on: +xomap + +configure.ac: + +Makefile.am: + +Include: +"gl_omap.hh" + +License: +GPL + +Maintainer: +all -- 2.7.4
>From f304938084333321882a1050ea55048a04f17781 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:08:15 +0100 Subject: [PATCH 10/11] omap-c++: Add tests. * tests/test-omap-c++.cc: New file. * modules/omap-c++-tests: New file. --- ChangeLog | 4 +++ modules/omap-c++-tests | 17 +++++++++++++ tests/test-omap-c++.cc | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 modules/omap-c++-tests create mode 100644 tests/test-omap-c++.cc diff --git a/ChangeLog b/ChangeLog index 3b2616e..05f0dcc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + omap-c++: Add tests. + * tests/test-omap-c++.cc: New file. + * modules/omap-c++-tests: New file. + omap-c++: New module. * lib/gl_omap.hh: New file, based on lib/gl_omap.h. * modules/omap-c++: New file. diff --git a/modules/omap-c++-tests b/modules/omap-c++-tests new file mode 100644 index 0000000..1f723dd --- /dev/null +++ b/modules/omap-c++-tests @@ -0,0 +1,17 @@ +Files: +tests/test-omap-c++.cc +tests/macros.h + +Depends-on: +ansi-c++-opt +array-omap + +configure.ac: + +Makefile.am: +if ANSICXX +TESTS += test-omap-c++ +check_PROGRAMS += test-omap-c++ +test_omap_c___SOURCES = test-omap-c++.cc +test_omap_c___LDADD = $(LDADD) @LIBINTL@ +endif diff --git a/tests/test-omap-c++.cc b/tests/test-omap-c++.cc new file mode 100644 index 0000000..7d3b061 --- /dev/null +++ b/tests/test-omap-c++.cc @@ -0,0 +1,68 @@ +/* Test of ordered map data type implementation as a C++ class. + Copyright (C) 2020 Free Software Foundation, Inc. + Written by Bruno Haible <br...@clisp.org>, 2020. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "gl_omap.hh" +#include "gl_array_omap.h" + +#include <string.h> + +#include "macros.h" + +static const int integers[6] = { 0, 1, 2, 3, 4, 5 }; + +int +main (int argc, char *argv[]) +{ + gl_OMap<const char *, const int *> map1; + + map1 = gl_OMap<const char *, const int *> (GL_ARRAY_OMAP, strcmp, NULL, NULL); + map1.put ("five", integers); + map1.put ("one", integers + 1); + map1.put ("two", integers + 2); + map1.put ("three", integers + 3); + map1.put ("four", integers + 4); + map1.put ("five", integers + 5); + ASSERT (map1.size () == 5); + + ASSERT (map1.get ("two")[0] == 2); + + gl_OMap<const char *, const int *>::iterator iter1 = map1.begin (); + const char *key; + const int *val; + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "five") == 0); + ASSERT (*val == 5); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "four") == 0); + ASSERT (*val == 4); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "one") == 0); + ASSERT (*val == 1); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "three") == 0); + ASSERT (*val == 3); + ASSERT (iter1.next (key, val)); + ASSERT (strcmp (key, "two") == 0); + ASSERT (*val == 2); + ASSERT (!iter1.next (key, val)); + + map1.free (); + + return 0; +} -- 2.7.4
>From f4a23b264e32e8c3101ffe39ad38c3114acd1a24 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 2 Feb 2020 19:25:05 +0100 Subject: [PATCH 11/11] Document the new modules list-c++, set-c++, oset-c++, map-c++, omap-c++. * doc/containers.texi: Document these new modules. --- ChangeLog | 5 +++++ doc/containers.texi | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/ChangeLog b/ChangeLog index 05f0dcc..2a86791 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2020-02-02 Bruno Haible <br...@clisp.org> + Document the new modules list-c++, set-c++, oset-c++, map-c++, omap-c++. + * doc/containers.texi: Document these new modules. + +2020-02-02 Bruno Haible <br...@clisp.org> + omap-c++: Add tests. * tests/test-omap-c++.cc: New file. * modules/omap-c++-tests: New file. diff --git a/doc/containers.texi b/doc/containers.texi index 739ed81..b3f154d 100644 --- a/doc/containers.texi +++ b/doc/containers.texi @@ -498,6 +498,35 @@ for the ``ordered map'' data type are: @tab @math{O(@log n)} @end multitable +For C++, Gnulib provides a C++ template class for each of these container data types. + +@multitable @columnfractions .30 .20 .25 .25 +@headitem Data type +@tab C++ class +@tab Module +@tab Include file +@item Sequential list +@tab @code{gl_List} +@tab @code{list-c++} +@tab @code{"gl_list.hh"} +@item Set +@tab @code{gl_Set} +@tab @code{set-c++} +@tab @code{"gl_set.hh"} +@item Ordered set +@tab @code{gl_OSet} +@tab @code{oset-c++} +@tab @code{"gl_oset.hh"} +@item Map +@tab @code{gl_Map} +@tab @code{map-c++} +@tab @code{"gl_map.hh"} +@item Ordered map +@tab @code{gl_OMap} +@tab @code{omap-c++} +@tab @code{"gl_omap.hh"} +@end multitable + @ifnottex @unmacro log @end ifnottex -- 2.7.4