1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
8 #include "MyGUI_BiIndexBase.h"
9 
10 namespace MyGUI
11 {
12 
getIndexCount() const13 	size_t BiIndexBase::getIndexCount() const
14 	{
15 		return mIndexFace.size();
16 	}
17 
insertItemAt(size_t _index)18 	size_t BiIndexBase::insertItemAt(size_t _index)
19 	{
20 #if MYGUI_DEBUG_MODE == 1
21 		MYGUI_ASSERT_RANGE_INSERT(_index, mIndexFace.size(), "BiIndexBase::insertItemAt");
22 		checkIndexes();
23 #endif
24 
25 		if (_index == MyGUI::ITEM_NONE)
26 			_index = mIndexFace.size();
27 
28 		size_t index;
29 
30 		if (_index == mIndexFace.size())
31 		{
32 			// для вставки айтема
33 			index = mIndexFace.size();
34 
35 			mIndexFace.push_back(_index);
36 			mIndexBack.push_back(_index);
37 		}
38 		else
39 		{
40 			// для вставки айтема
41 			index = mIndexFace[_index];
42 
43 			size_t count = mIndexFace.size();
44 			for (size_t pos = 0; pos < count; ++pos)
45 			{
46 				if (mIndexFace[pos] >= index)
47 					mIndexFace[pos]++;
48 			}
49 			mIndexFace.insert(mIndexFace.begin() + _index, index);
50 
51 			count ++;
52 			mIndexBack.push_back(0);
53 			for (size_t pos = 0; pos < count; ++pos)
54 			{
55 				mIndexBack[mIndexFace[pos]] = pos;
56 			}
57 		}
58 
59 #if MYGUI_DEBUG_MODE == 1
60 		checkIndexes();
61 #endif
62 
63 		return index;
64 	}
65 
removeItemAt(size_t _index)66 	size_t BiIndexBase::removeItemAt(size_t _index)
67 	{
68 #if MYGUI_DEBUG_MODE == 1
69 		MYGUI_ASSERT_RANGE(_index, mIndexFace.size(), "BiIndexBase::removeItemAt");
70 		checkIndexes();
71 #endif
72 
73 		// для удаления айтема
74 		size_t index = mIndexFace[_index];
75 
76 		mIndexFace.erase(mIndexFace.begin() + _index);
77 		mIndexBack.pop_back();
78 
79 		size_t count = mIndexFace.size();
80 		for (size_t pos = 0; pos < count; ++pos)
81 		{
82 			if (mIndexFace[pos] > index)
83 				mIndexFace[pos]--;
84 			mIndexBack[mIndexFace[pos]] = pos;
85 		}
86 
87 #if MYGUI_DEBUG_MODE == 1
88 		checkIndexes();
89 #endif
90 
91 		return index;
92 	}
93 
removeAllItems()94 	void BiIndexBase::removeAllItems()
95 	{
96 		mIndexFace.clear();
97 		mIndexBack.clear();
98 	}
99 
100 	// на входе индексы пользователя, на выходе реальные индексы
convertToBack(size_t _index) const101 	size_t BiIndexBase::convertToBack(size_t _index) const
102 	{
103 #if MYGUI_DEBUG_MODE == 1
104 		MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToBack");
105 #endif
106 		return _index == ITEM_NONE ? ITEM_NONE : mIndexFace[_index];
107 	}
108 
109 	// на входе индексы реальные, на выходе, то что видит пользователь
convertToFace(size_t _index) const110 	size_t BiIndexBase::convertToFace(size_t _index) const
111 	{
112 #if MYGUI_DEBUG_MODE == 1
113 		MYGUI_ASSERT_RANGE_AND_NONE(_index, mIndexFace.size(), "BiIndexBase::convertToFace");
114 #endif
115 		return _index == ITEM_NONE ? ITEM_NONE : mIndexBack[_index];
116 	}
117 
118 	// меняет местами два индекса, индексы со стороны пользователя
swapItemsFaceAt(size_t _index1,size_t _index2)119 	void BiIndexBase::swapItemsFaceAt(size_t _index1, size_t _index2)
120 	{
121 #if MYGUI_DEBUG_MODE == 1
122 		MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
123 		MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsFaceAt");
124 #endif
125 
126 		std::swap(mIndexFace[_index1], mIndexFace[_index2]);
127 		std::swap(mIndexBack[mIndexFace[_index1]], mIndexBack[mIndexFace[_index2]]);
128 	}
129 
130 	// меняет местами два индекса, индексы со сторонны данных
swapItemsBackAt(size_t _index1,size_t _index2)131 	void BiIndexBase::swapItemsBackAt(size_t _index1, size_t _index2)
132 	{
133 #if MYGUI_DEBUG_MODE == 1
134 		MYGUI_ASSERT_RANGE(_index1, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
135 		MYGUI_ASSERT_RANGE(_index2, mIndexFace.size(), "BiIndexBase::swapItemsBackAt");
136 #endif
137 
138 		std::swap(mIndexBack[_index1], mIndexBack[_index2]);
139 		std::swap(mIndexFace[mIndexBack[_index1]], mIndexFace[mIndexBack[_index2]]);
140 	}
141 
142 #if MYGUI_DEBUG_MODE == 1
143 
checkIndexes()144 	void BiIndexBase::checkIndexes()
145 	{
146 		assert(mIndexFace.size() == mIndexBack.size());
147 
148 		// проверяем на уникальность каждого индекса в маппинге
149 		std::vector<bool> vec;
150 		size_t count = mIndexFace.size();
151 
152 		vec.reserve(count);
153 		for (size_t pos = 0; pos < count; ++pos)
154 			vec.push_back(false);
155 
156 		for (size_t pos = 0; pos < count; ++pos)
157 		{
158 			// максимум
159 			size_t index = mIndexBack[pos];
160 			if (index >= count)
161 				throw new std::exception();
162 
163 			// максимум
164 			index = mIndexFace[pos];
165 			if (index >= count)
166 				throw new std::exception();
167 
168 			if (vec[index])
169 				throw new std::exception();
170 			vec[index] = true;
171 		}
172 
173 		for (size_t pos = 0; pos < count; ++pos)
174 		{
175 			if (!vec[pos])
176 				throw new std::exception();
177 		}
178 
179 		// проверяем на взаимоссылаемость индексов
180 		for (size_t pos = 0; pos < count; ++pos)
181 		{
182 			size_t index = mIndexFace[pos];
183 			if (mIndexBack[index] != pos)
184 				throw new std::exception();
185 		}
186 	}
187 
188 #endif
189 
190 } // namespace MyGUI
191