buffer: check logic simplification
authorTrevor Norris <trev.norris@gmail.com>
Tue, 19 Feb 2013 07:52:34 +0000 (23:52 -0800)
committerBen Noordhuis <info@bnoordhuis.nl>
Wed, 20 Feb 2013 19:34:34 +0000 (20:34 +0100)
Checks have been simplified and optimized for most-used cases.

Calling Buffer with another Buffer as the subject will now use the
SlowBuffer Copy method instead of the for loop.

No need to call for value coercion, just place the ternary inline.

lib/buffer.js

index ca4fedf..3378dce 100644 (file)
@@ -30,7 +30,7 @@ SlowBuffer.prototype.__proto__ = Buffer.prototype;
 
 
 function clamp(index, len, defaultValue) {
-  if (typeof index === 'undefined') return defaultValue;
+  if (typeof index !== 'number') return defaultValue;
   index = ~~index;  // Coerce to integer.
   if (index >= len) return len;
   if (index >= 0) return index;
@@ -49,7 +49,7 @@ function toHex(n) {
 SlowBuffer.prototype.toString = function(encoding, start, end) {
   encoding = String(encoding || 'utf8').toLowerCase();
   start = +start || 0;
-  if (typeof end == 'undefined') end = this.length;
+  if (typeof end !== 'number') end = this.length;
 
   // Fastpath empty strings
   if (+end == start) {
@@ -150,15 +150,6 @@ SlowBuffer.prototype.slice = function(start, end) {
 };
 
 
-function coerce(length) {
-  // Coerce length to a number (possibly NaN), round up
-  // in case it's fractional (e.g. 123.456). Since NaN
-  // comparisons are always false, use to return zero.
-  length = Math.ceil(+length);
-  return length > 0 ? length : 0;
-}
-
-
 var zeroBuffer = new SlowBuffer(0);
 
 // Buffer
@@ -175,22 +166,22 @@ function Buffer(subject, encoding, offset) {
       throw new TypeError('First argument must be a Buffer when slicing');
     }
 
-    this.length = coerce(encoding);
+    this.length = +encoding > 0 ? Math.ceil(encoding) : 0;
     this.parent = subject.parent ? subject.parent : subject;
     this.offset = offset;
   } else {
     // Find the length
     switch (type = typeof subject) {
       case 'number':
-        this.length = coerce(subject);
+        this.length = +subject > 0 ? Math.ceil(subject) : 0;
         break;
 
       case 'string':
         this.length = Buffer.byteLength(subject, encoding);
         break;
 
-      case 'object': // Assume object is an array
-        this.length = coerce(subject.length);
+      case 'object': // Assume object is array-ish
+        this.length = +subject.length > 0 ? Math.ceil(subject.length) : 0;
         break;
 
       default:
@@ -217,14 +208,24 @@ function Buffer(subject, encoding, offset) {
       this.offset = 0;
     }
 
-    // Treat array-ish objects as a byte array.
-    if (isArrayIsh(subject)) {
-      for (var i = 0; i < this.length; i++) {
-        this.parent[i + this.offset] = subject[i];
+    // optimize by branching logic for new allocations
+    if (typeof subject !== 'number') {
+      if (type === 'string') {
+        // We are a string
+        this.length = this.write(subject, 0, encoding);
+      // if subject is buffer then use built-in copy method
+      } else if (Buffer.isBuffer(subject)) {
+        if (subject.parent)
+          subject.parent.copy(this.parent,
+                              this.offset,
+                              subject.offset,
+                              this.length + subject.offset);
+        else
+          subject.copy(this.parent, this.offset, 0, this.length);
+      } else if (isArrayIsh(subject)) {
+        for (var i = 0; i < this.length; i++)
+          this.parent[i + this.offset] = subject[i];
       }
-    } else if (type == 'string') {
-      // We are a string
-      this.length = this.write(subject, 0, encoding);
     }
   }
 
@@ -232,7 +233,7 @@ function Buffer(subject, encoding, offset) {
 }
 
 function isArrayIsh(subject) {
-  return Array.isArray(subject) || Buffer.isBuffer(subject) ||
+  return Array.isArray(subject) ||
          subject && typeof subject === 'object' &&
          typeof subject.length === 'number';
 }
@@ -388,13 +389,13 @@ Buffer.prototype.toJSON = function() {
 Buffer.prototype.toString = function(encoding, start, end) {
   encoding = String(encoding || 'utf8').toLowerCase();
 
-  if (typeof start == 'undefined' || start < 0) {
+  if (typeof start !== 'number' || start < 0) {
     start = 0;
   } else if (start > this.length) {
     start = this.length;
   }
 
-  if (typeof end == 'undefined' || end > this.length) {
+  if (typeof end !== 'number' || end > this.length) {
     end = this.length;
   } else if (end < 0) {
     end = 0;
@@ -445,7 +446,7 @@ Buffer.prototype.fill = function fill(value, start, end) {
   if (typeof value === 'string') {
     value = value.charCodeAt(0);
   }
-  if (!(typeof value === 'number') || isNaN(value)) {
+  if (typeof value !== 'number' || isNaN(value)) {
     throw new TypeError('value is not a number');
   }