00001 /* 00002 * CntmLib - Подсчет ссылок, потоки, синхронизация, асинхронные процедуры, события 00003 * Copyright (c) 2005, Овсеевич Роман, CntmLib@mail.ru 00004 * _______________________________________________________________________________ 00005 * Разрешено свободное использование, копирование, распространение, изменение 00006 * (изменение сведений об авторских правах запрещено). Запрещена продажа и 00007 * включение всей библиотеки или ее частей в другие библиотеки. В сведениях об 00008 * авторских правах на программу (или сведениях о программе, об авторах, 00009 * использованных средствах разработки и т.д.) должна быть указана информация 00010 * о библиотеке CntmLib, ее авторе и, возможно, сайте или email'е. 00011 * Библиотека поставляется "как есть", без каких-либо гарантий со стороны автора. 00012 */ 00013 00014 #ifndef CNTM_REGISTER_H 00015 #define CNTM_REGISTER_H 00016 #include <boost/utility.hpp> 00017 #include <boost/thread/recursive_mutex.hpp> 00018 #include <Cntm/Utils/IntTypes.h> 00019 #include <Cntm/Utils/LinkedListItemBase.h> 00020 #include <Cntm/SystemUtils/ObjectAllocateBuffer.h> 00021 00022 namespace Cntm 00023 { 00024 00025 /** 00026 * Контейнерный класс перечня значений, хранящихся во внешних источниках. Данный перечень содержит только ссылки на зарегистрированные в нем значения. 00027 * 00028 * Для хранения значения используется класс эл-та внешнего перечня - Cntm::Register::Item (см. этот класс). При записи в него значения одновременно указывается и перечень, в котором будет зарегистрировано значение. При присвоении эл-ту перечня нового значения ссылка на старое значение удаляется из перечня, в котором оно было зарегистрировано, и происходит регистрация нового значения. При уничтожении эл-та производится удаление ссылки на знвчение из перечня. 00029 * 00030 * Просмотр значений перечня осуществляется через перечислители (см. Cntm::Register::Enumerator). Для получения перечислителя используется метод GetEnumerator(). 00031 * 00032 * Класс перечня является шаблонным классом с 2 параметрами. Параметр ValueT определяет тип значений, с которыми будет осуществляться работа (которые будут добавляться и перечисляться). Параметр StoreT определяет тип, который будет использоваться при хранении значений в контейнере. При добавлении значение типа ValueT будет преобразовано к значению StoreT, в котором будет храниться, при перечислении наоборот. Если второй параметр не задан, то StoreT = ValueT. Должна обеспечиваться взаимная конвертация типов StoreT и ValueT. Если это условие не будет выполнено, то при компиляции шаблона Register будет выдано сообщение об ошибке. Типы StoreT и ValueT должны иметь конструкторы и операторы копирования. Тип ValueT доступен через Cntm::Register::Type. 00033 * 00034 * Класс перечня обеспечивает многопоточность (объекты перечислителей составляют исключение). Т.е. операции получения перечислителей, работа с эл-тами и разными перечислителями синхронизированы, операции одного перечислителя - нет. 00035 * @author Овсеевич Р. 00036 * \ingroup Containers 00037 */ 00038 template < typename ValueT, typename StoreT = ValueT > 00039 class Register: boost::noncopyable 00040 { 00041 public: 00042 00043 typedef ValueT Type; 00044 00045 class Enumerator; 00046 class Item; 00047 00048 /** 00049 * Класс для перечисления значений, хранящихся в перечне. Используется для перебора всех значений перечня. 00050 * 00051 * После создания перечислитель не содержит текущего значения. Перечисление начинается с первого вызова Next(). Цикл перечисления выглядит так: 00052 * while (enum1.Next()) Process1(enum1.Current()). 00053 * 00054 * Изменения в контейнере не влияют на текущее состояние перечислителя. Если в перечне будет удалено текущее значение перечислителя, то оно по прежнему будет присутствовать в перечислителе, а следующим будет значение, которое было после текущего. Если будет удалено значение после текущего, то оно уже не будет перечислено. Если будет удалено значение перед текущим, то при повторном перечислении оно уже не будет перечислено. 00055 * 00056 * Перечислители бывают 2 видов: динамически включающие добавленные в перечень эл-ты и не включающие. В первом случае если после создания перечислителя в перечень будет добавлено новое значение, то оно будет перечислено. Во втором случае перечисляются только те эл-ты, которые находились в перечне на момент создания перечислителя (пример: если на момент создания перечислителя перечень был пуст, а после в него добавили новые эл-ты, то перечислитель не вернет ни одного значения). 00057 * 00058 * Для доступа к значениям одного перечня можно использовать сразу несколько перечислителей. 00059 * 00060 * Данный класс не является многопоточным. Чтобы получить доступ к эл-там перечня из разных потоков одновременно, следует создать перечислители для каждого потока. 00061 * @author Овсеевич Р. 00062 * \ingroup Containers 00063 */ 00064 class Enumerator: LinkedListItemBase 00065 { 00066 public: 00067 00068 typedef ValueT Type; 00069 00070 /** 00071 * Конструктор копирования. Создает точную копию перечислителя Src (полностью копирует его состояние: текущее значение Current() (если идет перечисление), текущую позицию, флаг Enumerated()). 00072 * @param Src - исходный перечислитель. 00073 */ 00074 Enumerator(const Enumerator& Src); 00075 00076 /** 00077 * Деструктор. 00078 */ 00079 ~Enumerator(); 00080 00081 /** 00082 * Оператор присвоения нового значения. Производит сброс перечислителя и присвоение нового состояния (см. конструктор копирования). 00083 * @param Src - исходный перечислитель. 00084 */ 00085 Enumerator& operator= (const Enumerator& Src); 00086 00087 /** 00088 * Перейти к следующему эл-ту. Вызывает функцию Next(). См. функцию Next(). 00089 */ 00090 Enumerator& operator++ () 00091 { 00092 Next(); 00093 return *this; 00094 } 00095 00096 /** 00097 * Возвращает Enumerated(). См. флаг Enumerated(). 00098 */ 00099 operator bool () const { return Enumerated(); } 00100 00101 /** 00102 * Возвращает !Enumerated(). См. флаг Enumerated(). 00103 */ 00104 bool operator! () const { return !Enumerated(); } 00105 00106 /** 00107 * Получить ссылку на текущее значение. См. Current(). 00108 */ 00109 const Type& operator* () const { return Current(); } 00110 00111 /** 00112 * Получить адрес текущего значения для доступа к его членам. См. Current(). 00113 */ 00114 const Type* operator-> () const { return &Current(); } 00115 00116 /** 00117 * Возвращает true - если идет перечисление, т.е. перечисление было начато и не достигнут конец перечня, иначе false. 00118 */ 00119 bool Enumerated() const { return enumerated; } 00120 00121 /** 00122 * Возвращает true - если текущее значение перечислителя можно использовать (оно инициализировано), иначе false. 00123 */ 00124 bool CurrentAvailable() const { return currentAvailable; } 00125 00126 /** 00127 * Возвращает текущее значение перечислителя. Значение доступно только после первого вызова Next() и до тех пор, пока Next(), в том числе и первый, возвращает true. Значение Current() доступно, пока установлен флаг Enumerated(). 00128 */ 00129 const Type& Current() const 00130 { 00131 return *(reinterpret_cast<const Type*>(currentBuffer.Place())); 00132 } 00133 00134 /** 00135 * Сбросить текущее значение перечислителя. После сброса текущее значение становится недоступным до следующего вызова Next(). При сбросе вызывается деструктор текущего значения. Сброс происходит, если текущее значение было инициализировано (если шло перечисление). 00136 */ 00137 void ResetCurrent(); 00138 00139 /** 00140 * При первом вызове после создания или сброса начинает перечисление. Если в перечне есть хотя бы 1 эл-т, то Current() будет содержать первый эл-т, флаг Enumerated() и возвращаемое значение будут равны true. Если значений нет, то значение Current() неопределено, а флаг Enumerated() и возвращаемое значение будут равны false. 00141 * 00142 * При последующих вызовах будет производится считывание следующих значений. Если будет достигнут конец перечня, то значение Current() будет неопределено, а флаг Enumerated() и возвращаемое значение будут равны false. 00143 * 00144 * При возникновении исключений в конструкторе и деструкторе типа Type при инициализации текущего значения перечисление прекращается. 00145 */ 00146 bool Next(); 00147 00148 /** 00149 * Сбросить перечислитель в исходное состояние, аналогичное состоянию после создания перечислителя. 00150 */ 00151 void Reset(); 00152 00153 protected: 00154 00155 friend class Register; 00156 00157 /** 00158 * Конструктор. Используется перечнем для инициализации перечислителя. 00159 */ 00160 Enumerator(Register* Reg, bool DynamicExpanded); 00161 00162 /** 00163 * Указатель на перечень. 00164 */ 00165 Register* Reg() const { return reg; } 00166 00167 /** 00168 * Указатель на текущий эл-т. 00169 */ 00170 LinkedListItemBase* CurrentItem() const { return currentItem; } 00171 00172 /** 00173 * Указатель на последний перечисляемый эл-т или NULL если перечислитель динамически включающий. 00174 */ 00175 LinkedListItemBase* LastItem() const { return lastItem; } 00176 00177 /** 00178 * Установить указатель на текущий эл-т. 00179 */ 00180 void SetCurrentItem(LinkedListItemBase* Item) { currentItem = Item; } 00181 00182 /** 00183 * Установить указатель на последний эл-т. 00184 */ 00185 void SetLastItem(LinkedListItemBase* Item) { lastItem = Item; } 00186 00187 private: 00188 00189 /** 00190 * Указатель на перечень. 00191 */ 00192 Register* reg; 00193 00194 /** 00195 * true - если идет перечисление, т.е. перечисление было начато и не достигнут конец перечня, иначе false. 00196 */ 00197 bool enumerated; 00198 00199 /** 00200 * true - если текущее значение перечислителя можно использовать (оно инициализировано), иначе false. 00201 */ 00202 bool currentAvailable; 00203 00204 /** 00205 * Буфер, в котором хранится текущее значение перечислителя. Значение доступно только после первого вызова Next() и до тех пор, пока Next(), в том числе и первый, возвращает true. 00206 */ 00207 SpecUtils::ObjectAllocateBuffer<Type> currentBuffer; 00208 00209 /** 00210 * Указатель на текущий эл-т. 00211 */ 00212 LinkedListItemBase* currentItem; 00213 00214 /** 00215 * Указатель на последний эл-т, который должен быть перечислен. Для динамически не включающих новые эл-ты перечислителей содержит указатель на последний эл-т (если указывает на голову, то ничего не будет перечислено), для включающих - NULL. 00216 */ 00217 LinkedListItemBase* lastItem; 00218 }; 00219 00220 00221 /** 00222 * Класс эл-та перечня. Используется для управления хранением значения и наличием его в определенном перечне. При инициализации эл-та указывается значение, которое будет в нем хранится, и перечень, в котором это значение будет зарегистрировано. При установке нового значения старое уничтожается и изымается из перечня, в котором оно присутствовало, а эл-т сохраняет новое значение и регистрирует его в новом списке. При уничтожении эл-та происходит уничтожение значения и изъятие его из перечня (если значение было установлено). 00223 * 00224 * Эл-т позволяет принудительно сбрасывать значение. При этом оно изымается из перечня и уничтожается. 00225 * 00226 * Эл-т может быть пустым или содержать значение. Эл-т пуст после вызова конструктора по умолчанию, вызова Unassign() или присвоения пустого эл-та. Наличие значения можно определить методом Assigned(). 00227 * 00228 * Класс обеспечивает многопоточность. 00229 * @author Овсеевич Р. 00230 * \ingroup Containers 00231 */ 00232 class Item: LinkedListItemBase 00233 { 00234 public: 00235 00236 typedef ValueT Type; 00237 00238 /** 00239 * Конструктор по умолчанию. Инициализирует перечень в NULL. Эл-т не содержит никакого значения, вызов метода Value() запрещен. 00240 */ 00241 Item(): reg(NULL) {} 00242 00243 /** 00244 * Конструктор инициализации. Сохраняет значение Value (преобразуя его к типу StoreT) и регистрирует его в перечне Reg. Если Reg равен NULL, то ни каких действий не выполняется. 00245 * @param Reg - перечень, в котором будет зарегистрировано значение. 00246 * @param Value - значение, которое будет зарегистрировано в перечне. 00247 */ 00248 Item(Register* Reg, const Type& Value): reg(Reg) 00249 { 00250 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00251 if (reg) 00252 { 00253 new(valueBuffer.Place()) StoreT(Value); 00254 reg->AddItem(this); 00255 } 00256 } 00257 00258 /** 00259 * Конструктор инициализации. Сохраняет значение Value (преобразуя его к типу StoreT) и регистрирует его в перечне Reg. Если Reg равен NULL, то ни каких действий не выполняется. 00260 * @param Reg - перечень, в котором будет зарегистрировано значение. 00261 * @param Value - значение, которое будет зарегистрировано в перечне. 00262 */ 00263 Item(Register& Reg, const Type& Value): reg(&Reg) 00264 { 00265 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00266 if (reg) 00267 { 00268 new(valueBuffer.Place()) StoreT(Value); 00269 reg->AddItem(this); 00270 } 00271 } 00272 00273 /** 00274 * Конструктор копирования. Копирует значение из исходного эл-та и регистрирует его в перечне, если исходный эл-т не пуст. 00275 * @param Src - исходный эл-т. 00276 */ 00277 Item(const Item& Src): reg(Src.Reg()) 00278 { 00279 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00280 if (reg) 00281 { 00282 new(valueBuffer.Place()) StoreT(Src.StoreValue()); 00283 reg->AddItem(this); 00284 } 00285 } 00286 00287 /** 00288 * Деструктор. Если эл-т не пуст, то значение изымается из перечня и удаляется. 00289 */ 00290 ~Item() 00291 { 00292 Unassign(); 00293 } 00294 00295 /** 00296 * Оператор копирования. Если эл-т не пуст, то значение изымается из перечня и удаляется. После этого копирует значение из исходного эл-та и регистрирует его в перечне, если исходный эл-т не пуст. 00297 * @param Src - исходный эл-т. 00298 */ 00299 Item& operator= (const Item& Src); 00300 00301 /** 00302 * Если эл-т содержит значение, то возвращает true иначе - false. 00303 */ 00304 bool Assigned() const { return reg; } 00305 00306 /** 00307 * Возвращает значение, хранящееся в эл-те. Метод следует вызывать только когда в эл-те имеется значение (для определения наличия значение можно использовать Assigned()). 00308 */ 00309 Type Value() const 00310 { 00311 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00312 return StoreValue(); 00313 } 00314 00315 /** 00316 * Возвращает перечень, в котором зарегистрировано значение. Если эл-т не содержит значения, то возвращается NULL. 00317 */ 00318 Register* Reg() const { return reg; } 00319 00320 /** 00321 * Установить новое значение. Если эл-т не пуст, то значение изымается из перечня и удаляется. После этого копирует значение из Value и регистрирует его в перечне Reg, если Reg не равен NULL. 00322 * @param Reg - перечень, в котором будет зарегистрировано значение. 00323 * @param Value - значение, которое будет зарегистрировано в перечне. 00324 */ 00325 void Set(Register* Reg, const Type& Value); 00326 00327 /** 00328 * Установить новое значение. Если эл-т не пуст, то значение изымается из перечня и удаляется. После этого копирует значение из Value и регистрирует его в перечне Reg, если Reg не равен NULL. 00329 * @param Reg - перечень, в котором будет зарегистрировано значение. 00330 * @param Value - значение, которое будет зарегистрировано в перечне. 00331 */ 00332 void Set(Register& Reg, const Type& Value) { Set(&Reg, Value); } 00333 00334 /** 00335 * Сброс значения. Если эл-т не пуст, то значение изымается из перечня и удаляется. 00336 */ 00337 void Unassign(); 00338 00339 private: 00340 00341 friend class Register; 00342 00343 /** 00344 * Значение эл-та. 00345 */ 00346 const StoreT& StoreValue() const 00347 { 00348 return *(reinterpret_cast<const StoreT*>(valueBuffer.Place())); 00349 } 00350 00351 private: 00352 00353 /** 00354 * Указатель на перечень. 00355 */ 00356 Register* reg; 00357 00358 /** 00359 * Буфер, в котором хранится значение эл-та. 00360 */ 00361 SpecUtils::ObjectAllocateBuffer<StoreT> valueBuffer; 00362 00363 /** 00364 * Значение эл-та. 00365 */ 00366 StoreT& StoreValue() 00367 { 00368 return *(reinterpret_cast<StoreT*>(valueBuffer.Place())); 00369 } 00370 }; 00371 00372 00373 /** 00374 * Возвращает true, если перечень пуст, в противном случае - false. 00375 */ 00376 bool IsEmpty() const { return itemsHead.IsSingle(); } 00377 00378 /** 00379 * Получить объект перечислителя для доступа к эл-там. 00380 * @param DynamicExpanded - true (значение по умолчанию) - перечислитель будет перечислять эл-ты, добавленные в перечень после создания перечислителя, false - перечислитель будет переслять только те эл-ты, которые были в перечне на момент создания перечислителя (удаленные эл-ты перечислитель не перечисляет в любом случае). 00381 */ 00382 Enumerator GetEnumerator(bool DynamicExpanded = true) const 00383 { 00384 return Enumerator(const_cast<Register*>(this), DynamicExpanded); 00385 } 00386 00387 private: 00388 00389 friend class Enumerator; 00390 friend class Item; 00391 00392 /** 00393 * Глобальная критическая секция для операций с перечнями, перечислителями и эл-тами данного типа. 00394 */ 00395 static boost::recursive_mutex mutex; 00396 00397 /** 00398 * Возвращает головной (фиктивный) эл-т цепочки эл-тов. Вызывается перечислителем. 00399 */ 00400 LinkedListItemBase* ItemsHead() { return &itemsHead; } 00401 00402 /** 00403 * Возвращает последний эл-т цепочки (перед головным эл-том) или головной (если эл-тов нет). Вызывается перечислителем. 00404 */ 00405 LinkedListItemBase* LastItem() { return itemsHead.PrevItem(); } 00406 00407 /** 00408 * Зарегистрировать новый эл-т в цепочке эл-тов. Операция не синхронизирована. Вызывается эл-том. 00409 */ 00410 void AddItem(Item* It) 00411 { 00412 It->InsertBefore(ItemsHead()); // Добавляем в конец (перед головой кольцевого списка). 00413 } 00414 00415 /** 00416 * Удалить эл-т из цепочки эл-тов перечня. Проверить все перечислители. Операция не синхронизирована. Вызывается эл-том. 00417 */ 00418 void DeleteItem(Item* It); 00419 00420 /** 00421 * Добавить перечислитьль в цепочку перечислителей для данного перечня. Операция не синхронизирована. Вызывается перечислителем. 00422 */ 00423 void AddEnumerator(Enumerator* Enum) 00424 { 00425 Enum->InsertAfter(&enumsHead); // Вставляем новый перечислитель в начало списка. 00426 } 00427 00428 /** 00429 * Удалить перечислитель из цепочки перечислителей для данного перечня. Операция не синхронизирована. Вызывается перечислителем. 00430 */ 00431 void DeleteEnumerator(Enumerator* Enum) 00432 { 00433 Enum->Remove(); // Удаляем перечислитель из списка перечислителей. 00434 } 00435 00436 /** 00437 * Перейти к следующему эл-ту. Операция не синхронизирована. Вызывается перечислителем. 00438 * 00439 * CurItem - указатель на переменную, содержащую текущий эл-т. CurBuffer - буфер, куда будет скопировано значение из эл-та. 00440 * 00441 * После выполнения: если не конец перечня, то CurItem содержит указатель на следующий эл-т, CurBuffer - значение из эл-та, возвращаемое значение - true; если достигнут конец, то CurItem содержит NULL, CurBuffer не содержит никакого значения, возвращаемое значение - false. 00442 */ 00443 bool Next(LinkedListItemBase** CurItem, void* CurBuffer); 00444 00445 private: 00446 00447 /** 00448 * Голова (фиктивный эл-т) двунаправленного связанного списка перечислителей данного перечня. 00449 */ 00450 LinkedListItemBase enumsHead; 00451 00452 /** 00453 * Голова (фиктивный эл-т) двунаправленного связанного списка эл-тов данного перечня. 00454 */ 00455 LinkedListItemBase itemsHead; 00456 }; 00457 00458 } 00459 00460 00461 // Enumerator ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00462 00463 template < typename ValueT, typename StoreT > 00464 Cntm::Register < ValueT, StoreT > ::Enumerator::Enumerator(const Enumerator& Src) 00465 { 00466 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00467 reg = Src.Reg(); 00468 reg->AddEnumerator(this); // Подключаемся к перечню. 00469 enumerated = Src.Enumerated(); 00470 currentAvailable = Src.CurrentAvailable(); 00471 currentItem = Src.CurrentItem(); 00472 lastItem = Src.LastItem(); 00473 if (currentAvailable) 00474 new(currentBuffer.Place()) Type(Src.Current()); // Если текущее значение доступно, то копируем текущее значение перечислителя. 00475 } 00476 00477 template < typename ValueT, typename StoreT > 00478 Cntm::Register < ValueT, StoreT > ::Enumerator::~Enumerator() 00479 { 00480 try { Reset(); } catch (...) {} 00481 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00482 try { reg->DeleteEnumerator(this); } catch (...) {} 00483 } 00484 00485 template < typename ValueT, typename StoreT > 00486 typename Cntm::Register < ValueT, StoreT > ::Enumerator& 00487 Cntm::Register < ValueT, StoreT > ::Enumerator::operator = (const Enumerator& Src) 00488 { 00489 if (this == &Src) return *this; 00490 00491 Reset(); 00492 00493 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00494 00495 // Если исходный перечислитель связан с другим перечнем, то отключаемся от 00496 // старого перечня и подключаемся к новому. 00497 if (reg != Src.Reg()) 00498 { 00499 reg->DeleteEnumerator(this); 00500 reg = Src.Reg(); 00501 reg->AddEnumerator(this); 00502 } 00503 00504 // Копируем новые значения 00505 enumerated = Src.Enumerated(); 00506 currentAvailable = Src.CurrentAvailable(); 00507 currentItem = Src.CurrentItem(); 00508 lastItem = Src.LastItem(); 00509 if (currentAvailable) 00510 new(currentBuffer.Place()) Type(Src.Current()); // Если текущее значение доступно, то копируем текущее значение перечислителя. 00511 00512 return *this; 00513 } 00514 00515 template < typename ValueT, typename StoreT > 00516 void Cntm::Register < ValueT, StoreT > ::Enumerator::ResetCurrent() 00517 { 00518 if (!currentAvailable) return; 00519 currentAvailable = false; 00520 reinterpret_cast<Type*>(currentBuffer.Place())->~Type(); 00521 } 00522 00523 template < typename ValueT, typename StoreT > 00524 bool Cntm::Register < ValueT, StoreT > ::Enumerator::Next() 00525 { 00526 try 00527 { 00528 // Подготовка 00529 if (enumerated) 00530 { 00531 ResetCurrent(); 00532 } 00533 else 00534 { 00535 enumerated = true; 00536 currentItem = reg->ItemsHead(); 00537 } 00538 00539 // Переход к следующему эл-ту 00540 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00541 if (currentItem != lastItem) 00542 { 00543 enumerated = currentAvailable = reg->Next(¤tItem, currentBuffer.Place()); 00544 } 00545 else 00546 { 00547 enumerated = false; 00548 currentItem = NULL; 00549 } 00550 } 00551 catch (...) 00552 { 00553 enumerated = false; 00554 currentItem = NULL; 00555 throw; 00556 } 00557 00558 return enumerated; 00559 } 00560 00561 template < typename ValueT, typename StoreT > 00562 void Cntm::Register < ValueT, StoreT > ::Enumerator::Reset() 00563 { 00564 if (enumerated) 00565 { 00566 enumerated = false; 00567 currentItem = NULL; 00568 ResetCurrent(); 00569 } 00570 } 00571 00572 template < typename ValueT, typename StoreT > 00573 Cntm::Register < ValueT, StoreT > ::Enumerator::Enumerator(Register* Reg, bool DynamicExpanded): 00574 reg(Reg), enumerated(false), currentAvailable(false), currentItem(NULL) 00575 { 00576 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00577 reg->AddEnumerator(this); 00578 lastItem = DynamicExpanded? NULL : reg->LastItem(); 00579 } 00580 00581 00582 // Item /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00583 00584 template < typename ValueT, typename StoreT > 00585 typename Cntm::Register < ValueT, StoreT > ::Item& 00586 Cntm::Register < ValueT, StoreT > ::Item::operator= (const Item& Src) 00587 { 00588 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00589 Unassign(); 00590 reg = Src.Reg(); 00591 if (reg) 00592 { 00593 try 00594 { 00595 new(valueBuffer.Place()) StoreT(Src.StoreValue()); 00596 try 00597 { 00598 reg->AddItem(this); 00599 } 00600 catch (...) 00601 { 00602 StoreValue().~StoreT(); 00603 throw; 00604 } 00605 } 00606 catch (...) 00607 { 00608 reg = NULL; 00609 throw; 00610 } 00611 } 00612 return *this; 00613 } 00614 00615 template < typename ValueT, typename StoreT > 00616 void Cntm::Register < ValueT, StoreT > ::Item::Set(Register* Reg, const Type& Value) 00617 { 00618 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00619 Unassign(); 00620 reg = Reg; 00621 if (reg) 00622 { 00623 try 00624 { 00625 new(valueBuffer.Place()) StoreT(Value); 00626 try 00627 { 00628 reg->AddItem(this); 00629 } 00630 catch (...) 00631 { 00632 StoreValue().~StoreT(); 00633 throw; 00634 } 00635 } 00636 catch (...) 00637 { 00638 reg = NULL; 00639 throw; 00640 } 00641 } 00642 } 00643 00644 template < typename ValueT, typename StoreT > 00645 void Cntm::Register < ValueT, StoreT > ::Item::Unassign() 00646 { 00647 boost::recursive_mutex::scoped_lock lock(Register::mutex); 00648 if (reg) 00649 { 00650 try { StoreValue().~StoreT(); } catch (...) {} 00651 try { reg->DeleteItem(this); } catch (...) {} 00652 reg = NULL; 00653 } 00654 } 00655 00656 00657 // Register /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00658 00659 template < typename ValueT, typename StoreT > 00660 boost::recursive_mutex Cntm::Register < ValueT, StoreT > ::mutex; 00661 00662 template < typename ValueT, typename StoreT > 00663 void Cntm::Register < ValueT, StoreT > ::DeleteItem(Item* It) 00664 { 00665 // В цикле проходим по всем перечислителям. Если перечислитель указывает 00666 // на удаляемый эл-т, то делаем предыдущий эл-т текущим, чтобы при вызове 00667 // операции Next перечислитель получил эл-т следующий за удаленным. 00668 for (LinkedListItemBase* e = enumsHead.NextItem(); e != &enumsHead; e = e->NextItem()) 00669 { 00670 Enumerator* en = static_cast<Enumerator*>(e); 00671 if (en->CurrentItem() == It) en->SetCurrentItem(It->PrevItem()); 00672 if (en->LastItem() == It) en->SetLastItem(It->PrevItem()); 00673 } 00674 00675 // Удаляем из списка. 00676 It->Remove(); 00677 } 00678 00679 template < typename ValueT, typename StoreT > 00680 bool Cntm::Register < ValueT, StoreT > ::Next(LinkedListItemBase** CurItem, void* CurBuffer) 00681 { 00682 bool res = (*CurItem = (*CurItem)->NextItem()) != ItemsHead(); 00683 if (res) 00684 new(CurBuffer) Type(static_cast<Item*>(*CurItem)->StoreValue()); 00685 else 00686 *CurItem = NULL; 00687 return res; 00688 } 00689 00690 #endif //CNTM_REGISTER_H
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой 1.5.3 |