Register.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_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(&currentItem, 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

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