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