4 /*****************************************************************************\
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 1996-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include "object_packers.h"
19 #include "string_array.h"
21 #include <basis/astring.h>
22 #include <basis/contracts.h>
23 #include <basis/definitions.h>
24 #include <basis/guards.h>
26 namespace structures {
28 //! Emulates a mathematical set, providing several standard set operations.
30 Note: this is not an efficient object and it should not be used for
31 sets of non-trivial sizes.
34 template <class contents>
35 class set : public basis::array<contents>
38 //! Constructs a set with "num" elements, copying them from "init".
39 /*! Be very careful to ensure that the array "init" has sufficient length
40 for "num" elements to be copied from it. */
41 set(int num = 0, const contents *init = NULL_POINTER,
42 basis::un_short flags = basis::array<contents>::EXPONE)
43 : basis::array<contents>(num, init, flags) {}
45 ~set() {} //!< Destroys any storage held for the set.
47 int elements() const { return this->length(); }
48 //!< Returns the number of elements in this set.
50 bool empty() const { return elements() == 0; }
51 //!< Returns true if the set has no elements.
52 bool non_empty() const { return elements() != 0; }
53 //!< Returns true if the set has some elements.
55 void clear() { this->reset(); } //!< Empties out this set.
57 bool member(const contents &to_test) const;
58 //!< Returns true if the item "to_test" is a member of this set.
60 bool add(const contents &to_add);
61 //!< Adds a new element "to_add" to the set.
62 /*!< This always succeeds, but will return true if the item was not
65 set &operator += (const contents &to_add)
66 { add(to_add); return *this; }
67 //!< An algebraic operator synonym for add() that operates on the contents.
68 set &operator += (const set &to_add)
69 { unionize(to_add); return *this; }
70 //!< An algebraic operator synonym for add() that operates on a set.
72 bool remove(const contents &to_remove);
73 //!< Removes the item "to_remove" from the set.
74 /*!< If it was not present, false is returned and the set is unchanged. */
76 set &operator -= (const contents &to_zap)
77 { remove(to_zap); return *this; }
78 //!< An algebraic operator synonym for remove that operates on the contents.
79 set &operator -= (const set &to_zap)
80 { differentiate(to_zap); return *this; }
81 //!< An algebraic operator synonym for remove that operates on a set.
83 set set_union(const set &union_with) const;
84 //!< Implements the set union of "this" with "union_with".
85 /*!< This returns the set formed from the union of "this" set with the set
86 specified in "union_with". (unfortunately, the name "set_union" must
87 be used to distinguish from the C keyword "union".) */
89 void unionize(const set &union_with);
90 //!< Makes "this" set a union of "this" and "union_with".
92 set operator + (const set &uw) const { return set_union(uw); }
93 //!< A synonym for set_union.
95 set intersection(const set &intersect_with) const;
96 //!< Returns the intersection of "this" with the set in "intersect_with".
98 set operator * (const set &iw) const { return intersection(iw); }
99 //!< A synonym for intersection.
101 set difference(const set &differ_with) const;
102 //!< Returns the difference of this with "differ_with".
103 /*!< Difference is defined as the subset of elements in "this" that are not
104 also in "differ_with". */
106 void differentiate(const set &differ_with);
107 //!< Makes "this" set equal to the difference of "this" and "differ_with".
108 /*!< That is, after the call, "this" will only contain elements that were
109 not also in "differ_with". */
111 set operator - (const set &dw) const { return difference(dw); }
112 //!< A synonym for difference.
114 int find(const contents &to_find) const;
115 //!< Returns the integer index of the item "to_find" in this set.
116 /*!< This returns a negative number if the index cannot be found. Note
117 that this only makes sense within our particular implementation of set as
120 //! Zaps the entry at the specified "index".
121 /*! This also treats the set like an array. The index must be within the
122 bounds of the existing members. */
123 bool remove_index(int index)
124 { return this->zap(index, index) == basis::common::OKAY; }
129 //! provides a way to pack any set that stores packable objects.
130 template <class contents>
131 void pack(basis::byte_array &packed_form, const set<contents> &to_pack)
133 obscure_attach(packed_form, to_pack.elements());
134 for (int i = 0; i < to_pack.elements(); i++) to_pack[i].pack(packed_form);
137 //! provides a way to unpack any set that stores packable objects.
138 template <class contents>
139 bool unpack(basis::byte_array &packed_form, set<contents> &to_unpack)
143 if (!obscure_detach(packed_form, len)) return false;
145 for (int i = 0; i < (int)len; i++) {
146 if (!to_fill.unpack(packed_form)) return false;
147 to_unpack.add(to_fill);
154 //! A simple object that wraps a templated set of ints.
155 class int_set : public set<int>, public virtual basis::root_object
159 //!< Constructs an empty set of ints.
160 int_set(const set<int> &to_copy) : set<int>(to_copy) {}
161 //!< Constructs a copy of the "to_copy" array.
163 DEFINE_CLASS_NAME("int_set");
166 //! A simple object that wraps a templated set of strings.
167 class string_set : public set<basis::astring>, public virtual basis::packable
171 //!< Constructs an empty set of strings.
172 string_set(const set<basis::astring> &to_copy)
173 : set<basis::astring>(to_copy) {}
174 //!< Constructs a copy of the "to_copy" array.
175 string_set(const string_array &to_copy) {
176 for (int i = 0; i < to_copy.length(); i++)
180 DEFINE_CLASS_NAME("string_set");
182 bool operator == (const string_set &compare) const {
183 for (int i = 0; i < elements(); i++)
184 if (get(i) != compare.get(i)) return false;
188 operator string_array() const {
189 string_array to_return;
190 for (int i = 0; i < length(); i++)
195 virtual void pack(basis::byte_array &packed_form) const
196 { structures::pack(packed_form, *this); }
197 virtual bool unpack(basis::byte_array &packed_form)
198 { return structures::unpack(packed_form, *this); }
199 virtual int packed_size() const {
200 int to_return = sizeof(int) * 2; // length packed in, using obscure.
201 for (int i = 0; i < length(); i++)
202 to_return += get(i).length() + 1;
207 //! A set of pointers that hides the platform's pointer size.
208 class pointer_set : public set<void *>
212 //!< Constructs an empty set of void pointers.
213 pointer_set(const set<void *> &to_copy) : set<void *>(to_copy)
215 //!< Constructs a copy of the "to_copy" array.
220 // implementation for longer functions is below...
222 template <class contents>
223 bool set<contents>::member(const contents &to_test) const
225 for (int i = 0; i < elements(); i++)
226 if (to_test == this->get(i))
231 template <class contents>
232 bool set<contents>::add(const contents &to_add)
234 if (member(to_add)) return false;
235 this->concatenate(to_add);
239 template <class contents>
240 int set<contents>::find(const contents &to_find) const
242 for (int i = 0; i < elements(); i++)
243 if (to_find == this->get(i))
245 return basis::common::NOT_FOUND;
248 template <class contents>
249 bool set<contents>::remove(const contents &to_remove)
251 for (int i = 0; i < elements(); i++)
252 if (to_remove == this->get(i)) {
259 template <class contents>
260 set<contents> set<contents>::intersection(const set &intersect_with) const
262 set<contents> created(0, NULL_POINTER, this->flags());
263 const set *smaller = this;
264 const set *larger = &intersect_with;
265 if (elements() > intersect_with.elements()) {
266 // switch the smaller one into place.
267 smaller = &intersect_with;
270 for (int i = 0; i < smaller->length(); i++)
271 if (larger->member(smaller->get(i)))
272 created.concatenate(smaller->get(i));
276 template <class contents>
277 set<contents> set<contents>::set_union(const set &union_with) const
279 set<contents> created = *this;
280 for (int i = 0; i < union_with.elements(); i++)
281 created.add(union_with.get(i));
285 template <class contents>
286 void set<contents>::unionize(const set &union_with)
288 for (int i = 0; i < union_with.elements(); i++)
289 add(union_with.get(i));
292 template <class contents>
293 set<contents> set<contents>::difference(const set &differ_with) const
295 set<contents> created = *this;
296 for (int i = 0; i < differ_with.elements(); i++) {
297 if (created.member(differ_with[i]))
298 created.remove(differ_with[i]);
303 template <class contents>
304 void set<contents>::differentiate(const set &differ_with)
306 for (int i = 0; i < differ_with.elements(); i++) {
307 if (member(differ_with[i]))
308 remove(differ_with[i]);