HandledList.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_HANDLEDLIST_H
00015 #define CNTM_HANDLEDLIST_H
00016 #include <list>
00017 #include <boost/thread/recursive_mutex.hpp>
00018 #include <Cntm/SystemUtils/AtomicUtils.h>
00019 #include <Cntm/SystemUtils/ObjectAllocateBuffer.h>
00020 #include <Cntm/SystemUtils/SyncUtils.h>
00021 #include <Cntm/Exceptions.h>
00022 #include <Cntm/Utils.h>
00023 
00024 namespace Cntm
00025 {
00026 
00027         /**
00028          * Контейнерный класс перечня. Особенностью является то, что присутствием эл-та в перечне управляют специальные объекты - хэндлы и время нахождения значенния в перечне определяется временем жизни хэндла. Используется для хранения неупорядоченного набора значений.
00029          * 
00030          * Для добавления значений в перечень применяется операция Add. Время нахождения добавленного значения в перечне определяется хэндлом - Cntm::HandledList::Handle. При добавлении значения устанавливается связь между объектом хэндла и добавленным значением. Когда связь разрывается, происходит удаление значения из перечня. Разрыв связи происходит, когда хэндл уничтожается, ему присваивается новое значение или он принудительно сбрасывается (см. описание Cntm::HandledList::Handle). Т.о. удалить значение из перечня может только тот, кто имеет доступ к хэндлу. Если результат операции Add не будет присвоен какому-либо хэндлу, то добавленное значение будет автоматически удалено из перечня.
00031          * 
00032          * Просмотр значений перечня осуществляется через перечислители (см. Cntm::HandledList::Enumerator). Для получения перечислителя используется метод GetEnumerator().
00033          * 
00034          * Класс перечня является шаблонным классом с 2 параметрами. Параметр ValueT определяет тип значений, с которыми будет осуществляться работа (которые будут добавляться и перечисляться). Параметр StoreT определяет тип, который будет использоваться при хранении значений в контейнере. При добавлении значение типа ValueT будет преобразовано к значению StoreT, в котором будет храниться, при перечислении наоборот. Если второй параметр не задан, то StoreT = ValueT. Должна обеспечиваться взаимная конвертация типов StoreT и ValueT. Если это условие не будет выполнено, то при компиляции шаблона HandledList будет выдано сообщение об ошибке. Для типа ValueT д.б. доступен конструктор копирования, для StoreT должны быть доступны конструктор по умолчанию, конструктор и оператор копирования. Тип ValueT доступен через Cntm::HandledList::Type. 
00035          * 
00036          * Класс перечня обеспечивает многопоточность (объекты перечислителей составляют исключение). Т.е. операции добавления, получения перечислителей, работа с хэндлами и разными перечислителями синхронизированы, операции одного перечислителя - нет.
00037          * @author Овсеевич Р.
00038          * \ingroup Containers
00039          */
00040         template < typename ValueT, typename StoreT = ValueT >
00041         class HandledList: boost::noncopyable
00042         {
00043         public:
00044         
00045                 class Enumerator;
00046                 class Handle;
00047                 class AddResult;
00048                 
00049                 typedef ValueT Type;
00050 
00051         private:
00052                 
00053                 friend class Enumerator;
00054                 friend class Handle;
00055                 friend class AddResult;
00056                 
00057                 typedef typename std::list < StoreT > ::iterator ItemId;
00058                 
00059                 /**
00060                  * Базовый класс для перечислителя эл-тов перечня. Содержит ссылки на предыдущий и следующий перечислители в цепочке перечислителей для определенного перечня.
00061                  * @author Овсеевич Р.
00062                  */
00063                 class EnumeratorBase
00064                 {
00065                 protected:
00066 
00067                         friend class HandledList;
00068                         
00069                         /**
00070                          * Конструктор. Зацикливает ссылки на себя.
00071                          */
00072                         EnumeratorBase(): prev(this), next(this) {}
00073                         
00074                         /**
00075                          * Предыдущий перечислитель в цепочке перечислителей.
00076                          */
00077                         EnumeratorBase* PrevEnum() const { return prev; }
00078                         
00079                         /**
00080                          * Следующий перечислитель в цепочке перечислителей.
00081                          */
00082                         EnumeratorBase* NextEnum() const { return next; }
00083                         
00084                         /**
00085                          * Вставить данный перечислитель в 2-направленный список перед Enum.
00086                          */
00087                         void InsertAfter(EnumeratorBase* Enum)
00088                         {
00089                                 Enum->next->prev = this;
00090                                 next = Enum->next;
00091                                 Enum->next = this;
00092                                 prev = Enum;
00093                         }
00094                         
00095                         /**
00096                          * Изъять данный перечислитель из 2-направленного списка.
00097                          */
00098                         void Remove()
00099                         {
00100                                 prev->next = next;
00101                                 next->prev = prev;
00102                                 prev = next = this;
00103                         }
00104                         
00105                 private:
00106                 
00107                         /**
00108                          * Предыдущий перечислитель в цепочке перечислителей.
00109                          */
00110                         EnumeratorBase* prev;
00111                         
00112                         /**
00113                          * Следующий перечислитель в цепочке перечислителей.
00114                          */
00115                         EnumeratorBase* next;                   
00116                 };
00117 
00118         public:
00119         
00120                 /**
00121                  * Класс для перечисления значений, хранящихся в перечне. Используется для перебора всех значений перечня.
00122                  * 
00123                  * После создания перечислитель не содержит текущего значения. Перечисление начинается с первого вызова Next(). Цикл перечисления выглядит так:
00124                  * while (enum1.Next()) Process1(enum1.Current()).
00125                  * 
00126                  * Изменения в контейнере не влияют на состояние перечислителя. Если в перечне будет удалено текущее значение перечислителя, то оно по прежнему будет присутствовать в перечислителе, а следующим будет значение, которое было после текущего. Если будет удалено значение после текущего, то оно уже не будет перечислено. Если в процессе перечисления в перечень будет добавлено новое значение, то оно будет перечислено.
00127                  * 
00128                  * Для доступа к значениям одного перечня можно использовать сразу несколько перечислителей.
00129                  * 
00130                  * Данный класс не является многопоточным. Чтобы получить доступ к эл-там перечня из разных потоков одновременно, следует создать перечислители для каждого потока.
00131                  * @author Овсеевич Р.
00132                  */
00133                 class Enumerator: EnumeratorBase
00134                 {
00135                 public:
00136                 
00137                         typedef ValueT Type;
00138 
00139                         /**
00140                          * Конструктор копирования. Создает точную копию перечислителя Src (полностью копирует его состояние: текущее значение Current() (если идет перечисление), текущую позицию, флаг Enumerated()).
00141                          */
00142                         Enumerator(const Enumerator& Src);
00143                         
00144                         /**
00145                          * Оператор присвоения нового значения. Производит сброс перечислителя и присвоение нового состояния (см. конструктор копирования).
00146                          */
00147                         Enumerator& operator = (const Enumerator& Src);
00148                         
00149                         /**
00150                          * Перейти к следующему эл-ту. Вызывает функцию Next(). См. функцию Next().
00151                          */
00152                         Enumerator& operator ++ () { Next(); return *this; }
00153                         
00154                         /**
00155                          * Деструктор.
00156                          */
00157                         ~Enumerator();
00158                         
00159                         /**
00160                          * Возвращает Enumerated(). См. флаг Enumerated().
00161                          */
00162                         operator bool () const { return Enumerated(); }
00163                         
00164                         /**
00165                          * Возвращает !Enumerated(). См. флаг Enumerated().
00166                          */
00167                         bool operator ! () const { return !Enumerated(); }
00168                         
00169                         /**
00170                          * Получить ссылку на текущее значение. См. Current().
00171                          */
00172                         const Type& operator * () const { return Current(); }
00173                         
00174                         /**
00175                          * Получить адрес текущего значения для доступа к его членам. См. Current().
00176                          */
00177                         const Type* operator -> () const { return &Current(); }
00178                         
00179                         /**
00180                          * Возвращает true - если идет перечисление, т.е. перечисление было начато и не достигнут конец перечня, иначе false.
00181                          */
00182                         bool Enumerated() const { return enumerated; }
00183                         
00184                         /**
00185                          * Возвращает текущее значение перечислителя. Значение доступно только после первого вызова Next() и до тех пор, пока Next(), в том числе и первый, возвращает true. Значение Current() доступно, пока установлен флаг Enumerated().
00186                          */
00187                         const Type& Current() const 
00188                         { 
00189                                 return *(reinterpret_cast<const Type*>(currentBuffer.Place())); 
00190                         }
00191                         
00192                         /**
00193                          * При первом вызове после создания или сброса начинает перечисление. Если в перечне есть хотя бы 1 эл-т, то Current() будет содержать первый эл-т, флаг Enumerated() и возвращаемое значение будут равны true. Если значений нет, то значение Current() неопределено, а флаг Enumerated() и возвращаемое значение будут равны false.
00194                          * 
00195                          * При последующих вызовах будет производится считывание следующих значений. Если будет достигнут конец перечня, то значение Current() будет неопределено, а флаг Enumerated() и возвращаемое значение будут равны false.
00196                          */
00197                         bool Next();
00198                         
00199                         /**
00200                          * Сбросить перечислитель в исходное состояние, аналогичное состоянию после создания перечислителя.
00201                          */
00202                         void Reset();
00203                         
00204                 protected:
00205                 
00206                         friend class HandledList;
00207                         
00208                         /**
00209                          * Конструктор. Используется перечнем для инициализации перечислителя.
00210                          */
00211                         Enumerator(HandledList* List);
00212                         
00213                         /**
00214                          * Указатель на перечислитель.
00215                          */
00216                         HandledList* List() const { return list; }
00217                         
00218                         /**
00219                          * Идентификатор текущего значения в списке эл-тов.
00220                          */
00221                         const ItemId& CurrentId() const { return currentId; }
00222                         
00223                         /**
00224                          * Идентификатор текущего значения в списке эл-тов.
00225                          */
00226                         ItemId& CurrentId() { return currentId; }
00227                         
00228                 private:
00229                 
00230                         /**
00231                          * Указатель на перечислитель.
00232                          */
00233                         HandledList* list;
00234                         
00235                         /**
00236                          * true - если идет перечисление, т.е. перечисление было начато и не достигнут конец перечня, иначе false.
00237                          */
00238                         bool enumerated;
00239                         
00240                         /**
00241                          * Буфер, в котором хранится текущее значение перечислителя. Значение доступно только после первого вызова Next() и до тех пор, пока Next(), в том числе и первый, возвращает true.
00242                          */
00243                         SpecUtils::ObjectAllocateBuffer<Type> currentBuffer;
00244                         
00245                         /**
00246                          * Идентификатор текущего значения в списке эл-тов.
00247                          */
00248                         ItemId currentId;               
00249                 };
00250 
00251 
00252                 /**
00253                  * Класс хэндла, отвечающий за присутствие связанного с ним значения в перечне. Когда в перечень добавляется новое значение с ним связывается хэндл. Когда такая связь уничтожается, значение, связанное с хэндлом удаляется из перечня. Это происходит когда хэндл уничтожается, когда ему присваивается новое значение или при вызове метода Release().
00254                  *
00255                  * При копировании хэндлов происходит дублирование значений в перечне, т.е. и принимающий и исходный хэндлы указывают на разные эл-ты в перечне, имеющие одинаковое значение.
00256                  *
00257                  * Класс обеспечивает многопоточность.
00258                  * @author Овсеевич Р.
00259                  */
00260                 class Handle
00261                 {
00262                 public:
00263                 
00264                         /**
00265                          * Конструктор по умолчанию. Создает пустой хэндл, который не связан ни с каким значением.
00266                          */
00267                         Handle(): list(NULL) {}
00268                         
00269                         /**
00270                          * Конструктор инициализации результатом операции Add. Хэнд связывается с добавленным значением.
00271                          */
00272                         Handle(const AddResult& Src): list(Src.List()), id(Src.Id()) {}
00273                         
00274                         /**
00275                          * Конструктор дублирования значения из другого хэндла. Перечень после дублирования будет содержать два одинаковых значения. Дублирование пустого значения приведет к тому, что хэнд не будет связан ни с каким значением.
00276                          */
00277                         Handle(const Handle& Src);
00278 
00279                         /**
00280                          * Деструктор. Если хэндл связан с каким либо значением, то это значение удаляется из перечня.
00281                          */
00282                         ~Handle() throw() { try { if (list) list->DeleteItem(id); } catch (...) { } }
00283                         
00284                         /**
00285                          * Оператор присвоения результата операции Add. Если хэндл был связан с каким либо значением, то оно удаляется из перечня, и хэнд связывается с новым значением.
00286                          */
00287                         Handle& operator = (const AddResult& Src);
00288                         
00289                         /**
00290                          * Оператор присвоения дубликата значения, связанного с хэндлом Src. Если хэндл был связан с каким либо значением, то оно удаляется из перечня, и хэнд связывается с дублированным значением хэндла Src. Перечень после дублирования будет содержать два одинаковых значения. Присвоение пустого значения приведет к тому, что хэнд не будет связан ни с каким значением.
00291                          */
00292                         Handle& operator = (const Handle& Src);
00293                         
00294                         /**
00295                          * Проверка, связан ли хэнд с каким либо значением. Возвращает true, если не связан и false - если связан.
00296                          */
00297                         bool IsReleased() const { return list; }
00298                         
00299                         /**
00300                          * Разорвать связь между хэндлом и значением в перечне, при этом значение из перечня удаляется. Если хэндл не связан со значением, то ни каких действий не выполняется.
00301                          */
00302                         void Release();
00303 
00304                 private:
00305 
00306                         /**
00307                          * Перечень, в котором находится добавленный эл-т, или NULL, если AddResult не содержит значения.
00308                          */
00309                         HandledList* list;
00310 
00311                         /**
00312                          * Идентификатор добавленного значения в перечне.
00313                          */
00314                         ItemId id;
00315 
00316                         /**
00317                          * Войти в критическую секцию хэндла и вернуть текущий указатель на перечень. При этом указатель на перечень будет содержать специальное блокирующее значение.
00318                          */
00319                         HandledList* Enter()
00320                         {
00321                                 return SpecUtils::FastWaitPtrNoEqualAndSet(&list, reinterpret_cast<HandledList*>(this));
00322                         }
00323                         
00324                         /**
00325                          * Выйти из критической секции хэндла и установить значение указателя на перечень.
00326                          */
00327                         void Leave(HandledList* UnlockValue)
00328                         {
00329                                 list = UnlockValue;
00330                         }
00331                         
00332                         /**
00333                          * Атомарное копирование обоих полей хэндла в приемники.
00334                          */
00335                         void AtomicCopyTo(HandledList** DestList, StoreT* DestValue) const;
00336                         
00337                         /**
00338                          * Дублирование значения хэндла Src и запись новых значений в DestList и DestId. Если хэндл Src пуст, то *DestList = NULL, а *DestId не определен.
00339                          */
00340                         void Duplicate(const Handle& Src, HandledList** DestList, ItemId* DestId) const;
00341 
00342                         /**
00343                          * Атомарная установка новых значений List и Id, удаление значения, с которым был связан хэндл, из перечня (если связь была).
00344                          */
00345                         void SetNewValues(HandledList* List, const ItemId& Id);
00346                 };
00347 
00348 
00349                 /**
00350                  * Класс, инкапсулирующий результат добавления нового эл-та в перечень. Непосредственное использование этого класса не предусмотрено, он используется в качестве посредника между вызовом Add() и присвоением значения хэндлу HandledList::Handle.
00351                  *
00352                  * Особенность класса в том, что при копировании из него изымается значение, т.е., если его скопировать в Handle или другой AddResult, то он больше не содержит значения. Это ускоряет процедуру присвоения Handle.
00353                  *
00354                  * Если результат добавления не присвоен хэндлу, то оно автоматически удаляется из перечня.
00355                  *
00356                  * Класс обеспечивает многопоточность.
00357                  * @author Овсеевич Р.
00358                  */
00359                 class AddResult
00360                 {
00361                 public:
00362                 
00363                         /**
00364                          * Конструктор копирования. Уничтожает исходное значение в источнике.
00365                          *
00366                          * Исключение BadArgException, если Src не содержит значение (т.е. уже было кому-то присвоено).
00367                          */
00368                         AddResult(const AddResult& Src);
00369 
00370                         /**
00371                          * Деструктор. Если имеется значение, то оно удаляется из перечня.
00372                          */
00373                         ~AddResult() throw() { try { if (list) list->DeleteItem(id); } catch (...) { } }
00374 
00375                 protected:
00376                 
00377                         friend class HandledList;
00378                         friend class Handle;
00379                         
00380                         /**
00381                          * Конструктор инициализации. Используется операцией Add для создания результата.
00382                          */
00383                         AddResult(HandledList* List, const ItemId& Id):
00384                                 list(List), id(Id) {}
00385 
00386                         /**
00387                          * Взять текущее значение указателя на перечень. При этом значение переходит в другое место, а сюда записывается NULL (в нарушение декларации const !!!).
00388                          */
00389                         HandledList* List() const
00390                         { 
00391                                 return SpecUtils::AtomicSwapPtr(const_cast<HandledList**>(&list), (HandledList*)NULL);
00392                         }
00393                         
00394                         /**
00395                          * Считать идентификатор эл-та в перечне.
00396                          */
00397                         const ItemId& Id() const { return id; }
00398                         
00399                 private:
00400                 
00401                         /**
00402                          * Перечень, в котором находится добавленный эл-т, или NULL, если AddResult не содержит значения.
00403                          */
00404                         HandledList* list;
00405 
00406                         /**
00407                          * Идентификатор добавленного значения в перечне.
00408                          */
00409                         ItemId id;
00410                 };
00411 
00412 
00413                 /**
00414                  * Кол-во эл-тов в перечне. При использовании следует учитывать, что класс многопоточный, поэтому между вызывом Count() и следующей операцией кол-во эл-тов может измениться.
00415                  */
00416                 uint Count() const
00417                 {
00418                         boost::recursive_mutex::scoped_lock lock(mutex);
00419                         return items.count();
00420                 }
00421 
00422                 /**
00423                  * Проверяет, что кол-во эл-тов в перечне равно 0. При использовании следует учитывать, что класс многопоточный, поэтому между вызывом Count() и следующей операцией кол-во эл-тов может измениться.
00424                  */
00425                 bool IsEmpty() const { return Count() == 0; }
00426 
00427                 /**
00428                  * Добавить значение к перечню. Результат операции д.б. присвоен какому-либо хэндлу. Если результат не будет присвоен хэндлу, то добавленное значение будет удалено из перечня. 
00429                  */
00430                 AddResult Add(const Type& Value) 
00431                 { 
00432                         return AddResult(this, AddStoreValue(Value));
00433                 }
00434 
00435                 /**
00436                  * Получить объект перечислителя для доступа к эл-там. 
00437                  */
00438                 Enumerator GetEnumerator() const 
00439                 { 
00440                         return Enumerator(const_cast<HandledList*>(this));
00441                 }
00442                 
00443         private:
00444 
00445                 /**
00446                  * Сохранить значение типа StoreT в списке. Операция синхронизирована. Вызывается хэндлом при дублировании. 
00447                  */
00448                 ItemId AddStoreValue(const StoreT& Value);
00449                 
00450                 /**
00451                  * Удалить значение по его итератору из списка. Операция синхронизирована.  Вызывается хэндлом и результатом добавления. 
00452                  */
00453                 void DeleteItem(const ItemId& Id);
00454                 
00455                 /**
00456                  * Добавить перечислитьль в цепочку перечислителей для данного перечня. Операция синхронизирована. Вызывается перечислителем. 
00457                  */
00458                 void AddEnumerator(Enumerator* Enum);
00459 
00460                 /**
00461                  * Удалить перечислитель из цепочки перечислителей для данного перечня. Операция синхронизирована. Вызывается перечислителем. 
00462                  */
00463                 void DeleteEnumerator(Enumerator* Enum);
00464                 
00465                 /**
00466                  * Сбросить итератор эл-та в фиктивное значение. Операция синхронизирована. Вызывается перечислителем. 
00467                  */
00468                 void ResetItemId(ItemId* DestId);
00469                 
00470                 /**
00471                  * Скопировать итератор из источника в приемник. Операция синхронизирована. Вызывается перечислителем. 
00472                  */
00473                 void CopyItemId(const Enumerator& Src, ItemId* DestId);
00474                 
00475                 /**
00476                  * Получить первый эл-т при перечислении. Операция синхронизирована. Вызывается перечислителем. 
00477                  */
00478                 bool FirstItem(ItemId* DestId, void* DestCurrentBuf);
00479                 
00480                 /**
00481                  * Получить следующий эл-т при перечислении. Операция синхронизирована. Вызывается перечислителем. 
00482                  */
00483                 bool NextItem(ItemId* VarId, void* DestCurrentBuf);             
00484                 
00485         private:
00486         
00487                 /**
00488                  * Список, хранящий значения. 
00489                  */
00490                 std::list<StoreT> items;
00491                 
00492                 /**
00493                  * Мьютекс, защищающий операции над перечнем. 
00494                  */
00495                 boost::recursive_mutex mutex;
00496                 
00497                 /**
00498                  * Голова (фиктивный эл-т) двунаправленного связанного списка перечислителей данного перечня. 
00499                  */
00500                 EnumeratorBase enumsHead;
00501                 
00502                 /**
00503                  * Вспомогательный метод при перечислении. 
00504                  */
00505                 bool ReturnItem(const ItemId& Id, void* DestCurrentBuf);
00506         };
00507 
00508 }
00509 
00510 
00511 // Enumerator /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00512 
00513 template < typename ValueT, typename StoreT >
00514 Cntm::HandledList < ValueT, StoreT > ::Enumerator::Enumerator(const Enumerator& Src):
00515         EnumeratorBase(), list(Src.List()), enumerated(Src.Enumerated())
00516 {
00517         if (enumerated)
00518                 new(currentBuffer.Place()) Type(Src.Current()); // Если шло перечисление, то копируем текущее значение перечислителя.
00519         list->ResetItemId(&currentId);          // Сбрасываем значение ссылки на эл-т.
00520         list->AddEnumerator(this);                      // Подключаемся к перечню.
00521         list->CopyItemId(Src, &currentId);      // Устанавливаем настоящее значение ссылки на эл-т (синхронно с прочими операциями перечня).
00522 }
00523 
00524 template < typename ValueT, typename StoreT >
00525 Cntm::HandledList < ValueT, StoreT > ::Enumerator::~Enumerator()
00526 {
00527         try
00528         {
00529                 try { list->DeleteEnumerator(this); } catch (...) {}
00530                 Reset();
00531         }
00532         catch (...)
00533         {
00534         }
00535 }                       
00536                         
00537 template < typename ValueT, typename StoreT >
00538 typename Cntm::HandledList < ValueT, StoreT > ::Enumerator&
00539         Cntm::HandledList < ValueT, StoreT > ::Enumerator::operator = (const Enumerator& Src)
00540 {
00541         if (this == &Src) return *this;
00542         
00543         // Если исходный перечислитель связан с другим перечнем, то отключаемся от
00544         // старого перечня и подключаемся к новому.
00545         if (list != Src.List())
00546         {
00547                 list->DeleteEnumerator(this);
00548                 Reset();
00549                 list = Src.List();
00550                 list->ResetItemId(&currentId);
00551                 list->AddEnumerator(this);
00552         }
00553         else
00554         {
00555                 Reset();
00556         }
00557         
00558         // Копируем новые значения
00559         enumerated = Src.Enumerated();
00560         if (enumerated) 
00561                 new(currentBuffer.Place()) Type(Src.Current()); // Если шло перечисление, то копируем текущее значение перечислителя.
00562         list->CopyItemId(Src, &currentId);
00563         
00564         return *this;
00565 }
00566 
00567 template < typename ValueT, typename StoreT >
00568 bool Cntm::HandledList < ValueT, StoreT > ::Enumerator::Next()
00569 {
00570         if (enumerated)
00571         {
00572                 try
00573                 {
00574                         reinterpret_cast<Type*>(currentBuffer.Place())->~Type();
00575                         enumerated = list->NextItem(&currentId, currentBuffer.Place()); // Получаем следующее значение.
00576                 }
00577                 catch (...)
00578                 {
00579                         enumerated = false;
00580                         throw;
00581                 }
00582         }
00583         else
00584         {
00585                 enumerated = list->FirstItem(&currentId, currentBuffer.Place()); // Получаем первый эл-т.
00586         }
00587         
00588         return enumerated;
00589 }
00590 
00591 template < typename ValueT, typename StoreT >
00592 void Cntm::HandledList < ValueT, StoreT > ::Enumerator::Reset()
00593 {
00594         if (enumerated)
00595         {
00596                 enumerated = false;
00597                 reinterpret_cast<Type*>(currentBuffer.Place())->~Type();
00598                 list->ResetItemId(&currentId);
00599         }
00600 }
00601 
00602 template < typename ValueT, typename StoreT >
00603 Cntm::HandledList < ValueT, StoreT > ::Enumerator::Enumerator(HandledList* List):
00604         list(List), enumerated(false)
00605 {
00606         list->ResetItemId(&currentId);
00607         list->AddEnumerator(this);
00608 }
00609 
00610 
00611 // Handle /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00612 
00613 template < typename ValueT, typename StoreT >
00614 Cntm::HandledList < ValueT, StoreT > ::Handle::Handle(const Handle& Src)
00615 {
00616         if (this != &Src) Duplicate(Src, &list, &id);
00617 }
00618 
00619 template < typename ValueT, typename StoreT >
00620 typename Cntm::HandledList < ValueT, StoreT > ::Handle& 
00621         Cntm::HandledList < ValueT, StoreT > ::Handle::operator = (const AddResult& Src)
00622 {
00623         SetNewValues(Src.List(), Src.Id());
00624         
00625         return *this;
00626 }
00627 
00628 template < typename ValueT, typename StoreT >
00629 typename Cntm::HandledList < ValueT, StoreT > ::Handle&
00630         Cntm::HandledList < ValueT, StoreT > ::Handle::operator = (const Handle& Src)
00631 {
00632         if (this != &Src)
00633         {
00634                 // Считывание новых парметров.
00635                 HandledList*    newList;
00636                 ItemId          newId;
00637                 Duplicate(Src, &newList, &newId);
00638 
00639                 // Установка новых параметров, удаление связанного эл-та.
00640                 SetNewValues(newList, newId); 
00641         }
00642         
00643         return *this;
00644 }
00645 
00646 template < typename ValueT, typename StoreT >
00647 void Cntm::HandledList < ValueT, StoreT > ::Handle::Release()
00648 {
00649         // Обнуление указателя на перечень, удаление связанного эл-та.
00650         SetNewValues(NULL, id);
00651 }
00652 
00653 template < typename ValueT, typename StoreT >
00654 inline void Cntm::HandledList < ValueT, StoreT > ::Handle::AtomicCopyTo
00655         (HandledList** DestList, StoreT * DestValue) const
00656 {
00657         *DestList = const_cast<Handle*>(this)->Enter();
00658         try
00659         {
00660                 if (*DestList) *DestValue = *id;
00661         }
00662         catch (...)
00663         {
00664                 const_cast<Handle*>(this)->Leave(*DestList);
00665                 throw;
00666         }
00667 
00668         const_cast<Handle*>(this)->Leave(*DestList);
00669 }
00670 
00671 template < typename ValueT, typename StoreT >
00672 inline void Cntm::HandledList < ValueT, StoreT > ::Handle::Duplicate
00673         (const Handle& Src, HandledList** DestList, ItemId* DestId) const
00674 {
00675         // Считывание парметров
00676         StoreT val;
00677         Src.AtomicCopyTo(DestList, &val);
00678         
00679         // Добавление нового значения
00680         if (*DestList) *DestId = (*DestList)->AddStoreValue(val); 
00681 }
00682                         
00683 template < typename ValueT, typename StoreT >
00684 inline void Cntm::HandledList < ValueT, StoreT > ::Handle::SetNewValues
00685         (HandledList* List, const ItemId& Id)
00686 {
00687         // Производим атомарный обмен значений. 
00688         ItemId oldId;
00689         HandledList* oldList = Enter();
00690         try
00691         {
00692                 oldId = id;
00693                 id = Id;
00694         }
00695         catch(...)
00696         {
00697                 Leave(NULL); 
00698                 throw;
00699         }
00700 
00701         Leave(List);
00702                 
00703         // Удаляем старое значение из перечня
00704         if (oldList) oldList->DeleteItem(oldId);
00705 }
00706 
00707 
00708 // AddResult //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00709 
00710 template < typename ValueT, typename StoreT >
00711 Cntm::HandledList < ValueT, StoreT > ::AddResult::AddResult(const AddResult& Src):
00712         list(Src.List()), id(Src.Id())
00713 {
00714         if (list == NULL) 
00715                 throw BadArgException("Cntm::HandledList::AddResult::AddResult", "Пустой источник");
00716 }
00717 
00718 
00719 // HandledList ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00720 
00721 template < typename ValueT, typename StoreT >
00722 inline typename Cntm::HandledList < ValueT, StoreT > ::ItemId
00723         Cntm::HandledList < ValueT, StoreT > ::AddStoreValue(const StoreT& Value)
00724 {
00725         boost::recursive_mutex::scoped_lock lock(mutex);        // Блокируем перечень.
00726         return items.insert(items.end(), Value);                        // Добавляем в конец.
00727 }
00728 
00729 template < typename ValueT, typename StoreT >
00730 inline void Cntm::HandledList < ValueT, StoreT > ::DeleteItem(const ItemId& Id)
00731 {
00732         // Блокируем перечень.
00733         boost::recursive_mutex::scoped_lock lock(mutex);
00734 
00735         // В цикле проходим по всем перечислителям. Если перечислитель указывает
00736         // на удаляемый эл-т, то уменьшаем итератор на 1, чтобы при вызове операции
00737         // Next перечислитель получил эл-т следующий за удаленным.
00738         for (EnumeratorBase* e = enumsHead.NextEnum(); e != &enumsHead; e = e->NextEnum())
00739                 if (static_cast<Enumerator*>(e)->CurrentId() == Id)
00740                         --(static_cast<Enumerator*>(e)->CurrentId());
00741         
00742         // Удаляем из списка.
00743         items.erase(Id);
00744 }
00745 
00746 template < typename ValueT, typename StoreT >
00747 inline void Cntm::HandledList < ValueT, StoreT > ::AddEnumerator(Enumerator* Enum)
00748 {
00749         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00750         Enum->InsertAfter(&enumsHead); // Вставляем новый перечислитель в начало списка.
00751 }
00752 
00753 template < typename ValueT, typename StoreT >
00754 inline void Cntm::HandledList < ValueT, StoreT > ::DeleteEnumerator(Enumerator* Enum)
00755 {
00756         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00757         Enum->Remove(); // Удаляем перечислитель из списка перечислителей.
00758 }
00759 
00760 template < typename ValueT, typename StoreT >
00761 inline void Cntm::HandledList < ValueT, StoreT > ::ResetItemId(ItemId* DestId)
00762 {
00763         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00764         *DestId = items.end(); // Устанавливаем пустое значение.
00765 }
00766                 
00767 
00768 template < typename ValueT, typename StoreT >
00769 inline void Cntm::HandledList < ValueT, StoreT > ::CopyItemId(const Enumerator& Src, ItemId* DestId)
00770 {
00771         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00772         *DestId = Src.CurrentId(); // Копируем итератор.
00773 }
00774 
00775 template < typename ValueT, typename StoreT >
00776 inline bool Cntm::HandledList < ValueT, StoreT > ::FirstItem(ItemId* DestId, void* DestCurrentBuf)
00777 {
00778         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00779         *DestId = items.begin(); // Берем первый эл-т.
00780         return ReturnItem(*DestId, DestCurrentBuf); // Возвращаем значения.
00781 }
00782 
00783 template < typename ValueT, typename StoreT >
00784 inline bool Cntm::HandledList < ValueT, StoreT > ::NextItem(ItemId* VarId, void* DestCurrentBuf)
00785 {
00786         boost::recursive_mutex::scoped_lock lock(mutex); // Блокируем перечень.
00787         ++(*VarId); // Переходим к следующему.
00788         return ReturnItem(*VarId, DestCurrentBuf); // Возвращаем значения.
00789 }
00790 
00791 template < typename ValueT, typename StoreT >
00792 inline bool Cntm::HandledList < ValueT, StoreT > ::ReturnItem(const ItemId& Id, void* DestCurrentBuf)
00793 {
00794         bool res = (Id != items.end()); // Текущий эл-т не вышел за пределы списка.
00795         if (res) new(DestCurrentBuf) Type(*Id); // Если не конец списка, присваиваем значение.
00796         return res;
00797 }
00798 
00799 
00800 #endif //CNTM_HANDLEDLIST_H

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