@@ -4,16 +4,19 @@ import { type InspectFn, defaultInspect } from './parser/utils';
44import { ByteUtils } from './utils/byte_utils' ;
55import { NumberUtils } from './utils/number_utils' ;
66
7+ // Settings for ObjectId Buffer pool
8+ // Disable pool by default in order to ensure compatibility
9+ // Specify larger poolSize to enable pool
710let currentPool : Uint8Array | null = null ;
8- let poolSize = 1000 ; // Default: Hold 1000 ObjectId buffers in a pool
11+ let poolSize = 1 ; // Disable pool by default.
912let currentPoolOffset = 0 ;
1013
1114/**
1215 * Retrieves a ObjectId pool and offset. This function may create a new ObjectId buffer pool and reset the pool offset
1316 * @internal
1417 */
1518function getPool ( ) : [ Uint8Array , number ] {
16- if ( ! currentPool || currentPoolOffset + 12 > currentPool . byteLength ) {
19+ if ( ! currentPool || currentPoolOffset + 12 > currentPool . length ) {
1720 currentPool = ByteUtils . allocateUnsafe ( poolSize * 12 ) ;
1821 currentPoolOffset = 0 ;
1922 }
@@ -75,7 +78,7 @@ export class ObjectId extends BSONValue {
7578 /** ObjectId buffer pool pointer @internal */
7679 private pool : Uint8Array ;
7780 /** Buffer pool offset @internal */
78- private offset : number ;
81+ private offset ? : number ;
7982
8083 /** ObjectId hexString cache @internal */
8184 private __id ?: string ;
@@ -151,43 +154,55 @@ export class ObjectId extends BSONValue {
151154 workingId = inputId ;
152155 }
153156
154- const [ pool , offset ] = getPool ( ) ;
155-
156- // The following cases use workingId to construct an ObjectId
157- if ( workingId == null || typeof workingId === 'number' ) {
158- // The most common use case (blank id, new objectId instance)
159- // Generate a new id
160- ObjectId . generate ( typeof workingId === 'number' ? workingId : undefined , pool , offset ) ;
161- } else if ( ArrayBuffer . isView ( workingId ) ) {
162- if ( workingId . byteLength === 12 ) {
163- inputIndex = 0 ;
164- } else if (
165- typeof inputIndex !== 'number' ||
166- inputIndex < 0 ||
167- workingId . byteLength < inputIndex + 12 ||
168- isNaN ( inputIndex )
169- ) {
170- throw new BSONError ( 'Buffer length must be 12 or a valid offset must be specified' ) ;
171- }
172- for ( let i = 0 ; i < 12 ; i ++ ) pool [ offset + i ] = workingId [ inputIndex + i ] ;
173- } else if ( typeof workingId === 'string' ) {
174- if ( workingId . length === 24 && checkForHexRegExp . test ( workingId ) ) {
175- pool . set ( ByteUtils . fromHex ( workingId ) , offset ) ;
157+ let pool : Uint8Array ;
158+ let offset : number ;
159+
160+ // Special case when poolSize === 1 and a 12 byte buffer is passed in - just persist buffer
161+ if ( poolSize === 1 && ArrayBuffer . isView ( workingId ) && workingId . length === 12 ) {
162+ pool = ByteUtils . toLocalBufferType ( workingId ) ;
163+ offset = 0 ;
164+ } else {
165+ [ pool , offset ] = getPool ( ) ;
166+
167+ // The following cases use workingId to construct an ObjectId
168+ if ( workingId == null || typeof workingId === 'number' ) {
169+ // The most common use case (blank id, new objectId instance)
170+ // Generate a new id
171+ ObjectId . generate ( typeof workingId === 'number' ? workingId : undefined , pool , offset ) ;
172+ } else if ( ArrayBuffer . isView ( workingId ) ) {
173+ if ( workingId . length === 12 ) {
174+ inputIndex = 0 ;
175+ } else if (
176+ typeof inputIndex !== 'number' ||
177+ inputIndex < 0 ||
178+ workingId . length < inputIndex + 12 ||
179+ isNaN ( inputIndex )
180+ ) {
181+ throw new BSONError ( 'Buffer length must be 12 or a valid offset must be specified' ) ;
182+ }
183+ for ( let i = 0 ; i < 12 ; i ++ ) pool [ offset + i ] = workingId [ inputIndex + i ] ;
184+ } else if ( typeof workingId === 'string' ) {
185+ if ( workingId . length === 24 && checkForHexRegExp . test ( workingId ) ) {
186+ pool . set ( ByteUtils . fromHex ( workingId ) , offset ) ;
187+ } else {
188+ throw new BSONError (
189+ 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer'
190+ ) ;
191+ }
176192 } else {
177- throw new BSONError (
178- 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer'
179- ) ;
193+ throw new BSONError ( 'Argument passed in does not match the accepted types' ) ;
180194 }
181- } else {
182- throw new BSONError ( 'Argument passed in does not match the accepted types' ) ;
183195 }
184196 // If we are caching the hex string
185197 if ( ObjectId . cacheHexString ) {
186198 this . __id = ByteUtils . toHex ( pool , offset , offset + 12 ) ;
187199 }
188200 // Increment pool offset once we have completed initialization
189201 this . pool = pool ;
190- this . offset = offset ;
202+ // Only set offset if pool is used
203+ if ( poolSize > 1 ) {
204+ this . offset = offset ;
205+ }
191206 incrementPool ( ) ;
192207 }
193208
@@ -201,6 +216,7 @@ export class ObjectId extends BSONValue {
201216 * @readonly
202217 */
203218 get id ( ) : Uint8Array {
219+ if ( this . offset === undefined ) return this . pool ;
204220 return this . pool . subarray ( this . offset , this . offset + 12 ) ;
205221 }
206222
@@ -219,8 +235,9 @@ export class ObjectId extends BSONValue {
219235 if ( ObjectId . cacheHexString && this . __id ) {
220236 return this . __id ;
221237 }
238+ const start = this . offset ?? 0 ;
222239
223- const hexString = ByteUtils . toHex ( this . pool , this . offset , this . offset + 12 ) ;
240+ const hexString = ByteUtils . toHex ( this . pool , start , start + 12 ) ;
224241
225242 if ( ObjectId . cacheHexString && ! this . __id ) {
226243 this . __id = hexString ;
@@ -329,16 +346,20 @@ export class ObjectId extends BSONValue {
329346 }
330347
331348 if ( ObjectId . is ( otherId ) ) {
332- if ( otherId . pool && typeof otherId . offset === 'number' ) {
349+ if ( otherId . pool ) {
333350 for ( let i = 11 ; i >= 0 ; i -- ) {
334- if ( this . pool [ this . offset + i ] !== otherId . pool [ otherId . offset + i ] ) {
351+ const offset = this . offset ?? 0 ;
352+ const otherOffset = otherId . offset ?? 0 ;
353+ if ( this . pool [ offset + i ] !== otherId . pool [ otherOffset + i ] ) {
335354 return false ;
336355 }
337356 }
338357 return true ;
339358 }
340359 // If otherId does not have pool and offset, fallback to buffer comparison for compatibility
341- return ByteUtils . equals ( this . buffer , otherId . buffer ) ;
360+ return (
361+ this . buffer [ 11 ] === otherId . buffer [ 11 ] && ByteUtils . equals ( this . buffer , otherId . buffer )
362+ ) ;
342363 }
343364
344365 if ( typeof otherId === 'string' ) {
@@ -357,7 +378,7 @@ export class ObjectId extends BSONValue {
357378 /** Returns the generation date (accurate up to the second) that this ID was generated. */
358379 getTimestamp ( ) : Date {
359380 const timestamp = new Date ( ) ;
360- const time = NumberUtils . getUint32BE ( this . pool , this . offset ) ;
381+ const time = NumberUtils . getUint32BE ( this . pool , this . offset ?? 0 ) ;
361382 timestamp . setTime ( Math . floor ( time ) * 1000 ) ;
362383 return timestamp ;
363384 }
@@ -370,7 +391,7 @@ export class ObjectId extends BSONValue {
370391 /** @internal */
371392 serializeInto ( uint8array : Uint8Array , index : number ) : 12 {
372393 const pool = this . pool ;
373- const offset = this . offset ;
394+ const offset = this . offset ?? 0 ;
374395 uint8array [ index ] = pool [ offset ] ;
375396 uint8array [ index + 1 ] = pool [ offset + 1 ] ;
376397 uint8array [ index + 2 ] = pool [ offset + 2 ] ;
0 commit comments