116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
/**
|
|
* @license Apache-2.0
|
|
*
|
|
* Copyright (c) 2018 The Stdlib Authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
// MODULES //
|
|
|
|
var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
|
|
var isCollection = require( '@stdlib/assert/is-collection' );
|
|
var format = require( './../../format' );
|
|
var UNICODE_MAX = require( '@stdlib/constants/unicode/max' );
|
|
var UNICODE_MAX_BMP = require( '@stdlib/constants/unicode/max-bmp' );
|
|
|
|
|
|
// VARIABLES //
|
|
|
|
var fromCharCode = String.fromCharCode;
|
|
|
|
// Factor to rescale a code point from a supplementary plane:
|
|
var Ox10000 = 0x10000|0; // 65536
|
|
|
|
// Factor added to obtain a high surrogate:
|
|
var OxD800 = 0xD800|0; // 55296
|
|
|
|
// Factor added to obtain a low surrogate:
|
|
var OxDC00 = 0xDC00|0; // 56320
|
|
|
|
// 10-bit mask: 2^10-1 = 1023 => 0x3ff => 00000000 00000000 00000011 11111111
|
|
var Ox3FF = 1023|0;
|
|
|
|
|
|
// MAIN //
|
|
|
|
/**
|
|
* Creates a string from a sequence of Unicode code points.
|
|
*
|
|
* ## Notes
|
|
*
|
|
* - UTF-16 encoding uses one 16-bit unit for non-surrogates (U+0000 to U+D7FF and U+E000 to U+FFFF).
|
|
* - UTF-16 encoding uses two 16-bit units (surrogate pairs) for U+10000 to U+10FFFF and encodes U+10000-U+10FFFF by subtracting 0x10000 from the code point, expressing the result as a 20-bit binary, and splitting the 20 bits of 0x0-0xFFFFF as upper and lower 10-bits. The respective 10-bits are stored in two 16-bit words: a high and a low surrogate.
|
|
*
|
|
*
|
|
* @param {...NonNegativeInteger} args - sequence of code points
|
|
* @throws {Error} must provide either an array-like object of code points or one or more code points as separate arguments
|
|
* @throws {TypeError} a code point must be a nonnegative integer
|
|
* @throws {RangeError} must provide a valid Unicode code point
|
|
* @returns {string} created string
|
|
*
|
|
* @example
|
|
* var str = fromCodePoint( 9731 );
|
|
* // returns '☃'
|
|
*/
|
|
function fromCodePoint( args ) {
|
|
var len;
|
|
var str;
|
|
var arr;
|
|
var low;
|
|
var hi;
|
|
var pt;
|
|
var i;
|
|
|
|
len = arguments.length;
|
|
if ( len === 1 && isCollection( args ) ) {
|
|
arr = arguments[ 0 ];
|
|
len = arr.length;
|
|
} else {
|
|
arr = [];
|
|
for ( i = 0; i < len; i++ ) {
|
|
arr.push( arguments[ i ] );
|
|
}
|
|
}
|
|
if ( len === 0 ) {
|
|
throw new Error( 'insufficient arguments. Must provide either an array of code points or one or more code points as separate arguments.' );
|
|
}
|
|
str = '';
|
|
for ( i = 0; i < len; i++ ) {
|
|
pt = arr[ i ];
|
|
if ( !isNonNegativeInteger( pt ) ) {
|
|
throw new TypeError( format( 'invalid argument. Must provide valid code points (i.e., nonnegative integers). Value: `%s`.', pt ) );
|
|
}
|
|
if ( pt > UNICODE_MAX ) {
|
|
throw new RangeError( format( 'invalid argument. Must provide a valid code point (i.e., cannot exceed %u). Value: `%s`.', UNICODE_MAX, pt ) );
|
|
}
|
|
if ( pt <= UNICODE_MAX_BMP ) {
|
|
str += fromCharCode( pt );
|
|
} else {
|
|
// Code point from a supplementary plane. Split into two 16-bit code units (surrogate pair).
|
|
pt -= Ox10000;
|
|
hi = (pt >> 10) + OxD800;
|
|
low = (pt & Ox3FF) + OxDC00;
|
|
str += fromCharCode( hi, low );
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
// EXPORTS //
|
|
|
|
module.exports = fromCodePoint;
|