| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef _DECAF_UTIL_CONCURRENT_COPYONWRITEARRAYLIST_H_ |
| #define _DECAF_UTIL_CONCURRENT_COPYONWRITEARRAYLIST_H_ |
| |
| #include <decaf/util/NoSuchElementException.h> |
| #include <decaf/lang/exceptions/IndexOutOfBoundsException.h> |
| #include <decaf/util/concurrent/Synchronizable.h> |
| #include <decaf/util/concurrent/locks/ReentrantReadWriteLock.h> |
| #include <decaf/lang/System.h> |
| #include <decaf/lang/Math.h> |
| #include <decaf/lang/Pointer.h> |
| #include <decaf/util/List.h> |
| |
| namespace decaf { |
| namespace util { |
| namespace concurrent { |
| |
| template< typename E > |
| class CopyOnWriteArrayList : public List<E> { |
| private: |
| |
| struct Array { |
| |
| int size; |
| int capacity; |
| E* elements; |
| |
| Array() : size(0), capacity(0), elements(NULL) { |
| } |
| |
| Array(int capacity) : size(0), capacity(0), elements(NULL) { |
| reserve(capacity); |
| } |
| |
| Array(const Array& src, int capacity) : size(0), capacity(0), elements(NULL) { |
| reserve(decaf::lang::Math::max(src.size, capacity)); |
| if (src.size > 0) { |
| decaf::lang::System::arraycopy<E>(src.elements, 0, this->elements, 0, src.size); |
| } |
| this->size = src.size; |
| } |
| |
| ~Array() { |
| delete [] elements; |
| } |
| |
| void reserve(int requested) { |
| if (capacity < requested) { |
| // growth as a factor of 1.5 |
| int newlen = decaf::lang::Math::max((int)(capacity*1.5), requested); |
| E* newbuf = newlen ? new E[newlen] : NULL; |
| |
| if (this->elements != NULL) { |
| decaf::lang::System::arraycopy<E>(this->elements, 0, newbuf, 0, size); |
| } |
| |
| delete[] this->elements; |
| this->elements = newbuf; |
| capacity = newlen; |
| } |
| } |
| |
| private: |
| |
| Array(const Array&); |
| Array operator= (const Array&); |
| |
| }; |
| |
| private: |
| |
| mutable decaf::util::concurrent::locks::ReentrantReadWriteLock arrayLock; |
| decaf::lang::Pointer<decaf::util::concurrent::locks::Condition> condition; |
| decaf::lang::Pointer<Array> array; |
| |
| public: |
| |
| class ArrayListIterator : public ListIterator<E> { |
| private: |
| |
| decaf::lang::Pointer<Array> array; |
| int position; |
| |
| private: |
| |
| ArrayListIterator(const ArrayListIterator&); |
| ArrayListIterator& operator=(const ArrayListIterator&); |
| |
| public: |
| |
| ArrayListIterator(decaf::lang::Pointer<Array> array, int index) : |
| ListIterator<E> (), array(array), position(index) { |
| |
| if (position < 0 || position > array->size) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Iterator created with invalid index."); |
| } |
| } |
| |
| virtual ~ArrayListIterator() { |
| this->array.reset(NULL); |
| }; |
| |
| virtual E next() { |
| if (position >= array->size) { |
| throw NoSuchElementException(); |
| } |
| |
| return this->array->elements[position++]; |
| } |
| |
| virtual bool hasNext() const { |
| return this->position < array->size; |
| } |
| |
| virtual void remove() { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "CopyOnWriteArrayList Iterator cannot remove elements."); |
| } |
| |
| virtual void add(const E& e DECAF_UNUSED ) { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "CopyOnWriteArrayList Iterator cannot add elements."); |
| } |
| |
| virtual void set(const E& e DECAF_UNUSED ) { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "CopyOnWriteArrayList Iterator cannot add elements."); |
| } |
| |
| virtual bool hasPrevious() const { |
| return this->position > 0; |
| } |
| |
| virtual E previous() { |
| if (position <= 0) { |
| throw NoSuchElementException(); |
| } |
| |
| return this->array->elements[position--]; |
| } |
| |
| virtual int nextIndex() const { |
| return this->position; |
| } |
| |
| virtual int previousIndex() const { |
| return this->position - 1; |
| } |
| |
| }; |
| |
| public: |
| |
| CopyOnWriteArrayList() : List<E>(), arrayLock(), condition(), array(new Array()) { |
| this->condition.reset(arrayLock.writeLock().newCondition()); |
| } |
| |
| CopyOnWriteArrayList(const Collection<E>& collection) : List<E>(), arrayLock(), condition(), array(new Array()) { |
| this->condition.reset(arrayLock.writeLock().newCondition()); |
| this->doCopyCollection(collection); |
| } |
| |
| CopyOnWriteArrayList(const CopyOnWriteArrayList<E>& collection) : List<E>(), arrayLock(), condition(), array(new Array()) { |
| this->condition.reset(arrayLock.writeLock().newCondition()); |
| this->doCopyCollection(collection); |
| } |
| |
| CopyOnWriteArrayList(const E* array, int size) : List<E>(), arrayLock(), condition(), array(new Array()) { |
| this->condition.reset(arrayLock.writeLock().newCondition()); |
| decaf::lang::Pointer<Array> temp(new Array(size)); |
| for (int i = 0; i < size; ++i) { |
| temp->elements[i] = array[i]; |
| temp->size++; |
| } |
| this->array.swap(temp); |
| } |
| |
| virtual ~CopyOnWriteArrayList() { |
| this->array.reset(NULL); |
| } |
| |
| public: |
| |
| CopyOnWriteArrayList<E>& operator=(const CopyOnWriteArrayList<E>& list) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| this->clear(); |
| this->doCopyCollection(list); |
| } catch (decaf::lang::Exception& ex) { |
| this->writeLock.unlock(); |
| throw; |
| } |
| |
| this->arrayLock.writeLock().unlock(); |
| return *this; |
| } |
| |
| CopyOnWriteArrayList<E>& operator=(const Collection<E>& list) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| this->clear(); |
| this->doCopyCollection(list); |
| } catch (decaf::lang::Exception& ex) { |
| this->writeLock.unlock(); |
| throw; |
| } |
| |
| this->arrayLock.writeLock().unlock(); |
| return *this; |
| } |
| |
| public: // Collections API |
| |
| virtual void copy(const Collection<E>& collection) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| this->clear(); |
| this->doCopyCollection(collection); |
| this->arrayLock.writeLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual bool add(const E& value) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| decaf::lang::Pointer<Array> newArray(new Array(*oldArray, size + 1)); |
| newArray->elements[size] = value; |
| newArray->size++; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual bool addAll(const Collection<E>& collection) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| decaf::lang::Pointer<Array> newArray(new Array(*oldArray, size + collection.size())); |
| std::auto_ptr<Iterator<E> > iter(collection.iterator()); |
| while (iter->hasNext()) { |
| newArray->elements[newArray->size++] = iter->next(); |
| } |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual void clear() { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> newArray(new Array()); |
| this->array.swap(newArray); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| |
| this->arrayLock.writeLock().unlock(); |
| } |
| |
| virtual bool contains(const E& value) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| for (int i = 0; i < current->size; ++i) { |
| if (current->elements[i] == value) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| virtual bool containsAll(const Collection<E>& collection) const { |
| std::auto_ptr<Iterator<E> > iter(collection.iterator()); |
| while (iter->hasNext()) { |
| E next = iter->next(); |
| if (!this->contains(next)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| virtual bool equals(const Collection<E>& collection) const { |
| |
| if ((void*) this == &collection) { |
| return true; |
| } |
| |
| const List<E>* asList = dynamic_cast<const List<E>*> (&collection); |
| if (asList == NULL) { |
| return false; |
| } |
| |
| if (this->size() != asList->size()) { |
| return false; |
| } |
| |
| std::auto_ptr<Iterator<E> > thisIter(this->iterator()); |
| std::auto_ptr<Iterator<E> > otherIter(asList->iterator()); |
| |
| while (thisIter->hasNext()) { |
| if (!otherIter->hasNext()) { |
| return false; |
| } |
| |
| E myNext = thisIter->next(); |
| E otherNext = otherIter->next(); |
| |
| if (myNext != otherNext) { |
| return false; |
| } |
| } |
| |
| if (otherIter->hasNext()) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| virtual bool isEmpty() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return current->size == 0; |
| } |
| |
| virtual bool remove(const E& value) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| int index = this->indexOf(value); |
| if (index == -1) { |
| this->arrayLock.writeLock().unlock(); |
| return false; |
| } |
| this->removeAt(index); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual bool removeAll(const Collection<E>& collection) { |
| if (collection.isEmpty()) { |
| return false; |
| } |
| |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| |
| if (size == 0) { |
| this->arrayLock.writeLock().unlock(); |
| return false; |
| } |
| |
| decaf::lang::Pointer<Array> buffer(new Array(size)); |
| int count = 0; |
| for (int i = 0; i < size; ++i) { |
| E value = oldArray->elements[i]; |
| if (!collection.contains(value)) { |
| buffer->elements[count++] = value; |
| buffer->size++; |
| } |
| } |
| |
| if (count == 0) { |
| this->array.reset(new Array()); |
| } else { |
| decaf::lang::Pointer<Array> newArray(new Array(*buffer, count)); |
| this->array.swap(newArray); |
| } |
| |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual bool retainAll(const Collection<E>& collection) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| |
| if (size == 0) { |
| this->arrayLock.writeLock().unlock(); |
| return false; |
| } |
| |
| if (collection.isEmpty()) { |
| this->array.reset(new Array()); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } |
| |
| decaf::lang::Pointer<Array> buffer(new Array(size)); |
| int count = 0; |
| |
| for (int i = 0; i < size; ++i) { |
| E value = oldArray->elements[i]; |
| if (collection.contains(value)) { |
| buffer->elements[count++] = value; |
| buffer->size++; |
| } |
| } |
| |
| if (count == 0) { |
| this->array.reset(new Array()); |
| } else { |
| this->array.swap(buffer); |
| } |
| |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual int size() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return current->size; |
| } |
| |
| virtual std::vector<E> toArray() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| std::vector<E> result((std::size_t) current->size); |
| for (int i = 0; i < current->size; ++i) { |
| result[i] = current->elements[i]; |
| } |
| |
| return result; |
| } |
| |
| public: // Iterable API |
| |
| virtual decaf::util::Iterator<E>* iterator() { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(current, 0); |
| } |
| virtual decaf::util::Iterator<E>* iterator() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(current, 0); |
| } |
| |
| public: // List API |
| |
| virtual ListIterator<E>* listIterator() { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(current, 0); |
| } |
| virtual ListIterator<E>* listIterator() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(current, 0); |
| } |
| |
| virtual ListIterator<E>* listIterator(int index) { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(current, index); |
| } |
| virtual ListIterator<E>* listIterator(int index) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| return new ArrayListIterator(this->array, index); |
| } |
| |
| virtual int indexOf(const E& value) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| for (int i = 0; i < current->size; ++i) { |
| if (current->elements[i] == value) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| virtual int lastIndexOf(const E& value) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| for (int i = current->size - 1; i >= 0; --i) { |
| if (current->elements[i] == value) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| virtual E get(int index) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| checkIndexExclusive(index, current->size); |
| return current->elements[index]; |
| } |
| |
| virtual E set(int index, const E& element) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| this->checkIndexExclusive(index, size); |
| decaf::lang::Pointer<Array> newArray(new Array(*oldArray, size)); |
| E old = newArray->elements[index]; |
| newArray->elements[index] = element; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return old; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual void add(int index, const E& element) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| this->checkIndexInclusive(index, size); |
| decaf::lang::Pointer<Array> newArray(new Array(size + 1)); |
| |
| if (size > 0) { |
| decaf::lang::System::arraycopy<E>(oldArray->elements, 0, newArray->elements, 0, index); |
| } |
| |
| if (size > index) { |
| decaf::lang::System::arraycopy<E>(oldArray->elements, index, newArray->elements, index + 1, size - index); |
| } |
| |
| newArray->elements[index] = element; |
| newArray->size = size + 1; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual bool addAll(int index, const Collection<E>& collection) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| this->checkIndexInclusive(index, size); |
| int csize = collection.size(); |
| |
| if (csize == 0) { |
| this->arrayLock.writeLock().unlock(); |
| return false; |
| } |
| |
| decaf::lang::Pointer<Array> newArray(new Array(size + csize)); |
| if (size > 0) { |
| decaf::lang::System::arraycopy(oldArray->elements, 0, newArray->elements, 0, index); |
| } |
| |
| std::auto_ptr<Iterator<E> > iter(collection.iterator()); |
| int pos = index; |
| while (iter->hasNext()) { |
| newArray->elements[pos++] = iter->next(); |
| } |
| |
| if (size > index) { |
| decaf::lang::System::arraycopy(oldArray->elements, index, newArray->elements, index + csize, size - index); |
| } |
| newArray->size = size + csize; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual E removeAt(int index) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| this->checkIndexExclusive(index, size); |
| E old = oldArray->elements[index]; |
| |
| if (size == 1) { |
| this->array.reset(new Array()); |
| this->arrayLock.writeLock().unlock(); |
| return old; |
| } |
| |
| decaf::lang::Pointer<Array> newArray(new Array(size - 1)); |
| decaf::lang::System::arraycopy<E>(oldArray->elements, 0, newArray->elements, 0, index); |
| |
| if (size > index) { |
| decaf::lang::System::arraycopy<E>(oldArray->elements, index + 1, newArray->elements, index, size - index - 1); |
| } |
| |
| newArray->size = size - 1; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return old; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| virtual std::string toString() const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| std::string result; |
| return result; |
| } |
| |
| public: |
| |
| /** |
| * Adds the given value to the end of this List if it is not already contained |
| * in this List. |
| * |
| * @param value |
| * The element to be added if not already contained in this List. |
| * |
| * @return true if the element is added to this List. |
| */ |
| bool addIfAbsent(const E& value) { |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| |
| if (size != 0) { |
| if (this->indexOf(value) != -1) { |
| this->arrayLock.writeLock().unlock(); |
| return false; |
| } |
| } |
| |
| decaf::lang::Pointer<Array> newArray(new Array(*oldArray, size + 1)); |
| newArray->elements[size] = value; |
| newArray->size++; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return true; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| /** |
| * Every element in the given collection that is not already contained in this Collection |
| * is added to the end of this collection. The order that the elements are added is ditacted |
| * by the order that the collection's iterator returns them. |
| * |
| * @param collection |
| * The collection whose elements are to be added if not already in this List. |
| * |
| * @return the number of elements that are added to this List. |
| */ |
| int addAllAbsent(const Collection<E>& collection) { |
| |
| if (collection.size() == 0) { |
| return 0; |
| } |
| |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| decaf::lang::Pointer<Array> buffer(new Array(collection.size())); |
| int count = 0; |
| |
| std::auto_ptr<Iterator<E> > iter(collection.iterator()); |
| while (iter->hasNext()) { |
| E value = iter->next(); |
| if (this->indexOf(value) == -1) { |
| buffer->elements[count++] = value; |
| buffer->size++; |
| } |
| } |
| |
| decaf::lang::Pointer<Array> newArray(new Array(*oldArray, size + count)); |
| decaf::lang::System::arraycopy(buffer->elements, 0, newArray->elements, size, count); |
| newArray->size = size + count; |
| this->array.swap(newArray); |
| this->arrayLock.writeLock().unlock(); |
| return count; |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| /** |
| * Searches backwards through the List for the given element starting at the index |
| * specified. |
| * |
| * @param value |
| * The value to search for in the List. |
| * @param index |
| * The index in the list to begin the search from. |
| * |
| * @return the index in the list that matches the value given, or -1 if not found. |
| * |
| * @throws IndexOutOfBoundsException if the given index is greater than or equal to the List size. |
| */ |
| int lastIndexOf(const E& value, int index) { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| |
| if (index >= current->size) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Index given %d, actual size %d", index, current->size); |
| } |
| |
| for (int i = index - 1; i >= 0; --i) { |
| if (current->elements[i] == value) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Searches the List starting from the specified index and returns the index of the |
| * first item in the list that is equal to the given value. |
| * |
| * @param value |
| * The value to search for in the List. |
| * @param index |
| * The index in the List to begin the search from. |
| * |
| * @return the index in the List that matches the given element or -1 if not found. |
| * |
| * @throws IndexOutOfBoundsException if the given index is negative. |
| */ |
| int indexOf(const E& value, int index) const { |
| decaf::lang::Pointer<Array> current; |
| this->arrayLock.readLock().lock(); |
| try { |
| current = this->array; |
| this->arrayLock.readLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.readLock().unlock(); |
| throw; |
| } |
| |
| |
| if (index < 0) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Index given %d, actual size %d", index, current->size); |
| } |
| |
| for (int i = index; i < current->size; ++i) { |
| if (current->elements[i] == value) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| public: // Synchronizable |
| |
| virtual void lock() { |
| this->arrayLock.writeLock().lock(); |
| } |
| |
| virtual bool tryLock() { |
| return this->arrayLock.writeLock().tryLock(); |
| } |
| |
| virtual void unlock() { |
| this->arrayLock.writeLock().unlock(); |
| } |
| |
| virtual void wait() { |
| this->condition->await(); |
| } |
| |
| virtual void wait(long long millisecs) { |
| this->condition->await(millisecs, decaf::util::concurrent::TimeUnit::MILLISECONDS); |
| } |
| |
| virtual void wait( long long millisecs, int nanos ) { |
| long long timeout = decaf::util::concurrent::TimeUnit::MILLISECONDS.toNanos(millisecs) + nanos; |
| this->condition->awaitNanos(timeout); |
| } |
| |
| virtual void notify() { |
| this->condition->signal(); |
| } |
| |
| virtual void notifyAll() { |
| this->condition->signalAll(); |
| } |
| |
| private: |
| |
| void doCopyCollection(const Collection<E>& collection) { |
| |
| if ((void*) this == &collection || collection.isEmpty()) { |
| return; |
| } |
| |
| this->arrayLock.writeLock().lock(); |
| try { |
| decaf::lang::Pointer<Array> oldArray = this->array; |
| int size = oldArray->size; |
| |
| decaf::lang::Pointer<Array> buffer(new Array(*oldArray, size + collection.size())); |
| std::auto_ptr<Iterator<E> > iter(collection.iterator()); |
| int index = 0; |
| while (iter->hasNext()) { |
| buffer->elements[size + index++] = iter->next(); |
| buffer->size++; |
| } |
| |
| this->array.swap(buffer); |
| this->arrayLock.writeLock().unlock(); |
| } catch (decaf::lang::Exception& ex) { |
| this->arrayLock.writeLock().unlock(); |
| throw; |
| } |
| } |
| |
| static void checkIndexInclusive(int index, int size) { |
| if (index < 0 || index > size) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Index is %d, size is %d", index, size); |
| } |
| } |
| |
| static void checkIndexExclusive(int index, int size) { |
| if (index < 0 || index >= size) { |
| throw decaf::lang::exceptions::IndexOutOfBoundsException( |
| __FILE__, __LINE__, "Index is %d, size is %d", index, size); |
| } |
| } |
| |
| }; |
| |
| }}} |
| |
| #endif /* _DECAF_UTIL_CONCURRENT_COPYONWRITEARRAYLIST_H_ */ |