jrpycpp 0.1.0__py3-none-any.whl

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 (96) hide show
  1. jrpycpp/__init__.py +3 -0
  2. jrpycpp/__version__.py +1 -0
  3. jrpycpp/examples/cpp_scripts/chapter2/demo/01-class.cpp +24 -0
  4. jrpycpp/examples/cpp_scripts/chapter2/demo/02-const.cpp +25 -0
  5. jrpycpp/examples/cpp_scripts/chapter2/exercise/stats.cpp +26 -0
  6. jrpycpp/examples/cpp_scripts/chapter2/solution/stats.cpp +44 -0
  7. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/bindings.cpp +11 -0
  8. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/pi.cpp +10 -0
  9. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/pi.h +3 -0
  10. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/pyproject.toml +11 -0
  11. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/setup.py +12 -0
  12. jrpycpp/examples/cpp_scripts/chapter3/demo/01-free-function/test_pi.py +11 -0
  13. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/bindings.cpp +17 -0
  14. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/pyproject.toml +11 -0
  15. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/setup.py +12 -0
  16. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/stats.cpp +26 -0
  17. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/stats.h +15 -0
  18. jrpycpp/examples/cpp_scripts/chapter3/demo/02-class/test_livstats.py +18 -0
  19. jrpycpp/examples/cpp_scripts/chapter3/exercise/bindings.cpp +12 -0
  20. jrpycpp/examples/cpp_scripts/chapter3/exercise/pyproject.toml +11 -0
  21. jrpycpp/examples/cpp_scripts/chapter3/exercise/setup.py +12 -0
  22. jrpycpp/examples/cpp_scripts/chapter3/exercise/stats.cpp +26 -0
  23. jrpycpp/examples/cpp_scripts/chapter3/exercise/stats.h +15 -0
  24. jrpycpp/examples/cpp_scripts/chapter3/solution/bindings.cpp +22 -0
  25. jrpycpp/examples/cpp_scripts/chapter3/solution/pyproject.toml +11 -0
  26. jrpycpp/examples/cpp_scripts/chapter3/solution/setup.py +12 -0
  27. jrpycpp/examples/cpp_scripts/chapter3/solution/stats.cpp +26 -0
  28. jrpycpp/examples/cpp_scripts/chapter3/solution/stats.h +15 -0
  29. jrpycpp/examples/cpp_scripts/chapter3/solution/test_livstats.py +18 -0
  30. jrpycpp/examples/cpp_scripts/chapter4/demo/arrays.cpp +13 -0
  31. jrpycpp/examples/cpp_scripts/chapter4/demo/arrays.h +7 -0
  32. jrpycpp/examples/cpp_scripts/chapter4/demo/bindings.cpp +73 -0
  33. jrpycpp/examples/cpp_scripts/chapter4/demo/pyproject.toml +11 -0
  34. jrpycpp/examples/cpp_scripts/chapter4/demo/setup.py +12 -0
  35. jrpycpp/examples/cpp_scripts/chapter4/demo/test_arrays.py +38 -0
  36. jrpycpp/examples/cpp_scripts/chapter4/exercise/arrays.cpp +13 -0
  37. jrpycpp/examples/cpp_scripts/chapter4/exercise/arrays.h +7 -0
  38. jrpycpp/examples/cpp_scripts/chapter4/exercise/bindings.cpp +36 -0
  39. jrpycpp/examples/cpp_scripts/chapter4/exercise/pyproject.toml +11 -0
  40. jrpycpp/examples/cpp_scripts/chapter4/exercise/setup.py +12 -0
  41. jrpycpp/examples/cpp_scripts/chapter4/solution/arrays.cpp +13 -0
  42. jrpycpp/examples/cpp_scripts/chapter4/solution/arrays.h +7 -0
  43. jrpycpp/examples/cpp_scripts/chapter4/solution/bindings.cpp +49 -0
  44. jrpycpp/examples/cpp_scripts/chapter4/solution/pyproject.toml +11 -0
  45. jrpycpp/examples/cpp_scripts/chapter4/solution/setup.py +12 -0
  46. jrpycpp/examples/cpp_scripts/chapter4/solution/test_arrays.py +19 -0
  47. jrpycpp/examples/cpp_scripts/chapter5/demo/01-cmake/CMakeLists.txt +22 -0
  48. jrpycpp/examples/cpp_scripts/chapter5/demo/01-cmake/include/stats.h +15 -0
  49. jrpycpp/examples/cpp_scripts/chapter5/demo/01-cmake/src/main.cpp +9 -0
  50. jrpycpp/examples/cpp_scripts/chapter5/demo/01-cmake/src/stats.cpp +26 -0
  51. jrpycpp/examples/cpp_scripts/chapter5/demo/01-cmake/tests/test_stats.cpp +20 -0
  52. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/CMakeLists.txt +28 -0
  53. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/include/stats.h +15 -0
  54. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/pyproject.toml +11 -0
  55. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/python/bindings.cpp +17 -0
  56. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/src/stats.cpp +26 -0
  57. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/tests/test_livstats.py +10 -0
  58. jrpycpp/examples/cpp_scripts/chapter5/demo/02-python/tests/test_stats.cpp +20 -0
  59. jrpycpp/examples/cpp_scripts/chapter5/exercise/CMakeLists.txt +17 -0
  60. jrpycpp/examples/cpp_scripts/chapter5/exercise/include/stats.h +15 -0
  61. jrpycpp/examples/cpp_scripts/chapter5/exercise/src/main.cpp +9 -0
  62. jrpycpp/examples/cpp_scripts/chapter5/exercise/src/stats.cpp +26 -0
  63. jrpycpp/examples/cpp_scripts/chapter5/exercise/tests/test_stats.cpp +16 -0
  64. jrpycpp/examples/cpp_scripts/chapter5/solution/CMakeLists.txt +22 -0
  65. jrpycpp/examples/cpp_scripts/chapter5/solution/include/stats.h +15 -0
  66. jrpycpp/examples/cpp_scripts/chapter5/solution/src/main.cpp +9 -0
  67. jrpycpp/examples/cpp_scripts/chapter5/solution/src/stats.cpp +26 -0
  68. jrpycpp/examples/cpp_scripts/chapter5/solution/tests/test_stats.cpp +20 -0
  69. jrpycpp/examples/cpp_scripts/chapter6/demo/01-map.cpp +19 -0
  70. jrpycpp/examples/cpp_scripts/chapter6/demo/02-lambda.cpp +22 -0
  71. jrpycpp/examples/cpp_scripts/chapter6/demo/03-move.cpp +14 -0
  72. jrpycpp/examples/cpp_scripts/chapter6/demo/04-unique.cpp +19 -0
  73. jrpycpp/examples/cpp_scripts/chapter6/exercise/copies.cpp +34 -0
  74. jrpycpp/examples/cpp_scripts/chapter6/exercise/integrate.cpp +20 -0
  75. jrpycpp/examples/cpp_scripts/chapter6/exercise/words.cpp +21 -0
  76. jrpycpp/examples/cpp_scripts/chapter6/solution/copies.cpp +37 -0
  77. jrpycpp/examples/cpp_scripts/chapter6/solution/integrate.cpp +25 -0
  78. jrpycpp/examples/cpp_scripts/chapter6/solution/words.cpp +21 -0
  79. jrpycpp/examples/templates/cpp-project/CMakeLists.txt +22 -0
  80. jrpycpp/examples/templates/cpp-project/README.md +68 -0
  81. jrpycpp/examples/templates/cpp-project/include/stats.h +15 -0
  82. jrpycpp/examples/templates/cpp-project/src/main.cpp +9 -0
  83. jrpycpp/examples/templates/cpp-project/src/stats.cpp +26 -0
  84. jrpycpp/examples/templates/cpp-project/tests/test_stats.cpp +20 -0
  85. jrpycpp/examples/templates/python-cpp-project/CMakeLists.txt +28 -0
  86. jrpycpp/examples/templates/python-cpp-project/README.md +72 -0
  87. jrpycpp/examples/templates/python-cpp-project/include/stats.h +15 -0
  88. jrpycpp/examples/templates/python-cpp-project/pyproject.toml +11 -0
  89. jrpycpp/examples/templates/python-cpp-project/python/bindings.cpp +17 -0
  90. jrpycpp/examples/templates/python-cpp-project/src/stats.cpp +26 -0
  91. jrpycpp/examples/templates/python-cpp-project/tests/test_livstats.py +10 -0
  92. jrpycpp/examples/templates/python-cpp-project/tests/test_stats.cpp +20 -0
  93. jrpycpp/examples.py +43 -0
  94. jrpycpp-0.1.0.dist-info/METADATA +16 -0
  95. jrpycpp-0.1.0.dist-info/RECORD +96 -0
  96. jrpycpp-0.1.0.dist-info/WHEEL +4 -0
jrpycpp/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .__version__ import __version__ # noqa: F401
2
+
3
+ from . import examples # noqa: F401
jrpycpp/__version__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,24 @@
1
+ #include <iostream>
2
+ #include <vector>
3
+
4
+ class Stats {
5
+ public:
6
+ Stats(const std::vector<double>& values) : values_(values) {}
7
+
8
+ double mean() {
9
+ double total = 0.0;
10
+ for (double v : values_) {
11
+ total += v;
12
+ }
13
+ return total / values_.size();
14
+ }
15
+
16
+ private:
17
+ std::vector<double> values_;
18
+ };
19
+
20
+ int main() {
21
+ Stats s({2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0});
22
+ std::cout << "mean " << s.mean() << "\n";
23
+ return 0;
24
+ }
@@ -0,0 +1,25 @@
1
+ #include <iostream>
2
+ #include <vector>
3
+
4
+ class Stats {
5
+ public:
6
+ Stats(const std::vector<double>& values) : values_(values) {}
7
+ double mean() const {
8
+ double total = 0.0;
9
+ for (double v : values_) {
10
+ total += v;
11
+ }
12
+ return total / values_.size();
13
+ }
14
+ private:
15
+ std::vector<double> values_;
16
+ };
17
+
18
+ void report(const Stats& s) {
19
+ std::cout << "mean " << s.mean() << "\n";
20
+ }
21
+
22
+ int main() {
23
+ report(Stats({2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0}));
24
+ return 0;
25
+ }
@@ -0,0 +1,26 @@
1
+ #include <cmath>
2
+ #include <iostream>
3
+ #include <vector>
4
+
5
+ double mean(const std::vector<double>& values) {
6
+ double total = 0.0;
7
+ for (double v : values) {
8
+ total += v;
9
+ }
10
+ return total / values.size();
11
+ }
12
+
13
+ double stddev(const std::vector<double>& values) {
14
+ double m = mean(values);
15
+ double total = 0.0;
16
+ for (double v : values) {
17
+ total += (v - m) * (v - m);
18
+ }
19
+ return std::sqrt(total / values.size());
20
+ }
21
+
22
+ int main() {
23
+ std::vector<double> values = {2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0};
24
+ std::cout << "mean " << mean(values) << ", standard deviation " << stddev(values) << "\n";
25
+ return 0;
26
+ }
@@ -0,0 +1,44 @@
1
+ #include <cmath>
2
+ #include <iostream>
3
+ #include <vector>
4
+
5
+ class Stats {
6
+ public:
7
+ Stats(const std::vector<double>& values) : values_(values) {}
8
+
9
+ double mean() const {
10
+ double total = 0.0;
11
+ for (double v : values_) {
12
+ total += v;
13
+ }
14
+ return total / values_.size();
15
+ }
16
+
17
+ double stddev() const {
18
+ double m = mean();
19
+ double total = 0.0;
20
+ for (double v : values_) {
21
+ total += (v - m) * (v - m);
22
+ }
23
+ return std::sqrt(total / values_.size());
24
+ }
25
+
26
+ int count() const {
27
+ return static_cast<int>(values_.size());
28
+ }
29
+
30
+ private:
31
+ std::vector<double> values_;
32
+ };
33
+
34
+ void report(const Stats& s) {
35
+ std::cout << "mean " << s.mean() << "\n";
36
+ }
37
+
38
+ int main() {
39
+ Stats s({2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0});
40
+ std::cout << "mean " << s.mean() << ", standard deviation " << s.stddev() << "\n";
41
+ std::cout << "count " << s.count() << "\n";
42
+ report(s);
43
+ return 0;
44
+ }
@@ -0,0 +1,11 @@
1
+ #include <pybind11/pybind11.h>
2
+
3
+ #include "pi.h"
4
+
5
+ namespace py = pybind11;
6
+
7
+ PYBIND11_MODULE(pidemo, m) {
8
+ m.doc() = "Yesterday's pi loop, callable from Python";
9
+ m.def("estimate_pi", &estimate_pi, py::arg("n"),
10
+ "Estimate pi with n rectangles");
11
+ }
@@ -0,0 +1,10 @@
1
+ #include "pi.h"
2
+
3
+ double estimate_pi(int n) {
4
+ double total = 0.0;
5
+ for (int i = 0; i < n; ++i) {
6
+ double x = (i + 0.5) / n;
7
+ total += 4.0 / (1.0 + x * x);
8
+ }
9
+ return total / n;
10
+ }
@@ -0,0 +1,3 @@
1
+ #pragma once
2
+
3
+ double estimate_pi(int n);
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "pybind11>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pidemo"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.9"
9
+
10
+ [tool.setuptools]
11
+ py-modules = []
@@ -0,0 +1,12 @@
1
+ from setuptools import setup
2
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
3
+
4
+ ext_modules = [
5
+ Pybind11Extension(
6
+ "pidemo",
7
+ ["bindings.cpp", "pi.cpp"],
8
+ cxx_std=17,
9
+ ),
10
+ ]
11
+
12
+ setup(ext_modules=ext_modules, cmdclass={"build_ext": build_ext})
@@ -0,0 +1,11 @@
1
+ import math
2
+
3
+ import pidemo
4
+
5
+
6
+ def test_estimate_pi_converges():
7
+ assert abs(pidemo.estimate_pi(1000000) - math.pi) < 1e-6
8
+
9
+
10
+ def test_estimate_pi_is_documented():
11
+ assert "Estimate pi" in pidemo.estimate_pi.__doc__
@@ -0,0 +1,17 @@
1
+ #include <pybind11/pybind11.h>
2
+ #include <pybind11/stl.h>
3
+
4
+ #include "stats.h"
5
+
6
+ namespace py = pybind11;
7
+
8
+ PYBIND11_MODULE(livstats, m) {
9
+ m.doc() = "Yesterday's stats program, callable from Python";
10
+
11
+ py::class_<Stats>(m, "Stats")
12
+ .def(py::init<const std::vector<double>&>(), py::arg("values"),
13
+ "Build from a sequence of numbers")
14
+ .def("mean", &Stats::mean, "Arithmetic mean")
15
+ .def("stddev", &Stats::stddev, "Standard deviation, dividing by n")
16
+ .def("count", &Stats::count, "How many values");
17
+ }
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "pybind11>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "livstats"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.9"
9
+
10
+ [tool.setuptools]
11
+ py-modules = []
@@ -0,0 +1,12 @@
1
+ from setuptools import setup
2
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
3
+
4
+ ext_modules = [
5
+ Pybind11Extension(
6
+ "livstats",
7
+ ["bindings.cpp", "stats.cpp"],
8
+ cxx_std=17,
9
+ ),
10
+ ]
11
+
12
+ setup(ext_modules=ext_modules, cmdclass={"build_ext": build_ext})
@@ -0,0 +1,26 @@
1
+ #include "stats.h"
2
+
3
+ #include <cmath>
4
+
5
+ Stats::Stats(const std::vector<double>& values) : values_(values) {}
6
+
7
+ double Stats::mean() const {
8
+ double total = 0.0;
9
+ for (double v : values_) {
10
+ total += v;
11
+ }
12
+ return total / values_.size();
13
+ }
14
+
15
+ double Stats::stddev() const {
16
+ double m = mean();
17
+ double total = 0.0;
18
+ for (double v : values_) {
19
+ total += (v - m) * (v - m);
20
+ }
21
+ return std::sqrt(total / values_.size());
22
+ }
23
+
24
+ int Stats::count() const {
25
+ return static_cast<int>(values_.size());
26
+ }
@@ -0,0 +1,15 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+
5
+ class Stats {
6
+ public:
7
+ Stats(const std::vector<double>& values);
8
+
9
+ double mean() const;
10
+ double stddev() const;
11
+ int count() const;
12
+
13
+ private:
14
+ std::vector<double> values_;
15
+ };
@@ -0,0 +1,18 @@
1
+ import pytest
2
+
3
+ import livstats
4
+
5
+
6
+ def test_the_chapter_one_promise():
7
+ s = livstats.Stats([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0])
8
+ assert s.mean() == pytest.approx(5.0)
9
+ assert s.stddev() == pytest.approx(2.0)
10
+ assert s.count() == 8
11
+
12
+
13
+ def test_a_list_of_ints_is_accepted():
14
+ assert livstats.Stats([1, 2, 3]).mean() == pytest.approx(2.0)
15
+
16
+
17
+ def test_the_constructor_takes_a_named_argument():
18
+ assert livstats.Stats(values=[1.0, 3.0]).mean() == pytest.approx(2.0)
@@ -0,0 +1,12 @@
1
+ #include <pybind11/pybind11.h>
2
+ #include <pybind11/stl.h>
3
+
4
+ #include "stats.h"
5
+
6
+ namespace py = pybind11;
7
+
8
+ PYBIND11_MODULE(livstats, m) {
9
+ py::class_<Stats>(m, "Stats")
10
+ .def(py::init<const std::vector<double>&>(), py::arg("values"))
11
+ .def("mean", &Stats::mean);
12
+ }
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "pybind11>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "livstats"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.9"
9
+
10
+ [tool.setuptools]
11
+ py-modules = []
@@ -0,0 +1,12 @@
1
+ from setuptools import setup
2
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
3
+
4
+ ext_modules = [
5
+ Pybind11Extension(
6
+ "livstats",
7
+ ["bindings.cpp", "stats.cpp"],
8
+ cxx_std=17,
9
+ ),
10
+ ]
11
+
12
+ setup(ext_modules=ext_modules, cmdclass={"build_ext": build_ext})
@@ -0,0 +1,26 @@
1
+ #include "stats.h"
2
+
3
+ #include <cmath>
4
+
5
+ Stats::Stats(const std::vector<double>& values) : values_(values) {}
6
+
7
+ double Stats::mean() const {
8
+ double total = 0.0;
9
+ for (double v : values_) {
10
+ total += v;
11
+ }
12
+ return total / values_.size();
13
+ }
14
+
15
+ double Stats::stddev() const {
16
+ double m = mean();
17
+ double total = 0.0;
18
+ for (double v : values_) {
19
+ total += (v - m) * (v - m);
20
+ }
21
+ return std::sqrt(total / values_.size());
22
+ }
23
+
24
+ int Stats::count() const {
25
+ return static_cast<int>(values_.size());
26
+ }
@@ -0,0 +1,15 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+
5
+ class Stats {
6
+ public:
7
+ Stats(const std::vector<double>& values);
8
+
9
+ double mean() const;
10
+ double stddev() const;
11
+ int count() const;
12
+
13
+ private:
14
+ std::vector<double> values_;
15
+ };
@@ -0,0 +1,22 @@
1
+ #include <pybind11/pybind11.h>
2
+ #include <pybind11/stl.h>
3
+
4
+ #include <string>
5
+
6
+ #include "stats.h"
7
+
8
+ namespace py = pybind11;
9
+
10
+ PYBIND11_MODULE(livstats, m) {
11
+ m.doc() = "Yesterday's stats program, callable from Python";
12
+
13
+ py::class_<Stats>(m, "Stats")
14
+ .def(py::init<const std::vector<double>&>(), py::arg("values"),
15
+ "Build from a sequence of numbers")
16
+ .def("mean", &Stats::mean, "Arithmetic mean")
17
+ .def("stddev", &Stats::stddev, "Standard deviation, dividing by n")
18
+ .def("count", &Stats::count, "How many values")
19
+ .def("__repr__", [](const Stats& s) {
20
+ return "Stats(count=" + std::to_string(s.count()) + ")";
21
+ });
22
+ }
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "pybind11>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "livstats"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.9"
9
+
10
+ [tool.setuptools]
11
+ py-modules = []
@@ -0,0 +1,12 @@
1
+ from setuptools import setup
2
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
3
+
4
+ ext_modules = [
5
+ Pybind11Extension(
6
+ "livstats",
7
+ ["bindings.cpp", "stats.cpp"],
8
+ cxx_std=17,
9
+ ),
10
+ ]
11
+
12
+ setup(ext_modules=ext_modules, cmdclass={"build_ext": build_ext})
@@ -0,0 +1,26 @@
1
+ #include "stats.h"
2
+
3
+ #include <cmath>
4
+
5
+ Stats::Stats(const std::vector<double>& values) : values_(values) {}
6
+
7
+ double Stats::mean() const {
8
+ double total = 0.0;
9
+ for (double v : values_) {
10
+ total += v;
11
+ }
12
+ return total / values_.size();
13
+ }
14
+
15
+ double Stats::stddev() const {
16
+ double m = mean();
17
+ double total = 0.0;
18
+ for (double v : values_) {
19
+ total += (v - m) * (v - m);
20
+ }
21
+ return std::sqrt(total / values_.size());
22
+ }
23
+
24
+ int Stats::count() const {
25
+ return static_cast<int>(values_.size());
26
+ }
@@ -0,0 +1,15 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+
5
+ class Stats {
6
+ public:
7
+ Stats(const std::vector<double>& values);
8
+
9
+ double mean() const;
10
+ double stddev() const;
11
+ int count() const;
12
+
13
+ private:
14
+ std::vector<double> values_;
15
+ };
@@ -0,0 +1,18 @@
1
+ import pytest
2
+
3
+ import livstats
4
+
5
+
6
+ def test_all_three_are_bound():
7
+ s = livstats.Stats([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0])
8
+ assert s.mean() == pytest.approx(5.0)
9
+ assert s.stddev() == pytest.approx(2.0)
10
+ assert s.count() == 8
11
+
12
+
13
+ def test_repr_says_what_it_holds():
14
+ assert repr(livstats.Stats([1.0, 2.0, 3.0])) == "Stats(count=3)"
15
+
16
+
17
+ def test_the_docstrings_arrived():
18
+ assert "Arithmetic mean" in livstats.Stats.mean.__doc__
@@ -0,0 +1,13 @@
1
+ #include "arrays.h"
2
+
3
+ double total(const double* data, std::size_t n) {
4
+ double sum = 0.0;
5
+ for (std::size_t i = 0; i < n; ++i) {
6
+ sum += data[i];
7
+ }
8
+ return sum;
9
+ }
10
+
11
+ double total_vector(const std::vector<double>& v) {
12
+ return total(v.data(), v.size());
13
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ #include <cstddef>
4
+ #include <vector>
5
+
6
+ double total(const double* data, std::size_t n);
7
+ double total_vector(const std::vector<double>& v);
@@ -0,0 +1,73 @@
1
+ #include <pybind11/pybind11.h>
2
+ #include <pybind11/numpy.h>
3
+ #include <pybind11/stl.h>
4
+
5
+ #include <vector>
6
+
7
+ #include "arrays.h"
8
+
9
+ namespace py = pybind11;
10
+
11
+ double total_array(py::array_t<double> values) {
12
+ auto v = values.unchecked<1>();
13
+ double sum = 0.0;
14
+ for (py::ssize_t i = 0; i < v.shape(0); ++i) {
15
+ sum += v(i);
16
+ }
17
+ return sum;
18
+ }
19
+
20
+ void scale_inplace(py::array_t<double> values, double factor) {
21
+ auto v = values.mutable_unchecked<1>();
22
+ for (py::ssize_t i = 0; i < v.shape(0); ++i) {
23
+ v(i) *= factor;
24
+ }
25
+ }
26
+
27
+ py::array_t<double> squares(py::ssize_t n) {
28
+ py::array_t<double> out(n);
29
+ auto o = out.mutable_unchecked<1>();
30
+ for (py::ssize_t i = 0; i < n; ++i) {
31
+ o(i) = static_cast<double>(i) * static_cast<double>(i);
32
+ }
33
+ return out;
34
+ }
35
+
36
+ class Grid {
37
+ public:
38
+ Grid(py::ssize_t n) : values_(static_cast<std::size_t>(n), 1.0) {}
39
+
40
+ py::ssize_t size() const { return static_cast<py::ssize_t>(values_.size()); }
41
+ double* data() { return values_.data(); }
42
+ void grow() { values_.push_back(1.0); }
43
+
44
+ private:
45
+ std::vector<double> values_;
46
+ };
47
+
48
+ PYBIND11_MODULE(livarrays, m) {
49
+ m.doc() = "NumPy arrays crossing into C++";
50
+
51
+ m.def("total_array", &total_array, py::arg("values"),
52
+ "Sum an array of doubles without copying it");
53
+
54
+ m.def("total_list", &total_vector, py::arg("values"),
55
+ "Sum a sequence, copying it into a vector first");
56
+
57
+ m.def("scale_inplace", &scale_inplace,
58
+ py::arg("values").noconvert(), py::arg("factor"),
59
+ "Multiply an array of doubles in place");
60
+
61
+ m.def("squares", &squares, py::arg("n"),
62
+ "Return the first n squares as a new array");
63
+
64
+ py::class_<Grid>(m, "Grid")
65
+ .def(py::init<py::ssize_t>(), py::arg("n"))
66
+ .def("grow", &Grid::grow, "Append one element")
67
+ .def("view", [](py::object self) {
68
+ Grid& g = self.cast<Grid&>();
69
+ return py::array_t<double>({g.size()},
70
+ {static_cast<py::ssize_t>(sizeof(double))},
71
+ g.data(), self);
72
+ }, "A NumPy view onto this Grid's own memory");
73
+ }
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "pybind11>=3.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "livarrays"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.9"
9
+
10
+ [tool.setuptools]
11
+ py-modules = []
@@ -0,0 +1,12 @@
1
+ from setuptools import setup
2
+ from pybind11.setup_helpers import Pybind11Extension, build_ext
3
+
4
+ ext_modules = [
5
+ Pybind11Extension(
6
+ "livarrays",
7
+ ["bindings.cpp", "arrays.cpp"],
8
+ cxx_std=17,
9
+ ),
10
+ ]
11
+
12
+ setup(ext_modules=ext_modules, cmdclass={"build_ext": build_ext})
@@ -0,0 +1,38 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ import livarrays
5
+
6
+
7
+ def test_total_reads_a_strided_view_correctly():
8
+ assert livarrays.total_array(np.arange(10.0)[::2]) == pytest.approx(20.0)
9
+
10
+
11
+ def test_total_list_goes_through_the_cpp_pointer_function():
12
+ assert livarrays.total_list([1.0, 2.0, 3.0]) == pytest.approx(6.0)
13
+
14
+
15
+ def test_scale_inplace_changes_the_callers_array():
16
+ a = np.arange(5.0)
17
+ livarrays.scale_inplace(a, 2.0)
18
+ assert a == pytest.approx(np.array([0.0, 2.0, 4.0, 6.0, 8.0]))
19
+
20
+
21
+ def test_noconvert_refuses_the_wrong_dtype():
22
+ with pytest.raises(TypeError):
23
+ livarrays.scale_inplace(np.arange(5, dtype=np.int32), 2.0)
24
+
25
+
26
+ def test_squares_owns_its_data():
27
+ out = livarrays.squares(4)
28
+ assert out == pytest.approx(np.array([0.0, 1.0, 4.0, 9.0]))
29
+ assert out.flags.owndata is True
30
+
31
+
32
+ def test_a_view_does_not_own_its_data_and_keeps_the_grid_alive():
33
+ g = livarrays.Grid(4)
34
+ v = g.view()
35
+ assert v.flags.owndata is False
36
+ assert v.base is g
37
+ v[0] = 7.0
38
+ assert g.view()[0] == pytest.approx(7.0)