/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #ifndef MULTISET_H #define MULTISET_H #include "Fundamentals.h" // // A multiset (i.e. set that can contain the same element more than once) // with elements of class Elt. Class Elt must provide the following operations: // // Copy constructor // operator== and operator!= // // Elt equality must be reflexive (every Elt is equal to itself), symmetric // (if a==b then b==a), and transitive. // // template class SimpleMultiset { struct Node { Node *next; Uint32 count; Elt element; Node(Elt element, Uint32 count): count(count), element(element) {} }; Pool &pool; Node *nodes; Uint32 nNodes; public: explicit SimpleMultiset(Pool &pool): pool(pool), nodes(0), nNodes(0) {} SimpleMultiset(const SimpleMultiset &src): pool(src.pool) {copy(src);} void operator=(const SimpleMultiset &src) {copy(src);} void move(SimpleMultiset &src); void clear() {nodes = 0; nNodes = 0;} private: void copy(const SimpleMultiset &src); public: bool empty() const {return !nodes;} bool operator==(const SimpleMultiset &s) const; bool operator!=(const SimpleMultiset &s) const {return !operator==(s);} Uint32 find(Elt element) const; Uint32 add(Elt element); Uint32 remove(Elt element); #ifdef DEBUG void verify() const; #endif }; // // Destructively move the src SimpleMultiset to this SimpleMultiset, leaving the // src SimpleMultiset empty. // template inline void SimpleMultiset::move(SimpleMultiset &src) { assert(&pool == &src.pool); nodes = src.nodes; nNodes = src.nNodes; src.clear(); #ifdef DEBUG verify(); #endif } // // Assign a copy of the src SimpleMultiset to this SimpleMultiset, whose previous // contents are destroyed. // template inline void SimpleMultiset::copy(const SimpleMultiset &src) { if (&src != this) { nNodes = src.nNodes; Node **link = &nodes; for (const Node *srcNode = src.nodes; srcNode; srcNode = srcNode->next) { Node *dstNode = new Node(srcNode->element, srcNode->count); *link = dstNode; link = &dstNode->next; } *link = 0; } #ifdef DEBUG verify(); #endif } // // Return true if this multiset contains the same elements with the same multiplicities // as multiset s. // template bool SimpleMultiset::operator==(const SimpleMultiset &s) const { if (nNodes != s.nNodes) return false; for (const Node *n = nodes; n; n = n->next) if (s.find(n->element) != n->count) return false; return true; } // // Return the number of times the element is present in the multiset. This number // is zero if the element is not present. // template Uint32 SimpleMultiset::find(Elt element) const { for (const Node *n = nodes; n; n = n->next) if (n->element == element) return n->count; return 0; } // // Add the element to the multiset. An element can be present multiple times in the // same multiset. Return the number of times the element was present in the multiset // before this latest addition. // template Uint32 SimpleMultiset::add(Elt element) { const Node *n; for (n = nodes; n; n = n->next) if (n->element == element) return n->count++; n = new(pool) Node(element, 1); n->next = nodes; nodes = n; nNodes++; #ifdef DEBUG verify(); #endif return 0; } // // Remove one instance of the element to the multiset. An element can be present // multiple times in the same multiset. Return the number of times the element was // present in the multiset before this latest removal. If the element was not // present at all in the multiset before this removal, do nothing and return 0. // template Uint32 SimpleMultiset::remove(Elt element) { const Node **prev; const Node *n; for (prev = &nodes; (n = *prev) != 0; prev = &n->next) if (n->element == element) { Uint32 count = n->count--; if (count == 1) { *prev = n->next; nNodes--; } #ifdef DEBUG verify(); #endif return count; } return 0; } #ifdef DEBUG // // Verify that the multiset is internally consistent. Assert if anything wrong is found. // template void SimpleMultiset::verify() const { // Check nNodes. Uint32 i = 0; const Node *n; for (n = nodes; n; n = n->next) i++; assert(i == nNodes); // Check that all elements are unique and none has a count of zero. for (n = nodes; n; n = n->next) { assert(n->count != 0); for (const Node *m = n->next; m; m = m->next) assert(m->element != n->element); } } #endif #endif