File indexing completed on 2024-12-22 05:17:14

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #ifndef ENUM_H
0021 #define ENUM_H
0022 
0023 #include <QList>
0024 
0025 namespace Wacom
0026 {
0027 
0028 /**
0029  * A typesafe enumeration template class. It can be used as a comfortable replacement
0030  * for C++ enums and supports the following features:
0031  *
0032  *   - enumerators can be listed and iterated over
0033  *   - enumerator lists are sorted by a given comparator
0034  *   - enumerators can have a key assigned
0035  *   - enumerator keys can be listed and searched for
0036  *
0037  * NOTICE
0038  * This class uses template specialization to store a static set of all instances.
0039  * Thereofore a specialization of the private instances member  'instances' has
0040  * to be declared and instantiated before this template can be used.
0041  *
0042  * \tparam D The derived sub class type. This is the class which contains the enum instances.
0043  * \tparam K The key type used for these instances.
0044  * \tparam L A "less than" functor which can compare objects of type D*.
0045  * \tparam E A "equal to" functor which can compare objects of type K.
0046  */
0047 template<class D, class K, class L, class E>
0048 class Enum
0049 {
0050 private:
0051     typedef QList<const D *> Container;
0052     typedef typename Container::const_iterator ContainerConstIterator;
0053 
0054 public:
0055     typedef typename Container::size_type size_type;
0056 
0057     /**
0058      * A constant iterator which can be used to iterator over all known Enum instances.
0059      */
0060     class const_iterator
0061     {
0062     public:
0063         const_iterator()
0064         {
0065         }
0066         const_iterator(const const_iterator &iter)
0067         {
0068             operator=(iter);
0069         }
0070         const_iterator(const ContainerConstIterator &iter)
0071         {
0072             m_iter = iter;
0073         }
0074 
0075         const D &operator*() const
0076         {
0077             return **m_iter;
0078         }
0079         const D *operator->() const
0080         {
0081             return *m_iter;
0082         }
0083         const_iterator &operator=(const const_iterator &iter)
0084         {
0085             m_iter = iter.m_iter;
0086             return *this;
0087         }
0088         bool operator==(const const_iterator &iter) const
0089         {
0090             return (m_iter == iter.m_iter);
0091         }
0092         bool operator!=(const const_iterator &iter) const
0093         {
0094             return (m_iter != iter.m_iter);
0095         }
0096         const_iterator &operator++()
0097         {
0098             ++m_iter;
0099             return *this;
0100         }
0101         const_iterator operator++(int)
0102         {
0103             const_iterator copy(*this);
0104             ++(*this);
0105             return copy;
0106         }
0107         const_iterator &operator--()
0108         {
0109             --m_iter;
0110             return *this;
0111         }
0112         const_iterator operator--(int)
0113         {
0114             const_iterator copy(*this);
0115             --(*this);
0116             return copy;
0117         }
0118 
0119     private:
0120         ContainerConstIterator m_iter;
0121     };
0122 
0123     /**
0124      * Equal-Compare Operator.
0125      */
0126     bool operator==(const Enum<D, K, L, E> &that) const
0127     {
0128         return (m_derived == that.m_derived);
0129     }
0130 
0131     /**
0132      * Not-Equal-Compare Operator.
0133      */
0134     bool operator!=(const Enum<D, K, L, E> &that) const
0135     {
0136         return (m_derived != that.m_derived);
0137     }
0138 
0139     /**
0140      * @return A constant iterator to the first element.
0141      */
0142     static const_iterator begin()
0143     {
0144         // force the use of const_iterator - fixes compile problem with some containers
0145         const Enum<D, K, L, E>::Container *container = &Enum<D, K, L, E>::instances;
0146         return const_iterator(container->begin());
0147     }
0148 
0149     /**
0150      * @return A constant iterator to the last element.
0151      */
0152     static const_iterator end()
0153     {
0154         // force the use of const_iterator - fixes compile problem with some containers
0155         const Enum<D, K, L, E>::Container *container = &Enum<D, K, L, E>::instances;
0156         return const_iterator(container->end());
0157     }
0158 
0159     /**
0160      * Searches for the enumeration instance by key.
0161      *
0162      * @param key The key of the instance to search.
0163      *
0164      * @return A constant pointer to the instance or nullptr if not found.
0165      */
0166     static const D *find(const K &key)
0167     {
0168         E comp;
0169         for (const_iterator i = begin(); i != end(); ++i) {
0170             if (comp(i->key(), key)) {
0171                 return &(*i);
0172             }
0173         }
0174         return nullptr;
0175     }
0176 
0177     /**
0178      * @return A list of all valid enum instances of this specialization.
0179      */
0180     static QList<D> list()
0181     {
0182         QList<D> enums;
0183         for (const_iterator i = begin(); i != end(); ++i) {
0184             enums.push_back(*i);
0185         }
0186         return enums;
0187     }
0188 
0189     /**
0190      * @return The key of this enum instance.
0191      */
0192     const K &key() const
0193     {
0194         return m_key;
0195     }
0196 
0197     /**
0198      * Returns a list of all instances' keys of this specialization.
0199      *
0200      * @return A list of keys sorted by the less-than-functor.
0201      */
0202     static QList<K> keys()
0203     {
0204         QList<K> keys;
0205         for (const_iterator i = begin(); i != end(); ++i) {
0206             keys.push_back(i->key());
0207         }
0208         return keys;
0209     }
0210 
0211     /**
0212      * @return The number of enum instances of this specialization.
0213      */
0214     static size_type size()
0215     {
0216         return Enum<D, K, L, E>::instances.size();
0217     }
0218 
0219 protected:
0220     /**
0221      * Initialization constructor.
0222      * Used to initialize class-static members. Never make this constructor
0223      * available to the public! Never use it for normal instances! It may
0224      * only be used to instantiate class-static Enum instances.
0225      *
0226      * @param derived A const pointer to the derived class of this instance.
0227      * @param key The key of this class-static Enum instance.
0228      */
0229     explicit Enum(const D *derived, const K &key)
0230         : m_key(key)
0231     {
0232         m_derived = derived;
0233         insert(derived);
0234     }
0235 
0236     /**
0237      * \return A const pointer to the derived class of this instance.
0238      */
0239     const D *derived() const
0240     {
0241         return m_derived;
0242     }
0243 
0244 private:
0245     /**
0246      * Inserts an element into to the static instances container.
0247      * This method should only be called by the constructor!
0248      *
0249      * \param derived An instance of the derived class, never NULL.
0250      */
0251     void insert(const D *derived)
0252     {
0253         L comp;
0254         typename Enum<D, K, L, E>::Container::iterator i = this->instances.begin();
0255 
0256         for (; i != this->instances.end(); ++i) {
0257             if (comp(derived, *i)) {
0258                 this->instances.insert(i, derived);
0259                 return;
0260             }
0261         }
0262 
0263         this->instances.push_back(derived);
0264     }
0265 
0266     K m_key; /**< The key of this instance */
0267     const D *m_derived; /**< Pointer to derived class for fast comparison */
0268 
0269     /**
0270      * A static container with all the class-static Enum instances.
0271      * Every specialization of this template has to declare and instantiate
0272      * the specialization of this member variable!
0273      */
0274     static Container instances;
0275 
0276 }; // CLASS
0277 } // NAMESPACE
0278 #endif // HEADER PROTECTION