@vbarbarosh/node-helpers 3.73.0 → 3.74.0

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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ npm install @vbarbarosh/node-helpers
20
20
  A subset of `@vbarbarosh/node-helpers` is available for browser:
21
21
 
22
22
  ```html
23
- <script src="https://unpkg.com/@vbarbarosh/node-helpers@3.73.0/dist/browser.js"></script>
23
+ <script src="https://unpkg.com/@vbarbarosh/node-helpers@3.74.0/dist/browser.js"></script>
24
24
  ```
25
25
 
26
26
  ⚠️ All browser functions are exposed globally.
package/dist/browser.js CHANGED
@@ -80,7 +80,7 @@ function serializer(replacer, cycleReplacer) {
80
80
 
81
81
  var map = {
82
82
  "./array_chunk.js": "./src/array_chunk.js",
83
- "./array_chunk_jobs.js": "./src/array_chunk_jobs.js",
83
+ "./array_chunk_balanced.js": "./src/array_chunk_balanced.js",
84
84
  "./array_fps.js": "./src/array_fps.js",
85
85
  "./array_gcd.js": "./src/array_gcd.js",
86
86
  "./array_group.js": "./src/array_group.js",
@@ -205,39 +205,44 @@ module.exports = array_chunk;
205
205
 
206
206
  /***/ }),
207
207
 
208
- /***/ "./src/array_chunk_jobs.js":
209
- /*!*********************************!*\
210
- !*** ./src/array_chunk_jobs.js ***!
211
- \*********************************/
208
+ /***/ "./src/array_chunk_balanced.js":
209
+ /*!*************************************!*\
210
+ !*** ./src/array_chunk_balanced.js ***!
211
+ \*************************************/
212
212
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
213
213
 
214
214
  const clamp = __webpack_require__(/*! ./clamp */ "./src/clamp.js");
215
215
 
216
216
  /**
217
- * Split an array of jobs between up to `max_threads`, while trying to put at least
218
- * `min_jobs_per_thread` items into each chunk.
217
+ * Split an array into up to `max_chunks` balanced chunks, while ensuring that
218
+ * each chunk contains at least `min_items_per_chunk` items (when possible).
219
219
  *
220
- * - If an array is empty → returns [].
221
- * - If there are too few items to satisfy `min_items_per_chunk`, even for 1 chunk,
222
- * everything goes into a single chunk.
220
+ * The function distributes items as evenly as possible:
221
+ * - Chunk sizes differ by at most 1 item.
222
+ * - The number of chunks never exceeds `max_chunks`.
223
223
  *
224
- * Alternative names:
225
- * - array_chunk_balanced
224
+ * Originally designed for distributing workload across threads
225
+ * (e.g. `array_chunk_balanced(jobs, max_threads, min_jobs_per_thread)`).
226
226
  *
227
- * @param array
228
- * @param max_threads
229
- * @param min_jobs_per_thread
230
- * @returns {*[]}
227
+ * Edge cases:
228
+ * - If the input array is empty → returns [].
229
+ * - If there are too few items to satisfy `min_items_per_chunk`, even for a single
230
+ * chunk, all items are placed into one chunk.
231
+ *
232
+ * @param {Array} array
233
+ * @param {number} max_chunks
234
+ * @param {number} min_items_per_chunk
235
+ * @returns {Array<Array>}
231
236
  */
232
- function array_chunk_jobs(array = [], max_threads = 1, min_jobs_per_thread = 1)
237
+ function array_chunk_balanced(array = [], max_chunks = 1, min_items_per_chunk = 1)
233
238
  {
234
- const total_threads = clamp(1, max_threads, Math.floor(array.length / min_jobs_per_thread));
235
- const jobs_per_thread = Math.floor(array.length / total_threads);
236
- let extra = array.length % total_threads;
239
+ const total_chunks = clamp(1, max_chunks, Math.floor(array.length / min_items_per_chunk));
240
+ const items_per_chunk = Math.floor(array.length / total_chunks);
241
+ let extra = array.length % total_chunks;
237
242
 
238
243
  const out = [];
239
244
  for (let i = 0; i < array.length; ) {
240
- const size = jobs_per_thread + (extra ? 1 : 0);
245
+ const size = items_per_chunk + (extra ? 1 : 0);
241
246
  out.push(array.slice(i, i + size));
242
247
  i += size;
243
248
  if (extra) {
@@ -247,7 +252,7 @@ function array_chunk_jobs(array = [], max_threads = 1, min_jobs_per_thread = 1)
247
252
  return out;
248
253
  }
249
254
 
250
- module.exports = array_chunk_jobs;
255
+ module.exports = array_chunk_balanced;
251
256
 
252
257
 
253
258
  /***/ }),
@@ -2479,10 +2484,10 @@ var __webpack_exports__ = {};
2479
2484
  \******************************/
2480
2485
  const ns = new URL(document.currentScript.src).searchParams.get('var') ?? 'h';
2481
2486
  if (typeof window[ns] !== 'undefined') {
2482
- console.log(`❌ @vbarbarosh/node-helpers@${"3.73.0"} was not injected — window.${ns} is already in use`);
2487
+ console.log(`❌ @vbarbarosh/node-helpers@${"3.74.0"} was not injected — window.${ns} is already in use`);
2483
2488
  }
2484
2489
  else {
2485
- console.log(`🎉 @vbarbarosh/node-helpers@${"3.73.0"} successfully exposed as window.${ns}`);
2490
+ console.log(`🎉 @vbarbarosh/node-helpers@${"3.74.0"} successfully exposed as window.${ns}`);
2486
2491
  window[ns] = {};
2487
2492
  // https://github.com/webpack/webpack/issues/625
2488
2493
  // https://webpack.js.org/guides/dependency-management/#require-context
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Vladimir Barbarosh <vladimir.barbarosh@gmail.com>",
3
3
  "license": "MIT",
4
4
  "name": "@vbarbarosh/node-helpers",
5
- "version": "3.73.0",
5
+ "version": "3.74.0",
6
6
  "description": "A set of helpers for JavaScript/Node.js",
7
7
  "unpkg": "dist/browser.js",
8
8
  "jsdelivr": "dist/browser.js",
@@ -0,0 +1,42 @@
1
+ const clamp = require('./clamp');
2
+
3
+ /**
4
+ * Split an array into up to `max_chunks` balanced chunks, while ensuring that
5
+ * each chunk contains at least `min_items_per_chunk` items (when possible).
6
+ *
7
+ * The function distributes items as evenly as possible:
8
+ * - Chunk sizes differ by at most 1 item.
9
+ * - The number of chunks never exceeds `max_chunks`.
10
+ *
11
+ * Originally designed for distributing workload across threads
12
+ * (e.g. `array_chunk_balanced(jobs, max_threads, min_jobs_per_thread)`).
13
+ *
14
+ * Edge cases:
15
+ * - If the input array is empty → returns [].
16
+ * - If there are too few items to satisfy `min_items_per_chunk`, even for a single
17
+ * chunk, all items are placed into one chunk.
18
+ *
19
+ * @param {Array} array
20
+ * @param {number} max_chunks
21
+ * @param {number} min_items_per_chunk
22
+ * @returns {Array<Array>}
23
+ */
24
+ function array_chunk_balanced(array = [], max_chunks = 1, min_items_per_chunk = 1)
25
+ {
26
+ const total_chunks = clamp(1, max_chunks, Math.floor(array.length / min_items_per_chunk));
27
+ const items_per_chunk = Math.floor(array.length / total_chunks);
28
+ let extra = array.length % total_chunks;
29
+
30
+ const out = [];
31
+ for (let i = 0; i < array.length; ) {
32
+ const size = items_per_chunk + (extra ? 1 : 0);
33
+ out.push(array.slice(i, i + size));
34
+ i += size;
35
+ if (extra) {
36
+ extra--;
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+
42
+ module.exports = array_chunk_balanced;
@@ -0,0 +1,37 @@
1
+ const array_chunk_balanced = require('./array_chunk_balanced');
2
+ const assert = require('assert');
3
+
4
+ describe('array_chunk_balanced', function () {
5
+ it('should handle basic input', function () {
6
+ assert.deepStrictEqual(array_chunk_balanced([1]), [[1]]);
7
+ assert.deepStrictEqual(array_chunk_balanced([1,2]), [[1,2]]);
8
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3]), [[1,2,3]]);
9
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5], 3, 2), [[1,2,3],[4,5]]);
10
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6], 3, 2), [[1,2],[3,4],[5,6]]);
11
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7], 3, 2), [[1,2,3],[4,5],[6,7]]);
12
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5], 3, 3), [[1,2,3,4,5]]);
13
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6], 3, 3), [[1,2,3],[4,5,6]]);
14
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7], 3, 3), [[1,2,3,4],[5,6,7]]);
15
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7,8], 3, 3), [[1,2,3,4],[5,6,7,8]]);
16
+ });
17
+ it('edge: If an array is empty → returns []', function () {
18
+ assert.deepStrictEqual(array_chunk_balanced([]), []);
19
+ });
20
+ it('edge: If there are too few items to satisfy `min_items_per_chunk`, even for 1 chunk, everything goes into a single chunk', function () {
21
+ assert.deepStrictEqual(array_chunk_balanced([1,2,3], 5, 5), [[1,2,3]]);
22
+ });
23
+ it('should never produce more chunks than max_threads', function () {
24
+ // 12 jobs, max 5 threads, min 2 jobs per thread
25
+ // Correct result MUST have exactly 5 chunks
26
+ assert.deepStrictEqual(
27
+ array_chunk_balanced([1,2,3,4,5,6,7,8,9,10,11,12], 5, 2),
28
+ [
29
+ [1,2,3],
30
+ [4,5,6],
31
+ [7,8],
32
+ [9,10],
33
+ [11,12]
34
+ ]
35
+ );
36
+ });
37
+ });
@@ -7,5 +7,66 @@ describe('array_fps', function () {
7
7
  assert.deepStrictEqual(array_fps(1, 2), [0, 0.99999]);
8
8
  assert.deepStrictEqual(array_fps(1, 3), [0, 0.49999, 0.99999]);
9
9
  assert.deepStrictEqual(array_fps(1, 4), [0, 0.33333, 0.66666, 0.99999]);
10
+ assert.deepStrictEqual(array_fps(5, 20), [
11
+ 0, 0.0505, 0.10101, 0.15151, 0.20202, 0.25252, 0.30303, 0.35353, 0.40404, 0.45454,
12
+ 0.50505, 0.55555, 0.60606, 0.65656, 0.70707, 0.75757, 0.80808, 0.85858, 0.90909, 0.95959,
13
+ 1.0101, 1.0606, 1.11111, 1.16161, 1.21212, 1.26262, 1.31313, 1.36363, 1.41414, 1.46464,
14
+ 1.51515, 1.56565, 1.61616, 1.66666, 1.71717, 1.76767, 1.81818, 1.86868, 1.91919, 1.96969,
15
+ 2.0202, 2.0707, 2.12121, 2.17171, 2.22222, 2.27272, 2.32323, 2.37373, 2.42424, 2.47474,
16
+ 2.52525, 2.57575, 2.62626, 2.67676, 2.72727, 2.77777, 2.82828, 2.87878, 2.92929, 2.97979,
17
+ 3.0303, 3.0808, 3.13131, 3.18181, 3.23232, 3.28282, 3.33333, 3.38383, 3.43434, 3.48484,
18
+ 3.53535, 3.58585, 3.63636, 3.68686, 3.73737, 3.78787, 3.83838, 3.88888, 3.93939, 3.98989,
19
+ 4.0404, 4.0909, 4.14141, 4.19191, 4.24242, 4.29292, 4.34343, 4.39393, 4.44444, 4.49494,
20
+ 4.54545, 4.59595, 4.64646, 4.69696, 4.74747, 4.79797, 4.84848, 4.89898, 4.94949, 4.99999,
21
+ ]);
22
+ assert.deepStrictEqual(array_fps(5, 30), [
23
+ 0, 0.03356, 0.06711, 0.10067, 0.13423, 0.16778, 0.20134, 0.2349, 0.26846, 0.30201,
24
+ 0.33557, 0.36913, 0.40268, 0.43624, 0.4698, 0.50335, 0.53691, 0.57047, 0.60403, 0.63758,
25
+ 0.67114, 0.7047, 0.73825, 0.77181, 0.80537, 0.83892, 0.87248, 0.90604, 0.9396, 0.97315,
26
+ 1.00671, 1.04027, 1.07382, 1.10738, 1.14094, 1.17449, 1.20805, 1.24161, 1.27517, 1.30872,
27
+ 1.34228, 1.37584, 1.40939, 1.44295, 1.47651, 1.51006, 1.54362, 1.57718, 1.61074, 1.64429,
28
+ 1.67785, 1.71141, 1.74496, 1.77852, 1.81208, 1.84563, 1.87919, 1.91275, 1.9463, 1.97986,
29
+ 2.01342, 2.04698, 2.08053, 2.11409, 2.14765, 2.1812, 2.21476, 2.24832, 2.28187, 2.31543,
30
+ 2.34899, 2.38255, 2.4161, 2.44966, 2.48322, 2.51677, 2.55033, 2.58389, 2.61744, 2.651,
31
+ 2.68456, 2.71812, 2.75167, 2.78523, 2.81879, 2.85234, 2.8859, 2.91946, 2.95301, 2.98657,
32
+ 3.02013, 3.05369, 3.08724, 3.1208, 3.15436, 3.18791, 3.22147, 3.25503, 3.28858, 3.32214,
33
+ 3.3557, 3.38925, 3.42281, 3.45637, 3.48993, 3.52348, 3.55704, 3.5906, 3.62415, 3.65771,
34
+ 3.69127, 3.72482, 3.75838, 3.79194, 3.8255, 3.85905, 3.89261, 3.92617, 3.95972, 3.99328,
35
+ 4.02684, 4.06039, 4.09395, 4.12751, 4.16107, 4.19462, 4.22818, 4.26174, 4.29529, 4.32885,
36
+ 4.36241, 4.39596, 4.42952, 4.46308, 4.49664, 4.53019, 4.56375, 4.59731, 4.63086, 4.66442,
37
+ 4.69798, 4.73153, 4.76509, 4.79865, 4.83221, 4.86576, 4.89932, 4.93288, 4.96643, 4.99999,
38
+ ]);
39
+ assert.deepStrictEqual(array_fps(5, 60), [
40
+ 0, 0.01672, 0.03344, 0.05017, 0.06689, 0.08361, 0.10033, 0.11706, 0.13378, 0.1505,
41
+ 0.16722, 0.18395, 0.20067, 0.21739, 0.23411, 0.25084, 0.26756, 0.28428, 0.301, 0.31773,
42
+ 0.33445, 0.35117, 0.36789, 0.38461, 0.40134, 0.41806, 0.43478, 0.4515, 0.46823, 0.48495,
43
+ 0.50167, 0.51839, 0.53512, 0.55184, 0.56856, 0.58528, 0.60201, 0.61873, 0.63545, 0.65217,
44
+ 0.66889, 0.68562, 0.70234, 0.71906, 0.73578, 0.75251, 0.76923, 0.78595, 0.80267, 0.8194,
45
+ 0.83612, 0.85284, 0.86956, 0.88629, 0.90301, 0.91973, 0.93645, 0.95318, 0.9699, 0.98662,
46
+ 1.00334, 1.02006, 1.03679, 1.05351, 1.07023, 1.08695, 1.10368, 1.1204, 1.13712, 1.15384,
47
+ 1.17057, 1.18729, 1.20401, 1.22073, 1.23746, 1.25418, 1.2709, 1.28762, 1.30435, 1.32107,
48
+ 1.33779, 1.35451, 1.37123, 1.38796, 1.40468, 1.4214, 1.43812, 1.45485, 1.47157, 1.48829,
49
+ 1.50501, 1.52174, 1.53846, 1.55518, 1.5719, 1.58863, 1.60535, 1.62207, 1.63879, 1.65552,
50
+ 1.67224, 1.68896, 1.70568, 1.7224, 1.73913, 1.75585, 1.77257, 1.78929, 1.80602, 1.82274,
51
+ 1.83946, 1.85618, 1.87291, 1.88963, 1.90635, 1.92307, 1.9398, 1.95652, 1.97324, 1.98996,
52
+ 2.00668, 2.02341, 2.04013, 2.05685, 2.07357, 2.0903, 2.10702, 2.12374, 2.14046, 2.15719,
53
+ 2.17391, 2.19063, 2.20735, 2.22408, 2.2408, 2.25752, 2.27424, 2.29097, 2.30769, 2.32441,
54
+ 2.34113, 2.35785, 2.37458, 2.3913, 2.40802, 2.42474, 2.44147, 2.45819, 2.47491, 2.49163,
55
+ 2.50836, 2.52508, 2.5418, 2.55852, 2.57525, 2.59197, 2.60869, 2.62541, 2.64214, 2.65886,
56
+ 2.67558, 2.6923, 2.70902, 2.72575, 2.74247, 2.75919, 2.77591, 2.79264, 2.80936, 2.82608,
57
+ 2.8428, 2.85953, 2.87625, 2.89297, 2.90969, 2.92642, 2.94314, 2.95986, 2.97658, 2.99331,
58
+ 3.01003, 3.02675, 3.04347, 3.06019, 3.07692, 3.09364, 3.11036, 3.12708, 3.14381, 3.16053,
59
+ 3.17725, 3.19397, 3.2107, 3.22742, 3.24414, 3.26086, 3.27759, 3.29431, 3.31103, 3.32775,
60
+ 3.34447, 3.3612, 3.37792, 3.39464, 3.41136, 3.42809, 3.44481, 3.46153, 3.47825, 3.49498,
61
+ 3.5117, 3.52842, 3.54514, 3.56187, 3.57859, 3.59531, 3.61203, 3.62876, 3.64548, 3.6622,
62
+ 3.67892, 3.69564, 3.71237, 3.72909, 3.74581, 3.76253, 3.77926, 3.79598, 3.8127, 3.82942,
63
+ 3.84615, 3.86287, 3.87959, 3.89631, 3.91304, 3.92976, 3.94648, 3.9632, 3.97993, 3.99665,
64
+ 4.01337, 4.03009, 4.04681, 4.06354, 4.08026, 4.09698, 4.1137, 4.13043, 4.14715, 4.16387,
65
+ 4.18059, 4.19732, 4.21404, 4.23076, 4.24748, 4.26421, 4.28093, 4.29765, 4.31437, 4.3311,
66
+ 4.34782, 4.36454, 4.38126, 4.39798, 4.41471, 4.43143, 4.44815, 4.46487, 4.4816, 4.49832,
67
+ 4.51504, 4.53176, 4.54849, 4.56521, 4.58193, 4.59865, 4.61538, 4.6321, 4.64882, 4.66554,
68
+ 4.68226, 4.69899, 4.71571, 4.73243, 4.74915, 4.76588, 4.7826, 4.79932, 4.81604, 4.83277,
69
+ 4.84949, 4.86621, 4.88293, 4.89966, 4.91638, 4.9331, 4.94982, 4.96655, 4.98327, 4.99999,
70
+ ]);
10
71
  });
11
72
  });
@@ -1,37 +0,0 @@
1
- const clamp = require('./clamp');
2
-
3
- /**
4
- * Split an array of jobs between up to `max_threads`, while trying to put at least
5
- * `min_jobs_per_thread` items into each chunk.
6
- *
7
- * - If an array is empty → returns [].
8
- * - If there are too few items to satisfy `min_items_per_chunk`, even for 1 chunk,
9
- * everything goes into a single chunk.
10
- *
11
- * Alternative names:
12
- * - array_chunk_balanced
13
- *
14
- * @param array
15
- * @param max_threads
16
- * @param min_jobs_per_thread
17
- * @returns {*[]}
18
- */
19
- function array_chunk_jobs(array = [], max_threads = 1, min_jobs_per_thread = 1)
20
- {
21
- const total_threads = clamp(1, max_threads, Math.floor(array.length / min_jobs_per_thread));
22
- const jobs_per_thread = Math.floor(array.length / total_threads);
23
- let extra = array.length % total_threads;
24
-
25
- const out = [];
26
- for (let i = 0; i < array.length; ) {
27
- const size = jobs_per_thread + (extra ? 1 : 0);
28
- out.push(array.slice(i, i + size));
29
- i += size;
30
- if (extra) {
31
- extra--;
32
- }
33
- }
34
- return out;
35
- }
36
-
37
- module.exports = array_chunk_jobs;
@@ -1,37 +0,0 @@
1
- const array_chunk_jobs = require('./array_chunk_jobs');
2
- const assert = require('assert');
3
-
4
- describe('array_chunk_jobs', function () {
5
- it('should handle basic input', function () {
6
- assert.deepStrictEqual(array_chunk_jobs([1]), [[1]]);
7
- assert.deepStrictEqual(array_chunk_jobs([1,2]), [[1,2]]);
8
- assert.deepStrictEqual(array_chunk_jobs([1,2,3]), [[1,2,3]]);
9
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5], 3, 2), [[1,2,3],[4,5]]);
10
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5,6], 3, 2), [[1,2],[3,4],[5,6]]);
11
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5,6,7], 3, 2), [[1,2,3],[4,5],[6,7]]);
12
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5], 3, 3), [[1,2,3,4,5]]);
13
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5,6], 3, 3), [[1,2,3],[4,5,6]]);
14
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5,6,7], 3, 3), [[1,2,3,4],[5,6,7]]);
15
- assert.deepStrictEqual(array_chunk_jobs([1,2,3,4,5,6,7,8], 3, 3), [[1,2,3,4],[5,6,7,8]]);
16
- });
17
- it('edge: If an array is empty → returns []', function () {
18
- assert.deepStrictEqual(array_chunk_jobs([]), []);
19
- });
20
- it('edge: If there are too few items to satisfy `min_items_per_chunk`, even for 1 chunk, everything goes into a single chunk', function () {
21
- assert.deepStrictEqual(array_chunk_jobs([1,2,3], 5, 5), [[1,2,3]]);
22
- });
23
- it('should never produce more chunks than max_threads', function () {
24
- // 12 jobs, max 5 threads, min 2 jobs per thread
25
- // Correct result MUST have exactly 5 chunks
26
- assert.deepStrictEqual(
27
- array_chunk_jobs([1,2,3,4,5,6,7,8,9,10,11,12], 5, 2),
28
- [
29
- [1,2,3],
30
- [4,5,6],
31
- [7,8],
32
- [9,10],
33
- [11,12]
34
- ]
35
- );
36
- });
37
- });