Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | // Copyright 2010 Google Inc. All Rights Reserved. |
michael@0 | 2 | // |
michael@0 | 3 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 4 | // modification, are permitted provided that the following conditions are |
michael@0 | 5 | // met: |
michael@0 | 6 | // |
michael@0 | 7 | // * Redistributions of source code must retain the above copyright |
michael@0 | 8 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 9 | // * Redistributions in binary form must reproduce the above |
michael@0 | 10 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 11 | // in the documentation and/or other materials provided with the |
michael@0 | 12 | // distribution. |
michael@0 | 13 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 14 | // contributors may be used to endorse or promote products derived from |
michael@0 | 15 | // this software without specific prior written permission. |
michael@0 | 16 | // |
michael@0 | 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 28 | |
michael@0 | 29 | // static_map-inl.h: StaticMap implementation. |
michael@0 | 30 | // |
michael@0 | 31 | // See static_map.h for documentation. |
michael@0 | 32 | // |
michael@0 | 33 | // Author: Siyang Xie (lambxsy@google.com) |
michael@0 | 34 | |
michael@0 | 35 | |
michael@0 | 36 | #ifndef PROCESSOR_STATIC_MAP_INL_H__ |
michael@0 | 37 | #define PROCESSOR_STATIC_MAP_INL_H__ |
michael@0 | 38 | |
michael@0 | 39 | #include "processor/static_map.h" |
michael@0 | 40 | #include "processor/static_map_iterator-inl.h" |
michael@0 | 41 | #include "common/logging.h" |
michael@0 | 42 | |
michael@0 | 43 | namespace google_breakpad { |
michael@0 | 44 | |
michael@0 | 45 | template<typename Key, typename Value, typename Compare> |
michael@0 | 46 | StaticMap<Key, Value, Compare>::StaticMap(const char* raw_data) |
michael@0 | 47 | : raw_data_(raw_data), |
michael@0 | 48 | compare_() { |
michael@0 | 49 | // First 4 Bytes store the number of nodes. |
michael@0 | 50 | num_nodes_ = *(reinterpret_cast<const uint32_t*>(raw_data_)); |
michael@0 | 51 | |
michael@0 | 52 | offsets_ = reinterpret_cast<const uint32_t*>( |
michael@0 | 53 | raw_data_ + sizeof(num_nodes_)); |
michael@0 | 54 | |
michael@0 | 55 | keys_ = reinterpret_cast<const Key*>( |
michael@0 | 56 | raw_data_ + (1 + num_nodes_) * sizeof(uint32_t)); |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | // find(), lower_bound() and upper_bound() implement binary search algorithm. |
michael@0 | 60 | template<typename Key, typename Value, typename Compare> |
michael@0 | 61 | StaticMapIterator<Key, Value, Compare> |
michael@0 | 62 | StaticMap<Key, Value, Compare>::find(const Key &key) const { |
michael@0 | 63 | int begin = 0; |
michael@0 | 64 | int end = num_nodes_; |
michael@0 | 65 | int middle; |
michael@0 | 66 | int compare_result; |
michael@0 | 67 | while (begin < end) { |
michael@0 | 68 | middle = begin + (end - begin) / 2; |
michael@0 | 69 | compare_result = compare_(key, GetKeyAtIndex(middle)); |
michael@0 | 70 | if (compare_result == 0) |
michael@0 | 71 | return IteratorAtIndex(middle); |
michael@0 | 72 | if (compare_result < 0) { |
michael@0 | 73 | end = middle; |
michael@0 | 74 | } else { |
michael@0 | 75 | begin = middle + 1; |
michael@0 | 76 | } |
michael@0 | 77 | } |
michael@0 | 78 | return this->end(); |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | template<typename Key, typename Value, typename Compare> |
michael@0 | 82 | StaticMapIterator<Key, Value, Compare> |
michael@0 | 83 | StaticMap<Key, Value, Compare>::lower_bound(const Key &key) const { |
michael@0 | 84 | int begin = 0; |
michael@0 | 85 | int end = num_nodes_; |
michael@0 | 86 | int middle; |
michael@0 | 87 | int comp_result; |
michael@0 | 88 | while (begin < end) { |
michael@0 | 89 | middle = begin + (end - begin) / 2; |
michael@0 | 90 | comp_result = compare_(key, GetKeyAtIndex(middle)); |
michael@0 | 91 | if (comp_result == 0) |
michael@0 | 92 | return IteratorAtIndex(middle); |
michael@0 | 93 | if (comp_result < 0) { |
michael@0 | 94 | end = middle; |
michael@0 | 95 | } else { |
michael@0 | 96 | begin = middle + 1; |
michael@0 | 97 | } |
michael@0 | 98 | } |
michael@0 | 99 | return IteratorAtIndex(begin); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | template<typename Key, typename Value, typename Compare> |
michael@0 | 103 | StaticMapIterator<Key, Value, Compare> |
michael@0 | 104 | StaticMap<Key, Value, Compare>::upper_bound(const Key &key) const { |
michael@0 | 105 | int begin = 0; |
michael@0 | 106 | int end = num_nodes_; |
michael@0 | 107 | int middle; |
michael@0 | 108 | int compare_result; |
michael@0 | 109 | while (begin < end) { |
michael@0 | 110 | middle = begin + (end - begin) / 2; |
michael@0 | 111 | compare_result = compare_(key, GetKeyAtIndex(middle)); |
michael@0 | 112 | if (compare_result == 0) |
michael@0 | 113 | return IteratorAtIndex(middle + 1); |
michael@0 | 114 | if (compare_result < 0) { |
michael@0 | 115 | end = middle; |
michael@0 | 116 | } else { |
michael@0 | 117 | begin = middle + 1; |
michael@0 | 118 | } |
michael@0 | 119 | } |
michael@0 | 120 | return IteratorAtIndex(begin); |
michael@0 | 121 | } |
michael@0 | 122 | |
michael@0 | 123 | template<typename Key, typename Value, typename Compare> |
michael@0 | 124 | bool StaticMap<Key, Value, Compare>::ValidateInMemoryStructure() const { |
michael@0 | 125 | // check the number of nodes is non-negative: |
michael@0 | 126 | if (!raw_data_) return false; |
michael@0 | 127 | int32_t num_nodes = *(reinterpret_cast<const int32_t*>(raw_data_)); |
michael@0 | 128 | if (num_nodes < 0) { |
michael@0 | 129 | BPLOG(INFO) << "StaticMap check failed: negative number of nodes"; |
michael@0 | 130 | return false; |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | int node_index = 0; |
michael@0 | 134 | if (num_nodes_) { |
michael@0 | 135 | uint64_t first_offset = sizeof(int32_t) * (num_nodes_ + 1) |
michael@0 | 136 | + sizeof(Key) * num_nodes_; |
michael@0 | 137 | // Num_nodes_ is too large. |
michael@0 | 138 | if (first_offset > 0xffffffffUL) { |
michael@0 | 139 | BPLOG(INFO) << "StaticMap check failed: size exceeds limit"; |
michael@0 | 140 | return false; |
michael@0 | 141 | } |
michael@0 | 142 | if (offsets_[node_index] != static_cast<uint32_t>(first_offset)) { |
michael@0 | 143 | BPLOG(INFO) << "StaticMap check failed: first node offset is incorrect"; |
michael@0 | 144 | return false; |
michael@0 | 145 | } |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | for (node_index = 1; node_index < num_nodes_; ++node_index) { |
michael@0 | 149 | // Check offsets[i] is strictly increasing: |
michael@0 | 150 | if (offsets_[node_index] <= offsets_[node_index - 1]) { |
michael@0 | 151 | BPLOG(INFO) << "StaticMap check failed: node offsets non-increasing"; |
michael@0 | 152 | return false; |
michael@0 | 153 | } |
michael@0 | 154 | // Check Key[i] is strictly increasing as no duplicate keys are allowed. |
michael@0 | 155 | if (compare_(GetKeyAtIndex(node_index), |
michael@0 | 156 | GetKeyAtIndex(node_index - 1)) <= 0) { |
michael@0 | 157 | BPLOG(INFO) << "StaticMap check failed: node keys non-increasing"; |
michael@0 | 158 | return false; |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | return true; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | template<typename Key, typename Value, typename Compare> |
michael@0 | 165 | const Key StaticMap<Key, Value, Compare>::GetKeyAtIndex(int index) const { |
michael@0 | 166 | if (index < 0 || index >= num_nodes_) { |
michael@0 | 167 | BPLOG(ERROR) << "Key index out of range error"; |
michael@0 | 168 | // Key type is required to be primitive type. Return 0 if index is invalid. |
michael@0 | 169 | return 0; |
michael@0 | 170 | } |
michael@0 | 171 | return keys_[index]; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | } // namespace google_breakpad |
michael@0 | 175 | |
michael@0 | 176 | #endif // PROCESSOR_STATIC_MAP_INL_H__ |