Merge branch 'master' of github.com:poolifier/poolifier
[poolifier.git] / src / utils.ts
1 import os from 'node:os'
2 import type {
3 MeasurementStatisticsRequirements,
4 WorkerChoiceStrategyOptions
5 } from './pools/selection-strategies/selection-strategies-types'
6
7 /**
8 * An intentional empty function.
9 */
10 export const EMPTY_FUNCTION: () => void = Object.freeze(() => {
11 /* Intentionally empty */
12 })
13
14 /**
15 * Default worker choice strategy options.
16 */
17 export const DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS: WorkerChoiceStrategyOptions =
18 {
19 runTime: { median: false },
20 waitTime: { median: false },
21 elu: { median: false }
22 }
23
24 /**
25 * Default measurement statistics requirements.
26 */
27 export const DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS: MeasurementStatisticsRequirements =
28 {
29 aggregate: false,
30 average: false,
31 median: false
32 }
33
34 /**
35 * Returns safe host OS optimized estimate of the default amount of parallelism a pool should use.
36 * Always returns a value greater than zero.
37 *
38 * @returns The host OS optimized maximum pool size.
39 */
40 export const availableParallelism = (): number => {
41 let availableParallelism = 1
42 try {
43 availableParallelism = os.availableParallelism()
44 } catch {
45 const cpus = os.cpus()
46 if (Array.isArray(cpus) && cpus.length > 0) {
47 availableParallelism = cpus.length
48 }
49 }
50 return availableParallelism
51 }
52
53 /**
54 * Computes the median of the given data set.
55 *
56 * @param dataSet - Data set.
57 * @returns The median of the given data set.
58 */
59 export const median = (dataSet: number[]): number => {
60 if (Array.isArray(dataSet) && dataSet.length === 0) {
61 return 0
62 }
63 if (Array.isArray(dataSet) && dataSet.length === 1) {
64 return dataSet[0]
65 }
66 const sortedDataSet = dataSet.slice().sort((a, b) => a - b)
67 return (
68 (sortedDataSet[(sortedDataSet.length - 1) >> 1] +
69 sortedDataSet[sortedDataSet.length >> 1]) /
70 2
71 )
72 }
73
74 /**
75 * Rounds the given number to the given scale.
76 *
77 * @param num - The number to round.
78 * @param scale - The scale to round to.
79 * @returns The rounded number.
80 */
81 export const round = (num: number, scale = 2): number => {
82 const rounder = Math.pow(10, scale)
83 return Math.round(num * rounder * (1 + Number.EPSILON)) / rounder
84 }
85
86 /**
87 * Is the given object a plain object?
88 *
89 * @param obj - The object to check.
90 * @returns `true` if the given object is a plain object, `false` otherwise.
91 */
92 export const isPlainObject = (obj: unknown): boolean =>
93 typeof obj === 'object' &&
94 obj !== null &&
95 obj?.constructor === Object &&
96 Object.prototype.toString.call(obj) === '[object Object]'