910e62b5创建于 1月15日历史提交
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GPU_COMMAND_BUFFER_SERVICE_CLIENT_SERVICE_MAP_H_
#define GPU_COMMAND_BUFFER_SERVICE_CLIENT_SERVICE_MAP_H_

#include <limits>
#include <unordered_map>
#include <vector>

#include "base/check.h"

namespace gpu {

namespace gles2 {

template <typename ClientType, typename ServiceType>
class ClientServiceMap {
 public:
  ClientServiceMap()
      : ClientServiceMap(std::numeric_limits<ServiceType>::max()) {}
  explicit ClientServiceMap(ServiceType invalid_service_id)
      : invalid_service_id_(invalid_service_id),
        client_to_service_array_(kInitialFlatArraySize, invalid_service_id),
        client_to_service_map_() {}

  void SetIDMapping(ClientType client_id, ServiceType service_id) {
    DCHECK(service_id != invalid_service_id());
    if (client_id < kMaxFlatArraySize) {
      if (client_id >= client_to_service_array_.size()) {
        // Resize the array to the next power of 2 above client_id
        size_t new_size = client_to_service_array_.size();
        while (client_id >= new_size) {
          new_size *= 2;
        }
        DCHECK(new_size <= kMaxFlatArraySize);
        client_to_service_array_.resize(new_size, invalid_service_id());
      }
      DCHECK(client_to_service_array_[client_id] == invalid_service_id());
      client_to_service_array_[client_id] = service_id;
    } else {
      DCHECK(client_to_service_map_.count(client_id) == 0);
      client_to_service_map_[client_id] = service_id;
    }
  }

  void RemoveClientID(ClientType client_id) {
    if (client_id < kMaxFlatArraySize) {
      if (client_id < client_to_service_array_.size()) {
        client_to_service_array_[client_id] = invalid_service_id();
      }
    } else {
      client_to_service_map_.erase(client_id);
    }
  }

  void Clear() {
    client_to_service_array_.clear();
    client_to_service_array_.resize(kInitialFlatArraySize,
                                    invalid_service_id());
    client_to_service_map_.clear();
  }

  ALWAYS_INLINE bool GetServiceID(ClientType client_id,
                                  ServiceType* service_id) const {
    DCHECK(service_id);
    if (client_id >= kMaxFlatArraySize) {
      return GetServiceIDFromMap(client_id, service_id);
    }

    if (client_id < client_to_service_array_.size() &&
        client_to_service_array_[client_id] != invalid_service_id()) {
      *service_id = client_to_service_array_[client_id];
      return true;
    }
    if (client_id == 0) {
      *service_id = ServiceType{};
      return true;
    }
    return false;
  }

  ALWAYS_INLINE bool HasClientID(ClientType client_id) const {
    if (client_id >= kMaxFlatArraySize) {
      return GetServiceIDFromMap(client_id, nullptr);
    }

    return client_id == 0 ||
           (client_id < client_to_service_array_.size() &&
            client_to_service_array_[client_id] != invalid_service_id());
  }

  ServiceType GetServiceIDOrInvalid(ClientType client_id) {
    ServiceType service_id;
    if (GetServiceID(client_id, &service_id)) {
      return service_id;
    }
    return invalid_service_id();
  }

  bool GetClientID(ServiceType service_id, ClientType* client_id) const {
    DCHECK(service_id != invalid_service_id());
    for (size_t client_id_idx = 0;
         client_id_idx < client_to_service_array_.size(); client_id_idx++) {
      if (client_to_service_array_[client_id_idx] == service_id) {
        if (client_id) {
          *client_id = client_id_idx;
        }
        return true;
      }
    }
    for (const auto& mapping : client_to_service_map_) {
      if (mapping.second == service_id) {
        if (client_id) {
          *client_id = mapping.first;
        }
        return true;
      }
    }
    if (service_id == 0) {
      *client_id = 0;
    }
    return false;
  }

  const ServiceType& invalid_service_id() const { return invalid_service_id_; }

  template <typename FunctionType>
  void ForEach(FunctionType func) const {
    for (size_t client_id_idx = 0;
         client_id_idx < client_to_service_array_.size(); client_id_idx++) {
      if (client_to_service_array_[client_id_idx] != invalid_service_id()) {
        func(client_id_idx, client_to_service_array_[client_id_idx]);
      }
    }
    for (const auto& mapping : client_to_service_map_) {
      func(mapping.first, mapping.second);
    }
  }

  // Start with 32 maximum elements in the map, which can grow.
  static constexpr size_t kInitialFlatArraySize = 0x20;

  // Experimental testing suggests that 16k is a reasonable upper limit.
  static constexpr size_t kMaxFlatArraySize = 0x4000;

 private:
  bool GetServiceIDFromMap(ClientType client_id,
                           ServiceType* service_id) const {
    DCHECK(client_id >= kMaxFlatArraySize);
    auto iter = client_to_service_map_.find(client_id);
    if (iter != client_to_service_map_.end()) {
      if (service_id) {
        *service_id = iter->second;
      }
      return true;
    }
    return false;
  }

  ServiceType invalid_service_id_;
  std::vector<ServiceType> client_to_service_array_;
  std::unordered_map<ClientType, ServiceType> client_to_service_map_;
};

}  // namespace gles2
}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_SERVICE_CLIENT_SERVICE_MAP_H_