<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/opencl_wrapper.h"

#include <dlfcn.h>

#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {

#define LoadFunction(function)                                                 \
  if (is_pixel) {                                                              \
    function = reinterpret_cast<PFN_##function>(loadOpenCLPointer(#function)); \
  } else {                                                                     \
    function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));  \
  }

absl::Status LoadOpenCL() {
  void* libopencl = dlopen("libOpenCL.so", RTLD_NOW | RTLD_LOCAL);
  if (libopencl) {
    LoadOpenCLFunctions(libopencl, false);
    return absl::OkStatus();
  } else {
    // Pixel phone?
    libopencl = dlopen("libOpenCL-pixel.so", RTLD_NOW | RTLD_LOCAL);
    if (libopencl) {
      typedef void (*enableOpenCL_t)();
      enableOpenCL_t enableOpenCL =
          reinterpret_cast<enableOpenCL_t>(dlsym(libopencl, "enableOpenCL"));
      enableOpenCL();
      LoadOpenCLFunctions(libopencl, true);
      return absl::OkStatus();
    } else {
      return absl::UnknownError(
          absl::StrCat("OpenCL library not loaded - ", dlerror()));
    }
  }
}

void LoadOpenCLFunctions(void* libopencl, bool is_pixel) {
  typedef void* (*loadOpenCLPointer_t)(const char* name);
  loadOpenCLPointer_t loadOpenCLPointer;
  if (is_pixel) {
    loadOpenCLPointer = reinterpret_cast<loadOpenCLPointer_t>(
        dlsym(libopencl, "loadOpenCLPointer"));
  }

  LoadFunction(clGetPlatformIDs);
  LoadFunction(clGetPlatformInfo);
  LoadFunction(clGetDeviceIDs);
  LoadFunction(clGetDeviceInfo);
  LoadFunction(clCreateSubDevices);
  LoadFunction(clRetainDevice);
  LoadFunction(clReleaseDevice);
  LoadFunction(clCreateContext);
  LoadFunction(clCreateContextFromType);
  LoadFunction(clRetainContext);
  LoadFunction(clReleaseContext);
  LoadFunction(clGetContextInfo);
  LoadFunction(clCreateCommandQueueWithProperties);
  LoadFunction(clRetainCommandQueue);
  LoadFunction(clReleaseCommandQueue);
  LoadFunction(clGetCommandQueueInfo);
  LoadFunction(clCreateBuffer);
  LoadFunction(clCreateSubBuffer);
  LoadFunction(clCreateImage);
  LoadFunction(clCreatePipe);
  LoadFunction(clRetainMemObject);
  LoadFunction(clReleaseMemObject);
  LoadFunction(clGetSupportedImageFormats);
  LoadFunction(clGetMemObjectInfo);
  LoadFunction(clGetImageInfo);
  LoadFunction(clGetPipeInfo);
  LoadFunction(clSetMemObjectDestructorCallback);
  LoadFunction(clSVMAlloc);
  LoadFunction(clSVMFree);
  LoadFunction(clCreateSamplerWithProperties);
  LoadFunction(clRetainSampler);
  LoadFunction(clReleaseSampler);
  LoadFunction(clGetSamplerInfo);
  LoadFunction(clCreateProgramWithSource);
  LoadFunction(clCreateProgramWithBinary);
  LoadFunction(clCreateProgramWithBuiltInKernels);
  LoadFunction(clRetainProgram);
  LoadFunction(clReleaseProgram);
  LoadFunction(clBuildProgram);
  LoadFunction(clCompileProgram);
  LoadFunction(clLinkProgram);
  LoadFunction(clUnloadPlatformCompiler);
  LoadFunction(clGetProgramInfo);
  LoadFunction(clGetProgramBuildInfo);
  LoadFunction(clCreateKernel);
  LoadFunction(clCreateKernelsInProgram);
  LoadFunction(clRetainKernel);
  LoadFunction(clReleaseKernel);
  LoadFunction(clSetKernelArg);
  LoadFunction(clSetKernelArgSVMPointer);
  LoadFunction(clSetKernelExecInfo);
  LoadFunction(clGetKernelInfo);
  LoadFunction(clGetKernelArgInfo);
  LoadFunction(clGetKernelWorkGroupInfo);
  LoadFunction(clWaitForEvents);
  LoadFunction(clGetEventInfo);
  LoadFunction(clCreateUserEvent);
  LoadFunction(clRetainEvent);
  LoadFunction(clReleaseEvent);
  LoadFunction(clSetUserEventStatus);
  LoadFunction(clSetEventCallback);
  LoadFunction(clGetEventProfilingInfo);
  LoadFunction(clFlush);
  LoadFunction(clFinish);
  LoadFunction(clEnqueueReadBuffer);
  LoadFunction(clEnqueueReadBufferRect);
  LoadFunction(clEnqueueWriteBuffer);
  LoadFunction(clEnqueueWriteBufferRect);
  LoadFunction(clEnqueueFillBuffer);
  LoadFunction(clEnqueueCopyBuffer);
  LoadFunction(clEnqueueCopyBufferRect);
  LoadFunction(clEnqueueReadImage);
  LoadFunction(clEnqueueWriteImage);
  LoadFunction(clEnqueueFillImage);
  LoadFunction(clEnqueueCopyImage);
  LoadFunction(clEnqueueCopyImageToBuffer);
  LoadFunction(clEnqueueCopyBufferToImage);
  LoadFunction(clEnqueueMapBuffer);
  LoadFunction(clEnqueueMapImage);
  LoadFunction(clEnqueueUnmapMemObject);
  LoadFunction(clEnqueueMigrateMemObjects);
  LoadFunction(clEnqueueNDRangeKernel);
  LoadFunction(clEnqueueNativeKernel);
  LoadFunction(clEnqueueMarkerWithWaitList);
  LoadFunction(clEnqueueBarrierWithWaitList);
  LoadFunction(clEnqueueSVMFree);
  LoadFunction(clEnqueueSVMMemcpy);
  LoadFunction(clEnqueueSVMMemFill);
  LoadFunction(clEnqueueSVMMap);
  LoadFunction(clEnqueueSVMUnmap);
  LoadFunction(clGetExtensionFunctionAddressForPlatform);
  LoadFunction(clCreateImage2D);
  LoadFunction(clCreateImage3D);
  LoadFunction(clEnqueueMarker);
  LoadFunction(clEnqueueWaitForEvents);
  LoadFunction(clEnqueueBarrier);
  LoadFunction(clUnloadCompiler);
  LoadFunction(clGetExtensionFunctionAddress);
  LoadFunction(clCreateCommandQueue);
  LoadFunction(clCreateSampler);
  LoadFunction(clEnqueueTask);

  // OpenGL sharing
  LoadFunction(clCreateFromGLBuffer);
  LoadFunction(clCreateFromGLTexture);
  LoadFunction(clEnqueueAcquireGLObjects);
  LoadFunction(clEnqueueReleaseGLObjects);

  // cl_khr_egl_event extension
  LoadFunction(clCreateEventFromEGLSyncKHR);

  // EGL sharing
  LoadFunction(clCreateFromEGLImageKHR);
  LoadFunction(clEnqueueAcquireEGLObjectsKHR);
  LoadFunction(clEnqueueReleaseEGLObjectsKHR);
}

// No OpenCL support, do not set function addresses
PFN_clGetPlatformIDs clGetPlatformIDs;
PFN_clGetPlatformInfo clGetPlatformInfo;
PFN_clGetDeviceIDs clGetDeviceIDs;
PFN_clGetDeviceInfo clGetDeviceInfo;
PFN_clCreateSubDevices clCreateSubDevices;
PFN_clRetainDevice clRetainDevice;
PFN_clReleaseDevice clReleaseDevice;
PFN_clCreateContext clCreateContext;
PFN_clCreateContextFromType clCreateContextFromType;
PFN_clRetainContext clRetainContext;
PFN_clReleaseContext clReleaseContext;
PFN_clGetContextInfo clGetContextInfo;
PFN_clCreateCommandQueueWithProperties clCreateCommandQueueWithProperties;
PFN_clRetainCommandQueue clRetainCommandQueue;
PFN_clReleaseCommandQueue clReleaseCommandQueue;
PFN_clGetCommandQueueInfo clGetCommandQueueInfo;
PFN_clCreateBuffer clCreateBuffer;
PFN_clCreateSubBuffer clCreateSubBuffer;
PFN_clCreateImage clCreateImage;
PFN_clCreatePipe clCreatePipe;
PFN_clRetainMemObject clRetainMemObject;
PFN_clReleaseMemObject clReleaseMemObject;
PFN_clGetSupportedImageFormats clGetSupportedImageFormats;
PFN_clGetMemObjectInfo clGetMemObjectInfo;
PFN_clGetImageInfo clGetImageInfo;
PFN_clGetPipeInfo clGetPipeInfo;
PFN_clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback;
PFN_clSVMAlloc clSVMAlloc;
PFN_clSVMFree clSVMFree;
PFN_clCreateSamplerWithProperties clCreateSamplerWithProperties;
PFN_clRetainSampler clRetainSampler;
PFN_clReleaseSampler clReleaseSampler;
PFN_clGetSamplerInfo clGetSamplerInfo;
PFN_clCreateProgramWithSource clCreateProgramWithSource;
PFN_clCreateProgramWithBinary clCreateProgramWithBinary;
PFN_clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels;
PFN_clRetainProgram clRetainProgram;
PFN_clReleaseProgram clReleaseProgram;
PFN_clBuildProgram clBuildProgram;
PFN_clCompileProgram clCompileProgram;
PFN_clLinkProgram clLinkProgram;
PFN_clUnloadPlatformCompiler clUnloadPlatformCompiler;
PFN_clGetProgramInfo clGetProgramInfo;
PFN_clGetProgramBuildInfo clGetProgramBuildInfo;
PFN_clCreateKernel clCreateKernel;
PFN_clCreateKernelsInProgram clCreateKernelsInProgram;
PFN_clRetainKernel clRetainKernel;
PFN_clReleaseKernel clReleaseKernel;
PFN_clSetKernelArg clSetKernelArg;
PFN_clSetKernelArgSVMPointer clSetKernelArgSVMPointer;
PFN_clSetKernelExecInfo clSetKernelExecInfo;
PFN_clGetKernelInfo clGetKernelInfo;
PFN_clGetKernelArgInfo clGetKernelArgInfo;
PFN_clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo;
PFN_clWaitForEvents clWaitForEvents;
PFN_clGetEventInfo clGetEventInfo;
PFN_clCreateUserEvent clCreateUserEvent;
PFN_clRetainEvent clRetainEvent;
PFN_clReleaseEvent clReleaseEvent;
PFN_clSetUserEventStatus clSetUserEventStatus;
PFN_clSetEventCallback clSetEventCallback;
PFN_clGetEventProfilingInfo clGetEventProfilingInfo;
PFN_clFlush clFlush;
PFN_clFinish clFinish;
PFN_clEnqueueReadBuffer clEnqueueReadBuffer;
PFN_clEnqueueReadBufferRect clEnqueueReadBufferRect;
PFN_clEnqueueWriteBuffer clEnqueueWriteBuffer;
PFN_clEnqueueWriteBufferRect clEnqueueWriteBufferRect;
PFN_clEnqueueFillBuffer clEnqueueFillBuffer;
PFN_clEnqueueCopyBuffer clEnqueueCopyBuffer;
PFN_clEnqueueCopyBufferRect clEnqueueCopyBufferRect;
PFN_clEnqueueReadImage clEnqueueReadImage;
PFN_clEnqueueWriteImage clEnqueueWriteImage;
PFN_clEnqueueFillImage clEnqueueFillImage;
PFN_clEnqueueCopyImage clEnqueueCopyImage;
PFN_clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer;
PFN_clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage;
PFN_clEnqueueMapBuffer clEnqueueMapBuffer;
PFN_clEnqueueMapImage clEnqueueMapImage;
PFN_clEnqueueUnmapMemObject clEnqueueUnmapMemObject;
PFN_clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects;
PFN_clEnqueueNDRangeKernel clEnqueueNDRangeKernel;
PFN_clEnqueueNativeKernel clEnqueueNativeKernel;
PFN_clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList;
PFN_clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList;
PFN_clEnqueueSVMFree clEnqueueSVMFree;
PFN_clEnqueueSVMMemcpy clEnqueueSVMMemcpy;
PFN_clEnqueueSVMMemFill clEnqueueSVMMemFill;
PFN_clEnqueueSVMMap clEnqueueSVMMap;
PFN_clEnqueueSVMUnmap clEnqueueSVMUnmap;
PFN_clGetExtensionFunctionAddressForPlatform
    clGetExtensionFunctionAddressForPlatform;
PFN_clCreateImage2D clCreateImage2D;
PFN_clCreateImage3D clCreateImage3D;
PFN_clEnqueueMarker clEnqueueMarker;
PFN_clEnqueueWaitForEvents clEnqueueWaitForEvents;
PFN_clEnqueueBarrier clEnqueueBarrier;
PFN_clUnloadCompiler clUnloadCompiler;
PFN_clGetExtensionFunctionAddress clGetExtensionFunctionAddress;
PFN_clCreateCommandQueue clCreateCommandQueue;
PFN_clCreateSampler clCreateSampler;
PFN_clEnqueueTask clEnqueueTask;

// OpenGL sharing
PFN_clCreateFromGLBuffer clCreateFromGLBuffer;
PFN_clCreateFromGLTexture clCreateFromGLTexture;
PFN_clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects;
PFN_clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects;

// cl_khr_egl_event extension
PFN_clCreateEventFromEGLSyncKHR clCreateEventFromEGLSyncKHR;

// EGL sharing
PFN_clCreateFromEGLImageKHR clCreateFromEGLImageKHR;
PFN_clEnqueueAcquireEGLObjectsKHR clEnqueueAcquireEGLObjectsKHR;
PFN_clEnqueueReleaseEGLObjectsKHR clEnqueueReleaseEGLObjectsKHR;

cl_mem CreateImage2DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage2D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_row_pitch, host_ptr, errcode_ret);
  }
}

cl_mem CreateImage3DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage3D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_depth, image_desc->image_row_pitch,
                           image_desc->image_slice_pitch, host_ptr,
                           errcode_ret);
  }
}
}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Removed mentioning of libOpenCL-pixel.so.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/opencl_wrapper.h"

#include <dlfcn.h>

#include <string>

#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {

#define LoadFunction(function)                                                 \
  if (is_pixel) {                                                              \
    function = reinterpret_cast<PFN_##function>(loadOpenCLPointer(#function)); \
  } else {                                                                     \
    function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));  \
  }

absl::Status LoadOpenCL() {
  void* libopencl = dlopen("libOpenCL.so", RTLD_NOW | RTLD_LOCAL);
  if (libopencl) {
    LoadOpenCLFunctions(libopencl, false);
    return absl::OkStatus();
  } else {
    // record error
    std::string error(dlerror());
    // Pixel phone?
    libopencl = dlopen("libOpenCL-pixel.so", RTLD_NOW | RTLD_LOCAL);
    if (libopencl) {
      typedef void (*enableOpenCL_t)();
      enableOpenCL_t enableOpenCL =
          reinterpret_cast<enableOpenCL_t>(dlsym(libopencl, "enableOpenCL"));
      enableOpenCL();
      LoadOpenCLFunctions(libopencl, true);
      return absl::OkStatus();
    } else {
      return absl::UnknownError(
          absl::StrCat("Can not open OpenCL library on this device - ", error));
    }
  }
}

void LoadOpenCLFunctions(void* libopencl, bool is_pixel) {
  typedef void* (*loadOpenCLPointer_t)(const char* name);
  loadOpenCLPointer_t loadOpenCLPointer;
  if (is_pixel) {
    loadOpenCLPointer = reinterpret_cast<loadOpenCLPointer_t>(
        dlsym(libopencl, "loadOpenCLPointer"));
  }

  LoadFunction(clGetPlatformIDs);
  LoadFunction(clGetPlatformInfo);
  LoadFunction(clGetDeviceIDs);
  LoadFunction(clGetDeviceInfo);
  LoadFunction(clCreateSubDevices);
  LoadFunction(clRetainDevice);
  LoadFunction(clReleaseDevice);
  LoadFunction(clCreateContext);
  LoadFunction(clCreateContextFromType);
  LoadFunction(clRetainContext);
  LoadFunction(clReleaseContext);
  LoadFunction(clGetContextInfo);
  LoadFunction(clCreateCommandQueueWithProperties);
  LoadFunction(clRetainCommandQueue);
  LoadFunction(clReleaseCommandQueue);
  LoadFunction(clGetCommandQueueInfo);
  LoadFunction(clCreateBuffer);
  LoadFunction(clCreateSubBuffer);
  LoadFunction(clCreateImage);
  LoadFunction(clCreatePipe);
  LoadFunction(clRetainMemObject);
  LoadFunction(clReleaseMemObject);
  LoadFunction(clGetSupportedImageFormats);
  LoadFunction(clGetMemObjectInfo);
  LoadFunction(clGetImageInfo);
  LoadFunction(clGetPipeInfo);
  LoadFunction(clSetMemObjectDestructorCallback);
  LoadFunction(clSVMAlloc);
  LoadFunction(clSVMFree);
  LoadFunction(clCreateSamplerWithProperties);
  LoadFunction(clRetainSampler);
  LoadFunction(clReleaseSampler);
  LoadFunction(clGetSamplerInfo);
  LoadFunction(clCreateProgramWithSource);
  LoadFunction(clCreateProgramWithBinary);
  LoadFunction(clCreateProgramWithBuiltInKernels);
  LoadFunction(clRetainProgram);
  LoadFunction(clReleaseProgram);
  LoadFunction(clBuildProgram);
  LoadFunction(clCompileProgram);
  LoadFunction(clLinkProgram);
  LoadFunction(clUnloadPlatformCompiler);
  LoadFunction(clGetProgramInfo);
  LoadFunction(clGetProgramBuildInfo);
  LoadFunction(clCreateKernel);
  LoadFunction(clCreateKernelsInProgram);
  LoadFunction(clRetainKernel);
  LoadFunction(clReleaseKernel);
  LoadFunction(clSetKernelArg);
  LoadFunction(clSetKernelArgSVMPointer);
  LoadFunction(clSetKernelExecInfo);
  LoadFunction(clGetKernelInfo);
  LoadFunction(clGetKernelArgInfo);
  LoadFunction(clGetKernelWorkGroupInfo);
  LoadFunction(clWaitForEvents);
  LoadFunction(clGetEventInfo);
  LoadFunction(clCreateUserEvent);
  LoadFunction(clRetainEvent);
  LoadFunction(clReleaseEvent);
  LoadFunction(clSetUserEventStatus);
  LoadFunction(clSetEventCallback);
  LoadFunction(clGetEventProfilingInfo);
  LoadFunction(clFlush);
  LoadFunction(clFinish);
  LoadFunction(clEnqueueReadBuffer);
  LoadFunction(clEnqueueReadBufferRect);
  LoadFunction(clEnqueueWriteBuffer);
  LoadFunction(clEnqueueWriteBufferRect);
  LoadFunction(clEnqueueFillBuffer);
  LoadFunction(clEnqueueCopyBuffer);
  LoadFunction(clEnqueueCopyBufferRect);
  LoadFunction(clEnqueueReadImage);
  LoadFunction(clEnqueueWriteImage);
  LoadFunction(clEnqueueFillImage);
  LoadFunction(clEnqueueCopyImage);
  LoadFunction(clEnqueueCopyImageToBuffer);
  LoadFunction(clEnqueueCopyBufferToImage);
  LoadFunction(clEnqueueMapBuffer);
  LoadFunction(clEnqueueMapImage);
  LoadFunction(clEnqueueUnmapMemObject);
  LoadFunction(clEnqueueMigrateMemObjects);
  LoadFunction(clEnqueueNDRangeKernel);
  LoadFunction(clEnqueueNativeKernel);
  LoadFunction(clEnqueueMarkerWithWaitList);
  LoadFunction(clEnqueueBarrierWithWaitList);
  LoadFunction(clEnqueueSVMFree);
  LoadFunction(clEnqueueSVMMemcpy);
  LoadFunction(clEnqueueSVMMemFill);
  LoadFunction(clEnqueueSVMMap);
  LoadFunction(clEnqueueSVMUnmap);
  LoadFunction(clGetExtensionFunctionAddressForPlatform);
  LoadFunction(clCreateImage2D);
  LoadFunction(clCreateImage3D);
  LoadFunction(clEnqueueMarker);
  LoadFunction(clEnqueueWaitForEvents);
  LoadFunction(clEnqueueBarrier);
  LoadFunction(clUnloadCompiler);
  LoadFunction(clGetExtensionFunctionAddress);
  LoadFunction(clCreateCommandQueue);
  LoadFunction(clCreateSampler);
  LoadFunction(clEnqueueTask);

  // OpenGL sharing
  LoadFunction(clCreateFromGLBuffer);
  LoadFunction(clCreateFromGLTexture);
  LoadFunction(clEnqueueAcquireGLObjects);
  LoadFunction(clEnqueueReleaseGLObjects);

  // cl_khr_egl_event extension
  LoadFunction(clCreateEventFromEGLSyncKHR);

  // EGL sharing
  LoadFunction(clCreateFromEGLImageKHR);
  LoadFunction(clEnqueueAcquireEGLObjectsKHR);
  LoadFunction(clEnqueueReleaseEGLObjectsKHR);
}

// No OpenCL support, do not set function addresses
PFN_clGetPlatformIDs clGetPlatformIDs;
PFN_clGetPlatformInfo clGetPlatformInfo;
PFN_clGetDeviceIDs clGetDeviceIDs;
PFN_clGetDeviceInfo clGetDeviceInfo;
PFN_clCreateSubDevices clCreateSubDevices;
PFN_clRetainDevice clRetainDevice;
PFN_clReleaseDevice clReleaseDevice;
PFN_clCreateContext clCreateContext;
PFN_clCreateContextFromType clCreateContextFromType;
PFN_clRetainContext clRetainContext;
PFN_clReleaseContext clReleaseContext;
PFN_clGetContextInfo clGetContextInfo;
PFN_clCreateCommandQueueWithProperties clCreateCommandQueueWithProperties;
PFN_clRetainCommandQueue clRetainCommandQueue;
PFN_clReleaseCommandQueue clReleaseCommandQueue;
PFN_clGetCommandQueueInfo clGetCommandQueueInfo;
PFN_clCreateBuffer clCreateBuffer;
PFN_clCreateSubBuffer clCreateSubBuffer;
PFN_clCreateImage clCreateImage;
PFN_clCreatePipe clCreatePipe;
PFN_clRetainMemObject clRetainMemObject;
PFN_clReleaseMemObject clReleaseMemObject;
PFN_clGetSupportedImageFormats clGetSupportedImageFormats;
PFN_clGetMemObjectInfo clGetMemObjectInfo;
PFN_clGetImageInfo clGetImageInfo;
PFN_clGetPipeInfo clGetPipeInfo;
PFN_clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback;
PFN_clSVMAlloc clSVMAlloc;
PFN_clSVMFree clSVMFree;
PFN_clCreateSamplerWithProperties clCreateSamplerWithProperties;
PFN_clRetainSampler clRetainSampler;
PFN_clReleaseSampler clReleaseSampler;
PFN_clGetSamplerInfo clGetSamplerInfo;
PFN_clCreateProgramWithSource clCreateProgramWithSource;
PFN_clCreateProgramWithBinary clCreateProgramWithBinary;
PFN_clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels;
PFN_clRetainProgram clRetainProgram;
PFN_clReleaseProgram clReleaseProgram;
PFN_clBuildProgram clBuildProgram;
PFN_clCompileProgram clCompileProgram;
PFN_clLinkProgram clLinkProgram;
PFN_clUnloadPlatformCompiler clUnloadPlatformCompiler;
PFN_clGetProgramInfo clGetProgramInfo;
PFN_clGetProgramBuildInfo clGetProgramBuildInfo;
PFN_clCreateKernel clCreateKernel;
PFN_clCreateKernelsInProgram clCreateKernelsInProgram;
PFN_clRetainKernel clRetainKernel;
PFN_clReleaseKernel clReleaseKernel;
PFN_clSetKernelArg clSetKernelArg;
PFN_clSetKernelArgSVMPointer clSetKernelArgSVMPointer;
PFN_clSetKernelExecInfo clSetKernelExecInfo;
PFN_clGetKernelInfo clGetKernelInfo;
PFN_clGetKernelArgInfo clGetKernelArgInfo;
PFN_clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo;
PFN_clWaitForEvents clWaitForEvents;
PFN_clGetEventInfo clGetEventInfo;
PFN_clCreateUserEvent clCreateUserEvent;
PFN_clRetainEvent clRetainEvent;
PFN_clReleaseEvent clReleaseEvent;
PFN_clSetUserEventStatus clSetUserEventStatus;
PFN_clSetEventCallback clSetEventCallback;
PFN_clGetEventProfilingInfo clGetEventProfilingInfo;
PFN_clFlush clFlush;
PFN_clFinish clFinish;
PFN_clEnqueueReadBuffer clEnqueueReadBuffer;
PFN_clEnqueueReadBufferRect clEnqueueReadBufferRect;
PFN_clEnqueueWriteBuffer clEnqueueWriteBuffer;
PFN_clEnqueueWriteBufferRect clEnqueueWriteBufferRect;
PFN_clEnqueueFillBuffer clEnqueueFillBuffer;
PFN_clEnqueueCopyBuffer clEnqueueCopyBuffer;
PFN_clEnqueueCopyBufferRect clEnqueueCopyBufferRect;
PFN_clEnqueueReadImage clEnqueueReadImage;
PFN_clEnqueueWriteImage clEnqueueWriteImage;
PFN_clEnqueueFillImage clEnqueueFillImage;
PFN_clEnqueueCopyImage clEnqueueCopyImage;
PFN_clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer;
PFN_clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage;
PFN_clEnqueueMapBuffer clEnqueueMapBuffer;
PFN_clEnqueueMapImage clEnqueueMapImage;
PFN_clEnqueueUnmapMemObject clEnqueueUnmapMemObject;
PFN_clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects;
PFN_clEnqueueNDRangeKernel clEnqueueNDRangeKernel;
PFN_clEnqueueNativeKernel clEnqueueNativeKernel;
PFN_clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList;
PFN_clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList;
PFN_clEnqueueSVMFree clEnqueueSVMFree;
PFN_clEnqueueSVMMemcpy clEnqueueSVMMemcpy;
PFN_clEnqueueSVMMemFill clEnqueueSVMMemFill;
PFN_clEnqueueSVMMap clEnqueueSVMMap;
PFN_clEnqueueSVMUnmap clEnqueueSVMUnmap;
PFN_clGetExtensionFunctionAddressForPlatform
    clGetExtensionFunctionAddressForPlatform;
PFN_clCreateImage2D clCreateImage2D;
PFN_clCreateImage3D clCreateImage3D;
PFN_clEnqueueMarker clEnqueueMarker;
PFN_clEnqueueWaitForEvents clEnqueueWaitForEvents;
PFN_clEnqueueBarrier clEnqueueBarrier;
PFN_clUnloadCompiler clUnloadCompiler;
PFN_clGetExtensionFunctionAddress clGetExtensionFunctionAddress;
PFN_clCreateCommandQueue clCreateCommandQueue;
PFN_clCreateSampler clCreateSampler;
PFN_clEnqueueTask clEnqueueTask;

// OpenGL sharing
PFN_clCreateFromGLBuffer clCreateFromGLBuffer;
PFN_clCreateFromGLTexture clCreateFromGLTexture;
PFN_clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects;
PFN_clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects;

// cl_khr_egl_event extension
PFN_clCreateEventFromEGLSyncKHR clCreateEventFromEGLSyncKHR;

// EGL sharing
PFN_clCreateFromEGLImageKHR clCreateFromEGLImageKHR;
PFN_clEnqueueAcquireEGLObjectsKHR clEnqueueAcquireEGLObjectsKHR;
PFN_clEnqueueReleaseEGLObjectsKHR clEnqueueReleaseEGLObjectsKHR;

cl_mem CreateImage2DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage2D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_row_pitch, host_ptr, errcode_ret);
  }
}

cl_mem CreateImage3DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage3D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_depth, image_desc->image_row_pitch,
                           image_desc->image_slice_pitch, host_ptr,
                           errcode_ret);
  }
}
}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>#ifndef AMGCL_AMGCL_HPP
#define AMGCL_AMGCL_HPP

/*
The MIT License

Copyright (c) 2012-2013 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Generic algebraic multigrid framework.
 */

#include <iostream>
#include <iomanip>
#include <utility>
#include <list>

#include <boost/static_assert.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/io/ios_state.hpp>

#include <amgcl/spmat.hpp>
#include <amgcl/tictoc.hpp>

/// Primary namespace for the library.
namespace amgcl {

/// Interpolation-related types and functions.
namespace interp {

/// Galerkin operator.
struct galerkin_operator {
    template <class spmat, class Params>
    static spmat apply(const spmat &R, const spmat &A, const spmat &P,
            const Params&)
    {
        return sparse::prod(sparse::prod(R, A), P);
    }
};

/// Returns coarse level construction scheme for a given interpolation scheme.
/**
 * By default, Galerkin operator is used to construct coarse level from system
 * matrix, restriction and prolongation operators:
 * \f[A^H = R A^h P.\f] Usually, \f$R = P^T.\f$
 *
 * \param Interpolation interpolation scheme.
 */
template <class Interpolation>
struct coarse_operator {
    typedef galerkin_operator type;
};

} // namespace interp

/// Possible relaxation (smoothing) schemes.
namespace relax {

/// Possible relaxation (smoothing) schemes.
/**
 * Each backend may support only a limited subset of these.
 * \sa relax_vs_backend
 */
enum scheme {
    damped_jacobi, ///< Damped Jacobi.
    spai0,         ///< SPAI-0 algorithm from \ref spai_2002 "Broeker (2002)".
    gauss_seidel,  ///< Gauss-Seidel.
    ilu0           ///< Incomplete LU decomposition with zero fill-in.
};

} // namespace relax.

/// Algebraic multigrid method.
/**
 * \param value_t  Type for matrix entries (double/float).
 * \param index_t  Type for matrix indices. Should be signed integral type.
 * \param interp_t \ref interpolation "Interpolation scheme".
 * \param level_t  Hierarchy level \ref levels "storage backend".
 */
template <
    typename value_t, typename index_t, typename interp_t, typename level_t
    >
class solver {
    private:
        typedef sparse::matrix<value_t, index_t> matrix;
        typedef typename level_t::template instance<value_t, index_t> level_type;

    public:
        typedef value_t value_type;
        typedef index_t index_type;

        /// Parameters for AMG components.
        struct params {
            /// When level is coarse enough to be solved directly?
            /**
             * If number of variables at a next level in hierarchy becomes
             * lower than this threshold, then the hierarchy construction is
             * stopped and the linear system is solved explicitly at this
             * level.
             */
            unsigned coarse_enough;

            typename interp_t::params interp; ///< Interpolation parameters.
            typename level_t::params  level;  ///< Level/Solution parameters.

            params() : coarse_enough(300) { }
        };

        /// Constructs the AMG hierarchy from the system matrix.
        /**
         * The input matrix is copied here and may be freed afterwards.
         *
         * \param A   The system matrix. Should be convertible to
         *            amgcl::sparse::matrix<>.
         * \param prm Parameters controlling the setup and solution phases.
         *
         * \sa amgcl::sparse::map()
         */
        template <typename spmat>
        solver(const spmat &A, const params &prm = params()) : prm(prm)
        {
            BOOST_STATIC_ASSERT_MSG(boost::is_signed<index_t>::value,
                    "Matrix index type should be signed");

            matrix copy(A);
            build_level(copy, prm);
        }

        /// The AMG hierarchy is used as a standalone solver.
        /**
         * The vector types should be compatible with level_t:
         *
         * -# Any type with operator[] should work on a CPU.
         * -# vex::vector<value_t> should be used with level::vexcl.
         * -# viennacl::vector<value_t> should be used with level::ViennaCL.
         *
         * \param rhs Right-hand side.
         * \param x   Solution. Contains an initial approximation on input, and
         *            the approximated solution on output.
         */
        template <class vector1, class vector2>
        std::pair< int, value_t > solve(const vector1 &rhs, vector2 &x) const {
            unsigned iter = 0;
            value_t  res  = 2 * prm.level.tol;

            for(; res > prm.level.tol && iter < prm.level.maxiter; ++iter) {
                apply(rhs, x);
                res = hier.front()->resid(rhs, x);
            }

            return std::make_pair(iter, res);
        }

        /// Performs single multigrid cycle.
        /**
         * Is intended to be used as a preconditioner with iterative methods.
         *
         * The vector types should be compatible with level_t:
         *
         * -# Any type with operator[] should work on a CPU.
         * -# vex::vector<value_t> should be used with level::vexcl.
         * -# viennacl::vector<value_t> should be used with level::ViennaCL.
         *
         * \param rhs Right-hand side.
         * \param x   Solution. Contains an initial approximation on input, and
         *            the approximated solution on output.
         */
        template <class vector1, class vector2>
        void apply(const vector1 &rhs, vector2 &x) const {
            level_type::cycle(hier.begin(), hier.end(), prm.level, rhs, x);
        }

        /// Output some general information about the AMG hierarchy.
        std::ostream& print(std::ostream &os) const {
            boost::io::ios_all_saver stream_state(os);

            index_t sum_dof = 0;
            index_t sum_nnz = 0;
            for(typename std::list< boost::shared_ptr<level_type> >::const_iterator lvl = hier.begin(); lvl != hier.end(); ++lvl) {
                sum_dof += (*lvl)->size();
                sum_nnz += (*lvl)->nonzeros();
            }

            os << "Number of levels:    "   << hier.size()
               << "\nOperator complexity: " << std::fixed << std::setprecision(2)
                                            << 1.0 * sum_nnz / hier.front()->nonzeros()
               << "\nGrid complexity:     " << std::fixed << std::setprecision(2)
                                            << 1.0 * sum_dof / hier.front()->size()
               << "\n\nlevel     unknowns       nonzeros\n"
               << "---------------------------------\n";

            index_t depth = 0;
            for(typename std::list< boost::shared_ptr<level_type> >::const_iterator lvl = hier.begin(); lvl != hier.end(); ++lvl, ++depth)
                os << std::setw(5)  << depth
                   << std::setw(13) << (*lvl)->size()
                   << std::setw(15) << (*lvl)->nonzeros() << " ("
                   << std::setw(5) << std::fixed << std::setprecision(2)
                   << 100.0 * (*lvl)->nonzeros() / sum_nnz
                   << "%)" << std::endl;

            return os;
        }

        /// Number of unknowns at the finest level.
        index_t size() const {
            return hier.front()->size();
        }

        /// Returns reference to the system matrix at the finest level.
        const typename level_type::matrix& top_matrix() const {
            return hier.front()->get_matrix();
        }
    private:
        void build_level(matrix &A, const params &prm, unsigned nlevel = 0)
        {
            if (static_cast<size_t>(A.rows) <= prm.coarse_enough) {
                TIC("coarsest level");
                matrix Ai = sparse::inverse(A);
                hier.push_back( boost::shared_ptr<level_type>(new level_type(A, Ai, prm.level, nlevel) ) );
                TOC("coarsest level");
            } else {
                TIC("construct level");

                TIC("interp");
                std::pair<sparse::matrix<value_t, index_t>, sparse::matrix<value_t, index_t> > PR = interp_t::interp(A, prm.interp);
                matrix &P = PR.first;
                matrix &R = PR.second;
                TOC("interp");

                TIC("coarse operator");
                matrix a = interp::coarse_operator<interp_t>::type::apply(
                        R, A, P, prm.interp);
                TOC("coarse operator");

                TOC("construct level");

                TIC("transfer level data");
                hier.push_back( boost::shared_ptr<level_type>(new level_type(A, P, R, prm.level, nlevel) ) );
                TOC("transfer level data");

                build_level(a, prm, nlevel + 1);
            }
        }

        params prm;
        std::list< boost::shared_ptr<level_type> > hier;
};

} // namespace amgcl

/// Output some general information about the AMG hierarchy.
template <
    typename value_t,
    typename index_t,
    typename interp_t,
    typename level_t
    >
std::ostream& operator<<(std::ostream &os, const amgcl::solver<value_t, index_t, interp_t, level_t> &amg) {
    return amg.print(os);
}

#endif
<commit_msg>Removed trailing spaces<commit_after>#ifndef AMGCL_AMGCL_HPP
#define AMGCL_AMGCL_HPP

/*
The MIT License

Copyright (c) 2012-2013 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Generic algebraic multigrid framework.
 */

#include <iostream>
#include <iomanip>
#include <utility>
#include <list>

#include <boost/static_assert.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/io/ios_state.hpp>

#include <amgcl/spmat.hpp>
#include <amgcl/tictoc.hpp>

/// Primary namespace for the library.
namespace amgcl {

/// Interpolation-related types and functions.
namespace interp {

/// Galerkin operator.
struct galerkin_operator {
    template <class spmat, class Params>
    static spmat apply(const spmat &R, const spmat &A, const spmat &P,
            const Params&)
    {
        return sparse::prod(sparse::prod(R, A), P);
    }
};

/// Returns coarse level construction scheme for a given interpolation scheme.
/**
 * By default, Galerkin operator is used to construct coarse level from system
 * matrix, restriction and prolongation operators:
 * \f[A^H = R A^h P.\f] Usually, \f$R = P^T.\f$
 *
 * \param Interpolation interpolation scheme.
 */
template <class Interpolation>
struct coarse_operator {
    typedef galerkin_operator type;
};

} // namespace interp

/// Possible relaxation (smoothing) schemes.
namespace relax {

/// Possible relaxation (smoothing) schemes.
/**
 * Each backend may support only a limited subset of these.
 * \sa relax_vs_backend
 */
enum scheme {
    damped_jacobi, ///< Damped Jacobi.
    spai0,         ///< SPAI-0 algorithm from \ref spai_2002 "Broeker (2002)".
    gauss_seidel,  ///< Gauss-Seidel.
    ilu0           ///< Incomplete LU decomposition with zero fill-in.
};

} // namespace relax.

/// Algebraic multigrid method.
/**
 * \param value_t  Type for matrix entries (double/float).
 * \param index_t  Type for matrix indices. Should be signed integral type.
 * \param interp_t \ref interpolation "Interpolation scheme".
 * \param level_t  Hierarchy level \ref levels "storage backend".
 */
template <
    typename value_t, typename index_t, typename interp_t, typename level_t
    >
class solver {
    private:
        typedef sparse::matrix<value_t, index_t> matrix;
        typedef typename level_t::template instance<value_t, index_t> level_type;

    public:
        typedef value_t value_type;
        typedef index_t index_type;

        /// Parameters for AMG components.
        struct params {
            /// When level is coarse enough to be solved directly?
            /**
             * If number of variables at a next level in hierarchy becomes
             * lower than this threshold, then the hierarchy construction is
             * stopped and the linear system is solved explicitly at this
             * level.
             */
            unsigned coarse_enough;

            typename interp_t::params interp; ///< Interpolation parameters.
            typename level_t::params  level;  ///< Level/Solution parameters.

            params() : coarse_enough(300) { }
        };

        /// Constructs the AMG hierarchy from the system matrix.
        /**
         * The input matrix is copied here and may be freed afterwards.
         *
         * \param A   The system matrix. Should be convertible to
         *            amgcl::sparse::matrix<>.
         * \param prm Parameters controlling the setup and solution phases.
         *
         * \sa amgcl::sparse::map()
         */
        template <typename spmat>
        solver(const spmat &A, const params &prm = params()) : prm(prm)
        {
            BOOST_STATIC_ASSERT_MSG(boost::is_signed<index_t>::value,
                    "Matrix index type should be signed");

            matrix copy(A);
            build_level(copy, prm);
        }

        /// The AMG hierarchy is used as a standalone solver.
        /**
         * The vector types should be compatible with level_t:
         *
         * -# Any type with operator[] should work on a CPU.
         * -# vex::vector<value_t> should be used with level::vexcl.
         * -# viennacl::vector<value_t> should be used with level::ViennaCL.
         *
         * \param rhs Right-hand side.
         * \param x   Solution. Contains an initial approximation on input, and
         *            the approximated solution on output.
         */
        template <class vector1, class vector2>
        std::pair< int, value_t > solve(const vector1 &rhs, vector2 &x) const {
            unsigned iter = 0;
            value_t  res  = 2 * prm.level.tol;

            for(; res > prm.level.tol && iter < prm.level.maxiter; ++iter) {
                apply(rhs, x);
                res = hier.front()->resid(rhs, x);
            }

            return std::make_pair(iter, res);
        }

        /// Performs single multigrid cycle.
        /**
         * Is intended to be used as a preconditioner with iterative methods.
         *
         * The vector types should be compatible with level_t:
         *
         * -# Any type with operator[] should work on a CPU.
         * -# vex::vector<value_t> should be used with level::vexcl.
         * -# viennacl::vector<value_t> should be used with level::ViennaCL.
         *
         * \param rhs Right-hand side.
         * \param x   Solution. Contains an initial approximation on input, and
         *            the approximated solution on output.
         */
        template <class vector1, class vector2>
        void apply(const vector1 &rhs, vector2 &x) const {
            level_type::cycle(hier.begin(), hier.end(), prm.level, rhs, x);
        }

        /// Output some general information about the AMG hierarchy.
        std::ostream& print(std::ostream &os) const {
            boost::io::ios_all_saver stream_state(os);

            index_t sum_dof = 0;
            index_t sum_nnz = 0;
            for(typename std::list< boost::shared_ptr<level_type> >::const_iterator lvl = hier.begin(); lvl != hier.end(); ++lvl) {
                sum_dof += (*lvl)->size();
                sum_nnz += (*lvl)->nonzeros();
            }

            os << "Number of levels:    "   << hier.size()
               << "\nOperator complexity: " << std::fixed << std::setprecision(2)
                                            << 1.0 * sum_nnz / hier.front()->nonzeros()
               << "\nGrid complexity:     " << std::fixed << std::setprecision(2)
                                            << 1.0 * sum_dof / hier.front()->size()
               << "\n\nlevel     unknowns       nonzeros\n"
               << "---------------------------------\n";

            index_t depth = 0;
            for(typename std::list< boost::shared_ptr<level_type> >::const_iterator lvl = hier.begin(); lvl != hier.end(); ++lvl, ++depth)
                os << std::setw(5)  << depth
                   << std::setw(13) << (*lvl)->size()
                   << std::setw(15) << (*lvl)->nonzeros() << " ("
                   << std::setw(5) << std::fixed << std::setprecision(2)
                   << 100.0 * (*lvl)->nonzeros() / sum_nnz
                   << "%)" << std::endl;

            return os;
        }

        /// Number of unknowns at the finest level.
        index_t size() const {
            return hier.front()->size();
        }

        /// Returns reference to the system matrix at the finest level.
        const typename level_type::matrix& top_matrix() const {
            return hier.front()->get_matrix();
        }
    private:
        void build_level(matrix &A, const params &prm, unsigned nlevel = 0)
        {
            if (static_cast<size_t>(A.rows) <= prm.coarse_enough) {
                TIC("coarsest level");
                matrix Ai = sparse::inverse(A);
                hier.push_back( boost::shared_ptr<level_type>(new level_type(A, Ai, prm.level, nlevel) ) );
                TOC("coarsest level");
            } else {
                TIC("construct level");

                TIC("interp");
                std::pair<sparse::matrix<value_t, index_t>, sparse::matrix<value_t, index_t> > PR = interp_t::interp(A, prm.interp);
                matrix &P = PR.first;
                matrix &R = PR.second;
                TOC("interp");

                TIC("coarse operator");
                matrix a = interp::coarse_operator<interp_t>::type::apply(
                        R, A, P, prm.interp);
                TOC("coarse operator");

                TOC("construct level");

                TIC("transfer level data");
                hier.push_back( boost::shared_ptr<level_type>(new level_type(A, P, R, prm.level, nlevel) ) );
                TOC("transfer level data");

                build_level(a, prm, nlevel + 1);
            }
        }

        params prm;
        std::list< boost::shared_ptr<level_type> > hier;
};

} // namespace amgcl

/// Output some general information about the AMG hierarchy.
template <
    typename value_t,
    typename index_t,
    typename interp_t,
    typename level_t
    >
std::ostream& operator<<(std::ostream &os, const amgcl::solver<value_t, index_t, interp_t, level_t> &amg) {
    return amg.print(os);
}

#endif
<|endoftext|>


<commit_before>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2017 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <boost/type_traits.hpp>
#include <boost/tuple/tuple.hpp>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            size_t n, m, nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            std::vector<Idx> _row; _row.reserve(nnz);
            std::vector<Idx> _col; _col.reserve(nnz);
            std::vector<Val> _val; _val.reserve(nnz);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                v = read_value<Val>(is);

                _row.push_back(i-1);
                _col.push_back(j-1);
                _val.push_back(v);
            }

            precondition(_val.size() == nnz, format_error("inconsistent data"));

            ptr.resize(n+1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];

                ++ptr[i+1];

                if (_symmetric && j != i) ++ptr[j+1];
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0; k < nnz; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;

                if (_symmetric && j != i) {
                    Idx head = ptr[j]++;
                    col[head] = i;
                    val[head] = v;
                }
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return boost::make_tuple(n, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        boost::tuple<size_t, size_t> operator()(std::vector<Val> &val) {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            size_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            val.resize(n * m);

            for(size_t j = 0; j < m; ++j) {
                for(size_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    is.clear(); is.str(line);
                    val[i * m + j] = read_value<Val>(is);
                }
            }

            return boost::make_tuple(n, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename boost::enable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename boost::disable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            T x;
            precondition(s >> x, format_error());
            return x;
        }

};

namespace detail {
template <typename Val>
typename boost::enable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename boost::disable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;
    typedef typename backend::row_iterator<Matrix>::type row_iterator;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(row_iterator a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<commit_msg>Fix MatrixMarket reader for 8bit integers<commit_after>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2017 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <boost/type_traits.hpp>
#include <boost/tuple/tuple.hpp>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        boost::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            size_t n, m, nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            std::vector<Idx> _row; _row.reserve(nnz);
            std::vector<Idx> _col; _col.reserve(nnz);
            std::vector<Val> _val; _val.reserve(nnz);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                v = read_value<Val>(is);

                _row.push_back(i-1);
                _col.push_back(j-1);
                _val.push_back(v);
            }

            precondition(_val.size() == nnz, format_error("inconsistent data"));

            ptr.resize(n+1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];

                ++ptr[i+1];

                if (_symmetric && j != i) ++ptr[j+1];
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0; k < nnz; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;

                if (_symmetric && j != i) {
                    Idx head = ptr[j]++;
                    col[head] = i;
                    val[head] = v;
                }
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return boost::make_tuple(n, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        boost::tuple<size_t, size_t> operator()(std::vector<Val> &val) {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(boost::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(boost::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            size_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            val.resize(n * m);

            for(size_t j = 0; j < m; ++j) {
                for(size_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    is.clear(); is.str(line);
                    val[i * m + j] = read_value<Val>(is);
                }
            }

            return boost::make_tuple(n, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename boost::enable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename boost::disable_if<typename boost::is_complex<T>::type, T>::type
        read_value(std::istream &s) {
            T x;
            if (std::is_same<T, char>::value) {
                // Special case:
                // We want to read 8bit integers from MatrixMarket, not chars.
                int i;
                precondition(s >> i, format_error());
                x = static_cast<char>(i);
            } else {
                precondition(s >> x, format_error());
            }
            return x;
        }

};

namespace detail {
template <typename Val>
typename boost::enable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename boost::disable_if<typename boost::is_complex<Val>::type, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;
    typedef typename backend::row_iterator<Matrix>::type row_iterator;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (boost::is_complex<Val>::value) {
        f << "complex ";
    } else if(boost::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(row_iterator a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>/**
 * \file
 * \brief SoftwareTimerControlBlock class header
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_

#include "distortos/internal/scheduler/SoftwareTimerListNode.hpp"

namespace distortos
{

class SoftwareTimer;

namespace internal
{

/// SoftwareTimerControlBlock class is a control block of software timer
class SoftwareTimerControlBlock : public SoftwareTimerListNode
{
public:

	/// type of runner for software timer's function
	using FunctionRunner = void(SoftwareTimer&);

	/**
	 * \brief SoftwareTimerControlBlock's constructor
	 *
	 * \param [in] functionRunner is a reference to runner for software timer's function
	 * \param [in] owner is a reference to SoftwareTimer object that owns this SoftwareTimerControlBlock
	 */

	constexpr SoftwareTimerControlBlock(FunctionRunner& functionRunner, SoftwareTimer& owner) :
			SoftwareTimerListNode{},
			functionRunner_{functionRunner},
			owner_{owner}
	{

	}

	/**
	 * \brief SoftwareTimerControlBlock's destructor
	 *
	 * If the timer is running it is stopped.
	 */

	~SoftwareTimerControlBlock()
	{
		stop();
	}

	/**
	 * \return true if the timer is running, false otherwise
	 */

	bool isRunning() const
	{
		return node.isLinked();
	}

	/**
	 * \brief Runs software timer's function.
	 *
	 * \note this should only be called by SoftwareTimerSupervisor::tickInterruptHandler()
	 */

	void run() const
	{
		functionRunner_(owner_);
	}

	/**
	 * \brief Starts the timer.
	 *
	 * \param [in] timePoint is the time point at which the function will be executed
	 */

	void start(TickClock::time_point timePoint);

	/**
	 * \brief Stops the timer.
	 */

	void stop();

	SoftwareTimerControlBlock(const SoftwareTimerControlBlock&) = delete;
	SoftwareTimerControlBlock(SoftwareTimerControlBlock&&) = default;
	const SoftwareTimerControlBlock& operator=(const SoftwareTimerControlBlock&) = delete;
	SoftwareTimerControlBlock& operator=(SoftwareTimerControlBlock&&) = delete;

private:

	/**
	 * \brief Stops the timer - internal version, with no interrupt masking.
	 */

	void stopInternal();

	/// reference to runner for software timer's function
	FunctionRunner& functionRunner_;

	/// reference to SoftwareTimer object that owns this SoftwareTimerControlBlock
	SoftwareTimer& owner_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_
<commit_msg>Add member variable with period to SoftwareTimerControlBlock<commit_after>/**
 * \file
 * \brief SoftwareTimerControlBlock class header
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_

#include "distortos/internal/scheduler/SoftwareTimerListNode.hpp"

namespace distortos
{

class SoftwareTimer;

namespace internal
{

/// SoftwareTimerControlBlock class is a control block of software timer
class SoftwareTimerControlBlock : public SoftwareTimerListNode
{
public:

	/// type of runner for software timer's function
	using FunctionRunner = void(SoftwareTimer&);

	/**
	 * \brief SoftwareTimerControlBlock's constructor
	 *
	 * \param [in] functionRunner is a reference to runner for software timer's function
	 * \param [in] owner is a reference to SoftwareTimer object that owns this SoftwareTimerControlBlock
	 */

	constexpr SoftwareTimerControlBlock(FunctionRunner& functionRunner, SoftwareTimer& owner) :
			SoftwareTimerListNode{},
			period_{},
			functionRunner_{functionRunner},
			owner_{owner}
	{

	}

	/**
	 * \brief SoftwareTimerControlBlock's destructor
	 *
	 * If the timer is running it is stopped.
	 */

	~SoftwareTimerControlBlock()
	{
		stop();
	}

	/**
	 * \return true if the timer is running, false otherwise
	 */

	bool isRunning() const
	{
		return node.isLinked();
	}

	/**
	 * \brief Runs software timer's function.
	 *
	 * \note this should only be called by SoftwareTimerSupervisor::tickInterruptHandler()
	 */

	void run() const
	{
		functionRunner_(owner_);
	}

	/**
	 * \brief Starts the timer.
	 *
	 * \param [in] timePoint is the time point at which the function will be executed
	 */

	void start(TickClock::time_point timePoint);

	/**
	 * \brief Stops the timer.
	 */

	void stop();

	SoftwareTimerControlBlock(const SoftwareTimerControlBlock&) = delete;
	SoftwareTimerControlBlock(SoftwareTimerControlBlock&&) = default;
	const SoftwareTimerControlBlock& operator=(const SoftwareTimerControlBlock&) = delete;
	SoftwareTimerControlBlock& operator=(SoftwareTimerControlBlock&&) = delete;

private:

	/**
	 * \brief Stops the timer - internal version, with no interrupt masking.
	 */

	void stopInternal();

	/// period used to restart repetitive software timer, 0 for one-shot software timers
	TickClock::duration period_;

	/// reference to runner for software timer's function
	FunctionRunner& functionRunner_;

	/// reference to SoftwareTimer object that owns this SoftwareTimerControlBlock
	SoftwareTimer& owner_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SOFTWARETIMERCONTROLBLOCK_HPP_
<|endoftext|>


<commit_before>#include <memory>
#include <algorithm>
#include <utility>

#include "main.h"

using ObjClass = uint32_t;

static inline ObjClass
getObjClass(unsigned char ei_class, unsigned char ei_data, unsigned char ei_osabi) {
	return (ei_data << 16) | (ei_class << 8) | ei_osabi;
}

static inline ObjClass
getObjClass(Elf *elf) {
	return getObjClass(elf->ei_class, elf->ei_data, elf->ei_osabi);
}

DB::~DB() {
	for (auto &pkg : packages)
		delete pkg;
}

PackageList::const_iterator
DB::find_pkg_i(const std::string& name) const
{
	return std::find_if(packages.begin(), packages.end(),
		[&name](const Package *pkg) { return pkg->name == name; });
}

Package*
DB::find_pkg(const std::string& name) const
{
	auto pkg = find_pkg_i(name);
	return (pkg != packages.end()) ? *pkg : nullptr;
}

bool
DB::delete_package(const std::string& name)
{
	Package *old; {
		auto pkgiter = find_pkg_i(name);
		if (pkgiter == packages.end())
			return true;

		old = *pkgiter;
		packages.erase(packages.begin() + (pkgiter - packages.begin()));
	}

	for (auto &elfsp : old->objects) {
		Elf *elf = elfsp.get();
		required_found.erase(elf);
		required_missing.erase(elf);
		// remove the object from the list
		auto self = std::find(objects.begin(), objects.end(), elf);
		objects.erase(self);

		// for each object which depends on this object, search for a replacing object
		for (auto &found : required_found) {
			// does this object depend on 'elf'?
			auto ref = std::find(found.second.begin(), found.second.end(), elf);
			if (ref == found.second.end())
				continue;
			// erase
			found.second.erase(ref);
			// search for this dependency anew
			Elf *seeker = found.first;
			Elf *other  = find_for(seeker, elf->basename);
			if (!other) {
				// it's missing now
				required_missing[seeker].insert(elf->basename);
			} else {
				// replace it with a new object
				found.second.insert(other);
			}
		}
	}

	delete old;

	std::remove_if(objects.begin(), objects.end(),
		[](rptr<Elf> &obj) { return 1 == obj->refcount; });

	return true;
}

static bool
pathlist_contains(const std::string& list, const std::string& path)
{
	size_t at = 0;
	size_t to = list.find_first_of(':', 0);
	while (to != std::string::npos) {
		if (list.compare(at, to-at, path) == 0)
			return true;
		at = to+1;
		to = list.find_first_of(':', at);
	}
	if (list.compare(at, std::string::npos, path) == 0)
		return true;
	return false;
}

bool
DB::elf_finds(Elf *elf, const std::string& path) const
{
	// DT_RPATH first
	if (elf->rpath_set && pathlist_contains(elf->rpath, path))
		return true;

	// LD_LIBRARY_PATH - ignored

	// DT_RUNPATH
	if (elf->runpath_set && pathlist_contains(elf->runpath, path))
		return true;

	// Trusted Paths
	if (path == "/lib" ||
	    path == "/usr/lib")
	{
		return true;
	}

	if (std::find(library_path.begin(), library_path.end(), path) != library_path.end())
		return true;

	return false;
}

bool
DB::install_package(Package* &&pkg)
{
	if (!delete_package(pkg->name))
		return false;

	packages.push_back(pkg);

	for (auto &obj : pkg->objects)
		objects.push_back(obj);

	for (auto &obj : pkg->objects) {
		ObjClass objclass = getObjClass(obj);
		// check if the object is required
		for (auto missing = required_missing.begin(); missing != required_missing.end();) {
			Elf *seeker = missing->first;
			if (getObjClass(seeker) != objclass ||
			    !elf_finds(seeker, obj->dirname))
			{
				++missing;
				continue;
			}

			bool needs = (0 != missing->second.erase(obj->basename));

			if (needs) // the library is indeed required and found:
				required_found[seeker].insert(obj);

			if (0 == missing->second.size())
				required_missing.erase(missing++);
			else
				++missing;
		}

		// search for whatever THIS object requires
#if 0
		ObjectSet req_found;
		StringSet req_missing;
		for (auto &needed : obj->needed) {
			Elf *found = find_for(obj, needed);
			if (found)
				req_found.insert(found);
			else
				req_missing.insert(needed);
		}
		if (req_found.size())
			required_found[obj]   = std::move(req_found);
		if (req_missing.size())
			required_missing[obj] = std::move(req_missing);
#else
		link_object(obj);
#endif
	}

	return true;
}

Elf*
DB::find_for(Elf *obj, const std::string& needed) const
{
	log(Debug, "dependency of %s/%s   :  %s\n", obj->dirname.c_str(), obj->basename.c_str(), needed.c_str());
	ObjClass objclass = getObjClass(obj);
	for (auto &lib : objects) {
		if (getObjClass(lib) != objclass)
			log(Debug, "  skipping %s/%s (objclass)\n", lib->dirname.c_str(), lib->basename.c_str());
		else if (lib->basename    != needed)
			log(Debug, "  skipping %s/%s (wrong name)\n", lib->dirname.c_str(), lib->basename.c_str());
		else if (!elf_finds(obj, lib->dirname))
			log(Debug, "  skipping %s/%s (not visible)\n", lib->dirname.c_str(), lib->basename.c_str());

		if (getObjClass(lib) != objclass ||
		    lib->basename    != needed   ||
		    !elf_finds(obj, lib->dirname))
		{
			continue;
		}
		// same class, same name, and visible...
		return lib;
	}
	return 0;
}

void
DB::link_object(Elf *obj)
{
	ObjectSet req_found;
	StringSet req_missing;
	for (auto &needed : obj->needed) {
		Elf *found = find_for(obj, needed);
		if (found)
			req_found.insert(found);
		else
			req_missing.insert(needed);
	}
	if (req_found.size())
		required_found[obj]   = std::move(req_found);
	if (req_missing.size())
		required_missing[obj] = std::move(req_missing);
}

void
DB::relink_all()
{
	required_found.clear();
	required_missing.clear();
	for (auto &obj : objects) {
		link_object(obj);
	}
}

void
DB::fix_paths()
{
	for (auto &obj : objects) {
		fixpath(obj->rpath);
		fixpath(obj->runpath);
	}
}

bool
DB::empty() const
{
	return packages.size()         == 0 &&
	       objects.size()          == 0 &&
	       required_found.size()   == 0 &&
	       required_missing.size() == 0;
}

bool
DB::ld_clear()
{
	if (library_path.size()) {
		library_path.clear();
		return true;
	}
	return false;
}

bool
DB::ld_append(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.begin() + (library_path.size()-1))
		return false;
	if (old != library_path.end())
		library_path.erase(old);
	library_path.push_back(dir);
	return true;
}

bool
DB::ld_prepend(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.begin())
		return false;
	if (old != library_path.end())
		library_path.erase(old);
	library_path.insert(library_path.begin(), dir);
	return true;
}

bool
DB::ld_delete(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old != library_path.end()) {
		library_path.erase(old);
		return true;
	}
	return false;
}

bool
DB::ld_insert(const std::string& dir, size_t i)
{
	if (!library_path.size())
		i = 0;
	else if (i >= library_path.size())
		i = library_path.size()-1;

	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.end()) {
		library_path.insert(library_path.begin() + i, dir);
		return true;
	}
	size_t oldidx = old - library_path.begin();
	if (oldidx == i)
		return false;
	// exists
	library_path.erase(old);
	library_path.insert(library_path.begin() + i, dir);
	return true;
}

void
DB::show_info()
{
	printf("DB version: %u\n", (unsigned)DB::version);
	printf("DB name:    [%s]\n", name.c_str());
	printf("Additional Library Paths:\n");
	unsigned id = 0;
	for (auto &p : library_path)
		printf("  %u: %s\n", id++, p.c_str());
}

void
DB::show_packages()
{
	printf("Packages:\n");
	for (auto &pkg : packages) {
		printf("  -> %s - %s\n", pkg->name.c_str(), pkg->version.c_str());
		if (opt_verbosity >= 1) {
			for (auto &obj : pkg->objects)
				printf("    contains %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		}
	}
}

void
DB::show_objects()
{
	if (!objects.size()) {
		printf("Objects: none\n");
		return;
	}
	printf("Objects:\n");
	for (auto &obj : objects) {
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		if (opt_verbosity < 1)
			continue;
		printf("     class: %u (%s)\n", (unsigned)obj->ei_class, obj->classString());
		printf("     data:  %u (%s)\n", (unsigned)obj->ei_data,  obj->dataString());
		printf("     osabi: %u (%s)\n", (unsigned)obj->ei_osabi, obj->osabiString());
		if (opt_verbosity < 2)
			continue;
		printf("     finds:\n"); {
			auto &set = required_found[obj];
			for (auto &found : set)
				printf("       -> %s / %s\n", found->dirname.c_str(), found->basename.c_str());
		}
		printf("     misses:\n"); {
			auto &set = required_missing[obj];
			for (auto &miss : set)
				printf("       -> %s\n", miss.c_str());
		}
		if (obj->rpath_set)
			printf("     rpath: %s\n", obj->rpath.c_str());
		if (obj->runpath_set)
			printf("     runpath: %s\n", obj->runpath.c_str());
	}
	printf("\n`found` entry set size: %lu\n",
	       (unsigned long)required_found.size());
	printf("`missing` entry set size: %lu\n",
	       (unsigned long)required_missing.size());
}

void
DB::show_missing()
{
	if (!required_missing.size()) {
		printf("Missing: nothing\n");
		return;
	}
	printf("Missing:\n");
	for (auto &mis : required_missing) {
		Elf       *obj = mis.first;
		StringSet &set = mis.second;
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		for (auto &s : set)
			printf("    misses: %s\n", s.c_str());
	}
}

void
DB::show_found()
{
	printf("Found:\n");
	for (auto &fnd : required_found) {
		Elf       *obj = fnd.first;
		ObjectSet &set = fnd.second;
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		for (auto &s : set)
			printf("    finds: %s\n", s->basename.c_str());
	}
}
<commit_msg>remove old #if-0-ed code<commit_after>#include <memory>
#include <algorithm>
#include <utility>

#include "main.h"

using ObjClass = uint32_t;

static inline ObjClass
getObjClass(unsigned char ei_class, unsigned char ei_data, unsigned char ei_osabi) {
	return (ei_data << 16) | (ei_class << 8) | ei_osabi;
}

static inline ObjClass
getObjClass(Elf *elf) {
	return getObjClass(elf->ei_class, elf->ei_data, elf->ei_osabi);
}

DB::~DB() {
	for (auto &pkg : packages)
		delete pkg;
}

PackageList::const_iterator
DB::find_pkg_i(const std::string& name) const
{
	return std::find_if(packages.begin(), packages.end(),
		[&name](const Package *pkg) { return pkg->name == name; });
}

Package*
DB::find_pkg(const std::string& name) const
{
	auto pkg = find_pkg_i(name);
	return (pkg != packages.end()) ? *pkg : nullptr;
}

bool
DB::delete_package(const std::string& name)
{
	Package *old; {
		auto pkgiter = find_pkg_i(name);
		if (pkgiter == packages.end())
			return true;

		old = *pkgiter;
		packages.erase(packages.begin() + (pkgiter - packages.begin()));
	}

	for (auto &elfsp : old->objects) {
		Elf *elf = elfsp.get();
		required_found.erase(elf);
		required_missing.erase(elf);
		// remove the object from the list
		auto self = std::find(objects.begin(), objects.end(), elf);
		objects.erase(self);

		// for each object which depends on this object, search for a replacing object
		for (auto &found : required_found) {
			// does this object depend on 'elf'?
			auto ref = std::find(found.second.begin(), found.second.end(), elf);
			if (ref == found.second.end())
				continue;
			// erase
			found.second.erase(ref);
			// search for this dependency anew
			Elf *seeker = found.first;
			Elf *other  = find_for(seeker, elf->basename);
			if (!other) {
				// it's missing now
				required_missing[seeker].insert(elf->basename);
			} else {
				// replace it with a new object
				found.second.insert(other);
			}
		}
	}

	delete old;

	std::remove_if(objects.begin(), objects.end(),
		[](rptr<Elf> &obj) { return 1 == obj->refcount; });

	return true;
}

static bool
pathlist_contains(const std::string& list, const std::string& path)
{
	size_t at = 0;
	size_t to = list.find_first_of(':', 0);
	while (to != std::string::npos) {
		if (list.compare(at, to-at, path) == 0)
			return true;
		at = to+1;
		to = list.find_first_of(':', at);
	}
	if (list.compare(at, std::string::npos, path) == 0)
		return true;
	return false;
}

bool
DB::elf_finds(Elf *elf, const std::string& path) const
{
	// DT_RPATH first
	if (elf->rpath_set && pathlist_contains(elf->rpath, path))
		return true;

	// LD_LIBRARY_PATH - ignored

	// DT_RUNPATH
	if (elf->runpath_set && pathlist_contains(elf->runpath, path))
		return true;

	// Trusted Paths
	if (path == "/lib" ||
	    path == "/usr/lib")
	{
		return true;
	}

	if (std::find(library_path.begin(), library_path.end(), path) != library_path.end())
		return true;

	return false;
}

bool
DB::install_package(Package* &&pkg)
{
	if (!delete_package(pkg->name))
		return false;

	packages.push_back(pkg);

	for (auto &obj : pkg->objects)
		objects.push_back(obj);

	for (auto &obj : pkg->objects) {
		ObjClass objclass = getObjClass(obj);
		// check if the object is required
		for (auto missing = required_missing.begin(); missing != required_missing.end();) {
			Elf *seeker = missing->first;
			if (getObjClass(seeker) != objclass ||
			    !elf_finds(seeker, obj->dirname))
			{
				++missing;
				continue;
			}

			bool needs = (0 != missing->second.erase(obj->basename));

			if (needs) // the library is indeed required and found:
				required_found[seeker].insert(obj);

			if (0 == missing->second.size())
				required_missing.erase(missing++);
			else
				++missing;
		}

		// search for whatever THIS object requires
		link_object(obj);
	}

	return true;
}

Elf*
DB::find_for(Elf *obj, const std::string& needed) const
{
	log(Debug, "dependency of %s/%s   :  %s\n", obj->dirname.c_str(), obj->basename.c_str(), needed.c_str());
	ObjClass objclass = getObjClass(obj);
	for (auto &lib : objects) {
		if (getObjClass(lib) != objclass)
			log(Debug, "  skipping %s/%s (objclass)\n", lib->dirname.c_str(), lib->basename.c_str());
		else if (lib->basename    != needed)
			log(Debug, "  skipping %s/%s (wrong name)\n", lib->dirname.c_str(), lib->basename.c_str());
		else if (!elf_finds(obj, lib->dirname))
			log(Debug, "  skipping %s/%s (not visible)\n", lib->dirname.c_str(), lib->basename.c_str());

		if (getObjClass(lib) != objclass ||
		    lib->basename    != needed   ||
		    !elf_finds(obj, lib->dirname))
		{
			continue;
		}
		// same class, same name, and visible...
		return lib;
	}
	return 0;
}

void
DB::link_object(Elf *obj)
{
	ObjectSet req_found;
	StringSet req_missing;
	for (auto &needed : obj->needed) {
		Elf *found = find_for(obj, needed);
		if (found)
			req_found.insert(found);
		else
			req_missing.insert(needed);
	}
	if (req_found.size())
		required_found[obj]   = std::move(req_found);
	if (req_missing.size())
		required_missing[obj] = std::move(req_missing);
}

void
DB::relink_all()
{
	required_found.clear();
	required_missing.clear();
	for (auto &obj : objects) {
		link_object(obj);
	}
}

void
DB::fix_paths()
{
	for (auto &obj : objects) {
		fixpath(obj->rpath);
		fixpath(obj->runpath);
	}
}

bool
DB::empty() const
{
	return packages.size()         == 0 &&
	       objects.size()          == 0 &&
	       required_found.size()   == 0 &&
	       required_missing.size() == 0;
}

bool
DB::ld_clear()
{
	if (library_path.size()) {
		library_path.clear();
		return true;
	}
	return false;
}

bool
DB::ld_append(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.begin() + (library_path.size()-1))
		return false;
	if (old != library_path.end())
		library_path.erase(old);
	library_path.push_back(dir);
	return true;
}

bool
DB::ld_prepend(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.begin())
		return false;
	if (old != library_path.end())
		library_path.erase(old);
	library_path.insert(library_path.begin(), dir);
	return true;
}

bool
DB::ld_delete(const std::string& dir)
{
	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old != library_path.end()) {
		library_path.erase(old);
		return true;
	}
	return false;
}

bool
DB::ld_insert(const std::string& dir, size_t i)
{
	if (!library_path.size())
		i = 0;
	else if (i >= library_path.size())
		i = library_path.size()-1;

	auto old = std::find(library_path.begin(), library_path.end(), dir);
	if (old == library_path.end()) {
		library_path.insert(library_path.begin() + i, dir);
		return true;
	}
	size_t oldidx = old - library_path.begin();
	if (oldidx == i)
		return false;
	// exists
	library_path.erase(old);
	library_path.insert(library_path.begin() + i, dir);
	return true;
}

void
DB::show_info()
{
	printf("DB version: %u\n", (unsigned)DB::version);
	printf("DB name:    [%s]\n", name.c_str());
	printf("Additional Library Paths:\n");
	unsigned id = 0;
	for (auto &p : library_path)
		printf("  %u: %s\n", id++, p.c_str());
}

void
DB::show_packages()
{
	printf("Packages:\n");
	for (auto &pkg : packages) {
		printf("  -> %s - %s\n", pkg->name.c_str(), pkg->version.c_str());
		if (opt_verbosity >= 1) {
			for (auto &obj : pkg->objects)
				printf("    contains %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		}
	}
}

void
DB::show_objects()
{
	if (!objects.size()) {
		printf("Objects: none\n");
		return;
	}
	printf("Objects:\n");
	for (auto &obj : objects) {
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		if (opt_verbosity < 1)
			continue;
		printf("     class: %u (%s)\n", (unsigned)obj->ei_class, obj->classString());
		printf("     data:  %u (%s)\n", (unsigned)obj->ei_data,  obj->dataString());
		printf("     osabi: %u (%s)\n", (unsigned)obj->ei_osabi, obj->osabiString());
		if (opt_verbosity < 2)
			continue;
		printf("     finds:\n"); {
			auto &set = required_found[obj];
			for (auto &found : set)
				printf("       -> %s / %s\n", found->dirname.c_str(), found->basename.c_str());
		}
		printf("     misses:\n"); {
			auto &set = required_missing[obj];
			for (auto &miss : set)
				printf("       -> %s\n", miss.c_str());
		}
		if (obj->rpath_set)
			printf("     rpath: %s\n", obj->rpath.c_str());
		if (obj->runpath_set)
			printf("     runpath: %s\n", obj->runpath.c_str());
	}
	printf("\n`found` entry set size: %lu\n",
	       (unsigned long)required_found.size());
	printf("`missing` entry set size: %lu\n",
	       (unsigned long)required_missing.size());
}

void
DB::show_missing()
{
	if (!required_missing.size()) {
		printf("Missing: nothing\n");
		return;
	}
	printf("Missing:\n");
	for (auto &mis : required_missing) {
		Elf       *obj = mis.first;
		StringSet &set = mis.second;
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		for (auto &s : set)
			printf("    misses: %s\n", s.c_str());
	}
}

void
DB::show_found()
{
	printf("Found:\n");
	for (auto &fnd : required_found) {
		Elf       *obj = fnd.first;
		ObjectSet &set = fnd.second;
		printf("  -> %s / %s\n", obj->dirname.c_str(), obj->basename.c_str());
		for (auto &s : set)
			printf("    finds: %s\n", s->basename.c_str());
	}
}
<|endoftext|>