openinterfaces 0.6.2__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/CMakeLists.txt +23 -12
  2. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/PKG-INFO +33 -4
  3. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/README.md +32 -3
  4. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/common/oif_config_dict.c +29 -14
  5. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/common/util.c +35 -0
  6. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/dispatch/dispatch.c +26 -25
  7. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/api.h +40 -14
  8. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/internal/bridge_api.h +2 -1
  9. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/internal/dispatch.h +4 -2
  10. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/util.h +8 -0
  11. openinterfaces-0.7.0/lang_c/CMakeLists.txt +2 -0
  12. openinterfaces-0.7.0/lang_c/oif/CMakeLists.txt +12 -0
  13. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/_convert.c +7 -7
  14. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/openinterfaces/CMakeLists.txt +1 -3
  15. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/openinterfaces/core.py +125 -39
  16. openinterfaces-0.7.0/lang_python/oif/openinterfaces/version.py +1 -0
  17. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/CMakeLists.txt +3 -3
  18. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/_callback.c +75 -45
  19. openinterfaces-0.7.0/lang_python/oif_impl/bridge_python.c +828 -0
  20. openinterfaces-0.7.0/lang_python/oif_impl/openinterfaces/_impl/interfaces/optim.py +36 -0
  21. openinterfaces-0.7.0/lang_python/oif_impl/openinterfaces/_impl/optim/scipy_optimize/scipy_optimize.conf +2 -0
  22. openinterfaces-0.7.0/lang_python/oif_impl/openinterfaces/_impl/optim/scipy_optimize/scipy_optimize.py +105 -0
  23. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/callback.py +5 -5
  24. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_interfaces/openinterfaces/interfaces/ivp.py +12 -6
  25. openinterfaces-0.7.0/lang_python/oif_interfaces/openinterfaces/interfaces/optim.py +152 -0
  26. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/pyproject.toml +1 -1
  27. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/CMakeLists.txt +1 -0
  28. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/lang_c/CMakeLists.txt +4 -0
  29. openinterfaces-0.7.0/tests/lang_python/test_examples.py +121 -0
  30. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/lang_python/test_ivp.py +1 -1
  31. openinterfaces-0.7.0/tests/lang_python/test_optim.py +155 -0
  32. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/LICENSE +0 -21
  33. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/README.md +0 -102
  34. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/example/README.md +0 -14
  35. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/README.md +0 -17
  36. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/basic-contexts/README.md +0 -16
  37. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/dump/README.md +0 -53
  38. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/numeric-extensions/README.md +0 -21
  39. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/objC/README.md +0 -98
  40. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/objC/obsolete/README.md +0 -40
  41. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/swift/README.md +0 -126
  42. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/goodies/utils/README.md +0 -52
  43. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/src/README.md +0 -28
  44. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-src/test/README.md +0 -17
  45. openinterfaces-0.6.2/cmake-build-debug/_deps/cwpack-subbuild/CMakeLists.txt +0 -42
  46. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/CMakeLists.txt +0 -39
  47. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/LICENSE +0 -28
  48. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/README.md +0 -117
  49. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googlemock/CMakeLists.txt +0 -218
  50. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googlemock/README.md +0 -40
  51. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googlemock/docs/README.md +0 -4
  52. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googlemock/include/gmock/internal/custom/README.md +0 -18
  53. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googletest/CMakeLists.txt +0 -338
  54. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googletest/README.md +0 -217
  55. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googletest/docs/README.md +0 -4
  56. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-src/googletest/include/gtest/internal/custom/README.md +0 -44
  57. openinterfaces-0.6.2/cmake-build-debug/_deps/googletest-subbuild/CMakeLists.txt +0 -34
  58. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-src/CMakeLists.txt +0 -120
  59. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-src/LICENSE +0 -21
  60. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-src/README.md +0 -155
  61. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-src/examples/CMakeLists.txt +0 -7
  62. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-src/test/CMakeLists.txt +0 -10
  63. openinterfaces-0.6.2/cmake-build-debug/_deps/hashmap-subbuild/CMakeLists.txt +0 -42
  64. openinterfaces-0.6.2/examples/call_ivp_from_python.py +0 -50
  65. openinterfaces-0.6.2/examples/call_ivp_from_python_burgers_eq.py +0 -110
  66. openinterfaces-0.6.2/examples/call_ivp_from_python_vdp.py +0 -133
  67. openinterfaces-0.6.2/examples/call_linsolve_from_python.py +0 -49
  68. openinterfaces-0.6.2/examples/call_qeq_from_python.py +0 -38
  69. openinterfaces-0.6.2/examples/compare_performance_ivp_burgers_eq.py +0 -241
  70. openinterfaces-0.6.2/examples/compare_performance_ivp_burgers_eq_pure_comparison.py +0 -294
  71. openinterfaces-0.6.2/examples/compare_performance_ivp_cvode_gray_scott.py +0 -455
  72. openinterfaces-0.6.2/lang_python/oif/openinterfaces/version.py +0 -1
  73. openinterfaces-0.6.2/lang_python/oif_impl/bridge_python.c +0 -597
  74. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/.pytest_cache/README.md +0 -0
  75. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/LICENSE +0 -0
  76. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/common/CMakeLists.txt +0 -0
  77. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/dispatch/CMakeLists.txt +0 -0
  78. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/_platform.h +0 -0
  79. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/_platform.h.gch +0 -0
  80. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/c_bindings.h +0 -0
  81. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/include/oif/config_dict.h +0 -0
  82. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_julia/CMakeLists.txt +0 -0
  83. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/CMakeLists.txt +0 -0
  84. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/CMakeLists.txt +0 -0
  85. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/openinterfaces/_conversion.c +0 -0
  86. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif/openinterfaces/util.py +0 -0
  87. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/_serialization.py +0 -0
  88. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/CMakeLists.txt +0 -0
  89. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/CMakeLists.txt +0 -0
  90. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/interfaces/ivp.py +0 -0
  91. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/interfaces/linsolve.py +0 -0
  92. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/interfaces/qeq.py +0 -0
  93. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/ivp/scipy_ode/scipy_ode.conf +0 -0
  94. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/ivp/scipy_ode/scipy_ode.py +0 -0
  95. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/linsolve/numpy/linsolve.py +0 -0
  96. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/linsolve/numpy/numpy.conf +0 -0
  97. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/qeq/py_qeq_solver/py_qeq_solver.conf +0 -0
  98. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_impl/openinterfaces/_impl/qeq/py_qeq_solver/qeq_solver.py +0 -0
  99. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_interfaces/openinterfaces/interfaces/linsolve.py +0 -0
  100. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/lang_python/oif_interfaces/openinterfaces/interfaces/qeq.py +0 -0
  101. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/lang_python/test_linsolve.py +0 -0
  102. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/lang_python/test_qeq.py +0 -0
  103. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/tests/lang_python/test_util.py +0 -0
  104. {openinterfaces-0.6.2 → openinterfaces-0.7.0}/vendor/CMakeLists.txt +0 -0
@@ -1,14 +1,19 @@
1
1
  cmake_minimum_required(VERSION 3.18)
2
2
 
3
3
  project(
4
- oif-toy-example
5
- LANGUAGES C CXX
6
- VERSION 0.6.2)
4
+ open-interfaces
5
+ VERSION 0.7.0
6
+ # SPDX_LICENSE BSD-2-Clause -- Available in CMake 4.2+
7
+ DESCRIPTION "Improving interoperability in scientific computing"
8
+ HOMEPAGE_URL https://github.com/MaRDI4NFDI/open-interfaces
9
+ LANGUAGES C CXX)
7
10
 
8
11
  option(OIF_OPTION_VERBOSE_DEBUG_INFO
9
12
  "Enable verbose debug info in Debug builds" OFF)
10
13
 
11
- option(OIF_OPTION_SANITIZE "Enable sanitizers in Debug builds" OFF)
14
+ option(OIF_OPTION_SANITIZE "Enable sanitizers, only in Debug builds" OFF)
15
+
16
+ option(OIF_OPTION_COVERAGE "Enable test coverage, only in Debug builds" OFF)
12
17
 
13
18
  # Enforce using `-std=c11`, without any extensions like `gnu11`.
14
19
  set(CMAKE_C_STANDARD 11)
@@ -26,8 +31,12 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
26
31
  add_compile_definitions(OIF_OPTION_VERBOSE_DEBUG_INFO)
27
32
  endif()
28
33
  if(OIF_OPTION_SANITIZE)
29
- add_compile_options(-fno-omit-frame-pointer -fsanitize=address)
30
- add_link_options(-fno-omit-frame-pointer -fsanitize=address)
34
+ add_compile_options(-fno-omit-frame-pointer -fsanitize=address,undefined)
35
+ add_link_options(-fno-omit-frame-pointer -fsanitize=address,undefined)
36
+ endif()
37
+ if(OIF_OPTION_COVERAGE)
38
+ add_compile_options(--coverage)
39
+ add_link_options(--coverage)
31
40
  endif()
32
41
  endif()
33
42
 
@@ -60,14 +69,16 @@ add_subdirectory(vendor)
60
69
  add_subdirectory(common)
61
70
  add_subdirectory(dispatch)
62
71
 
63
- add_subdirectory(lang_julia)
64
- add_subdirectory(lang_python)
72
+ if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang_c")
73
+ add_subdirectory(lang_c)
74
+ endif()
65
75
 
66
- if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/oif")
67
- add_subdirectory(oif)
76
+ if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang_julia")
77
+ add_subdirectory(lang_julia)
68
78
  endif()
69
- if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/oif_impl")
70
- add_subdirectory(oif_impl)
79
+
80
+ if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lang_python")
81
+ add_subdirectory(lang_python)
71
82
  endif()
72
83
 
73
84
  if(EXISTS examples/CMakeLists.txt)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openinterfaces
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: Open Interfaces for improving Interoperability in Scientific Computing
5
5
  Author-Email: "Dmitry I. Kabanov" <dmitry.kabanov@uni-muenster.de>, Stephan Rave <stephan.rave@uni-muenster.de>, Mario Ohlberger <mario.ohlberger@uni-muenster.de>
6
6
  License-File: LICENSE
@@ -54,9 +54,15 @@ marshalling between different languages and a set of interfaces for typical
54
54
  numerical problems such as integration of differential equations and
55
55
  optimization.
56
56
 
57
- | Traditional pairwise bindings-----| | Decoupled bindings via _Open Interfaces_ |
58
- |:----------------------------------|---|-----------------------------------------:|
59
- | ![](assets/pairwise_bindings.png) | | ![](assets/oif_bindings.png) |
57
+ <p align="center">
58
+ <img src="https://media.githubusercontent.com/media/MaRDI4NFDI/open-interfaces/refs/heads/main/assets/pairwise_bindings.png" />
59
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
60
+ <img src="https://media.githubusercontent.com/media/MaRDI4NFDI/open-interfaces/refs/heads/main/assets/oif_bindings.png" />
61
+ <br />
62
+ <strong>A</strong>&nbsp;Traditional pairwise bindings
63
+ <br />
64
+ <strong>B</strong>&nbsp;Decoupled bindings via <em>Open Interfaces</em>
65
+ </p>
60
66
 
61
67
  This project is the part of the [_Mathematical Research Data Initiative
62
68
  (MaRDI)_](https://mardi4nfdi.de).
@@ -76,6 +82,29 @@ Please use the
76
82
  for bug reports and feature requests and asking questions.
77
83
 
78
84
 
85
+ ## License
86
+
87
+ [![License](https://img.shields.io/badge/License-BSD_2--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
88
+
89
+
90
+ ## Citing
91
+
92
+ If you _MaRDI Open Interfaces_, please consider citing
93
+ [this paper](https://openresearchsoftware.metajnl.com/articles/10.5334/jors.569):
94
+ ```bibtex
95
+ @Article{KabanovEtAl2025,
96
+ author = {Kabanov, Dmitry I. and Rave, Stephan and Ohlberger, Mario},
97
+ journal = {Journal of Open Research Software},
98
+ title = {Improving Interoperability in Scientific Computing via {MaRDI Open Interfaces}},
99
+ year = {2025},
100
+ issn = {2049-9647},
101
+ volume = {13},
102
+ doi = {10.5334/jors.569},
103
+ publisher = {Ubiquity Press, Ltd.},
104
+ }
105
+ ```
106
+
107
+
79
108
  ## Funding
80
109
 
81
110
  This work is funded by the _Deutsche Forschungsgemeinschaft_ (DFG, _German
@@ -25,9 +25,15 @@ marshalling between different languages and a set of interfaces for typical
25
25
  numerical problems such as integration of differential equations and
26
26
  optimization.
27
27
 
28
- | Traditional pairwise bindings-----| | Decoupled bindings via _Open Interfaces_ |
29
- |:----------------------------------|---|-----------------------------------------:|
30
- | ![](assets/pairwise_bindings.png) | | ![](assets/oif_bindings.png) |
28
+ <p align="center">
29
+ <img src="https://media.githubusercontent.com/media/MaRDI4NFDI/open-interfaces/refs/heads/main/assets/pairwise_bindings.png" />
30
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
31
+ <img src="https://media.githubusercontent.com/media/MaRDI4NFDI/open-interfaces/refs/heads/main/assets/oif_bindings.png" />
32
+ <br />
33
+ <strong>A</strong>&nbsp;Traditional pairwise bindings
34
+ <br />
35
+ <strong>B</strong>&nbsp;Decoupled bindings via <em>Open Interfaces</em>
36
+ </p>
31
37
 
32
38
  This project is the part of the [_Mathematical Research Data Initiative
33
39
  (MaRDI)_](https://mardi4nfdi.de).
@@ -47,6 +53,29 @@ Please use the
47
53
  for bug reports and feature requests and asking questions.
48
54
 
49
55
 
56
+ ## License
57
+
58
+ [![License](https://img.shields.io/badge/License-BSD_2--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
59
+
60
+
61
+ ## Citing
62
+
63
+ If you _MaRDI Open Interfaces_, please consider citing
64
+ [this paper](https://openresearchsoftware.metajnl.com/articles/10.5334/jors.569):
65
+ ```bibtex
66
+ @Article{KabanovEtAl2025,
67
+ author = {Kabanov, Dmitry I. and Rave, Stephan and Ohlberger, Mario},
68
+ journal = {Journal of Open Research Software},
69
+ title = {Improving Interoperability in Scientific Computing via {MaRDI Open Interfaces}},
70
+ year = {2025},
71
+ issn = {2049-9647},
72
+ volume = {13},
73
+ doi = {10.5334/jors.569},
74
+ publisher = {Ubiquity Press, Ltd.},
75
+ }
76
+ ```
77
+
78
+
50
79
  ## Funding
51
80
 
52
81
  This work is funded by the _Deutsche Forschungsgemeinschaft_ (DFG, _German
@@ -31,6 +31,8 @@ static size_t SIZE_ = 65;
31
31
  #define MAX_KEY_LENGTH_ 1024
32
32
  #define BUF_SIZE_ 128
33
33
 
34
+ static char prefix_[] = "oif_config_dict";
35
+
34
36
  static char *
35
37
  copy_key_(const char *key)
36
38
  {
@@ -67,7 +69,7 @@ oif_config_dict_init(void)
67
69
  OIFConfigDict *dict = oif_util_malloc(sizeof(OIFConfigDict));
68
70
  assert(dict != NULL);
69
71
 
70
- dict->type = OIF_CONFIG_DICT;
72
+ dict->type = OIF_TYPE_CONFIG_DICT;
71
73
  dict->src = OIF_LANG_C;
72
74
  dict->size = 0;
73
75
  dict->buffer = NULL;
@@ -86,7 +88,7 @@ oif_config_dict_free(void *_dict)
86
88
  return;
87
89
  }
88
90
  OIFConfigDict *dict = _dict;
89
- assert(dict->type == OIF_CONFIG_DICT);
91
+ assert(dict->type == OIF_TYPE_CONFIG_DICT);
90
92
  const char *key;
91
93
  OIFConfigEntry *entry;
92
94
  hashmap_foreach(key, entry, &dict->map)
@@ -113,7 +115,7 @@ oif_config_dict_add_int(OIFConfigDict *dict, const char *key, int value)
113
115
  fprintf(stderr, "Could not add an entry to the config dictionary\n");
114
116
  exit(1);
115
117
  }
116
- entry->type = OIF_INT;
118
+ entry->type = OIF_TYPE_INT;
117
119
  entry->value = oif_util_malloc(sizeof(int));
118
120
  if (entry->value == NULL) {
119
121
  fprintf(stderr, "Could not allocate memory for adding an int entry\n");
@@ -135,7 +137,7 @@ oif_config_dict_add_double(OIFConfigDict *dict, const char *key, double value)
135
137
  fprintf(stderr, "Could not add an entry to the config dictionary\n");
136
138
  exit(1);
137
139
  }
138
- entry->type = OIF_FLOAT64;
140
+ entry->type = OIF_TYPE_F64;
139
141
  entry->value = oif_util_malloc(sizeof(double));
140
142
  if (entry->value == NULL) {
141
143
  fprintf(stderr, "Could not allocate memory for adding a double entry\n");
@@ -157,7 +159,7 @@ oif_config_dict_add_str(OIFConfigDict *dict, const char *key, const char *value)
157
159
  fprintf(stderr, "Could not add an entry to the config dictionary\n");
158
160
  exit(1);
159
161
  }
160
- entry->type = OIF_STR;
162
+ entry->type = OIF_TYPE_STRING;
161
163
  entry->value = oif_util_str_duplicate(value);
162
164
  if (entry->value == NULL) {
163
165
  fprintf(stderr, "Could not allocate memory for adding a string entry\n");
@@ -216,7 +218,7 @@ oif_config_dict_get_int(OIFConfigDict *dict, const char *key)
216
218
  exit(1);
217
219
  }
218
220
 
219
- assert(entry->type == OIF_INT);
221
+ assert(entry->type == OIF_TYPE_INT);
220
222
  int int_value = *(int *)entry->value;
221
223
  return int_value;
222
224
  }
@@ -230,7 +232,7 @@ oif_config_dict_get_double(OIFConfigDict *dict, const char *key)
230
232
  exit(1);
231
233
  }
232
234
 
233
- assert(entry->type == OIF_FLOAT64);
235
+ assert(entry->type == OIF_TYPE_F64);
234
236
  double double_value = *(double *)entry->value;
235
237
  return double_value;
236
238
  }
@@ -247,13 +249,13 @@ oif_config_dict_print(OIFConfigDict *dict)
247
249
  else {
248
250
  hashmap_foreach(key, entry, &dict->map)
249
251
  {
250
- if (entry->type == OIF_INT) {
252
+ if (entry->type == OIF_TYPE_INT) {
251
253
  printf("Key = '%s', value = '%d'\n", key, *(int *)entry->value);
252
254
  }
253
- else if (entry->type == OIF_FLOAT64) {
255
+ else if (entry->type == OIF_TYPE_F64) {
254
256
  printf("Key = '%s', value = '%f'\n", key, *(double *)entry->value);
255
257
  }
256
- else if (entry->type == OIF_STR) {
258
+ else if (entry->type == OIF_TYPE_STRING) {
257
259
  printf("Key = '%s', value = '%s'\n", key, (char *)entry->value);
258
260
  }
259
261
  else {
@@ -280,6 +282,18 @@ oif_config_dict_print(OIFConfigDict *dict)
280
282
  void
281
283
  oif_config_dict_serialize(OIFConfigDict *dict)
282
284
  {
285
+ if (dict == NULL) {
286
+ logerr(prefix_, "Serialization is possible only for non-NULL dict");
287
+ exit(1);
288
+ }
289
+
290
+ // Probably, not the best solution, as multiple invocation of serialization
291
+ // should be possible, but I just want to rectify a memory leak for now.
292
+ if (dict->pc != NULL) {
293
+ logerr(prefix_, "Serialization was already done");
294
+ exit(1);
295
+ }
296
+
283
297
  cw_pack_context *pc = oif_util_malloc(sizeof(*pc));
284
298
  if (pc == NULL) {
285
299
  fprintf(stderr,
@@ -307,14 +321,14 @@ oif_config_dict_serialize(OIFConfigDict *dict)
307
321
  {
308
322
  cw_pack_str(pc, key, oif_util_u32_from_size_t(strlen(key)));
309
323
 
310
- if (entry->type == OIF_INT) {
324
+ if (entry->type == OIF_TYPE_INT) {
311
325
  int64_t i64_value = *(int *)entry->value;
312
326
  cw_pack_signed(pc, i64_value);
313
327
  }
314
- else if (entry->type == OIF_FLOAT64) {
328
+ else if (entry->type == OIF_TYPE_F64) {
315
329
  cw_pack_double(pc, *(double *)entry->value);
316
330
  }
317
- else if (entry->type == OIF_STR) {
331
+ else if (entry->type == OIF_TYPE_STRING) {
318
332
  cw_pack_str(pc, (char *)entry->value,
319
333
  oif_util_u32_from_size_t(strlen(entry->value)));
320
334
  }
@@ -471,7 +485,8 @@ oif_config_dict_copy_serialization(OIFConfigDict *to, const OIFConfigDict *from)
471
485
  }
472
486
  memcpy(to->buffer, from->buffer, from->buffer_length);
473
487
  to->buffer_length = from->buffer_length;
474
- to->buffer[to->buffer_length] = '\0'; // Ensure null-termination.
488
+ // We put nul-terminator to be able to print out the buffer as a string.
489
+ to->buffer[to->buffer_length] = '\0';
475
490
  return 0;
476
491
  }
477
492
 
@@ -182,6 +182,41 @@ oif_util_str_contains(const char **arr, const char *s)
182
182
  return false;
183
183
  }
184
184
 
185
+ char *
186
+ oif_util_make_string(const char *fmt, ...)
187
+ {
188
+ // Number of required bytes for the string *excluding* the null byte.
189
+ int nbytes_required = 0;
190
+ // Number of allocated bytes for the string *including* the null byte.
191
+ size_t str_length;
192
+
193
+ va_list args;
194
+
195
+ va_start(args, fmt);
196
+ // `snprintf` with an empty destination string provides
197
+ // the information about the required number of bytes.
198
+ nbytes_required = vsnprintf(NULL, 0, fmt, args);
199
+ va_end(args);
200
+ if (nbytes_required < 0) {
201
+ fprintf(stderr, "[oif_util] Could not make a string\n");
202
+ return NULL;
203
+ }
204
+
205
+ str_length = (size_t)nbytes_required + 1;
206
+ char *s = oif_util_malloc(str_length * sizeof(*s));
207
+
208
+ va_start(args, fmt);
209
+ int nbytes_written = vsnprintf(s, str_length, fmt, args);
210
+ va_end(args);
211
+ if (nbytes_written + 1 != str_length) {
212
+ fprintf(stderr, "[oif_util] Could not make a string\n");
213
+ oif_util_free(s);
214
+ return NULL;
215
+ }
216
+
217
+ return s;
218
+ }
219
+
185
220
  int
186
221
  logwarn(const char *prefix, const char *fmt, ...)
187
222
  {
@@ -103,13 +103,8 @@ load_interface_impl(const char *interface, const char *impl, size_t version_majo
103
103
  /* One must be a pessimist, while programming in C. */
104
104
  ImplHandle retval = OIF_IMPL_INIT_ERROR;
105
105
 
106
- char conf_filename_fixed_part[512] = {'\0'};
107
- strcat(conf_filename_fixed_part, interface);
108
- strcat(conf_filename_fixed_part, "/");
109
- strcat(conf_filename_fixed_part, impl);
110
- strcat(conf_filename_fixed_part, "/");
111
- strcat(conf_filename_fixed_part, impl);
112
- strcat(conf_filename_fixed_part, ".conf");
106
+ char *conf_filename_fixed_part =
107
+ oif_util_make_string("%s/%s/%s.conf", interface, impl, impl);
113
108
 
114
109
  // We cannot tokenize OIF_IMPL_PATH because `strtok`
115
110
  // modifies the original string during tokenization
@@ -118,33 +113,29 @@ load_interface_impl(const char *interface, const char *impl, size_t version_majo
118
113
  // OIF_IMPL_PATH will not have the original value.
119
114
  char *oif_impl_path_dup = oif_util_str_duplicate(OIF_IMPL_PATH);
120
115
  char *path = strtok((char *)oif_impl_path_dup, ":");
121
- char conf_filename[1024] = "";
122
- char *conf_filename_p = conf_filename;
116
+ char *conf_filename = NULL;
123
117
  while (path) {
124
- strcat(conf_filename_p, path);
125
- strcat(conf_filename_p, "/");
126
- strcat(conf_filename_p, conf_filename_fixed_part);
127
-
118
+ conf_filename = oif_util_make_string("%s/%s", path, conf_filename_fixed_part);
128
119
  conf_file = fopen(conf_filename, "re");
129
120
  if (conf_file != NULL) {
130
121
  break;
131
122
  }
123
+ oif_util_free(conf_filename);
132
124
  path = strtok(NULL, ":");
133
- conf_filename_p = conf_filename;
134
- conf_filename_p[0] = '\0';
135
125
  }
136
126
 
137
127
  if (conf_file == NULL) {
138
128
  logerr(prefix_,
139
129
  "Cannot open conf file '%s'\n"
140
- "\tSearch was done in the following paths: %s\n",
141
- conf_filename_fixed_part, oif_impl_path_dup);
130
+ "\tSearch was done in the following paths: '%s'\n",
131
+ conf_filename_fixed_part, OIF_IMPL_PATH);
142
132
  oif_util_free(oif_impl_path_dup);
143
133
  perror("Error message is: ");
144
134
  return -1;
145
135
  }
146
136
  else {
147
137
  fprintf(stderr, "[%s] Configuration file: %s\n", prefix_, conf_filename);
138
+ oif_util_free(conf_filename);
148
139
  }
149
140
  oif_util_free(oif_impl_path_dup);
150
141
 
@@ -262,6 +253,8 @@ cleanup:
262
253
  fclose(conf_file);
263
254
  }
264
255
 
256
+ oif_util_free(conf_filename_fixed_part);
257
+
265
258
  return retval;
266
259
  }
267
260
 
@@ -321,36 +314,44 @@ unload_interface_impl(ImplHandle implh)
321
314
  }
322
315
 
323
316
  int
324
- call_interface_impl(ImplHandle implh, const char *method, OIFArgs *in_args, OIFArgs *out_args)
317
+ call_interface_impl(ImplHandle implh, const char *method, OIFArgs *in_args, OIFArgs *out_args,
318
+ OIFArgs *return_args)
325
319
  {
326
320
  int status;
327
321
 
328
322
  ImplInfo *impl_info = hashmap_get(&IMPL_MAP, &implh);
323
+ if (impl_info == NULL) {
324
+ logerr(prefix_,
325
+ "Cannot find implementation with id '%d' in the list of loaded implementations",
326
+ implh);
327
+ return -1;
328
+ }
329
+
329
330
  DispatchHandle dh = impl_info->dh;
330
331
  if (OIF_DISPATCH_HANDLES[dh] == NULL) {
331
332
  logerr(prefix_,
332
333
  "Cannot call interface implementation "
333
334
  "for language '%s'\n",
334
335
  OIF_LANG_FROM_LANG_ID[dh]);
335
- exit(EXIT_FAILURE);
336
+ return -2;
336
337
  }
337
- void *lib_handle = OIF_DISPATCH_HANDLES[dh];
338
338
 
339
- int (*call_impl_fn)(ImplInfo *, const char *, OIFArgs *, OIFArgs *);
339
+ void *lib_handle = OIF_DISPATCH_HANDLES[dh];
340
+ int (*call_impl_fn)(ImplInfo *, const char *, OIFArgs *, OIFArgs *, OIFArgs *);
340
341
  call_impl_fn = dlsym(lib_handle, "call_impl");
341
342
  if (call_impl_fn == NULL) {
342
343
  logerr(prefix_,
343
344
  "Could not load function 'call_impl' "
344
- "for language '%s'\n",
345
+ "for language '%s'",
345
346
  OIF_LANG_FROM_LANG_ID[dh]);
346
- return -1;
347
+ return -3;
347
348
  }
348
- status = call_impl_fn(impl_info, method, in_args, out_args);
349
+ status = call_impl_fn(impl_info, method, in_args, out_args, return_args);
349
350
 
350
351
  if (status) {
351
352
  logerr(prefix_,
352
353
  "During execution of the function "
353
- "'%s::%s' an error occurred\n",
354
+ "'%s::%s' an error occurred",
354
355
  impl_info->interface, method);
355
356
  }
356
357
  return status;
@@ -7,6 +7,11 @@ extern "C" {
7
7
 
8
8
  #include <stddef.h>
9
9
  #include <stdint.h>
10
+ #include <sys/types.h>
11
+
12
+ #include <oif/_platform.h>
13
+
14
+ static_assert(sizeof(intptr_t) == sizeof(ssize_t), "We expect a 64-bit platform");
10
15
 
11
16
  // Handle to an instantiated implementation.
12
17
  typedef int ImplHandle;
@@ -21,15 +26,33 @@ enum {
21
26
  };
22
27
 
23
28
  typedef enum {
24
- OIF_INT = 1,
25
- // OIF_FLOAT32 = 2,
26
- OIF_FLOAT64 = 3,
27
- // OIF_FLOAT32_P = 4,
28
- OIF_ARRAY_F64 = 5,
29
- OIF_STR = 6,
30
- OIF_CALLBACK = 7,
31
- OIF_USER_DATA = 8,
32
- OIF_CONFIG_DICT = 9,
29
+ OIF_TYPE_BOOL = 1,
30
+
31
+ OIF_TYPE_CHAR = 2,
32
+ OIF_TYPE_I8 = 2,
33
+ OIF_TYPE_UCHAR = 3,
34
+ OIF_TYPE_U8 = 3,
35
+
36
+ OIF_TYPE_I32 = 4,
37
+ OIF_TYPE_INT = 4, // Use int as an alias to int32
38
+ OIF_TYPE_U32 = 5,
39
+ OIF_TYPE_UINT = 5, // Use uint as an alias to uint32
40
+
41
+ OIF_TYPE_I64 = 6,
42
+ OIF_TYPE_U64 = 7,
43
+
44
+ OIF_TYPE_F32 = 8,
45
+ OIF_TYPE_F64 = 9,
46
+
47
+ OIF_TYPE_ARRAY_F32 = 10,
48
+ OIF_TYPE_ARRAY_F64 = 11,
49
+
50
+ OIF_TYPE_STRING = 12,
51
+ OIF_TYPE_CALLBACK = 13,
52
+ OIF_USER_DATA = 14,
53
+ OIF_TYPE_USER_DATA = 14,
54
+ OIF_TYPE_POINTER = 14,
55
+ OIF_TYPE_CONFIG_DICT = 15,
33
56
  } OIFArgType;
34
57
 
35
58
  enum {
@@ -57,7 +80,7 @@ typedef struct {
57
80
  // Number of dimensions in the array.
58
81
  int nd;
59
82
  // Size of each axis, i = 0, .., nd-1.
60
- intptr_t *dimensions;
83
+ ssize_t *dimensions;
61
84
  // Pointer to actual data.
62
85
  double *data;
63
86
  // Flags that describe the array: things like row-major order, etc.
@@ -72,10 +95,13 @@ typedef struct {
72
95
 
73
96
  // This structure is used for callback functions.
74
97
  typedef struct {
75
- int src; // Language of the function (one of OIF_LANG_* constants)
76
- void *fn_p_c; // Function pointer in C
77
- void *fn_p_jl; // Function pointer in Julia
78
- void *fn_p_py; // Function pointer in Python
98
+ int src; // Language of the function (one of OIF_LANG_* constants)
99
+ void *fn_p_c; // Function pointer in C
100
+ void *fn_p_jl; // Function pointer in Julia
101
+ void *fn_p_py; // Function pointer in Python
102
+ unsigned int nargs; // Number of arguments
103
+ OIFArgType *arg_types;
104
+ OIFArgType restype;
79
105
  } OIFCallback;
80
106
 
81
107
  /**
@@ -30,7 +30,8 @@ ImplInfo *
30
30
  load_impl(const char *impl_details, size_t version_major, size_t version_minor);
31
31
 
32
32
  int
33
- call_impl(ImplInfo *impl_info, const char *method, OIFArgs *in_args, OIFArgs *out_args);
33
+ call_impl(ImplInfo *impl_info, const char *method, OIFArgs *in_args, OIFArgs *out_args,
34
+ OIFArgs *return_args);
34
35
 
35
36
  int
36
37
  unload_impl(ImplInfo *impl_info);
@@ -39,11 +39,13 @@ unload_interface_impl(ImplHandle implh);
39
39
  * @param implh Implementat handle that identifies the implementation
40
40
  * @param method Name of the method (function) to invoke
41
41
  * @param in_args Array of input arguments
42
- * @param out_args Array of output arguments
42
+ * @param out_args Array of output (mutable) arguments
43
+ * @param return_args Array of return arguments
43
44
  * @return status code that signals about an error if non-zero
44
45
  */
45
46
  int
46
- call_interface_impl(ImplHandle implh, const char *method, OIFArgs *in_args, OIFArgs *out_args);
47
+ call_interface_impl(ImplHandle implh, const char *method, OIFArgs *in_args, OIFArgs *out_args,
48
+ OIFArgs *return_args);
47
49
 
48
50
  #ifdef __cplusplus
49
51
  }
@@ -80,6 +80,14 @@ oif_strcmp_nocase(const char *s1, const char *s2);
80
80
  bool
81
81
  oif_util_str_contains(const char **arr, const char *s);
82
82
 
83
+ /**
84
+ * Make a string from given format and data and pass it to caller.
85
+ *
86
+ * @return Allocated string or NULL on failure
87
+ */
88
+ char *
89
+ oif_util_make_string(const char *fmt, ...);
90
+
83
91
  /**
84
92
  * Log a warning message to stderr.
85
93
  *
@@ -0,0 +1,2 @@
1
+ add_subdirectory(oif)
2
+ add_subdirectory(oif_impl)
@@ -0,0 +1,12 @@
1
+ # User-facing C library that allows to interact with Open Interfaces.
2
+ add_library(
3
+ oif_c SHARED
4
+ c_bindings.c ${PROJECT_SOURCE_DIR}/lang_c/oif_interfaces/src/qeq.c
5
+ ${PROJECT_SOURCE_DIR}/lang_c/oif_interfaces/src/linsolve.c
6
+ ${PROJECT_SOURCE_DIR}/lang_c/oif_interfaces/src/ivp.c)
7
+ target_include_directories(oif_c PUBLIC ${PROJECT_SOURCE_DIR}/include)
8
+ target_include_directories(
9
+ oif_c PUBLIC ${PROJECT_SOURCE_DIR}/lang_c/oif_interfaces/include/)
10
+ target_link_libraries(oif_c PUBLIC oif_common_data_structures)
11
+ target_link_libraries(oif_c PUBLIC oif_common_util)
12
+ target_link_libraries(oif_c PRIVATE oif_dispatch)
@@ -80,15 +80,15 @@ python_types_from_oif_types(PyObject *py_args, PyObject *c_args, PyObject *arg_t
80
80
  PyObject *py_type = PyTuple_GET_ITEM(arg_types, i);
81
81
  long c_type = PyLong_AsLong(py_type);
82
82
  PyObject *py_cur_arg = PyTuple_GET_ITEM(c_args, i);
83
- if (c_type == OIF_INT) {
83
+ if (c_type == OIF_TYPE_INT) {
84
84
  cur_arg = py_cur_arg;
85
85
  }
86
- else if (c_type == OIF_FLOAT64) {
86
+ else if (c_type == OIF_TYPE_F64) {
87
87
  cur_arg = py_cur_arg;
88
88
  }
89
- else if (c_type == OIF_ARRAY_F64) {
89
+ else if (c_type == OIF_TYPE_ARRAY_F64) {
90
90
  if (!PyObject_HasAttrString(py_cur_arg, "contents")) {
91
- fprintf(stderr, "[_convert] Pass OIF_ARRAY_F64 is not ctypes object\n");
91
+ fprintf(stderr, "[_convert] Passed OIF_TYPE_ARRAY_F64 is not ctypes object\n");
92
92
  exit(EXIT_FAILURE);
93
93
  }
94
94
 
@@ -162,13 +162,13 @@ c_wrapper_over_py_callable(void *py_fn, OIFArgs *args)
162
162
  for (size_t i = 0; i < num_args; ++i) {
163
163
  void *c_arg = args->arg_values[i];
164
164
  switch (args->arg_types[i]) {
165
- case OIF_INT:
165
+ case OIF_TYPE_INT:
166
166
  cur_arg = PyLong_FromLong(*(int *)c_arg);
167
167
  break;
168
- case OIF_FLOAT64:
168
+ case OIF_TYPE_F64:
169
169
  cur_arg = PyFloat_FromDouble(*(double *)c_arg);
170
170
  break;
171
- case OIF_ARRAY_F64:
171
+ case OIF_TYPE_ARRAY_F64:
172
172
  arr = *(OIFArrayF64 **)c_arg;
173
173
  assert(arr->nd == 1);
174
174
  cur_arg = PyArray_SimpleNewFromData(arr->nd, arr->dimensions, NPY_FLOAT64,
@@ -5,9 +5,7 @@ pkg_check_modules(FFI REQUIRED IMPORTED_TARGET libffi)
5
5
 
6
6
  add_library(oif_python_conversion MODULE _conversion.c)
7
7
  target_include_directories(
8
- oif_python_conversion
9
- PRIVATE ${CMAKE_SOURCE_DIR}/include
10
- PRIVATE ${FFI_INCLUDE_DIRS})
8
+ oif_python_conversion PRIVATE ${CMAKE_SOURCE_DIR}/include ${FFI_INCLUDE_DIRS})
11
9
  target_link_libraries(oif_python_conversion PRIVATE Python::Python)
12
10
  target_link_libraries(oif_python_conversion PRIVATE Python::NumPy)
13
11
  target_link_libraries(oif_python_conversion PRIVATE PkgConfig::FFI)