Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 class _IsolateEncoder { | |
| 6 final manglingToken; | |
| 7 // TODO(floitsch): switch to identity set. | |
| 8 final Map _encoded = new Map(); | |
|
Anton Muhin
2012/11/25 10:23:16
why not = {}?
floitsch
2012/11/28 14:13:18
If I'm not wrong that would be a Map<String, dynam
| |
| 9 final Map _visiting = new Map(); | |
| 10 final Function _mangle; | |
| 11 static const int _REFERENCE = 0; | |
| 12 static const int _DECLARATION = 1; | |
| 13 static const int _ESCAPED = 2; | |
| 14 static const int _MANGLED = 3; | |
| 15 | |
| 16 _IsolateEncoder(this.manglingToken, mangle(data)) | |
|
Anton Muhin
2012/11/25 10:23:16
why not this._mangle here?
floitsch
2012/11/28 14:13:18
This way I get a little bit of typing. The field i
| |
| 17 : this._mangle = mangle; | |
| 18 | |
| 19 encode(var data) { | |
| 20 if (data is num || data is String || data is bool || data == null) { | |
| 21 return data; | |
| 22 } | |
| 23 | |
| 24 if (_encoded.containsKey(data)) return _encoded[data]; | |
| 25 if (_visiting.containsKey(data)) { | |
| 26 // Self reference. | |
| 27 var selfReference = _visiting[data]; | |
| 28 if (selfReference == data) { | |
| 29 // Nobody used the self-reference yet. | |
| 30 selfReference = _createReference(); | |
| 31 _visiting[data] = selfReference; | |
| 32 } | |
| 33 return selfReference; | |
| 34 } | |
| 35 _visiting[data] = data; | |
| 36 | |
| 37 var result; | |
| 38 | |
| 39 if (data is List) { | |
| 40 bool hasBeenDuplicated = false; | |
| 41 result = data; | |
| 42 for (int i = 0; i < data.length; i++) { | |
| 43 var mangled = encode(data[i]); | |
| 44 if (mangled != data[i] && !hasBeenDuplicated) { | |
| 45 result = new List(data.length); | |
| 46 for (int j = 0; j < i; j++) { | |
| 47 result[j] = data[j]; | |
| 48 } | |
| 49 hasBeenDuplicated = true; | |
| 50 } | |
| 51 if (hasBeenDuplicated) { | |
| 52 result[i] = mangled; | |
| 53 } | |
| 54 } | |
| 55 result = _escapeIfNecessary(result); | |
| 56 } else if (data is Set) { | |
| 57 // TODO(floitsch): should we accept sets? | |
| 58 bool needsCopy = false; | |
| 59 for (var entry in data) { | |
| 60 var encoded = encode(entry); | |
| 61 if (encoded != entry) { | |
| 62 needsCopy = true; | |
| 63 break; | |
| 64 } | |
| 65 } | |
| 66 result = data; | |
| 67 if (needsCopy) { | |
| 68 result = new Set(); | |
| 69 data.forEach((entry) { | |
| 70 result.add(encode(entry)); | |
| 71 }); | |
| 72 } | |
| 73 } else if (data is Map) { | |
| 74 bool needsCopy = false; | |
| 75 data.forEach((key, value) { | |
| 76 var encodedKey = encode(key); | |
| 77 var encodedValue = encode(value); | |
| 78 if (encodedKey != key) needsCopy = true; | |
| 79 if (encodedValue != value) needsCopy = true; | |
| 80 }); | |
| 81 result = data; | |
| 82 if (needsCopy) { | |
| 83 result = new Map(); | |
| 84 data.forEach((key, value) { | |
| 85 result[encode(key)] = encode(value); | |
| 86 }); | |
| 87 } | |
| 88 } else { | |
| 89 // We don't handle self-references for user data. | |
| 90 // TODO(floitsch): we could keep the reference and throw when we see it | |
| 91 // again. However now the user has at least the possibility to do | |
| 92 // cyclic data-structures. | |
| 93 _visiting.remove(data); | |
| 94 result = _mangle(data); | |
| 95 if (result != data) { | |
| 96 result = _wrapMangled(encode(result)); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 var selfReference = _visiting[data]; | |
| 101 if (selfReference != null && selfReference != data) { | |
| 102 // A self-reference has been used. | |
| 103 result = _declareReference(selfReference, result); | |
| 104 } | |
| 105 _encoded[data] = result; | |
| 106 | |
| 107 _visiting.remove(data); | |
| 108 return result; | |
| 109 } | |
| 110 | |
| 111 _createReference() => [manglingToken, _REFERENCE]; | |
| 112 _declareReference(reference, data) { | |
| 113 return [manglingToken, _DECLARATION, reference, data]; | |
| 114 } | |
| 115 | |
| 116 _wrapMangled(data) => [manglingToken, _MANGLED, data]; | |
| 117 _escapeIfNecessary(List list) { | |
| 118 if (!list.isEmpty && list[0] == manglingToken) { | |
| 119 return [manglingToken, _ESCAPED, list]; | |
| 120 } else { | |
| 121 return list; | |
| 122 } | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 class _IsolateDecoder { | |
| 127 final manglingToken; | |
| 128 final Map _decoded = new Map(); | |
| 129 final Function _unmangle; | |
| 130 static const int _REFERENCE = _IsolateEncoder._REFERENCE; | |
| 131 static const int _DECLARATION = _IsolateEncoder._DECLARATION; | |
| 132 static const int _ESCAPED = _IsolateEncoder._ESCAPED; | |
| 133 static const int _MANGLED = _IsolateEncoder._MANGLED; | |
| 134 | |
| 135 _IsolateDecoder(this.manglingToken, unmangle(data)) | |
| 136 : this._unmangle = unmangle; | |
| 137 | |
| 138 decode(var data) { | |
| 139 if (data is num || data is String || data is bool || data == null) { | |
| 140 return data; | |
| 141 } | |
| 142 | |
| 143 if (_decoded.containsKey(data)) return _decoded[data]; | |
| 144 | |
| 145 if (_isDeclaration(data)) { | |
| 146 var reference = _extractReference(data); | |
| 147 var declared = _extractDeclared(data); | |
| 148 return _decodeObject(declared, reference); | |
| 149 } else { | |
| 150 return _decodeObject(data, null); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 _decodeObject(data, reference) { | |
| 155 if (_decoded.containsKey(data)) { | |
| 156 assert(reference == null); | |
| 157 return _decoded[data]; | |
| 158 } | |
| 159 | |
| 160 // If the data was a reference then we would have found it in the _decoded | |
| 161 // map. | |
| 162 assert(!_isReference(data)); | |
| 163 | |
| 164 var result; | |
| 165 if (_isMangled(data)) { | |
| 166 assert(reference == null); | |
| 167 List mangled = _extractMangled(data); | |
| 168 var decoded = decode(mangled); | |
| 169 result = _unmangle(decoded); | |
| 170 } else if (data is List) { | |
| 171 if (_isEscaped(data)) data = _extractEscaped(data); | |
| 172 assert(!_isMarked(data)); | |
| 173 result = data; | |
| 174 bool hasBeenDuplicated = false; | |
| 175 List duplicate() { | |
| 176 assert(!hasBeenDuplicated); | |
| 177 result = new List(); | |
| 178 result.length = data.length; | |
| 179 if (reference != null) _decoded[reference] = result; | |
| 180 hasBeenDuplicated = true; | |
| 181 } | |
| 182 | |
| 183 if (reference != null) duplicate(); | |
| 184 for (int i = 0; i < data.length; i++) { | |
| 185 var decoded = decode(data[i]); | |
| 186 if (decoded != data[i] && !hasBeenDuplicated) { | |
| 187 duplicate(); | |
| 188 for (int j = 0; j < i; j++) { | |
| 189 result[j] = data[j]; | |
| 190 } | |
| 191 } | |
| 192 if (hasBeenDuplicated) { | |
| 193 result[i] = decoded; | |
| 194 } | |
| 195 } | |
| 196 } else if (data is Set) { | |
| 197 bool needsCopy = reference != null; | |
| 198 if (!needsCopy) { | |
| 199 for (var entry in data) { | |
| 200 var decoded = decode(entry); | |
| 201 if (decoded != entry) { | |
| 202 needsCopy = true; | |
| 203 break; | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 result = data; | |
| 208 if (needsCopy) { | |
| 209 result = new Set(); | |
| 210 if (reference != null) _decoded[reference] = result; | |
| 211 for (var entry in data) { | |
| 212 result.add(decode(entry)); | |
| 213 } | |
| 214 } | |
| 215 } else if (data is Map) { | |
| 216 bool needsCopy = reference != null; | |
| 217 if (!needsCopy) { | |
| 218 data.forEach((key, value) { | |
| 219 var decodedKey = decode(key); | |
| 220 var decodedValue = decode(value); | |
| 221 if (decodedKey != key) needsCopy = true; | |
| 222 if (decodedValue != value) needsCopy = true; | |
| 223 }); | |
| 224 } | |
| 225 result = data; | |
| 226 if (needsCopy) { | |
| 227 result = new Map(); | |
| 228 if (reference != null) _decoded[reference] = result; | |
| 229 data.forEach((key, value) { | |
| 230 result[decode(key)] = decode(value); | |
| 231 }); | |
| 232 } | |
| 233 } else { | |
| 234 result = data; | |
| 235 } | |
| 236 _decoded[data] = result; | |
| 237 return result; | |
| 238 } | |
| 239 | |
| 240 _isMarked(data) { | |
| 241 if (data is List && !data.isEmpty && data[0] == manglingToken) { | |
| 242 assert(data.length > 1); | |
| 243 return true; | |
| 244 } | |
| 245 return false; | |
| 246 } | |
| 247 _isReference(data) => _isMarked(data) && data[1] == _REFERENCE; | |
| 248 _isDeclaration(data) => _isMarked(data) && data[1] == _DECLARATION; | |
| 249 _isMangled(data) => _isMarked(data) && data[1] == _MANGLED; | |
| 250 _isEscaped(data) => _isMarked(data) && data[1] == _ESCAPED; | |
| 251 | |
| 252 _extractReference(declaration) { | |
| 253 assert(_isDeclaration(declaration)); | |
| 254 return declaration[2]; | |
| 255 } | |
| 256 _extractDeclared(declaration) { | |
| 257 assert(_isDeclaration(declaration)); | |
| 258 return declaration[3]; | |
| 259 } | |
| 260 _extractMangled(wrappedMangled) { | |
| 261 assert(_isMangled(wrappedMangled)); | |
| 262 return wrappedMangled[2]; | |
| 263 } | |
| 264 _extractEscaped(data) { | |
| 265 assert(_isEscaped(data)); | |
| 266 return data[2]; | |
| 267 } | |
| 268 } | |
| OLD | NEW |