Skip to content

Commit fa12b7b

Browse files
committed
Add C implementation for @stdlib/math/base/special/heaviside
- Add C header file defining STDLIB_BASE_HEAVISIDE_CONTINUITY enum - Implement stdlib_base_heaviside in C for double-precision - Create Node-API addon bridge for JavaScript integration - Add GYP build configuration (binding.gyp, include.gypi, manifest.json) - Create lib/native.js dispatcher with string-to-enum mapping - Update lib/index.js to use native implementation when available - Update package.json to enable gypfile and add src/include directories - Add comprehensive native test suite (test/test.native.js) - All tests passing (213/213 native, 2013/2013 standard) This implementation follows the pattern established by heavisidef and provides performance improvements through native C code while maintaining full API compatibility with the existing JavaScript implementation.
1 parent 0a3bfa2 commit fa12b7b

11 files changed

Lines changed: 748 additions & 1 deletion

File tree

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# @license Apache-2.0
2+
#
3+
# Copyright (c) 2026 The Stdlib Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
{
18+
# List of files to include in this file:
19+
'includes': [
20+
'./include.gypi',
21+
],
22+
23+
# Define variables to be used throughout the configuration for all targets:
24+
'variables': {
25+
# Target name should match the add-on export name:
26+
'addon_target_name%': 'addon',
27+
28+
# Set variables based on the host OS:
29+
'conditions': [
30+
[
31+
'OS=="win"',
32+
{
33+
# Define the object file suffix:
34+
'obj': 'obj',
35+
},
36+
{
37+
# Define the object file suffix:
38+
'obj': 'o',
39+
}
40+
], # end condition (OS=="win")
41+
], # end conditions
42+
}, # end variables
43+
44+
# Define compile targets:
45+
'targets': [
46+
47+
# Target to generate an add-on:
48+
{
49+
# The target name should match the add-on export name:
50+
'target_name': '<(addon_target_name)',
51+
52+
# Define dependencies:
53+
'dependencies': [],
54+
55+
# Define directories which contain relevant include headers:
56+
'include_dirs': [
57+
# Local include directory:
58+
'<@(include_dirs)',
59+
],
60+
61+
# List of source files:
62+
'sources': [
63+
'<@(src_files)',
64+
],
65+
66+
# Settings which should be applied when a target's object files are used as linker input:
67+
'link_settings': {
68+
# Define libraries:
69+
'libraries': [
70+
'<@(libraries)',
71+
],
72+
73+
# Define library directories:
74+
'library_dirs': [
75+
'<@(library_dirs)',
76+
],
77+
},
78+
79+
# C/C++ compiler flags:
80+
'cflags': [
81+
# Enable commonly used warning options:
82+
'-Wall',
83+
84+
# Aggressive optimization:
85+
'-O3',
86+
],
87+
88+
# C specific compiler flags:
89+
'cflags_c': [
90+
# Specify the C standard to which a program is expected to conform:
91+
'-std=c99',
92+
],
93+
94+
# C++ specific compiler flags:
95+
'cflags_cpp': [
96+
# Specify the C++ standard to which a program is expected to conform:
97+
'-std=c++11',
98+
],
99+
100+
# Linker flags:
101+
'ldflags': [],
102+
103+
# Apply conditions based on the host OS:
104+
'conditions': [
105+
[
106+
'OS=="mac"',
107+
{
108+
# Linker flags:
109+
'ldflags': [
110+
'-undefined dynamic_lookup',
111+
'-Wl,-no-pie',
112+
'-Wl,-search_paths_first',
113+
],
114+
},
115+
], # end condition (OS=="mac")
116+
[
117+
'OS!="win"',
118+
{
119+
# C/C++ flags:
120+
'cflags': [
121+
# Generate platform-independent code:
122+
'-fPIC',
123+
],
124+
},
125+
], # end condition (OS!="win")
126+
], # end conditions
127+
}, # end target <(addon_target_name)
128+
129+
# Target to copy a generated add-on to a standard location:
130+
{
131+
'target_name': 'copy_addon',
132+
133+
# Declare that the output of this target is not linked:
134+
'type': 'none',
135+
136+
# Define dependencies:
137+
'dependencies': [
138+
# Require that the add-on be generated before building this target:
139+
'<(addon_target_name)',
140+
],
141+
142+
# Define a list of actions:
143+
'actions': [
144+
{
145+
'action_name': 'copy_addon',
146+
'message': 'Copying addon...',
147+
148+
# Explicitly list the inputs in the command-line invocation below:
149+
'inputs': [],
150+
151+
# Declare the expected outputs:
152+
'outputs': [
153+
'<(addon_output_dir)/<(addon_target_name).node',
154+
],
155+
156+
# Define the command-line invocation:
157+
'action': [
158+
'cp',
159+
'<(PRODUCT_DIR)/<(addon_target_name).node',
160+
'<(addon_output_dir)/<(addon_target_name).node',
161+
],
162+
},
163+
], # end actions
164+
}, # end target copy_addon
165+
], # end targets
166+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# @license Apache-2.0
2+
#
3+
# Copyright (c) 2026 The Stdlib Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
{
18+
# Define variables to be used throughout the configuration for all targets:
19+
'variables': {
20+
# Source directory:
21+
'src_dir': './src',
22+
23+
# Include directories:
24+
'include_dirs': [
25+
'<!@(node -e "var arr = require(\'@stdlib/utils/library-manifest\')(\'./manifest.json\',{},{\'basedir\':process.cwd(),\'paths\':\'posix\'}).include; for ( var i = 0; i < arr.length; i++ ) { console.log( arr[ i ] ); }")',
26+
],
27+
28+
# Add-on destination directory:
29+
'addon_output_dir': './src',
30+
31+
# Source files:
32+
'src_files': [
33+
'<(src_dir)/addon.c',
34+
'<!@(node -e "var arr = require(\'@stdlib/utils/library-manifest\')(\'./manifest.json\',{},{\'basedir\':process.cwd(),\'paths\':\'posix\'}).src; for ( var i = 0; i < arr.length; i++ ) { console.log( arr[ i ] ); }")',
35+
],
36+
37+
# Library dependencies:
38+
'libraries': [
39+
'<!@(node -e "var arr = require(\'@stdlib/utils/library-manifest\')(\'./manifest.json\',{},{\'basedir\':process.cwd(),\'paths\':\'posix\'}).libraries; for ( var i = 0; i < arr.length; i++ ) { console.log( arr[ i ] ); }")',
40+
],
41+
42+
# Library directories:
43+
'library_dirs': [
44+
'<!@(node -e "var arr = require(\'@stdlib/utils/library-manifest\')(\'./manifest.json\',{},{\'basedir\':process.cwd(),\'paths\':\'posix\'}).libpath; for ( var i = 0; i < arr.length; i++ ) { console.log( arr[ i ] ); }")',
45+
],
46+
}, # end variables
47+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#ifndef STDLIB_MATH_BASE_SPECIAL_HEAVISIDE_H
20+
#define STDLIB_MATH_BASE_SPECIAL_HEAVISIDE_H
21+
22+
/*
23+
* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler.
24+
*/
25+
#ifdef __cplusplus
26+
extern "C" {
27+
#endif
28+
29+
// Enumeration of function continuity:
30+
enum STDLIB_BASE_HEAVISIDE_CONTINUITY {
31+
// Half-maximum:
32+
STDLIB_BASE_HEAVISIDE_CONTINUITY_HALF_MAXIMUM = 0,
33+
34+
// Left-continuous:
35+
STDLIB_BASE_HEAVISIDE_CONTINUITY_LEFT_CONTINUOUS = 1,
36+
37+
// Right-continuous:
38+
STDLIB_BASE_HEAVISIDE_CONTINUITY_RIGHT_CONTINUOUS = 2,
39+
40+
// Discontinuous:
41+
STDLIB_BASE_HEAVISIDE_CONTINUITY_DISCONTINUOUS = 3
42+
};
43+
44+
/**
45+
* Evaluates the Heaviside function for a double-precision floating-point number.
46+
*/
47+
double stdlib_base_heaviside( const double x, const enum STDLIB_BASE_HEAVISIDE_CONTINUITY continuity );
48+
49+
#ifdef __cplusplus
50+
}
51+
#endif
52+
53+
#endif // !STDLIB_MATH_BASE_SPECIAL_HEAVISIDE_H

lib/node_modules/@stdlib/math/base/special/heaviside/lib/index.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,52 @@
5050

5151
// MODULES //
5252

53+
var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
5354
var main = require( './main.js' );
55+
var native = require( './native.js' );
56+
57+
58+
// MAIN //
59+
60+
/**
61+
* Evaluate the Heaviside function.
62+
*
63+
* @module @stdlib/math/base/special/heaviside
64+
*
65+
* @example
66+
* var heaviside = require( '@stdlib/math/base/special/heaviside' );
67+
*
68+
* var v = heaviside( 3.14 );
69+
* // returns 1.0
70+
*
71+
* v = heaviside( -3.14 );
72+
* // returns 0.0
73+
*
74+
* v = heaviside( 0.0 );
75+
* // returns NaN
76+
*
77+
* v = heaviside( 0.0, 'half-maximum' );
78+
* // returns 0.5
79+
*
80+
* v = heaviside( 0.0, 'left-continuous' );
81+
* // returns 0.0
82+
*
83+
* v = heaviside( 0.0, 'right-continuous' );
84+
* // returns 1.0
85+
*
86+
* v = heaviside( NaN );
87+
* // returns NaN
88+
*/
89+
var heaviside;
90+
if (native) {
91+
heaviside = native;
92+
} else {
93+
heaviside = main;
94+
}
95+
96+
setReadOnly(heaviside, 'native', native);
5497

5598

5699
// EXPORTS //
57100

58-
module.exports = main;
101+
module.exports = heaviside;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var addon = require( './../src/addon.node' );
24+
25+
26+
// VARIABLES //
27+
28+
var CONTINUITY = {
29+
'half-maximum': 0,
30+
'left-continuous': 1,
31+
'right-continuous': 2
32+
};
33+
34+
35+
// MAIN //
36+
37+
/**
38+
* Evaluates the Heaviside function using native code.
39+
*
40+
* @private
41+
* @param {number} x - input value
42+
* @param {string} [continuity] - continuity option
43+
* @returns {number} function value
44+
*
45+
* @example
46+
* var v = heaviside( 3.14, 'half-maximum' );
47+
* // returns 1.0
48+
*/
49+
function heaviside(x, continuity) {
50+
var c = CONTINUITY[continuity];
51+
if (c === void 0) {
52+
c = 3; // Discontinuous
53+
}
54+
return addon(x, c);
55+
}
56+
57+
58+
// EXPORTS //
59+
60+
module.exports = heaviside;

0 commit comments

Comments
 (0)