Skip to content

Cpp32¤

Wrapper around a 32-bit C++ library.

Example of a server that loads a 32-bit library, cpp_lib, in a 32-bit Python interpreter to host the library. The corresponding Cpp64 class is created in a 64-bit Python interpreter and the Cpp64 class sends requests to the Cpp32 class which calls the 32-bit library to execute the request and then returns the response from the library.

Cpp32 ¤

Cpp32(host, port)

Bases: Server32

Wrapper around a 32-bit C++ library.

This class demonstrates how to send/receive various data types to/from a 32-bit C++ library via ctypes.

Parameters:

Name Type Description Default
host str

The IP address (or hostname) to use for the server.

required
port int

The port to open for the server.

required
Source code in src/msl/examples/loadlib/cpp32.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def __init__(self, host: str, port: int) -> None:
    """Wrapper around a 32-bit C++ library.

    This class demonstrates how to send/receive various data types to/from a
    32-bit C++ library via [ctypes][]{:target="_blank"}.

    Args:
        host: The IP address (or hostname) to use for the server.
        port: The port to open for the server.
    """
    # By not specifying the extension of the library file the server will open
    # the appropriate file based on the operating system.
    path = Path(__file__).parent / "cpp_lib32"
    super().__init__(path, "cdll", host, port)

add ¤

add(a, b)

Add two integers.

The corresponding C++ code is

int add(int a, int b) {
    return a + b;
}

See the corresponding Cpp64.add method.

Parameters:

Name Type Description Default
a int

First integer.

required
b int

Second integer.

required

Returns:

Type Description
int

The sum, a + b.

Source code in src/msl/examples/loadlib/cpp32.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def add(self, a: int, b: int) -> int:
    """Add two integers.

    The corresponding C++ code is

    ```cpp
    int add(int a, int b) {
        return a + b;
    }
    ```

    See the corresponding [Cpp64.add][msl.examples.loadlib.Cpp64.add] method.

    Args:
        a: First integer.
        b: Second integer.

    Returns:
        The sum, `a + b`.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.add.restype = ctypes.c_int32
    self.lib.add.argtypes = [ctypes.c_int32, ctypes.c_int32]
    result: int = self.lib.add(a, b)
    return result

add_or_subtract ¤

add_or_subtract(a, b, *, do_addition)

Add or subtract two double-precision numbers ('double' refers to the C++ data type).

The corresponding C++ code is

double add_or_subtract(double a, double b, bool do_addition) {
    if (do_addition) {
        return a + b;
    } else {
        return a - b;
    }
}

See the corresponding Cpp64.add_or_subtract method.

Parameters:

Name Type Description Default
a float

First double-precision number.

required
b float

Second double-precision number.

required
do_addition bool

Whether to add or subtract the numbers.

required

Returns:

Type Description
float

a + b if do_addition is True else a - b.

Source code in src/msl/examples/loadlib/cpp32.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
def add_or_subtract(self, a: float, b: float, *, do_addition: bool) -> float:
    """Add or subtract two double-precision numbers *('double' refers to the C++ data type)*.

    The corresponding C++ code is

    ```cpp
    double add_or_subtract(double a, double b, bool do_addition) {
        if (do_addition) {
            return a + b;
        } else {
            return a - b;
        }
    }
    ```

    See the corresponding [Cpp64.add_or_subtract][msl.examples.loadlib.Cpp64.add_or_subtract] method.

    Args:
        a: First double-precision number.
        b: Second double-precision number.
        do_addition: Whether to add or subtract the numbers.

    Returns:
        `a + b` if `do_addition` is `True` else `a - b`.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.add_or_subtract.restype = ctypes.c_double
    self.lib.add_or_subtract.argtypes = [ctypes.c_double, ctypes.c_double, ctypes.c_bool]
    result: float = self.lib.add_or_subtract(a, b, do_addition)
    return result

circumference ¤

circumference(radius, n)

Estimates the circumference of a circle.

This method calls the distance_n_points function in cpp_lib.

The corresponding C++ code uses the NPoints struct as the input parameter to sum the distance between adjacent points on the circle.

double distance_n_points(NPoints p) {
    if (p.n < 2) {
        return 0.0;
    }
    double d = distance(p.points[0], p.points[p.n-1]);
    for (int i = 1; i < p.n; i++) {
        d += distance(p.points[i], p.points[i-1]);
    }
    return d;
}

See the corresponding Cpp64.circumference method.

Parameters:

Name Type Description Default
radius float

The radius of the circle.

required
n int

The number of points to use to estimate the circumference.

required

Returns:

Type Description
float

The estimated circumference of the circle.

Source code in src/msl/examples/loadlib/cpp32.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def circumference(self, radius: float, n: int) -> float:
    """Estimates the circumference of a circle.

    This method calls the `distance_n_points` function in [cpp_lib][cpp-lib].

    The corresponding C++ code uses the [NPoints][msl.examples.loadlib.cpp32.NPoints]
    struct as the input parameter to sum the distance between adjacent points on the circle.

    ```cpp
    double distance_n_points(NPoints p) {
        if (p.n < 2) {
            return 0.0;
        }
        double d = distance(p.points[0], p.points[p.n-1]);
        for (int i = 1; i < p.n; i++) {
            d += distance(p.points[i], p.points[i-1]);
        }
        return d;
    }
    ```

    See the corresponding [Cpp64.circumference][msl.examples.loadlib.Cpp64.circumference] method.

    Args:
        radius: The radius of the circle.
        n: The number of points to use to estimate the circumference.

    Returns:
        The estimated circumference of the circle.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.distance_n_points.restype = ctypes.c_double
    self.lib.distance_n_points.argtypes = [NPoints]

    theta = 0.0
    delta = (2.0 * math.pi) / float(n) if n != 0 else 0

    pts = NPoints()
    pts.n = n
    pts.points = (Point * n)()
    for i in range(n):
        pts.points[i] = Point(radius * math.cos(theta), radius * math.sin(theta))
        theta += delta
    result: float = self.lib.distance_n_points(pts)
    return result

distance_4_points ¤

distance_4_points(four_points)

Calculates the total distance connecting 4 Points.

The corresponding C++ code is

double distance_4_points(FourPoints p) {
    double d = distance(p.points[0], p.points[3]);
    for (int i = 1; i < 4; i++) {
        d += distance(p.points[i], p.points[i-1]);
    }
    return d;
}

See the corresponding Cpp64.distance_4_points method.

Parameters:

Name Type Description Default
four_points FourPoints

The points to use to calculate the total distance.

required

Returns:

Type Description
float

The total distance connecting the 4 points.

Source code in src/msl/examples/loadlib/cpp32.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def distance_4_points(self, four_points: FourPoints) -> float:
    """Calculates the total distance connecting 4 [Point][msl.examples.loadlib.cpp32.Point]s.

    The corresponding C++ code is

    ```cpp
    double distance_4_points(FourPoints p) {
        double d = distance(p.points[0], p.points[3]);
        for (int i = 1; i < 4; i++) {
            d += distance(p.points[i], p.points[i-1]);
        }
        return d;
    }
    ```

    See the corresponding [Cpp64.distance_4_points][msl.examples.loadlib.Cpp64.distance_4_points] method.

    Args:
        four_points: The points to use to calculate the total distance.

    Returns:
        The total distance connecting the 4 points.
    """
    # restype should be defined elsewhere, shown here for illustrative purposes
    self.lib.distance_4_points.restype = ctypes.c_double
    result: float = self.lib.distance_4_points(four_points)
    return result

reverse_string_v1 ¤

reverse_string_v1(original)

Reverse a string (version 1).

In this method Python allocates the memory for the reversed string and passes the string to C++.

The corresponding C++ code is

void reverse_string_v1(const char* original, int n, char* reversed) {
    for (int i = 0; i < n; i++) {
        reversed[i] = original[n-i-1];
    }
}

See the corresponding Cpp64.reverse_string_v1 method.

Parameters:

Name Type Description Default
original str

The original string.

required

Returns:

Type Description
str

The string reversed.

Source code in src/msl/examples/loadlib/cpp32.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def reverse_string_v1(self, original: str) -> str:
    """Reverse a string (version 1).

    In this method Python allocates the memory for the reversed string and
    passes the string to C++.

    The corresponding C++ code is

    ```cpp
    void reverse_string_v1(const char* original, int n, char* reversed) {
        for (int i = 0; i < n; i++) {
            reversed[i] = original[n-i-1];
        }
    }
    ```

    See the corresponding [Cpp64.reverse_string_v1][msl.examples.loadlib.Cpp64.reverse_string_v1] method.

    Args:
        original: The original string.

    Returns:
        The string reversed.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.reverse_string_v1.restype = None
    self.lib.reverse_string_v1.argtypes = [ctypes.c_char_p, ctypes.c_int32, ctypes.c_char_p]

    n = len(original)
    rev = ctypes.create_string_buffer(n)
    self.lib.reverse_string_v1(original.encode(), n, rev)
    return rev.raw.decode()

reverse_string_v2 ¤

reverse_string_v2(original)

Reverse a string (version 2).

In this method C++ allocates the memory for the reversed string and passes the string to Python.

The corresponding C++ code is

char* reverse_string_v2(char* original, int n) {
    char* reversed = new char[n];
    for (int i = 0; i < n; i++) {
        reversed[i] = original[n - i - 1];
    }
    return reversed;
}

See the corresponding Cpp64.reverse_string_v2 method.

Parameters:

Name Type Description Default
original str

The original string.

required

Returns:

Type Description
str

The string reversed.

Source code in src/msl/examples/loadlib/cpp32.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
def reverse_string_v2(self, original: str) -> str:
    """Reverse a string (version 2).

    In this method C++ allocates the memory for the reversed string and passes
    the string to Python.

    The corresponding C++ code is

    ```cpp
    char* reverse_string_v2(char* original, int n) {
        char* reversed = new char[n];
        for (int i = 0; i < n; i++) {
            reversed[i] = original[n - i - 1];
        }
        return reversed;
    }
    ```

    See the corresponding [Cpp64.reverse_string_v2][msl.examples.loadlib.Cpp64.reverse_string_v2] method.

    Args:
        original: The original string.

    Returns:
        The string reversed.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.reverse_string_v2.restype = ctypes.c_char_p
    self.lib.reverse_string_v2.argtypes = [ctypes.c_char_p, ctypes.c_int32]

    n = len(original)
    rev = self.lib.reverse_string_v2(original.encode(), n)
    return ctypes.string_at(rev, n).decode()

scalar_multiply ¤

scalar_multiply(a, xin)

Multiply each element in an array by a number.

The corresponding C++ code is

void scalar_multiply(double a, double* xin, int n, double* xout) {
    for (int i = 0; i < n; i++) {
        xout[i] = a * xin[i];
    }
}

See the corresponding Cpp64.scalar_multiply method.

Parameters:

Name Type Description Default
a float

Scalar value.

required
xin Sequence[float]

Array to modify.

required

Returns:

Type Description
list[float]

A new array with each element in xin multiplied by a.

Source code in src/msl/examples/loadlib/cpp32.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def scalar_multiply(self, a: float, xin: Sequence[float]) -> list[float]:
    """Multiply each element in an array by a number.

    The corresponding C++ code is

    ```cpp
    void scalar_multiply(double a, double* xin, int n, double* xout) {
        for (int i = 0; i < n; i++) {
            xout[i] = a * xin[i];
        }
    }
    ```

    See the corresponding [Cpp64.scalar_multiply][msl.examples.loadlib.Cpp64.scalar_multiply] method.

    Args:
        a: Scalar value.
        xin: Array to modify.

    Returns:
        A new array with each element in `xin` multiplied by `a`.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.scalar_multiply.restype = None
    self.lib.scalar_multiply.argtypes = [
        ctypes.c_double,
        ctypes.POINTER(ctypes.c_double),
        ctypes.c_int32,
        ctypes.POINTER(ctypes.c_double),
    ]

    n = len(xin)
    c_xin = (ctypes.c_double * n)(*xin)  # convert input array to ctypes
    c_xout = (ctypes.c_double * n)()  # allocate memory for output array
    self.lib.scalar_multiply(a, c_xin, n, c_xout)
    return list(c_xout)

subtract ¤

subtract(a, b)

Subtract two floating-point numbers ('float' refers to the C++ data type).

The corresponding C++ code is

float subtract(float a, float b) {
    return a - b;
}

See the corresponding Cpp64.subtract method.

Parameters:

Name Type Description Default
a float

First floating-point number.

required
b float

Second floating-point number.

required

Returns:

Type Description
float

The difference, a - b.

Source code in src/msl/examples/loadlib/cpp32.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def subtract(self, a: float, b: float) -> float:
    """Subtract two floating-point numbers *('float' refers to the C++ data type)*.

    The corresponding C++ code is

    ```cpp
    float subtract(float a, float b) {
        return a - b;
    }
    ```

    See the corresponding [Cpp64.subtract][msl.examples.loadlib.Cpp64.subtract] method.

    Args:
        a: First floating-point number.
        b: Second floating-point number.

    Returns:
        The difference, `a - b`.
    """
    # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
    self.lib.subtract.restype = ctypes.c_float
    self.lib.subtract.argtypes = [ctypes.c_float, ctypes.c_float]
    result: float = self.lib.subtract(a, b)
    return result

FourPoints ¤

FourPoints(point1, point2, point3, point4)

Bases: Structure

C++ struct that is a fixed size in memory.

This object can be pickled.

struct FourPoints {
    Point points[4];
};

Parameters:

Name Type Description Default
point1 Point

The first point.

required
point2 Point

The second point.

required
point3 Point

The third point.

required
point4 Point

The fourth point.

required
Source code in src/msl/examples/loadlib/cpp32.py
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
def __init__(self, point1: Point, point2: Point, point3: Point, point4: Point) -> None:
    """C++ struct that is a fixed size in memory.

    This object can be [pickle][]{:target="_blank"}d.

    ```cpp
    struct FourPoints {
        Point points[4];
    };
    ```

    Args:
        point1: The first point.
        point2: The second point.
        point3: The third point.
        point4: The fourth point.
    """
    super().__init__()
    self.points: Array[Point] = (Point * 4)(point1, point2, point3, point4)

NPoints ¤

Bases: Structure

C++ struct that is not a fixed size in memory.

This object cannot be pickled because it contains a pointer. A 32-bit process and a 64-bit process cannot share a pointer.

struct NPoints {
    int n;
    Point *points;
};

Point ¤

Bases: Structure

C++ struct that is a fixed size in memory.

This object can be pickled.

struct Point {
    double x;
    double y;
};