| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef NET_SPDY_SPDY_PRIORITY_FOREST_H_ | 5 #ifndef NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
| 6 #define NET_SPDY_SPDY_PRIORITY_FOREST_H_ | 6 #define NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
| 7 | 7 |
| 8 #include <map> | 8 #include <map> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 private: | 112 private: |
| 113 enum NodeType { ROOT_NODE, NONROOT_ORDERED, NONROOT_UNORDERED }; | 113 enum NodeType { ROOT_NODE, NONROOT_ORDERED, NONROOT_UNORDERED }; |
| 114 struct Node { | 114 struct Node { |
| 115 Node() : type(ROOT_NODE), flags(0), child() { | 115 Node() : type(ROOT_NODE), flags(0), child() { |
| 116 depends_on.priority = Priority(); | 116 depends_on.priority = Priority(); |
| 117 } | 117 } |
| 118 NodeType type; | 118 NodeType type; |
| 119 unsigned int flags; // bitfield of flags | 119 unsigned int flags; // bitfield of flags |
| 120 union { | 120 union { |
| 121 Priority priority; // used for root nodes | 121 Priority priority; // used for root nodes |
| 122 NodeId parent_id; // used for non-root nodes | 122 NodeId parent_id; // used for non-root nodes |
| 123 } depends_on; | 123 } depends_on; |
| 124 NodeId child; // node ID of child (or NodeId() for no child) | 124 NodeId child; // node ID of child (or NodeId() for no child) |
| 125 }; | 125 }; |
| 126 | 126 |
| 127 typedef base::hash_map<NodeId, Node> NodeMap; | 127 typedef base::hash_map<NodeId, Node> NodeMap; |
| 128 | 128 |
| 129 // Constants for the Node.flags bitset: | 129 // Constants for the Node.flags bitset: |
| 130 // kReadToRead: set for nodes that are ready for reading | 130 // kReadToRead: set for nodes that are ready for reading |
| 131 static const unsigned int kReadyToRead = (1 << 0); | 131 static const unsigned int kReadyToRead = (1 << 0); |
| 132 // kReadToWrite: set for nodes that are ready for writing | 132 // kReadToWrite: set for nodes that are ready for writing |
| 133 static const unsigned int kReadyToWrite = (1 << 1); | 133 static const unsigned int kReadyToWrite = (1 << 1); |
| 134 | 134 |
| 135 // Common code for IsMarkedReadyToRead and IsMarkedReadyToWrite. | 135 // Common code for IsMarkedReadyToRead and IsMarkedReadyToWrite. |
| 136 bool IsMarked(NodeId node_id, unsigned int flag) const; | 136 bool IsMarked(NodeId node_id, unsigned int flag) const; |
| 137 // Common code for MarkReadyToRead and MarkReadyToWrite. | 137 // Common code for MarkReadyToRead and MarkReadyToWrite. |
| 138 bool Mark(NodeId node_id, unsigned int flag); | 138 bool Mark(NodeId node_id, unsigned int flag); |
| 139 // Common code for MarkNoLongerReadyToRead and MarkNoLongerReadyToWrite. | 139 // Common code for MarkNoLongerReadyToRead and MarkNoLongerReadyToWrite. |
| 140 bool Unmark(NodeId node_id, unsigned int flag); | 140 bool Unmark(NodeId node_id, unsigned int flag); |
| 141 // Common code for NextNodeToRead and NextNodeToWrite; | 141 // Common code for NextNodeToRead and NextNodeToWrite; |
| 142 NodeId FirstMarkedNode(unsigned int flag); | 142 NodeId FirstMarkedNode(unsigned int flag); |
| 143 // Get the given node, or return NULL if it doesn't exist. | 143 // Get the given node, or return NULL if it doesn't exist. |
| 144 const Node* FindNode(NodeId node_id) const; | 144 const Node* FindNode(NodeId node_id) const; |
| 145 | 145 |
| 146 NodeMap all_nodes_; // maps from node IDs to Node objects | 146 NodeMap all_nodes_; // maps from node IDs to Node objects |
| 147 | 147 |
| 148 DISALLOW_COPY_AND_ASSIGN(SpdyPriorityForest); | 148 DISALLOW_COPY_AND_ASSIGN(SpdyPriorityForest); |
| 149 }; | 149 }; |
| 150 | 150 |
| 151 template <typename NodeId, typename Priority> | 151 template <typename NodeId, typename Priority> |
| 152 SpdyPriorityForest<NodeId, Priority>::SpdyPriorityForest() {} | 152 SpdyPriorityForest<NodeId, Priority>::SpdyPriorityForest() { |
| 153 } |
| 153 | 154 |
| 154 template <typename NodeId, typename Priority> | 155 template <typename NodeId, typename Priority> |
| 155 SpdyPriorityForest<NodeId, Priority>::~SpdyPriorityForest() {} | 156 SpdyPriorityForest<NodeId, Priority>::~SpdyPriorityForest() { |
| 157 } |
| 156 | 158 |
| 157 template <typename NodeId, typename Priority> | 159 template <typename NodeId, typename Priority> |
| 158 int SpdyPriorityForest<NodeId, Priority>::num_nodes() const { | 160 int SpdyPriorityForest<NodeId, Priority>::num_nodes() const { |
| 159 return all_nodes_.size(); | 161 return all_nodes_.size(); |
| 160 } | 162 } |
| 161 | 163 |
| 162 template <typename NodeId, typename Priority> | 164 template <typename NodeId, typename Priority> |
| 163 bool SpdyPriorityForest<NodeId, Priority>::NodeExists(NodeId node_id) const { | 165 bool SpdyPriorityForest<NodeId, Priority>::NodeExists(NodeId node_id) const { |
| 164 return all_nodes_.count(node_id) != 0; | 166 return all_nodes_.count(node_id) != 0; |
| 165 } | 167 } |
| 166 | 168 |
| 167 template <typename NodeId, typename Priority> | 169 template <typename NodeId, typename Priority> |
| 168 bool SpdyPriorityForest<NodeId, Priority>::AddRootNode( | 170 bool SpdyPriorityForest<NodeId, Priority>::AddRootNode(NodeId node_id, |
| 169 NodeId node_id, Priority priority) { | 171 Priority priority) { |
| 170 if (NodeExists(node_id)) { | 172 if (NodeExists(node_id)) { |
| 171 return false; | 173 return false; |
| 172 } | 174 } |
| 173 Node* new_node = &all_nodes_[node_id]; | 175 Node* new_node = &all_nodes_[node_id]; |
| 174 new_node->type = ROOT_NODE; | 176 new_node->type = ROOT_NODE; |
| 175 new_node->depends_on.priority = priority; | 177 new_node->depends_on.priority = priority; |
| 176 return true; | 178 return true; |
| 177 } | 179 } |
| 178 | 180 |
| 179 template <typename NodeId, typename Priority> | 181 template <typename NodeId, typename Priority> |
| 180 bool SpdyPriorityForest<NodeId, Priority>::AddNonRootNode( | 182 bool SpdyPriorityForest<NodeId, Priority>::AddNonRootNode(NodeId node_id, |
| 181 NodeId node_id, NodeId parent_id, bool unordered) { | 183 NodeId parent_id, |
| 184 bool unordered) { |
| 182 if (NodeExists(node_id) || !NodeExists(parent_id)) { | 185 if (NodeExists(node_id) || !NodeExists(parent_id)) { |
| 183 return false; | 186 return false; |
| 184 } | 187 } |
| 185 | 188 |
| 186 Node* parent = &all_nodes_[parent_id]; | 189 Node* parent = &all_nodes_[parent_id]; |
| 187 if (parent->child != NodeId()) { | 190 if (parent->child != NodeId()) { |
| 188 return false; | 191 return false; |
| 189 } | 192 } |
| 190 | 193 |
| 191 Node* new_node = &all_nodes_[node_id]; | 194 Node* new_node = &all_nodes_[node_id]; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 NodeId SpdyPriorityForest<NodeId, Priority>::GetChild(NodeId node_id) const { | 270 NodeId SpdyPriorityForest<NodeId, Priority>::GetChild(NodeId node_id) const { |
| 268 const Node* node = FindNode(node_id); | 271 const Node* node = FindNode(node_id); |
| 269 if (node != NULL) { | 272 if (node != NULL) { |
| 270 return node->child; | 273 return node->child; |
| 271 } else { | 274 } else { |
| 272 return NodeId(); | 275 return NodeId(); |
| 273 } | 276 } |
| 274 } | 277 } |
| 275 | 278 |
| 276 template <typename NodeId, typename Priority> | 279 template <typename NodeId, typename Priority> |
| 277 bool SpdyPriorityForest<NodeId, Priority>::SetPriority( | 280 bool SpdyPriorityForest<NodeId, Priority>::SetPriority(NodeId node_id, |
| 278 NodeId node_id, Priority priority) { | 281 Priority priority) { |
| 279 if (!NodeExists(node_id)) { | 282 if (!NodeExists(node_id)) { |
| 280 return false; | 283 return false; |
| 281 } | 284 } |
| 282 | 285 |
| 283 Node* node = &all_nodes_[node_id]; | 286 Node* node = &all_nodes_[node_id]; |
| 284 // If this is not already a root node, we need to make it be a root node. | 287 // If this is not already a root node, we need to make it be a root node. |
| 285 if (node->type != ROOT_NODE) { | 288 if (node->type != ROOT_NODE) { |
| 286 DCHECK(NodeExists(node->depends_on.parent_id)); | 289 DCHECK(NodeExists(node->depends_on.parent_id)); |
| 287 Node* parent = &all_nodes_[node->depends_on.parent_id]; | 290 Node* parent = &all_nodes_[node->depends_on.parent_id]; |
| 288 parent->child = NodeId(); | 291 parent->child = NodeId(); |
| 289 node->type = ROOT_NODE; | 292 node->type = ROOT_NODE; |
| 290 } | 293 } |
| 291 | 294 |
| 292 node->depends_on.priority = priority; | 295 node->depends_on.priority = priority; |
| 293 return true; | 296 return true; |
| 294 } | 297 } |
| 295 | 298 |
| 296 template <typename NodeId, typename Priority> | 299 template <typename NodeId, typename Priority> |
| 297 bool SpdyPriorityForest<NodeId, Priority>::SetParent( | 300 bool SpdyPriorityForest<NodeId, Priority>::SetParent(NodeId node_id, |
| 298 NodeId node_id, NodeId parent_id, bool unordered) { | 301 NodeId parent_id, |
| 302 bool unordered) { |
| 299 if (!NodeExists(node_id) || !NodeExists(parent_id)) { | 303 if (!NodeExists(node_id) || !NodeExists(parent_id)) { |
| 300 return false; | 304 return false; |
| 301 } | 305 } |
| 302 | 306 |
| 303 Node* node = &all_nodes_[node_id]; | 307 Node* node = &all_nodes_[node_id]; |
| 304 Node* new_parent = &all_nodes_[parent_id]; | 308 Node* new_parent = &all_nodes_[parent_id]; |
| 305 // If the new parent is already the node's parent, all we have to do is | 309 // If the new parent is already the node's parent, all we have to do is |
| 306 // update the node type and we're done. | 310 // update the node type and we're done. |
| 307 if (new_parent->child == node_id) { | 311 if (new_parent->child == node_id) { |
| 308 node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED); | 312 node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED); |
| 309 return true; | 313 return true; |
| 310 } | 314 } |
| 311 // Otherwise, if the new parent already has a child, we fail. | 315 // Otherwise, if the new parent already has a child, we fail. |
| 312 if (new_parent->child != NodeId()) { | 316 if (new_parent->child != NodeId()) { |
| 313 return false; | 317 return false; |
| 314 } | 318 } |
| 315 | 319 |
| 316 // Next, make sure we won't create a cycle. | 320 // Next, make sure we won't create a cycle. |
| 317 if (node_id == parent_id) return false; | 321 if (node_id == parent_id) |
| 322 return false; |
| 318 Node* last = node; | 323 Node* last = node; |
| 319 NodeId last_id = node_id; | 324 NodeId last_id = node_id; |
| 320 while (last->child != NodeId()) { | 325 while (last->child != NodeId()) { |
| 321 if (last->child == parent_id) return false; | 326 if (last->child == parent_id) |
| 327 return false; |
| 322 last_id = last->child; | 328 last_id = last->child; |
| 323 DCHECK(NodeExists(last_id)); | 329 DCHECK(NodeExists(last_id)); |
| 324 last = &all_nodes_[last_id]; | 330 last = &all_nodes_[last_id]; |
| 325 } | 331 } |
| 326 | 332 |
| 327 // If the node is not a root, we need clear its old parent's child field | 333 // If the node is not a root, we need clear its old parent's child field |
| 328 // (unless the old parent is the same as the new parent). | 334 // (unless the old parent is the same as the new parent). |
| 329 if (node->type != ROOT_NODE) { | 335 if (node->type != ROOT_NODE) { |
| 330 const NodeId old_parent_id = node->depends_on.parent_id; | 336 const NodeId old_parent_id = node->depends_on.parent_id; |
| 331 DCHECK(NodeExists(old_parent_id)); | 337 DCHECK(NodeExists(old_parent_id)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 NodeId node_id) { | 386 NodeId node_id) { |
| 381 return Unmark(node_id, kReadyToWrite); | 387 return Unmark(node_id, kReadyToWrite); |
| 382 } | 388 } |
| 383 | 389 |
| 384 template <typename NodeId, typename Priority> | 390 template <typename NodeId, typename Priority> |
| 385 NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToWrite() { | 391 NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToWrite() { |
| 386 return FirstMarkedNode(kReadyToWrite); | 392 return FirstMarkedNode(kReadyToWrite); |
| 387 } | 393 } |
| 388 | 394 |
| 389 template <typename NodeId, typename Priority> | 395 template <typename NodeId, typename Priority> |
| 390 bool SpdyPriorityForest<NodeId, Priority>::IsMarked( | 396 bool SpdyPriorityForest<NodeId, Priority>::IsMarked(NodeId node_id, |
| 391 NodeId node_id, unsigned int flag) const { | 397 unsigned int flag) const { |
| 392 const Node* node = FindNode(node_id); | 398 const Node* node = FindNode(node_id); |
| 393 return node != NULL && (node->flags & flag) != 0; | 399 return node != NULL && (node->flags & flag) != 0; |
| 394 } | 400 } |
| 395 | 401 |
| 396 template <typename NodeId, typename Priority> | 402 template <typename NodeId, typename Priority> |
| 397 bool SpdyPriorityForest<NodeId, Priority>::Mark( | 403 bool SpdyPriorityForest<NodeId, Priority>::Mark(NodeId node_id, |
| 398 NodeId node_id, unsigned int flag) { | 404 unsigned int flag) { |
| 399 if (!NodeExists(node_id)) { | 405 if (!NodeExists(node_id)) { |
| 400 return false; | 406 return false; |
| 401 } | 407 } |
| 402 all_nodes_[node_id].flags |= flag; | 408 all_nodes_[node_id].flags |= flag; |
| 403 return true; | 409 return true; |
| 404 } | 410 } |
| 405 | 411 |
| 406 template <typename NodeId, typename Priority> | 412 template <typename NodeId, typename Priority> |
| 407 bool SpdyPriorityForest<NodeId, Priority>::Unmark( | 413 bool SpdyPriorityForest<NodeId, Priority>::Unmark(NodeId node_id, |
| 408 NodeId node_id, unsigned int flag) { | 414 unsigned int flag) { |
| 409 if (!NodeExists(node_id)) { | 415 if (!NodeExists(node_id)) { |
| 410 return false; | 416 return false; |
| 411 } | 417 } |
| 412 all_nodes_[node_id].flags &= ~flag; | 418 all_nodes_[node_id].flags &= ~flag; |
| 413 return true; | 419 return true; |
| 414 } | 420 } |
| 415 | 421 |
| 416 template <typename NodeId, typename Priority> | 422 template <typename NodeId, typename Priority> |
| 417 NodeId SpdyPriorityForest<NodeId, Priority>::FirstMarkedNode( | 423 NodeId SpdyPriorityForest<NodeId, Priority>::FirstMarkedNode( |
| 418 unsigned int flag) { | 424 unsigned int flag) { |
| 419 // TODO(mdsteele): This is an *incredibly* stupid brute force solution. | 425 // TODO(mdsteele): This is an *incredibly* stupid brute force solution. |
| 420 | 426 |
| 421 // Get all root nodes that have at least one marked child. | 427 // Get all root nodes that have at least one marked child. |
| 422 uint64 total_weight = 0; | 428 uint64 total_weight = 0; |
| 423 std::map<uint64, NodeId> roots; // maps cumulative weight to root node ID | 429 std::map<uint64, NodeId> roots; // maps cumulative weight to root node ID |
| 424 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); | 430 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); |
| 425 iter != all_nodes_.end(); ++iter) { | 431 iter != all_nodes_.end(); |
| 432 ++iter) { |
| 426 const NodeId root_id = iter->first; | 433 const NodeId root_id = iter->first; |
| 427 const Node& root = iter->second; | 434 const Node& root = iter->second; |
| 428 if (root.type == ROOT_NODE) { | 435 if (root.type == ROOT_NODE) { |
| 429 // See if there is at least one marked node in this root's chain. | 436 // See if there is at least one marked node in this root's chain. |
| 430 for (const Node* node = &root; ; node = &all_nodes_[node->child]) { | 437 for (const Node* node = &root;; node = &all_nodes_[node->child]) { |
| 431 if ((node->flags & flag) != 0) { | 438 if ((node->flags & flag) != 0) { |
| 432 total_weight += static_cast<uint64>(root.depends_on.priority); | 439 total_weight += static_cast<uint64>(root.depends_on.priority); |
| 433 roots[total_weight] = root_id; | 440 roots[total_weight] = root_id; |
| 434 break; | 441 break; |
| 435 } | 442 } |
| 436 if (node->child == NodeId()) { | 443 if (node->child == NodeId()) { |
| 437 break; | 444 break; |
| 438 } | 445 } |
| 439 DCHECK(NodeExists(node->child)); | 446 DCHECK(NodeExists(node->child)); |
| 440 } | 447 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 460 while (true) { | 467 while (true) { |
| 461 DCHECK(NodeExists(node_id)); | 468 DCHECK(NodeExists(node_id)); |
| 462 Node* node = &all_nodes_[node_id]; | 469 Node* node = &all_nodes_[node_id]; |
| 463 if ((node->flags & flag) != 0) { | 470 if ((node->flags & flag) != 0) { |
| 464 // There might be more nodes that are ready and that are linked to this | 471 // There might be more nodes that are ready and that are linked to this |
| 465 // one in an unordered chain. Find all of them, then pick one randomly. | 472 // one in an unordered chain. Find all of them, then pick one randomly. |
| 466 std::vector<NodeId> group; | 473 std::vector<NodeId> group; |
| 467 group.push_back(node_id); | 474 group.push_back(node_id); |
| 468 for (Node* next = node; next->child != NodeId();) { | 475 for (Node* next = node; next->child != NodeId();) { |
| 469 DCHECK(NodeExists(next->child)); | 476 DCHECK(NodeExists(next->child)); |
| 470 Node *child = &all_nodes_[next->child]; | 477 Node* child = &all_nodes_[next->child]; |
| 471 DCHECK_NE(ROOT_NODE, child->type); | 478 DCHECK_NE(ROOT_NODE, child->type); |
| 472 if (child->type != NONROOT_UNORDERED) { | 479 if (child->type != NONROOT_UNORDERED) { |
| 473 break; | 480 break; |
| 474 } | 481 } |
| 475 if ((child->flags & flag) != 0) { | 482 if ((child->flags & flag) != 0) { |
| 476 group.push_back(next->child); | 483 group.push_back(next->child); |
| 477 } | 484 } |
| 478 next = child; | 485 next = child; |
| 479 } | 486 } |
| 480 return group[base::RandGenerator(group.size())]; | 487 return group[base::RandGenerator(group.size())]; |
| 481 } | 488 } |
| 482 node_id = node->child; | 489 node_id = node->child; |
| 483 } | 490 } |
| 484 } | 491 } |
| 485 | 492 |
| 486 template <typename NodeId, typename Priority> | 493 template <typename NodeId, typename Priority> |
| 487 const typename SpdyPriorityForest<NodeId, Priority>::Node* | 494 const typename SpdyPriorityForest<NodeId, Priority>::Node* |
| 488 SpdyPriorityForest<NodeId, Priority>::FindNode(NodeId node_id) const { | 495 SpdyPriorityForest<NodeId, Priority>::FindNode(NodeId node_id) const { |
| 489 typename NodeMap::const_iterator iter = all_nodes_.find(node_id); | 496 typename NodeMap::const_iterator iter = all_nodes_.find(node_id); |
| 490 if (iter == all_nodes_.end()) { | 497 if (iter == all_nodes_.end()) { |
| 491 return NULL; | 498 return NULL; |
| 492 } | 499 } |
| 493 return &iter->second; | 500 return &iter->second; |
| 494 } | 501 } |
| 495 | 502 |
| 496 template <typename NodeId, typename Priority> | 503 template <typename NodeId, typename Priority> |
| 497 bool SpdyPriorityForest<NodeId, Priority>::ValidateInvariantsForTests() const { | 504 bool SpdyPriorityForest<NodeId, Priority>::ValidateInvariantsForTests() const { |
| 498 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); | 505 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); |
| 499 iter != all_nodes_.end(); ++iter) { | 506 iter != all_nodes_.end(); |
| 507 ++iter) { |
| 500 const NodeId node_id = iter->first; | 508 const NodeId node_id = iter->first; |
| 501 const Node& node = iter->second; | 509 const Node& node = iter->second; |
| 502 if (node.type != ROOT_NODE && | 510 if (node.type != ROOT_NODE && |
| 503 (!NodeExists(node.depends_on.parent_id) || | 511 (!NodeExists(node.depends_on.parent_id) || |
| 504 GetChild(node.depends_on.parent_id) != node_id)) { | 512 GetChild(node.depends_on.parent_id) != node_id)) { |
| 505 return false; | 513 return false; |
| 506 } | 514 } |
| 507 if (node.child != NodeId()) { | 515 if (node.child != NodeId()) { |
| 508 if (!NodeExists(node.child) || node_id != GetParent(node.child)) { | 516 if (!NodeExists(node.child) || node_id != GetParent(node.child)) { |
| 509 return false; | 517 return false; |
| 510 } | 518 } |
| 511 } | 519 } |
| 512 | 520 |
| 513 NodeId child_id = node.child; | 521 NodeId child_id = node.child; |
| 514 int count = 0; | 522 int count = 0; |
| 515 while (child_id != NodeId()) { | 523 while (child_id != NodeId()) { |
| 516 if (count > num_nodes() || node_id == child_id) { | 524 if (count > num_nodes() || node_id == child_id) { |
| 517 return false; | 525 return false; |
| 518 } | 526 } |
| 519 child_id = GetChild(child_id); | 527 child_id = GetChild(child_id); |
| 520 ++count; | 528 ++count; |
| 521 } | 529 } |
| 522 } | 530 } |
| 523 return true; | 531 return true; |
| 524 } | 532 } |
| 525 | 533 |
| 526 } // namespace net | 534 } // namespace net |
| 527 | 535 |
| 528 #endif // NET_SPDY_SPDY_PRIORITY_FOREST_H_ | 536 #endif // NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
| OLD | NEW |