MyGUI  3.0.1
MyGUI_BiIndexBase.h
Go to the documentation of this file.
1 
7 /*
8  This file is part of MyGUI.
9 
10  MyGUI is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  MyGUI is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #ifndef __MYGUI_BIINDEX_BASE_H__
24 #define __MYGUI_BIINDEX_BASE_H__
25 
26 #include "MyGUI_Prerequest.h"
27 
28 namespace MyGUI
29 {
30 
32  {
33  public:
34  virtual ~BiIndexBase() { }
35  protected:
36 
37  size_t getIndexCount() { return mIndexFace.size(); }
38 
39  size_t insertItemAt(size_t _index)
40  {
41  #if MYGUI_DEBUG_MODE == 1
42  MYGUI_ASSERT_RANGE_INSERT(_index, mIndexFace.size(), "BiIndexBase::insertItemAt");
43  checkIndexes();
44  #endif
45 
46  if (_index == MyGUI::ITEM_NONE) _index = mIndexFace.size();
47 
48  size_t index;
49 
50  if (_index == mIndexFace.size())
51  {
52  // для вставки айтема
53  index = mIndexFace.size();
54 
55  mIndexFace.push_back(_index);
56  mIndexBack.push_back(_index);
57  }
58  else
59  {
60  // для вставки айтема
61  index = mIndexFace[_index];
62 
63  size_t count = mIndexFace.size();
64  for (size_t pos=0; pos<count; ++pos)
65  {
66  if (mIndexFace[pos] >= index) mIndexFace[pos]++;
67  }
68  mIndexFace.insert(mIndexFace.begin() + _index, index);
69 
70  count ++;
71  mIndexBack.push_back(0);
72  for (size_t pos=0; pos<count; ++pos)
73  {
74  mIndexBack[mIndexFace[pos]] = pos;
75  }
76  }
77 
78  #if MYGUI_DEBUG_MODE == 1
79  checkIndexes();
80  #endif
81 
82  return index;
83  }
84 
85  size_t removeItemAt(size_t _index)
86  {
87  #if MYGUI_DEBUG_MODE == 1
88  MYGUI_ASSERT_RANGE(_index, mIndexFace.size(), "BiIndexBase::removeItemAt");
89  checkIndexes();
90  #endif
91 
92  // для удаления айтема
93  size_t index = mIndexFace[_index];
94 
95  mIndexFace.erase(mIndexFace.begin() + _index);
96  mIndexBack.pop_back();
97 
98  size_t count = mIndexFace.size();
99  for (size_t pos=0; pos<count; ++pos)
100  {
101  if (mIndexFace[pos] > index) mIndexFace[pos]--;
102  mIndexBack[mIndexFace[pos]] = pos;
103  }
104 
105  #if MYGUI_DEBUG_MODE == 1
106  checkIndexes();
107  #endif
108 
109  return index;
110  }
111 
113  {
114  mIndexFace.clear();
115  mIndexBack.clear();
116  }
117 
118  // на входе индексы пользователя, на выходе реальные индексы
119  size_t convertToBack(size_t _index) const
120  {
121  #if MYGUI_DEBUG_MODE == 1
122  MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToBack");
123  #endif
124  return _index == ITEM_NONE ? ITEM_NONE : mIndexFace[_index];
125  }
126 
127  // на входе индексы реальные, на выходе, то что видит пользователь
128  size_t convertToFace(size_t _index) const
129  {
130  #if MYGUI_DEBUG_MODE == 1
131  MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToFace");
132  #endif
133  return _index == ITEM_NONE ? ITEM_NONE : mIndexBack[_index];
134  }
135 
136  // меняет местами два индекса, индексы со стороны пользователя
137  void swapItemsFaceAt(size_t _index1, size_t _index2)
138  {
139  #if MYGUI_DEBUG_MODE == 1
140  MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
141  MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
142  #endif
143 
144  std::swap(mIndexFace[_index1], mIndexFace[_index2]);
145  std::swap(mIndexBack[mIndexFace[_index1]], mIndexBack[mIndexFace[_index2]]);
146  }
147 
148  // меняет местами два индекса, индексы со сторонны данных
149  void swapItemsBackAt(size_t _index1, size_t _index2)
150  {
151  #if MYGUI_DEBUG_MODE == 1
152  MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
153  MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
154  #endif
155 
156  std::swap(mIndexBack[_index1], mIndexBack[_index2]);
157  std::swap(mIndexFace[mIndexBack[_index1]], mIndexFace[mIndexBack[_index2]]);
158  }
159 
160  #if MYGUI_DEBUG_MODE == 1
161 
162  void checkIndexes()
163  {
164  assert(mIndexFace.size() == mIndexBack.size());
165 
166  // проверяем на уникальность каждого индекса в маппинге
167  std::vector<bool> vec;
168  size_t count = mIndexFace.size();
169 
170  vec.reserve(count);
171  for (size_t pos=0; pos<count; ++pos) vec.push_back(false);
172 
173  for (size_t pos=0; pos<count; ++pos)
174  {
175  // максимум
176  size_t index = mIndexBack[pos];
177  if (index >= count) throw new std::exception();
178 
179  // максимум
180  index = mIndexFace[pos];
181  if (index >= count) throw new std::exception();
182 
183  if (vec[index]) throw new std::exception();
184  vec[index] = true;
185  }
186 
187  for (size_t pos=0; pos<count; ++pos)
188  {
189  if (!vec[pos]) throw new std::exception();
190  }
191 
192  // проверяем на взаимоссылаемость индексов
193  for (size_t pos=0; pos<count; ++pos)
194  {
195  size_t index = mIndexFace[pos];
196  if (mIndexBack[index] != pos) throw new std::exception();
197  }
198  }
199 
200  #endif
201 
202  private:
203  typedef std::vector<size_t> VectorSizeT;
204 
205  // маппинг с индексов, которые видны наружу
206  // на индексы которые реально используются данными
207  VectorSizeT mIndexFace;
208 
209  // маппинг с индексов, которые используют данные
210  // на индексы которые виндны наружу
211  VectorSizeT mIndexBack;
212  };
213 
214 } // namespace MyGUI
215 
216 #endif // __MYGUI_BIINDEX_BASE_H__