/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkEquivalencyTable_h #define itkEquivalencyTable_h #include "itkProcessObject.h" #include namespace itk { /** \class EquivalencyTable * \brief Hash table to manage integral label equivalencies * * EquivalencyTable is a hash table for recording equivalencies among * unsigned long integer values. EquivalencyTable can store recursive * relationships (8=7, 7=6, 6=5, ...) or be "flattened" to eliminate * recursion. The table uses an efficient algorithm for eliminating * redundancy and preventing circular dependencies. * * \par * In the context of the watershed segmentation algorithm * (itk::WatershedImageFilter), this table is used to store connections * identified among image segments and as the input to * itk::watershed::Relabeler. * \ingroup WatershedSegmentation * \ingroup ITKCommon */ class ITKCommon_EXPORT EquivalencyTable : public DataObject { public: ITK_DISALLOW_COPY_AND_MOVE(EquivalencyTable); /** Standard smart pointer declarations */ using Self = EquivalencyTable; using Superclass = DataObject; using Pointer = SmartPointer; using ConstPointer = SmartPointer; itkNewMacro(Self); itkOverrideGetNameOfClassMacro(EquivalencyTable); /** Define the container type for the table. */ using HashTableType = std::unordered_map>; using Iterator = HashTableType::iterator; using ConstIterator = HashTableType::const_iterator; using ValueType = HashTableType::value_type; /** "Flattens" the equivalency table by eliminating all redundant * and recursive equivalencies. I.e. the set { 2=1; 3=2; 4=3 } is * converted to {4=1; 3=1; 2=1}. */ void Flatten(); /** Insert an equivalency into the table. A return value of TRUE * indicates that the equivalency did not previously exist in the * table and was successfully added. A FALSE return value indicates * that the equivalency was not added to the table because a * conflict with an existing entry occurred (most likely, the * equivalency was already recorded directly or indirectly). */ bool Add(unsigned long a, unsigned long b); /** Insert an equivalency into the table and flatten that * equivalency. A return value of TRUE indicates that the * equivalency did not previously exist in the table and was * successfully added. A FALSE return value indicates that the * equivalency was not added to the table because a conflict with an * existing entry occurred (most likely, the equivalency was already * recorded directly or indirectly). */ bool AddAndFlatten(unsigned long a, unsigned long b); /** Lookup an equivalency in the table. If no entry is found in the * table, the method returns its the value of the argument. Does * not recursively descent through equivalencies. */ unsigned long Lookup(const unsigned long a) const { auto result = m_HashMap.find(a); if (result == m_HashMap.end()) { return a; } else { return result->second; } } /** Lookup an equivalency in the table by recursing through all * successive equivalencies. For example, if the follow entries * exist in the table {8=7, 7=6, 6=5}, then RecursiveLookup(8) * returns 5. */ unsigned long RecursiveLookup(const unsigned long a) const; /** Returns TRUE if the label is found in the table and FALSE is the label is * not found in the table. */ bool IsEntry(const unsigned long a) const { if (m_HashMap.find(a) == m_HashMap.end()) { return false; } else { return true; } } /** Erases the entry with key a. */ void Erase(const unsigned long a) { m_HashMap.erase(a); } /** Erases all the entries in the table. */ void Clear() { m_HashMap.clear(); } /** Returns TRUE if the table is empty, FALSE if it is not empty. */ bool Empty() const { return m_HashMap.empty(); } /** Returns the number of entries in the table. */ HashTableType::size_type Size() const { return m_HashMap.size(); } /** Returns an iterator pointing to the first element of the (unordered) * table. */ Iterator Begin() { return m_HashMap.begin(); } /** Returns and iterator pointing to one position past the last * element of the (unordered) table. */ Iterator End() { return m_HashMap.end(); } /** Convenience method for debugging. */ // void PrintHashTable(); protected: EquivalencyTable() = default; ~EquivalencyTable() override = default; void PrintSelf(std::ostream & os, Indent indent) const override; HashTableType m_HashMap{}; }; } // end namespace itk #endif