• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "StorageMap.h"
28 
29 #if ENABLE(DOM_STORAGE)
30 
31 namespace WebCore {
32 
create()33 PassRefPtr<StorageMap> StorageMap::create()
34 {
35     return adoptRef(new StorageMap);
36 }
37 
StorageMap()38 StorageMap::StorageMap()
39     : m_iterator(m_map.end())
40     , m_iteratorIndex(UINT_MAX)
41 {
42 }
43 
copy()44 PassRefPtr<StorageMap> StorageMap::copy()
45 {
46     RefPtr<StorageMap> newMap = create();
47     newMap->m_map = m_map;
48     return newMap.release();
49 }
50 
invalidateIterator()51 void StorageMap::invalidateIterator()
52 {
53     m_iterator = m_map.end();
54     m_iteratorIndex = UINT_MAX;
55 }
56 
setIteratorToIndex(unsigned index) const57 void StorageMap::setIteratorToIndex(unsigned index) const
58 {
59     // FIXME: Once we have bidirectional iterators for HashMap we can be more intelligent about this.
60     // The requested index will be closest to begin(), our current iterator, or end(), and we
61     // can take the shortest route.
62     // Until that mechanism is available, we'll always increment our iterator from begin() or current.
63 
64     if (m_iteratorIndex == index)
65         return;
66 
67     if (index < m_iteratorIndex) {
68         m_iteratorIndex = 0;
69         m_iterator = m_map.begin();
70         ASSERT(m_iterator != m_map.end());
71     }
72 
73     while (m_iteratorIndex < index) {
74         ++m_iteratorIndex;
75         ++m_iterator;
76         ASSERT(m_iterator != m_map.end());
77     }
78 }
79 
length() const80 unsigned StorageMap::length() const
81 {
82     return m_map.size();
83 }
84 
key(unsigned index) const85 String StorageMap::key(unsigned index) const
86 {
87     if (index >= length())
88         return String();
89 
90     setIteratorToIndex(index);
91     return m_iterator->first;
92 }
93 
getItem(const String & key) const94 String StorageMap::getItem(const String& key) const
95 {
96     return m_map.get(key);
97 }
98 
setItem(const String & key,const String & value,String & oldValue)99 PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue)
100 {
101     ASSERT(!value.isNull());
102 
103     // Implement copy-on-write semantics here.  We're guaranteed that the only refs of StorageMaps belong to Storage objects
104     // so if more than one Storage object refs this map, copy it before mutating it.
105     if (refCount() > 1) {
106         RefPtr<StorageMap> newStorageMap = copy();
107         newStorageMap->setItem(key, value, oldValue);
108         return newStorageMap.release();
109     }
110 
111     pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
112 
113     if (addResult.second) {
114         // There was no "oldValue" so null it out.
115         oldValue = String();
116     } else {
117         oldValue = addResult.first->second;
118         addResult.first->second = value;
119     }
120 
121     invalidateIterator();
122 
123     return 0;
124 }
125 
removeItem(const String & key,String & oldValue)126 PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValue)
127 {
128     // Implement copy-on-write semantics here.  We're guaranteed that the only refs of StorageMaps belong to Storage objects
129     // so if more than one Storage object refs this map, copy it before mutating it.
130     if (refCount() > 1) {
131         RefPtr<StorageMap> newStorage = copy();
132         newStorage->removeItem(key, oldValue);
133         return newStorage.release();
134     }
135 
136     oldValue = m_map.take(key);
137     if (!oldValue.isNull())
138         invalidateIterator();
139 
140     return 0;
141 }
142 
contains(const String & key) const143 bool StorageMap::contains(const String& key) const
144 {
145     return m_map.contains(key);
146 }
147 
importItem(const String & key,const String & value) const148 void StorageMap::importItem(const String& key, const String& value) const
149 {
150     // Be sure to copy the keys/values as items imported on a background thread are destined
151     // to cross a thread boundary
152     pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.copy(), String());
153 
154     if (result.second)
155         result.first->second = value.copy();
156 }
157 
158 }
159 
160 #endif // ENABLE(DOM_STORAGE)
161 
162