chromium/native_client_sdk/src/tests/nacl_io_test/fake_ppapi/fake_resource_manager.h

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TESTS_NACL_IO_TEST_FAKE_PPAPI_FAKE_RESOURCE_MANAGER_H_
#define TESTS_NACL_IO_TEST_FAKE_PPAPI_FAKE_RESOURCE_MANAGER_H_

#include <map>

#include <ppapi/c/pp_resource.h>

#include "sdk_util/atomicops.h"
#include "sdk_util/macros.h"
#include "sdk_util/simple_lock.h"

class FakeResource;
class FakeResourceTracker;

class FakeResourceManager {
 public:
  FakeResourceManager();

  FakeResourceManager(const FakeResourceManager&) = delete;
  FakeResourceManager& operator=(const FakeResourceManager&) = delete;

  ~FakeResourceManager();

  PP_Resource Create(FakeResource* resource,
                     const char* classname,
                     const char* file,
                     int line);
  void AddRef(PP_Resource handle);
  void Release(PP_Resource handle);
  template <typename T>
  T* Get(PP_Resource handle, bool not_found_ok=false);

 private:
  FakeResourceTracker* Get(PP_Resource handle, bool not_found_ok);

  typedef std::map<PP_Resource, FakeResourceTracker*> ResourceMap;
  PP_Resource next_handle_;
  ResourceMap resource_map_;
  sdk_util::SimpleLock lock_;  // Protects next_handle_ and resource_map_.
};

// FakeResourceTracker wraps a FakeResource to keep metadata about the
// resource, including its refcount, the type of resource, etc.
class FakeResourceTracker {
 public:
  FakeResourceTracker(FakeResource* resource,
                      const char* classname,
                      const char* file,
                      int line);

  FakeResourceTracker(const FakeResourceTracker&) = delete;
  FakeResourceTracker& operator=(const FakeResourceTracker&) = delete;

  ~FakeResourceTracker();

  void AddRef() { sdk_util::AtomicAddFetch(&ref_count_, 1); }
  void Release() { sdk_util::AtomicAddFetch(&ref_count_, -1); }
  int32_t ref_count() const { return ref_count_; }

  // Give up ownership of this resource. It is the responsibility of the caller
  // to delete this FakeResource.
  FakeResource* Pass() {
    FakeResource* result = resource_;
    resource_ = NULL;
    return result;
  }

  template <typename T>
  T* resource() {
    if (!CheckType(T::classname()))
      return NULL;

    return static_cast<T*>(resource_);
  }

  FakeResource* resource() { return resource_; }

  const char* classname() const { return classname_; }
  const char* file() const { return file_; }
  int line() const { return line_; }

 private:
  bool CheckType(const char* classname) const;

  FakeResource* resource_;  // Owned.
  const char* classname_;   // Weak reference.
  const char* file_;        // Weak reference.
  int line_;
  int32_t ref_count_;
};

class FakeResource {
 public:
  FakeResource() {}

  FakeResource(const FakeResource&) = delete;
  FakeResource& operator=(const FakeResource&) = delete;

  // Called when the resource is destroyed. For debugging purposes, this does
  // not happen until the resource manager is destroyed.
  virtual ~FakeResource() {}
  // Called when the last reference to the resource is released.
  virtual void Destroy() {}
};

template <typename T>
inline T* FakeResourceManager::Get(PP_Resource handle, bool not_found_ok) {
  FakeResourceTracker* tracker = Get(handle, not_found_ok);
  if (!tracker)
    return NULL;
  return tracker->resource<T>();
}

#define CREATE_RESOURCE(MANAGER, TYPE, RESOURCE) \
  (MANAGER)->Create((RESOURCE), #TYPE, __FILE__, __LINE__)

#endif  // TESTS_NACL_IO_TEST_FAKE_PPAPI_FAKE_RESOURCE_MANAGER_H_