Repository: conan-io/conan-center-index

Issue:
[request] nsimd/2.2
### Package Details
  * Package Name/Version: **nsimd/2.2**
  * Website: **https://agenium-scale.com/en/nsimd-simd**
  * Source code: **https://github.com/agenium-scale/nsimd**


### Description Of The Library / Tool
At its core, NSIMD is a vectorization library that abstracts SIMD programming. It was designed to exploit the maximum power of processors at a low development cost. NSIMD comes with modules. As of now two of them adds support for GPUs to NSIMD. The direction that NSIMD is taking is to provide several programming paradigms to address different problems and to allow a wider support of architectures. With two of its modules NSIMD provides three programming paradigms:

    * Imperative programming provided by NSIMD core that supports a lots of CPU/SIMD extensions.
    * Expressions templates provided by the TET1D module that supports all architectures from NSIMD core and adds support for NVIDIA and AMD GPUs.
    * Single Program Multiple Data provided by the SPMD module that supports all architectures from NSIMD core and adds support for NVIDIA and AMD GPUs.



Discussion:

Resolving patch:
diff --git a/recipes/nsimd/2.x/conanfile.py b/recipes/nsimd/2.x/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/nsimd/2.x/conanfile.py
@@ -0,0 +1,89 @@
+import os
+from conans import ConanFile, CMake, tools
+
+required_conan_version = ">=1.33.0"
+
+
+class NsimdConan(ConanFile):
+    name = "nsimd"
+    homepage = "https://github.com/agenium-scale/nsimd"
+    description = "Agenium Scale vectorization library for CPUs and GPUs"
+    topics = ("hpc", "neon", "cuda", "avx", "simd", "avx2", "sse2", "aarch64", "avx512", "sse42", "rocm", "sve", "neon128")
+    url = "https://github.com/conan-io/conan-center-index"
+    license = "MIT"
+    exports_sources = ["CMakeLists.txt", "patches/*"]
+    generators = "cmake"
+    settings = "os", "compiler", "build_type", "arch"
+    options = {
+        "shared": [True, False],
+        "fPIC": [True, False],
+        # This used only when building the library.
+        # Most functionality is header only.
+        "simd": [None, "cpu", "sse2", "sse42", "avx", "avx2", "avx512_knl", "avx512_skylake", "neon128", "aarch64", "sve", "sve128", "sve256", "sve512", "sve1024", "sve2048", "cuda", "rocm"]
+    }
+    default_options = {
+        "shared": False,
+        "fPIC": True,
+        "simd": None
+    }
+
+    _cmake = None
+
+    @property
+    def _source_subfolder(self):
+        return "source_subfolder"
+
+    @property
+    def _build_subfolder(self):
+        return "build_subfolder"
+
+    def config_options(self):
+        if self.settings.os == "Windows":
+            del self.options.fPIC
+
+    def configure(self):
+        if self.options.shared:
+            del self.options.fPIC
+        # Most of the library is header only.
+        # cpp files do not use STL.
+        del self.settings.compiler.libcxx
+
+    def source(self):
+        tools.get(**self.conan_data["sources"][self.version], strip_root=True, destination=self._source_subfolder)
+
+    def _configure_cmake(self):
+        if self._cmake:
+            return self._cmake
+        self._cmake = CMake(self)
+        if self.options.simd:
+            self._cmake.definitions["simd"] = self.options.simd
+        if self.settings.arch == "armv7hf":
+            self._cmake.definitions["NSIMD_ARM32_IS_ARMEL"] = False
+        self._cmake.definitions["CMAKE_POSITION_INDEPENDENT_CODE"] = self.options.get_safe("fPIC", True)
+        self._cmake.configure(build_folder=self._build_subfolder)
+        return self._cmake
+
+    def _patch_sources(self):
+        cmakefile_path = os.path.join(self._source_subfolder, "CMakeLists.txt")
+        tools.replace_in_file(cmakefile_path,
+                              " SHARED ",
+                              " ")
+        tools.replace_in_file(cmakefile_path,
+                              "RUNTIME DESTINATION lib",
+                              "RUNTIME DESTINATION bin")
+        tools.replace_in_file(cmakefile_path,
+                              "set_property(TARGET ${o} PROPERTY POSITION_INDEPENDENT_CODE ON)",
+                              "")
+
+    def build(self):
+        self._patch_sources()
+        cmake = self._configure_cmake()
+        cmake.build()
+
+    def package(self):
+        self.copy("LICENSE", dst="licenses", src=self._source_subfolder)
+        cmake = self._configure_cmake()
+        cmake.install()
+
+    def package_info(self):
+        self.cpp_info.libs = tools.collect_libs(self)


Test patch:
diff --git a/recipes/nsimd/2.x/test_package/CMakeLists.txt b/recipes/nsimd/2.x/test_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/nsimd/2.x/test_package/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.1)
+project(test_package CXX)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup(TARGETS)
+
+find_package(nsimd CONFIG REQUIRED)
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} nsimd::nsimd)
diff --git a/recipes/nsimd/2.x/test_package/conanfile.py b/recipes/nsimd/2.x/test_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/nsimd/2.x/test_package/conanfile.py
@@ -0,0 +1,18 @@
+import os
+
+from conans import ConanFile, CMake, tools
+
+
+class NsimdTestConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "cmake", "cmake_find_package_multi"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        if not tools.cross_building(self):
+            bin_path = os.path.join("bin", "test_package")
+            self.run(bin_path, run_environment=True)
diff --git a/recipes/nsimd/2.x/test_package/test_package.cpp b/recipes/nsimd/2.x/test_package/test_package.cpp
new file mode 100644
--- /dev/null
+++ b/recipes/nsimd/2.x/test_package/test_package.cpp
@@ -0,0 +1,102 @@
+/* Tutorial from NSIMD library, modified to use a constant string */
+
+#include <nsimd/nsimd-all.hpp>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+#include <string.h>
+
+template <typename T>
+void uppercase_scalar(T *dst, const T *src, int n) {
+  for (int i = 0; i < n; i++) {
+    if (src[i] >= 'a' && src[i] <= 'z') {
+      dst[i] = src[i] + ('A' - 'a');
+    } else {
+      dst[i] = src[i];
+    }
+  }
+}
+
+template <typename T>
+void uppercase_simd(T *dst, const T *src, int n) {
+  using namespace nsimd;
+  typedef pack<T> p_t;
+  typedef packl<T> pl_t;
+  int l = len<p_t>();
+
+  int i;
+  for (i = 0; i + l <= n; i += l) {
+    p_t text = loadu<p_t>(src + i);
+    pl_t mask = text >= 'a' && text <= 'z';
+    p_t then_pack = text + ('A' - 'a');
+    p_t TEXT = if_else(mask, then_pack, text);
+    storeu(dst + i, TEXT);
+  }
+
+  pl_t mask = mask_for_loop_tail<pl_t>(i, n);
+  p_t text = maskz_loadu(mask, src + i);
+  p_t TEXT = if_else(text >= 'a' && text <= 'z', text + ('A' - 'a'), text);
+  mask_storeu(mask, dst + i, TEXT);
+}
+
+int test_uppercase_simd() {
+  std::string input("The quick brown fox jumps over the lazy dog");
+
+  std::cout << "Original text         : " << input << std::endl;
+
+  std::vector<i8> dst_scalar(input.size() + 1);
+  uppercase_scalar(&dst_scalar[0], (i8 *)input.c_str(), (int)input.size());
+  std::cout << "Scalar uppercase text: " << &dst_scalar[0] << std::endl;
+
+  std::vector<i8> dst_simd(input.size() + 1);
+  uppercase_simd(&dst_simd[0], (i8 *)input.c_str(), (int)input.size());
+  std::cout << "NSIMD uppercase text : " << &dst_simd[0] << std::endl;
+
+  if (memcmp(&dst_scalar[0], &dst_simd[0], dst_simd.size()) != 0) {
+    std::cerr << "ERROR: SIMD results don't match!" << std::endl;
+    return 1;
+  }
+
+  return 0;
+}
+
+// From nsimd-all.cpp
+
+int test_unroll() {
+  using namespace nsimd;
+  const int unroll = 3;
+  typedef pack<float, unroll> upack;
+
+  const int n_max = unroll * NSIMD_MAX_LEN(f32);
+  const int n = len(upack());
+  float buf[n_max];
+
+  for(int i = 0; i < n; i++) {
+    buf[i] = float(i);
+  }
+
+  upack p = loadu<upack>(buf);
+  p = -(p * p) + 1.0f;
+  storeu(buf, p);
+
+  for (int i = 0; i < n; i++) {
+    fprintf(stdout, "%f vs %f\n", double(buf[i]), double(-i * i));
+  }
+
+  for (int i = 0; i < n; i++) {
+    if (buf[i] != float(-(i * i) + 1)) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+int main() {
+  if (test_uppercase_simd() || test_unroll())
+    return 1;
+
+  return 0;
+}