MyGUI 3.0.1
MyGUI_BiIndexBase.h
Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of MyGUI.
00009 
00010     MyGUI is free software: you can redistribute it and/or modify
00011     it under the terms of the GNU Lesser General Public License as published by
00012     the Free Software Foundation, either version 3 of the License, or
00013     (at your option) any later version.
00014 
00015     MyGUI is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU Lesser General Public License for more details.
00019 
00020     You should have received a copy of the GNU Lesser General Public License
00021     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 #ifndef __MYGUI_BIINDEX_BASE_H__
00024 #define __MYGUI_BIINDEX_BASE_H__
00025 
00026 #include "MyGUI_Prerequest.h"
00027 
00028 namespace MyGUI
00029 {
00030 
00031     class BiIndexBase
00032     {
00033     public:
00034         virtual ~BiIndexBase() { }
00035     protected:
00036 
00037         size_t getIndexCount() { return mIndexFace.size(); }
00038 
00039         size_t insertItemAt(size_t _index)
00040         {
00041             #if MYGUI_DEBUG_MODE == 1
00042                 MYGUI_ASSERT_RANGE_INSERT(_index, mIndexFace.size(), "BiIndexBase::insertItemAt");
00043                 checkIndexes();
00044             #endif
00045 
00046             if (_index == MyGUI::ITEM_NONE) _index = mIndexFace.size();
00047 
00048             size_t index;
00049 
00050             if (_index == mIndexFace.size())
00051             {
00052                 // для вставки айтема
00053                 index = mIndexFace.size();
00054 
00055                 mIndexFace.push_back(_index);
00056                 mIndexBack.push_back(_index);
00057             }
00058             else
00059             {
00060                 // для вставки айтема
00061                 index = mIndexFace[_index];
00062 
00063                 size_t count = mIndexFace.size();
00064                 for (size_t pos=0; pos<count; ++pos)
00065                 {
00066                     if (mIndexFace[pos] >= index) mIndexFace[pos]++;
00067                 }
00068                 mIndexFace.insert(mIndexFace.begin() + _index, index);
00069 
00070                 count ++;
00071                 mIndexBack.push_back(0);
00072                 for (size_t pos=0; pos<count; ++pos)
00073                 {
00074                     mIndexBack[mIndexFace[pos]] = pos;
00075                 }
00076             }
00077 
00078             #if MYGUI_DEBUG_MODE == 1
00079                 checkIndexes();
00080             #endif
00081 
00082             return index;
00083         }
00084 
00085         size_t removeItemAt(size_t _index)
00086         {
00087             #if MYGUI_DEBUG_MODE == 1
00088                 MYGUI_ASSERT_RANGE(_index, mIndexFace.size(), "BiIndexBase::removeItemAt");
00089                 checkIndexes();
00090             #endif
00091 
00092             // для удаления айтема
00093             size_t index = mIndexFace[_index];
00094 
00095             mIndexFace.erase(mIndexFace.begin() + _index);
00096             mIndexBack.pop_back();
00097 
00098             size_t count = mIndexFace.size();
00099             for (size_t pos=0; pos<count; ++pos)
00100             {
00101                 if (mIndexFace[pos] > index) mIndexFace[pos]--;
00102                 mIndexBack[mIndexFace[pos]] = pos;
00103             }
00104 
00105             #if MYGUI_DEBUG_MODE == 1
00106                 checkIndexes();
00107             #endif
00108 
00109             return index;
00110         }
00111 
00112         void removeAllItems()
00113         {
00114             mIndexFace.clear();
00115             mIndexBack.clear();
00116         }
00117 
00118         // на входе индексы пользователя, на выходе реальные индексы
00119         size_t convertToBack(size_t _index) const
00120         {
00121             #if MYGUI_DEBUG_MODE == 1
00122                 MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToBack");
00123             #endif
00124             return _index == ITEM_NONE ? ITEM_NONE : mIndexFace[_index];
00125         }
00126 
00127         // на входе индексы реальные, на выходе, то что видит пользователь
00128         size_t convertToFace(size_t _index) const
00129         {
00130             #if MYGUI_DEBUG_MODE == 1
00131                 MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToFace");
00132             #endif
00133             return _index == ITEM_NONE ? ITEM_NONE : mIndexBack[_index];
00134         }
00135 
00136         // меняет местами два индекса, индексы со стороны пользователя
00137         void swapItemsFaceAt(size_t _index1, size_t _index2)
00138         {
00139             #if MYGUI_DEBUG_MODE == 1
00140                 MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
00141                 MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
00142             #endif
00143 
00144             std::swap(mIndexFace[_index1], mIndexFace[_index2]);
00145             std::swap(mIndexBack[mIndexFace[_index1]], mIndexBack[mIndexFace[_index2]]);
00146         }
00147 
00148         // меняет местами два индекса, индексы со сторонны данных
00149         void swapItemsBackAt(size_t _index1, size_t _index2)
00150         {
00151             #if MYGUI_DEBUG_MODE == 1
00152                 MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
00153                 MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
00154             #endif
00155 
00156             std::swap(mIndexBack[_index1], mIndexBack[_index2]);
00157             std::swap(mIndexFace[mIndexBack[_index1]], mIndexFace[mIndexBack[_index2]]);
00158         }
00159 
00160         #if MYGUI_DEBUG_MODE == 1
00161 
00162         void checkIndexes()
00163         {
00164             assert(mIndexFace.size() == mIndexBack.size());
00165 
00166             // проверяем на уникальность каждого индекса в маппинге
00167             std::vector<bool> vec;
00168             size_t count = mIndexFace.size();
00169 
00170             vec.reserve(count);
00171             for (size_t pos=0; pos<count; ++pos) vec.push_back(false);
00172 
00173             for (size_t pos=0; pos<count; ++pos)
00174             {
00175                 // максимум
00176                 size_t index = mIndexBack[pos];
00177                 if (index >= count) throw new std::exception();
00178 
00179                 // максимум
00180                 index = mIndexFace[pos];
00181                 if (index >= count) throw new std::exception();
00182 
00183                 if (vec[index]) throw new std::exception();
00184                 vec[index] = true;
00185             }
00186 
00187             for (size_t pos=0; pos<count; ++pos)
00188             {
00189                 if (!vec[pos]) throw new std::exception();
00190             }
00191 
00192             // проверяем на взаимоссылаемость индексов
00193             for (size_t pos=0; pos<count; ++pos)
00194             {
00195                 size_t index = mIndexFace[pos];
00196                 if (mIndexBack[index] != pos) throw new std::exception();
00197             }
00198         }
00199 
00200         #endif
00201 
00202     private:
00203         typedef std::vector<size_t> VectorSizeT;
00204 
00205         // маппинг с индексов, которые видны наружу
00206         // на индексы которые реально используются данными
00207         VectorSizeT mIndexFace;
00208 
00209         // маппинг с индексов, которые используют данные
00210         // на индексы которые виндны наружу
00211         VectorSizeT mIndexBack;
00212     };
00213 
00214 } // namespace MyGUI
00215 
00216 #endif // __MYGUI_BIINDEX_BASE_H__