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