Skip to content

Fast React ID Generator #528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/React.Core/AssemblyRegistration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2014-Present, Facebook, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -37,6 +37,7 @@ public void Register(TinyIoCContainer container)
container.Register<IFileCacheHash, FileCacheHash>().AsPerRequestSingleton();
container.Register<JsEngineSwitcher>((c, o) => JsEngineSwitcher.Instance);
container.Register<IJavaScriptEngineFactory, JavaScriptEngineFactory>().AsSingleton();
container.Register<IReactIdGenerator, ReactIdGenerator>().AsSingleton();

container.Register<IReactEnvironment, ReactEnvironment>().AsPerRequestSingleton();
}
Expand Down
32 changes: 0 additions & 32 deletions src/React.Core/GuidExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2016-Present, Facebook, Inc.
* All rights reserved.
*
Expand All @@ -7,18 +7,14 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

using System;
using Xunit;

namespace React.Tests.Core
namespace React
{
public class GuidExtensionsTests
public interface IReactIdGenerator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, sorry. Missed this one. There is no XML comment for this type which is generating a warning at build time.

{
[Fact]
public void ToShortGuid()
{
var guid = Guid.Parse("c027191d-3785-485d-9fd7-5e0b376bd547");
Assert.Equal("HRknwIU3XUif114LN2vVRw", guid.ToShortGuid());
}
/// <summary>
/// Returns a short react identifier starts with "react_".
/// </summary>
/// <returns></returns>
string Generate();
}
}
14 changes: 3 additions & 11 deletions src/React.Core/ReactComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,16 @@ public object Props
/// </summary>
/// <param name="environment">The environment.</param>
/// <param name="configuration">Site-wide configuration.</param>
/// <param name="reactIdGenerator">React Id generator.</param>
/// <param name="componentName">Name of the component.</param>
/// <param name="containerId">The ID of the container DIV for this component</param>
public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, string componentName, string containerId)
public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId)
{
EnsureComponentNameValid(componentName);
_environment = environment;
_configuration = configuration;
ComponentName = componentName;
ContainerId = string.IsNullOrEmpty(containerId) ? GenerateId() : containerId;
ContainerId = string.IsNullOrEmpty(containerId) ? reactIdGenerator.Generate() : containerId;
ContainerTag = "div";
}

Expand Down Expand Up @@ -229,14 +230,5 @@ internal static void EnsureComponentNameValid(string componentName)
));
}
}

/// <summary>
/// Generates a unique identifier for this component, if one was not passed in.
/// </summary>
/// <returns></returns>
private static string GenerateId()
{
return "react_" + Guid.NewGuid().ToShortGuid();
}
}
}
13 changes: 10 additions & 3 deletions src/React.Core/ReactEnvironment.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2014-Present, Facebook, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -55,6 +55,10 @@ public class ReactEnvironment : IReactEnvironment, IDisposable
/// Hash algorithm for file-based cache
/// </summary>
protected readonly IFileCacheHash _fileCacheHash;
/// <summary>
/// React Id generator
/// </summary>
private readonly IReactIdGenerator _reactIdGenerator;

/// <summary>
/// JSX Transformer instance for this environment
Expand Down Expand Up @@ -120,19 +124,22 @@ public static IReactEnvironment GetCurrentOrThrow
/// <param name="cache">The cache to use for JSX compilation</param>
/// <param name="fileSystem">File system wrapper</param>
/// <param name="fileCacheHash">Hash algorithm for file-based cache</param>
/// <param name="reactIdGenerator">React ID generator</param>
public ReactEnvironment(
IJavaScriptEngineFactory engineFactory,
IReactSiteConfiguration config,
ICache cache,
IFileSystem fileSystem,
IFileCacheHash fileCacheHash
IFileCacheHash fileCacheHash,
IReactIdGenerator reactIdGenerator
)
{
_engineFactory = engineFactory;
_config = config;
_cache = cache;
_fileSystem = fileSystem;
_fileCacheHash = fileCacheHash;
_reactIdGenerator = reactIdGenerator;
_babelTransformer = new Lazy<IBabel>(() =>
new Babel(this, _cache, _fileSystem, _fileCacheHash, _config)
);
Expand Down Expand Up @@ -294,7 +301,7 @@ public virtual IReactComponent CreateComponent<T>(string componentName, T props,
EnsureUserScriptsLoaded();
}

var component = new ReactComponent(this, _config, componentName, containerId)
var component = new ReactComponent(this, _config, _reactIdGenerator, componentName, containerId)
{
Props = props,
ServerOnly = serverOnly
Expand Down
68 changes: 68 additions & 0 deletions src/React.Core/ReactIdGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2016-Present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

using System;
using System.Threading;

namespace React
{
/// <summary>
/// React ID generator.
/// </summary>
public class ReactIdGenerator : IReactIdGenerator
{
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";

private static long _random = DateTime.UtcNow.Ticks;

private static readonly char[] reactPrefix = "react_".ToCharArray();

/// <summary>
/// "react_".Length = 6 + 13 random symbols
/// </summary>
private const int reactIdLength = 19;

[ThreadStatic]
private static char[] _chars;

/// <summary>
/// Returns a short react identifier starts with "react_".
/// </summary>
/// <returns></returns>
public string Generate()
{
var chars = _chars;
if (chars == null)
{
_chars = chars = new char[reactIdLength];
Array.Copy(reactPrefix, 0, chars, 0, reactPrefix.Length);
}

var id = Interlocked.Increment(ref _random);

// from 6 because "react_".Length == 6, _encode32Chars.Length == 32 (base32),
// base32 characters are 5 bits in length and from long (64 bits) we can get 13 symbols
chars[6] = _encode32Chars[(int)(id >> 60) & 31];
chars[7] = _encode32Chars[(int)(id >> 55) & 31];
chars[8] = _encode32Chars[(int)(id >> 50) & 31];
chars[9] = _encode32Chars[(int)(id >> 45) & 31];
chars[10] = _encode32Chars[(int)(id >> 40) & 31];
chars[11] = _encode32Chars[(int)(id >> 35) & 31];
chars[12] = _encode32Chars[(int)(id >> 30) & 31];
chars[13] = _encode32Chars[(int)(id >> 25) & 31];
chars[14] = _encode32Chars[(int)(id >> 20) & 31];
chars[15] = _encode32Chars[(int)(id >> 15) & 31];
chars[16] = _encode32Chars[(int)(id >> 10) & 31];
chars[17] = _encode32Chars[(int)(id >> 5) & 31];
chars[18] = _encode32Chars[(int)id & 31];

return new string(chars, 0, reactIdLength);
}
}
}
9 changes: 4 additions & 5 deletions src/React.Router/ReactEnvironmentExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2014-Present, Facebook, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -35,11 +35,10 @@ public static ReactRouterComponent CreateRouterComponent<T>(
bool clientOnly = false
)
{
var config = AssemblyRegistration.Container.Resolve<IReactSiteConfiguration>();

var component = new ReactRouterComponent(
env,
config,
env,
AssemblyRegistration.Container.Resolve<IReactSiteConfiguration>(),
AssemblyRegistration.Container.Resolve<IReactIdGenerator>(),
componentName,
containerId,
path
Expand Down
4 changes: 3 additions & 1 deletion src/React.Router/ReactRouterComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ public class ReactRouterComponent : ReactComponent
/// </summary>
/// <param name="environment">The environment.</param>
/// <param name="configuration">Site-wide configuration.</param>
/// <param name="reactIdGenerator">React Id generator.</param>
/// <param name="componentName">Name of the component.</param>
/// <param name="containerId">The ID of the container DIV for this component</param>
/// <param name="path">F.x. from Request.Path. Used by React Static Router to determine context and routing.</param>
public ReactRouterComponent(
IReactEnvironment environment,
IReactSiteConfiguration configuration,
IReactIdGenerator reactIdGenerator,
string componentName,
string containerId,
string path
) : base(environment, configuration, componentName, containerId)
) : base(environment, configuration, reactIdGenerator, componentName, containerId)
{
_path = path;
}
Expand Down
Loading