--- /dev/null
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 5 Comm
+ */
+
+#include "DescriptorSet.h"
+
+// pre-allocates descriptor store and index for Squid_MaxFD descriptors
+DescriptorSet::DescriptorSet(): descriptors_(NULL), index_(NULL),
+ capacity_(0), size_(0)
+{
+ // we allocate once and never realloc, at least for now
+ capacity_ = Squid_MaxFD;
+ descriptors_ = new int[capacity_];
+ index_ = new int[capacity_];
+
+ // fill index with -1s to be able to say whether a descriptor is present
+ // it is not essential to fill the descriptors, but it enables more checks
+ for (int i = 0; i < capacity_; ++i)
+ index_[i] = descriptors_[i] = -1;
+}
+
+DescriptorSet::~DescriptorSet()
+{
+ delete[] descriptors_;
+ delete[] index_;
+}
+
+/// adds if unique; returns true if added
+bool
+DescriptorSet::add(int fd)
+{
+ assert(0 <= fd && fd < capacity_); // \todo: replace with Must()
+
+ if (has(fd))
+ return false; // already have it
+
+ assert(size_ < capacity_); // \todo: replace with Must()
+ const int pos = size_++;
+ index_[fd] = pos;
+ descriptors_[pos] = fd;
+ return true; // really added
+}
+
+/// deletes if there; returns true if deleted
+bool
+DescriptorSet::del(int fd)
+{
+ assert(0 <= fd && fd < capacity_); // \todo: here and below, use Must()
+
+ if (!has(fd))
+ return false; // we do not have it
+
+ assert(!empty());
+ const int delPos = index_[fd];
+ assert(0 <= delPos && delPos < capacity_);
+
+ // move the last descriptor to the deleted fd position
+ // to avoid skipping deleted descriptors in pop()
+ const int lastPos = size_-1;
+ const int lastFd = descriptors_[lastPos];
+ assert(delPos <= lastPos); // may be the same
+ descriptors_[delPos] = lastFd;
+ index_[lastFd] = delPos;
+
+ descriptors_[lastPos] = -1;
+ index_[fd] = -1;
+ --size_;
+
+ return true; // really added
+}
+
+/// ejects one descriptor in unspecified order
+int
+DescriptorSet::pop()
+{
+ assert(!empty());
+ const int lastPos =--size_;
+ const int lastFd = descriptors_[lastPos];
+ assert(0 <= lastFd && lastFd < capacity_);
+
+ // cleanup
+ descriptors_[lastPos] = -1;
+ index_[lastFd] = -1;
+
+ return lastFd;
+}
+
+void
+DescriptorSet::print(std::ostream &os) const
+{
+ // \todo add "name" if the set is used for more than just half-closed FDs
+ os << size_ << " FDs";
+}
--- /dev/null
+#ifndef SQUID_DESCRIPTOR_SET_H
+#define SQUID_DESCRIPTOR_SET_H
+
+#include "squid.h"
+
+/** \ingroup Comm
+
+ \todo: Should we use std::set<int> with its flexibility? Our implementation
+ has constant overhead, which is smaller than log(n) of std::set.
+
+an unordered collection of unique descriptors with O(1) add/del/has ops */
+class DescriptorSet {
+public:
+ // for STL compatibility, should we decide to switch to std::set or similar
+ typedef const int *const_iterator;
+
+ DescriptorSet();
+ ~DescriptorSet();
+
+ /// checks whether fd is in the set
+ bool has(const int fd) const { return 0 <= fd && fd < capacity_ &&
+ index_[fd] >= 0; }
+
+ bool add(int fd); ///< adds if unique; returns true if added
+ bool del(int fd); ///< deletes if there; returns true if deleted
+ int pop(); ///< deletes and returns one descriptor, in unspecified order
+
+ bool empty() const { return !size_; } ///< number of descriptors in the set
+
+ /// begin iterator a la STL; may become invalid if the object is modified
+ const_iterator begin() const { return descriptors_; }
+ /// end iterator a la STL; may become invalid if the object is modified
+ const_iterator end() const { return begin() + size_; }
+
+ /// outputs debugging info about the set
+ void print(std::ostream &os) const;
+
+private:
+ // these would be easy to support when needed; prohibit for now
+ DescriptorSet(const DescriptorSet &s); // declared but undefined
+ DescriptorSet &operator =(const DescriptorSet &s); // declared, undefined
+
+ int *descriptors_; ///< descriptor values in random order
+ int *index_; ///< descriptor:position index into descriptors_
+ int capacity_; ///< total number of descriptor slots
+ int size_; ///< number of descriptors in the set
+};
+
+/// convenience wrapper to be used in debugs() context
+inline std::ostream &
+operator <<(std::ostream &os, const DescriptorSet &ds)
+{
+ ds.print(os);
+ return os;
+}
+
+#endif /* SQUID_DESCRIPTOR_SET_H */
+