Index: src/Formula.cpp
===================================================================
--- src/Formula.cpp	(revision 6f43ab53afcb10b11789dfb8789489256a97116b)
+++ src/Formula.cpp	(revision 6f43ab53afcb10b11789dfb8789489256a97116b)
@@ -0,0 +1,265 @@
+/*
+ * Formula.cpp
+ *
+ *  Created on: Jul 21, 2010
+ *      Author: crueger
+ */
+
+#include "Formula.hpp"
+
+#include <sstream>
+
+#include "World.hpp"
+#include "periodentafel.hpp"
+#include "element.hpp"
+#include "Helpers/Assert.hpp"
+
+using namespace std;
+
+Formula::Formula() :
+  numElements(0)
+{}
+
+Formula::Formula(const Formula &src) :
+  elementCounts(src.elementCounts),
+  numElements(src.numElements)
+{}
+
+Formula::~Formula()
+{}
+
+Formula &Formula::operator=(const Formula &rhs){
+  // No self-assignment check needed
+  elementCounts=rhs.elementCounts;
+  numElements=rhs.numElements;
+  return *this;
+}
+
+std::string Formula::toString() const{
+  stringstream sstr;
+  for(const_reverse_iterator iter=rbegin();iter!=rend();++iter){
+    sstr << (*iter).first->symbol << (*iter).second;
+  }
+  return sstr.str();
+}
+
+bool Formula::checkOut(ostream *output) const{
+  bool result = true;
+  int No = 1;
+
+  if (output != NULL) {
+    *output << "# Ion type data (PP = PseudoPotential, Z = atomic number)" << endl;
+    *output << "#Ion_TypeNr.\tAmount\tZ\tRGauss\tL_Max(PP)L_Loc(PP)IonMass\t# chemical name, symbol" << endl;
+    for(const_iterator iter=begin(); iter!=end();++iter){
+      (*iter).first->No = No;
+      result = result && (*iter).first->Checkout(output, No++, (*iter).second);
+    }
+    return result;
+  } else
+    return false;
+}
+
+unsigned int Formula::getElementCount(){
+  return numElements;
+}
+
+bool Formula::hasElement(const element *element) const{
+  ASSERT(element,"Invalid pointer in Formula::hasElement(element*)");
+  return hasElement(element->getNumber());
+}
+
+bool Formula::hasElement(atomicNumber_t Z) const{
+  ASSERT(Z>0,"Invalid atomic Number");
+  ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
+  return elementCounts.size()>=Z && elementCounts[Z-1];
+}
+
+bool Formula::hasElement(const string &shorthand) const{
+  element * element = World::getInstance().getPeriode()->FindElement(shorthand);
+  return hasElement(element);
+}
+
+void Formula::operator+=(const element *element){
+  ASSERT(element,"Invalid pointer in increment of Formula");
+  operator+=(element->getNumber());
+}
+
+void Formula::operator+=(atomicNumber_t Z){
+  ASSERT(Z>0,"Invalid atomic Number");
+  ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
+  elementCounts.resize(Z); // No-op when we already have the right size
+  // might need to update number of elements
+  if(!elementCounts[Z-1]){
+    numElements++;
+  }
+  elementCounts[Z-1]++;    // atomic numbers start at 1
+}
+
+void Formula::operator+=(const string &shorthand){
+  element * element = World::getInstance().getPeriode()->FindElement(shorthand);
+  operator+=(element);
+}
+
+void Formula::operator-=(const element *element){
+  ASSERT(element,"Invalid pointer in decrement of Formula");
+  operator-=(element->getNumber());
+}
+
+void Formula::operator-=(atomicNumber_t Z){
+  ASSERT(Z>0,"Invalid atomic Number");
+  ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
+  ASSERT(elementCounts.size()>=Z && elementCounts[Z-1], "Element not in Formula upon decrement");
+  elementCounts[Z-1]--;    // atomic numbers start at 1
+  // might need to update number of elements
+  if(!elementCounts[Z-1]){
+    numElements--;
+  }
+}
+
+void Formula::operator-=(const string &shorthand){
+  element * element = World::getInstance().getPeriode()->FindElement(shorthand);
+  operator-=(element);
+}
+
+const unsigned int &Formula::operator[](const element *element) const{
+  ASSERT(element,"Invalid pointer in access of Formula");
+  return operator[](element->getNumber());
+}
+
+const unsigned int &Formula::operator[](atomicNumber_t Z) const{
+  ASSERT(Z>0,"Invalid atomic Number");
+  ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
+  elementCounts.resize(Z);   // No-op when we already have the right size
+  return elementCounts[Z-1]; // atomic numbers start at 1
+}
+
+const unsigned int &Formula::operator[](string shorthand) const{
+  element * element = World::getInstance().getPeriode()->FindElement(shorthand);
+  return operator[](element);
+}
+
+bool Formula::operator==(const Formula &rhs) const{
+  // quick check... number of elements used
+  if(numElements != rhs.numElements){
+    return false;
+  }
+  // slow check: all elements
+  // direct access to internal structure means all element-counts have to be compared
+  // this avoids access to periodentafel to find elements though and is probably faster
+  // in total
+  return equal(elementCounts.begin(),
+               elementCounts.end(),
+               rhs.elementCounts.begin());
+}
+
+bool Formula::operator!=(const Formula &rhs) const{
+  return !operator==(rhs);
+}
+
+Formula::iterator Formula::begin(){
+  return iterator(elementCounts,0);
+}
+Formula::const_iterator Formula::begin() const{
+  return const_iterator(elementCounts,0);
+}
+Formula::iterator Formula::end(){
+  return iterator(elementCounts);
+}
+Formula::const_iterator Formula::end() const{
+  return const_iterator(elementCounts);
+}
+
+Formula::reverse_iterator Formula::rbegin(){
+  return reverse_iterator(end());
+}
+Formula::const_reverse_iterator Formula::rbegin() const{
+  return const_reverse_iterator(end());
+}
+Formula::reverse_iterator Formula::rend(){
+  return reverse_iterator(begin());
+}
+Formula::const_reverse_iterator Formula::rend() const{
+  return const_reverse_iterator(begin());
+}
+
+/**************** Iterator structure ********************/
+
+template <class result_type>
+Formula::_iterator<result_type>::_iterator(set_t &_set) :
+    set(&_set)
+{
+  pos=set->size();
+}
+
+template <class result_type>
+Formula::_iterator<result_type>::_iterator(set_t &_set,size_t _pos) :
+  set(&_set),pos(_pos)
+{
+  ASSERT(pos<=set->size(),"invalid position in iterator construction");
+  while(pos<set->size() && (*set)[pos]!=0) ++pos;
+}
+
+template <class result_type>
+Formula::_iterator<result_type>::~_iterator(){}
+
+template <class result_type>
+Formula::_iterator<result_type>&
+Formula::_iterator<result_type>::operator=(const _iterator<result_type> &rhs){
+  set=rhs.set;
+  pos=rhs.pos;
+  return *this;
+}
+
+template <class result_type>
+bool
+Formula::_iterator<result_type>::operator==(const _iterator<result_type> &rhs){
+  return set==rhs.set && pos==rhs.pos;
+}
+
+template <class result_type>
+bool
+Formula::_iterator<result_type>::operator!=(const _iterator<result_type> &rhs){
+  return !operator==(rhs);
+}
+
+template <class result_type>
+Formula::_iterator<result_type>
+Formula::_iterator<result_type>::operator++(){
+  ASSERT(pos!=set->size(),"Incrementing Formula::iterator beyond end");
+  while(pos<set->size() && (*set)[pos]!=0) ++pos;
+  return *this;
+}
+
+template <class result_type>
+Formula::_iterator<result_type>
+Formula::_iterator<result_type>::operator--(){
+  ASSERT(pos!=0,"Decrementing Formula::iterator beyobd begin");
+  while(pos>0 && (*set)[pos]!=0) ++pos;
+  return *this;
+}
+
+template <class result_type>
+result_type
+Formula::_iterator<result_type>::operator*(){
+  element *element = World::getInstance().getPeriode()->FindElement(pos+1);
+  ASSERT(element,"Element with position of iterator not found");
+  return make_pair(element,(*set)[pos]);
+}
+
+template <class result_type>
+result_type*
+Formula::_iterator<result_type>::operator->(){
+  // no one can keep this value around, so a static is ok to avoid temporaries
+  static value_type value=make_pair(reinterpret_cast<element*>(0),0); // no default constructor for std::pair
+  element *element = World::getInstance().getPeriode()->FindElement(pos+1);
+  ASSERT(element,"Element with position of iterator not found");
+  value = make_pair(element,(*set)[pos]);
+  return &value;
+}
+
+/********************** I/O of Formulas ************************************************/
+
+std::ostream &operator<<(std::ostream &ost,const Formula &formula){
+  ost << formula.toString();
+  return ost;
+}
Index: src/Formula.hpp
===================================================================
--- src/Formula.hpp	(revision 6f43ab53afcb10b11789dfb8789489256a97116b)
+++ src/Formula.hpp	(revision 6f43ab53afcb10b11789dfb8789489256a97116b)
@@ -0,0 +1,102 @@
+/*
+ * Formula.hpp
+ *
+ *  Created on: Jul 21, 2010
+ *      Author: crueger
+ */
+
+#ifndef FORMULA_HPP_
+#define FORMULA_HPP_
+
+#include <vector>
+#include <iosfwd>
+#include <iterator>
+
+#include "types.hpp"
+
+class element;
+
+class Formula
+{
+public:
+  typedef element*                                      key_type;
+  typedef unsigned int                                  mapped_type;
+  typedef std::pair<key_type, mapped_type>              value_type;
+  typedef std::vector<unsigned int>                     set_t;
+
+  template <class result_type>
+  class _iterator : public std::iterator <std::bidirectional_iterator_tag,
+                                         result_type>
+  {
+  public:
+    _iterator(set_t&);
+    _iterator(set_t&,size_t);
+    ~_iterator();
+    _iterator   &operator=(const _iterator &);
+    bool         operator==(const _iterator&);
+    bool         operator!=(const _iterator&);
+    _iterator    operator++();
+    _iterator    operator++(int);
+    _iterator    operator--();
+    _iterator    operator--(int);
+    result_type  operator*();
+    result_type *operator->();
+  private:
+    set_t *set;
+    size_t pos; // cannot use an iterator, because we need a position to access the element
+  };
+
+  typedef _iterator<value_type>                 iterator;
+  typedef _iterator<const value_type>           const_iterator;
+  typedef std::reverse_iterator<iterator>       reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  Formula();
+  Formula(const Formula&);
+  virtual ~Formula();
+
+  Formula &operator=(const Formula&);
+
+  std::string toString() const;
+  bool checkOut(std::ostream*) const;
+
+  unsigned int getElementCount();
+  bool hasElement(const element*)       const;
+  bool hasElement(atomicNumber_t)       const;
+  bool hasElement(const std::string&)   const;
+
+  void operator+=(const element*);
+  void operator+=(atomicNumber_t);
+  void operator+=(const std::string&);
+
+  void operator-=(const element*);
+  void operator-=(atomicNumber_t);
+  void operator-=(const std::string&);
+
+  // only const versions, because someone might try to increment a previously
+  // not set element
+  const unsigned int &operator[](const element*) const;
+  const unsigned int &operator[](atomicNumber_t) const;
+  const unsigned int &operator[](std::string)    const;
+
+  bool operator==(const Formula&) const;
+  bool operator!=(const Formula&) const;
+
+  iterator       begin();
+  const_iterator begin() const;
+  iterator       end();
+  const_iterator end()   const;
+
+  reverse_iterator       rbegin();
+  const_reverse_iterator rbegin() const;
+  reverse_iterator       rend();
+  const_reverse_iterator rend()   const;
+
+private:
+  mutable set_t elementCounts; // we might need to resize even at const places
+  unsigned int numElements;
+};
+
+std::ostream &operator<<(std::ostream&,const Formula&);
+
+#endif /* FORMULA_HPP_ */
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision f308e66546defa4255f80fbf3c82f29c462acdb7)
+++ src/Makefile.am	(revision 6f43ab53afcb10b11789dfb8789489256a97116b)
@@ -198,4 +198,5 @@
   ellipsoid.cpp \
   errorlogger.cpp \
+  Formula.cpp \
   graph.cpp \
   helpers.cpp \
@@ -248,4 +249,5 @@
   ellipsoid.hpp \
   errorlogger.hpp \
+  Formula.hpp \
   graph.hpp \
   helpers.hpp \
