text: // Copyright 2019 The IREE Authors
  //
  // Licensed under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  
  #ifndef IREE_BINDINGS_PYTHON_IREE_BINDING_H_
  #define IREE_BINDINGS_PYTHON_IREE_BINDING_H_
  
  #include <optional>
  #include <vector>
  
  #include "iree/base/api.h"
  #include "pybind11/pybind11.h"
  #include "pybind11/stl.h"
  
  namespace iree {
  namespace python {
  
  namespace py = pybind11;
  
  template <typename T>
  struct ApiPtrAdapter {};
  
  template <typename Self, typename T>
  class ApiRefCounted {
   public:
    ApiRefCounted() : instance_(nullptr) {}
    ApiRefCounted(ApiRefCounted&& other) : instance_(other.instance_) {
      other.instance_ = nullptr;
    }
    ApiRefCounted& operator=(ApiRefCounted&& other) {
      instance_ = other.instance_;
      other.instance_ = nullptr;
      return *this;
    }
    void operator=(const ApiRefCounted&) = delete;
  
    ~ApiRefCounted() { Release(); }
  
    // Steals the reference to the object referenced by the given raw pointer and
    // returns a wrapper (transfers ownership).
    static Self StealFromRawPtr(T* retained_inst) {
      auto self = Self();
      self.instance_ = retained_inst;
      return self;
    }
  
    // Retains the object referenced by the given raw pointer and returns
    // a wrapper.
    static Self BorrowFromRawPtr(T* non_retained_inst) {
      auto self = Self();
      self.instance_ = non_retained_inst;
      if (non_retained_inst) {
        ApiPtrAdapter<T>::Retain(non_retained_inst);
      }
      return self;
    }
  
    // Whether it is nullptr.
    operator bool() const { return instance_; }
  
    T* steal_raw_ptr() {
      T* ret = instance_;
      instance_ = nullptr;
      return ret;
    }
  
    T* raw_ptr() {
      if (!instance_) {
        throw std::invalid_argument("API object is null");
      }
      return instance_;
    }
  
    const T* raw_ptr() const {
      return const_cast<ApiRefCounted*>(this)->raw_ptr();
    }
  
    void Retain() {
      if (instance_) {
        ApiPtrAdapter<T>::Retain(instance_);
      }
    }
    void Release() {
      if (instance_) {
        ApiPtrAdapter<T>::Release(instance_);
      }
    }
  
   private:
    T* instance_;
  };
  
  }  // namespace python
  }  // namespace iree
  
  #endif  // IREE_BINDINGS_PYTHON_IREE_BINDING_H_
  