bool Timer::add(Event* e, int id, int64_t cycle, void* param) { const intptr_t key((intptr_t)e); auto ib = m_clients.find(key); if ( ib == m_clients.end() ) { auto res = m_clients.insert(client_cont::value_type(key, event_cont())); if ( res.second == false ) { PWLOGLIB("failed to insert timer event: e:%p id:%d cycle:%jd param:%p", e, id, intmax_t(cycle), param); return false; } event_cont& ec(res.first->second); // 이후 코드는 insert 성공 여부와 상관 없이 반복자가 무효하다. invalidateIterator(); if ( false == ec.insert(event_cont::value_type(id, event_type(param, cycle, s_getNow()))).second ) { PWLOGLIB("failed to insert timer event: e:%p id:%d cycle:%jd param:%p", e, id, intmax_t(cycle), param); m_clients.erase(ib); return false; } //PWTRACE("add new timer event: e:%p type:%s id:%d cycle:%jdms", e, typeid(*e).name(), id, cycle); return true; } auto& ec = ib->second; auto ib_event = ec.find(id); if ( ec.end() == ib_event ) { if ( false == ec.insert(event_cont::value_type(id, event_type(param, cycle, s_getNow()))).second ) { PWLOGLIB("failed to insert timer event: e:%p id:%d cycle:%jd param:%p", e, id, intmax_t(cycle), param); return false; } invalidateIterator(); //PWTRACE("add new timer event: e:%p type:%s id:%d cycle:%jdms", e, typeid(*e).name(), id, cycle); return true; } // 반복자를 건들지 않았으므로 invalidateIterator를 호출하지 않는다. auto& et = ib_event->second; et.param = param; et.cycle = cycle; et.start = s_getNow(); //PWTRACE("add new timer event: e:%p type:%s id:%d cycle:%jdms", e, typeid(*e).name(), id, cycle); return true; }
PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue) { ASSERT(!value.isNull()); // Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects // so if more than one Storage object refs this map, copy it before mutating it. if (refCount() > 1) { RefPtr<StorageMap> newStorageMap = copy(); newStorageMap->setItem(key, value, oldValue); return newStorageMap.release(); } pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value); if (addResult.second) { // There was no "oldValue" so null it out. oldValue = String(); } else { oldValue = addResult.first->second; addResult.first->second = value; } invalidateIterator(); return 0; }
PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValue) { // Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects // so if more than one Storage object refs this map, copy it before mutating it. if (refCount() > 1) { RefPtr<StorageMap> newStorage = copy(); newStorage->removeItem(key, oldValue); return newStorage.release(); } oldValue = m_map.take(key); if (!oldValue.isNull()) invalidateIterator(); return 0; }
void Timer::remove(Event* e, int id) { const auto key(reinterpret_cast<intptr_t>(e)); auto ib(m_clients.find(key)); if ( ib == m_clients.end() ) return; auto& ec(ib->second); do { auto ib_event(ec.find(id)); if ( ib_event == ec.end() ) return; ec.erase(ib_event); if ( ec.empty() ) m_clients.erase(ib); } while (false); invalidateIterator(); }
PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue, bool& quotaException) { ASSERT(!value.isNull()); quotaException = false; // Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects // so if more than one Storage object refs this map, copy it before mutating it. if (refCount() > 1) { RefPtr<StorageMap> newStorageMap = copy(); newStorageMap->setItem(key, value, oldValue, quotaException); return newStorageMap.release(); } // Quota tracking. This is done in a couple of steps to keep the overflow tracking simple. unsigned newLength = m_currentLength; bool overflow = newLength + value.length() < newLength; newLength += value.length(); oldValue = m_map.get(key); overflow |= newLength - oldValue.length() > newLength; newLength -= oldValue.length(); unsigned adjustedKeyLength = oldValue.isNull() ? key.length() : 0; overflow |= newLength + adjustedKeyLength < newLength; newLength += adjustedKeyLength; ASSERT(!overflow); // Overflow is bad...even if quotas are off. bool overQuota = newLength > m_quotaSize / sizeof(UChar); if (m_quotaSize != noQuota && (overflow || overQuota)) { quotaException = true; return 0; } m_currentLength = newLength; HashMap<String, String>::AddResult addResult = m_map.add(key, value); if (!addResult.isNewEntry) addResult.iterator->value = value; invalidateIterator(); return 0; }
bool MultiMap::Iterator::next() { if (!valid()) return false; while (m_ptrToNode != nullptr) { // check is cur->duplicate counter is greater than 0 // if it is, check where this (next or prev) function last left off if (m_ptrToNode->duplicateTotal > 0) { if (m_ptrToNodeList->next != nullptr) { m_ptrToNodeList = m_ptrToNodeList->next; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } // Check non nullptr right child if (m_ptrToNode->right != nullptr) { m_ptrToNode = m_ptrToNode->right; // Now check for left children if (m_ptrToNode->left == nullptr) { m_ptrToNodeList = m_ptrToNode->val; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } else { while (m_ptrToNode->left != nullptr) m_ptrToNode = m_ptrToNode->left; m_ptrToNodeList = m_ptrToNode->val; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } // If right child nullptr, check parent (loop up through parents) if (m_ptrToNode->right == nullptr) { std::string tempKey = m_ptrToNode->key; while (m_ptrToNode->parent != nullptr) { m_ptrToNode = m_ptrToNode->parent; if (m_ptrToNode->key > tempKey) { m_ptrToNodeList = m_ptrToNode->val; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } // Invalidates iterator to prevent undefined behavior invalidateIterator(); return false; } } invalidateIterator(); return false; }
bool MultiMap::Iterator::prev() { if (!valid()) return false; while (m_ptrToNode != nullptr) { // First check for duplicate values beginning from current tail pointer if (m_ptrToNode->duplicateTotal > 0) { if (m_ptrToNodeList->prev != nullptr) { m_ptrToNodeList = m_ptrToNodeList->prev; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } // If left child is not nullptr go down that branch // and check if that child has a right child if (m_ptrToNode->left != nullptr) { m_ptrToNode = m_ptrToNode->left; // If that child has a right child, loop down the right child branch // until we hit a nullptr if (m_ptrToNode->right != nullptr) { while (m_ptrToNode->right != nullptr) m_ptrToNode = m_ptrToNode->right; m_ptrToNodeList = m_ptrToNode->tail; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } // Otherwise if right child is nullptr, we are at the right (prev) spot else { m_ptrToNodeList = m_ptrToNode->tail; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } // If left child IS a nullptr, loop through parents until we find // the first node that is less than the current key or until // we hit a parent nullptr (return false in this case) if (m_ptrToNode->left == nullptr) { std::string tempKey = m_ptrToNode->key; while (m_ptrToNode->parent != nullptr) { m_ptrToNode = m_ptrToNode->parent; if (m_ptrToNode->key < tempKey) { m_ptrToNodeList = m_ptrToNode->tail; m_currentDuplicateValue = m_ptrToNodeList->value; return true; } } invalidateIterator(); return false; } } invalidateIterator(); return false; }