RegisterEx.h

См. документацию.
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(&currentItem, 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

SourceForge.net Logo
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой  doxygen 1.5.3