├── ProjectSettings
├── ProjectVersion.txt
├── ClusterInputManager.asset
├── PresetManager.asset
├── EditorBuildSettings.asset
├── XRSettings.asset
├── TimeManager.asset
├── VFXManager.asset
├── AudioManager.asset
├── TagManager.asset
├── EditorSettings.asset
├── UnityConnectSettings.asset
├── DynamicsManager.asset
├── NavMeshAreas.asset
├── Physics2DSettings.asset
├── GraphicsSettings.asset
├── InputManager.asset
├── QualitySettings.asset
└── ProjectSettings.asset
├── Assets
├── SampleScene.unity.meta
├── Svelto.meta
├── StringKey.cs.meta
├── Tester.cs.meta
├── NativeSpan.cs.meta
├── Svelto
│ ├── HashHelpers.cs.meta
│ ├── FasterDictionary.cs.meta
│ ├── HashHelpers.cs
│ └── FasterDictionary.cs
├── NativeFasterDictionary.cs.meta
├── StringKey.cs
├── SampleScene.unity
├── Tester.cs
├── NativeSpan.cs
└── NativeFasterDictionary.cs
├── README.md
├── .gitignore
├── LICENSE
└── Packages
└── manifest.json
/ProjectSettings/ProjectVersion.txt:
--------------------------------------------------------------------------------
1 | m_EditorVersion: 2019.1.0f1
2 | m_EditorVersionWithRevision: 2019.1.0f1 (5c52223b18d4)
3 |
--------------------------------------------------------------------------------
/ProjectSettings/ClusterInputManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!236 &1
4 | ClusterInputManager:
5 | m_ObjectHideFlags: 0
6 | m_Inputs: []
7 |
--------------------------------------------------------------------------------
/ProjectSettings/PresetManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1386491679 &1
4 | PresetManager:
5 | m_ObjectHideFlags: 0
6 | m_DefaultList: []
7 |
--------------------------------------------------------------------------------
/Assets/SampleScene.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9fc0d4010bbf28b4594072e72b8655ab
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Assets/Svelto.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5f248e551d75d2d4e9afda24ff5af466
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/ProjectSettings/EditorBuildSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1045 &1
4 | EditorBuildSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | m_Scenes: []
8 | m_configObjects: {}
9 |
--------------------------------------------------------------------------------
/ProjectSettings/XRSettings.asset:
--------------------------------------------------------------------------------
1 | {
2 | "m_SettingKeys": [
3 | "VR Device Disabled",
4 | "VR Device User Alert"
5 | ],
6 | "m_SettingValues": [
7 | "False",
8 | "False"
9 | ]
10 | }
--------------------------------------------------------------------------------
/ProjectSettings/TimeManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!5 &1
4 | TimeManager:
5 | m_ObjectHideFlags: 0
6 | Fixed Timestep: 0.02
7 | Maximum Allowed Timestep: 0.33333334
8 | m_TimeScale: 1
9 | Maximum Particle Timestep: 0.03
10 |
--------------------------------------------------------------------------------
/Assets/StringKey.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e2e7c5e3595d9ac4386d05ab33c973c8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/Tester.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 991fbc0dd450b94478ea976b4d81e905
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/NativeSpan.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5b3467d3a8927ba48bd811376d09b631
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/Svelto/HashHelpers.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bc9227137760ce84eb4f602715f3d35d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/NativeFasterDictionary.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 42ffa7c6f25e0d444ad94833ec52860d
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assets/Svelto/FasterDictionary.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 06eece63469c15e40b7c4738b1eb71f4
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/ProjectSettings/VFXManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!937362698 &1
4 | VFXManager:
5 | m_ObjectHideFlags: 0
6 | m_IndirectShader: {fileID: 0}
7 | m_CopyBufferShader: {fileID: 0}
8 | m_SortShader: {fileID: 0}
9 | m_RenderPipeSettingsPath:
10 | m_FixedTimeStep: 0.016666668
11 | m_MaxDeltaTime: 0.05
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NativeFasterDictionary
2 | An experiment to write a faster/native version of [SveltoECS's FasterDictionary](https://github.com/sebas77/Svelto.Tasks.Examples/blob/205506feef7557a8aed74d65f2a86353d90afcb7/Assets/Svelto.Tasks/Svelto.Common/DataStructures/FasterDictionary.cs) that can run in Burst jobs.
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ProjectSettings/AudioManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!11 &1
4 | AudioManager:
5 | m_ObjectHideFlags: 0
6 | m_Volume: 1
7 | Rolloff Scale: 1
8 | Doppler Factor: 1
9 | Default Speaker Mode: 2
10 | m_SampleRate: 0
11 | m_DSPBufferSize: 1024
12 | m_VirtualVoiceCount: 512
13 | m_RealVoiceCount: 32
14 | m_SpatializerPlugin:
15 | m_AmbisonicDecoderPlugin:
16 | m_DisableAudio: 0
17 | m_VirtualizeEffects: 1
18 |
--------------------------------------------------------------------------------
/ProjectSettings/TagManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!78 &1
4 | TagManager:
5 | serializedVersion: 2
6 | tags: []
7 | layers:
8 | - Default
9 | - TransparentFX
10 | - Ignore Raycast
11 | -
12 | - Water
13 | - UI
14 | -
15 | -
16 | -
17 | -
18 | -
19 | -
20 | -
21 | -
22 | -
23 | -
24 | -
25 | -
26 | -
27 | -
28 | -
29 | -
30 | -
31 | -
32 | -
33 | -
34 | -
35 | -
36 | -
37 | -
38 | -
39 | -
40 | m_SortingLayers:
41 | - name: Default
42 | uniqueID: 0
43 | locked: 0
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Ll]ibrary/
2 | [Tt]emp/
3 | [Oo]bj/
4 | [Bb]uild/
5 | [Bb]uilds/
6 | [Ll]ogs/
7 | Assets/AssetStoreTools*
8 |
9 | # Visual Studio cache directory
10 | .vs/
11 |
12 | # Autogenerated VS/MD/Consulo solution and project files
13 | ExportedObj/
14 | .consulo/
15 | *.csproj
16 | *.unityproj
17 | *.sln
18 | *.suo
19 | *.tmp
20 | *.user
21 | *.userprefs
22 | *.pidb
23 | *.booproj
24 | *.svd
25 | *.pdb
26 | *.opendb
27 |
28 | # Unity3D generated meta files
29 | *.pidb.meta
30 | *.pdb.meta
31 |
32 | # Unity3D Generated File On Crash Reports
33 | sysinfo.txt
34 |
35 | # Builds
36 | *.apk
37 | *.unitypackage
38 |
--------------------------------------------------------------------------------
/ProjectSettings/EditorSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!159 &1
4 | EditorSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 7
7 | m_ExternalVersionControlSupport: Hidden Meta Files
8 | m_SerializationMode: 2
9 | m_LineEndingsForNewScripts: 2
10 | m_DefaultBehaviorMode: 0
11 | m_PrefabRegularEnvironment: {fileID: 0}
12 | m_PrefabUIEnvironment: {fileID: 0}
13 | m_SpritePackerMode: 0
14 | m_SpritePackerPaddingPower: 1
15 | m_EtcTextureCompressorBehavior: 1
16 | m_EtcTextureFastCompressor: 1
17 | m_EtcTextureNormalCompressor: 2
18 | m_EtcTextureBestCompressor: 4
19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp
20 | m_ProjectGenerationRootNamespace:
21 | m_CollabEditorSettings:
22 | inProgressEnabled: 1
23 | m_EnableTextureStreamingInEditMode: 1
24 | m_EnableTextureStreamingInPlayMode: 1
25 | m_AsyncShaderCompilation: 1
26 |
--------------------------------------------------------------------------------
/ProjectSettings/UnityConnectSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!310 &1
4 | UnityConnectSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 1
7 | m_Enabled: 0
8 | m_TestMode: 0
9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com
12 | m_TestInitMode: 0
13 | CrashReportingSettings:
14 | m_EventUrl: https://perf-events.cloud.unity3d.com
15 | m_Enabled: 0
16 | m_LogBufferSize: 10
17 | m_CaptureEditorExceptions: 1
18 | UnityPurchasingSettings:
19 | m_Enabled: 0
20 | m_TestMode: 0
21 | UnityAnalyticsSettings:
22 | m_Enabled: 0
23 | m_TestMode: 0
24 | m_InitializeOnStartup: 1
25 | UnityAdsSettings:
26 | m_Enabled: 0
27 | m_InitializeOnStartup: 1
28 | m_TestMode: 0
29 | m_IosGameId:
30 | m_AndroidGameId:
31 | m_GameIds: {}
32 | m_GameId:
33 | PerformanceReportingSettings:
34 | m_Enabled: 0
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Jeffrey Vella
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ProjectSettings/DynamicsManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!55 &1
4 | PhysicsManager:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 11
7 | m_Gravity: {x: 0, y: -9.81, z: 0}
8 | m_DefaultMaterial: {fileID: 0}
9 | m_BounceThreshold: 2
10 | m_SleepThreshold: 0.005
11 | m_DefaultContactOffset: 0.01
12 | m_DefaultSolverIterations: 6
13 | m_DefaultSolverVelocityIterations: 1
14 | m_QueriesHitBackfaces: 0
15 | m_QueriesHitTriggers: 1
16 | m_EnableAdaptiveForce: 0
17 | m_ClothInterCollisionDistance: 0
18 | m_ClothInterCollisionStiffness: 0
19 | m_ContactsGeneration: 1
20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
21 | m_AutoSimulation: 1
22 | m_AutoSyncTransforms: 0
23 | m_ReuseCollisionCallbacks: 1
24 | m_ClothInterCollisionSettingsToggle: 0
25 | m_ContactPairsMode: 0
26 | m_BroadphaseType: 0
27 | m_WorldBounds:
28 | m_Center: {x: 0, y: 0, z: 0}
29 | m_Extent: {x: 250, y: 250, z: 250}
30 | m_WorldSubdivisions: 8
31 | m_FrictionType: 0
32 | m_EnableEnhancedDeterminism: 0
33 | m_EnableUnifiedHeightmaps: 1
34 | m_DefaultMaxAngluarSpeed: 7
35 |
--------------------------------------------------------------------------------
/ProjectSettings/NavMeshAreas.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!126 &1
4 | NavMeshProjectSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | areas:
8 | - name: Walkable
9 | cost: 1
10 | - name: Not Walkable
11 | cost: 1
12 | - name: Jump
13 | cost: 2
14 | - name:
15 | cost: 1
16 | - name:
17 | cost: 1
18 | - name:
19 | cost: 1
20 | - name:
21 | cost: 1
22 | - name:
23 | cost: 1
24 | - name:
25 | cost: 1
26 | - name:
27 | cost: 1
28 | - name:
29 | cost: 1
30 | - name:
31 | cost: 1
32 | - name:
33 | cost: 1
34 | - name:
35 | cost: 1
36 | - name:
37 | cost: 1
38 | - name:
39 | cost: 1
40 | - name:
41 | cost: 1
42 | - name:
43 | cost: 1
44 | - name:
45 | cost: 1
46 | - name:
47 | cost: 1
48 | - name:
49 | cost: 1
50 | - name:
51 | cost: 1
52 | - name:
53 | cost: 1
54 | - name:
55 | cost: 1
56 | - name:
57 | cost: 1
58 | - name:
59 | cost: 1
60 | - name:
61 | cost: 1
62 | - name:
63 | cost: 1
64 | - name:
65 | cost: 1
66 | - name:
67 | cost: 1
68 | - name:
69 | cost: 1
70 | - name:
71 | cost: 1
72 | m_LastAgentTypeID: -887442657
73 | m_Settings:
74 | - serializedVersion: 2
75 | agentTypeID: 0
76 | agentRadius: 0.5
77 | agentHeight: 2
78 | agentSlope: 45
79 | agentClimb: 0.75
80 | ledgeDropHeight: 0
81 | maxJumpAcrossDistance: 0
82 | minRegionArea: 2
83 | manualCellSize: 0
84 | cellSize: 0.16666667
85 | manualTileSize: 0
86 | tileSize: 256
87 | accuratePlacement: 0
88 | debug:
89 | m_Flags: 0
90 | m_SettingNames:
91 | - Humanoid
92 |
--------------------------------------------------------------------------------
/Packages/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "com.unity.ads": "2.0.8",
4 | "com.unity.analytics": "3.3.2",
5 | "com.unity.burst": "0.2.4-preview.45",
6 | "com.unity.collab-proxy": "1.2.15",
7 | "com.unity.collections": "0.0.9-preview.12",
8 | "com.unity.entities": "0.0.12-preview.24",
9 | "com.unity.package-manager-ui": "2.1.2",
10 | "com.unity.purchasing": "2.0.1",
11 | "com.unity.textmeshpro": "2.0.0",
12 | "com.unity.timeline": "1.0.0",
13 | "com.unity.modules.ai": "1.0.0",
14 | "com.unity.modules.animation": "1.0.0",
15 | "com.unity.modules.assetbundle": "1.0.0",
16 | "com.unity.modules.audio": "1.0.0",
17 | "com.unity.modules.cloth": "1.0.0",
18 | "com.unity.modules.director": "1.0.0",
19 | "com.unity.modules.imageconversion": "1.0.0",
20 | "com.unity.modules.imgui": "1.0.0",
21 | "com.unity.modules.jsonserialize": "1.0.0",
22 | "com.unity.modules.particlesystem": "1.0.0",
23 | "com.unity.modules.physics": "1.0.0",
24 | "com.unity.modules.physics2d": "1.0.0",
25 | "com.unity.modules.screencapture": "1.0.0",
26 | "com.unity.modules.terrain": "1.0.0",
27 | "com.unity.modules.terrainphysics": "1.0.0",
28 | "com.unity.modules.tilemap": "1.0.0",
29 | "com.unity.modules.ui": "1.0.0",
30 | "com.unity.modules.uielements": "1.0.0",
31 | "com.unity.modules.umbra": "1.0.0",
32 | "com.unity.modules.unityanalytics": "1.0.0",
33 | "com.unity.modules.unitywebrequest": "1.0.0",
34 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
35 | "com.unity.modules.unitywebrequestaudio": "1.0.0",
36 | "com.unity.modules.unitywebrequesttexture": "1.0.0",
37 | "com.unity.modules.unitywebrequestwww": "1.0.0",
38 | "com.unity.modules.vehicles": "1.0.0",
39 | "com.unity.modules.video": "1.0.0",
40 | "com.unity.modules.vr": "1.0.0",
41 | "com.unity.modules.wind": "1.0.0",
42 | "com.unity.modules.xr": "1.0.0"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ProjectSettings/Physics2DSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!19 &1
4 | Physics2DSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 4
7 | m_Gravity: {x: 0, y: -9.81}
8 | m_DefaultMaterial: {fileID: 0}
9 | m_VelocityIterations: 8
10 | m_PositionIterations: 3
11 | m_VelocityThreshold: 1
12 | m_MaxLinearCorrection: 0.2
13 | m_MaxAngularCorrection: 8
14 | m_MaxTranslationSpeed: 100
15 | m_MaxRotationSpeed: 360
16 | m_BaumgarteScale: 0.2
17 | m_BaumgarteTimeOfImpactScale: 0.75
18 | m_TimeToSleep: 0.5
19 | m_LinearSleepTolerance: 0.01
20 | m_AngularSleepTolerance: 2
21 | m_DefaultContactOffset: 0.01
22 | m_JobOptions:
23 | serializedVersion: 2
24 | useMultithreading: 0
25 | useConsistencySorting: 0
26 | m_InterpolationPosesPerJob: 100
27 | m_NewContactsPerJob: 30
28 | m_CollideContactsPerJob: 100
29 | m_ClearFlagsPerJob: 200
30 | m_ClearBodyForcesPerJob: 200
31 | m_SyncDiscreteFixturesPerJob: 50
32 | m_SyncContinuousFixturesPerJob: 50
33 | m_FindNearestContactsPerJob: 100
34 | m_UpdateTriggerContactsPerJob: 100
35 | m_IslandSolverCostThreshold: 100
36 | m_IslandSolverBodyCostScale: 1
37 | m_IslandSolverContactCostScale: 10
38 | m_IslandSolverJointCostScale: 10
39 | m_IslandSolverBodiesPerJob: 50
40 | m_IslandSolverContactsPerJob: 50
41 | m_AutoSimulation: 1
42 | m_QueriesHitTriggers: 1
43 | m_QueriesStartInColliders: 1
44 | m_CallbacksOnDisable: 1
45 | m_ReuseCollisionCallbacks: 1
46 | m_AutoSyncTransforms: 0
47 | m_AlwaysShowColliders: 0
48 | m_ShowColliderSleep: 1
49 | m_ShowColliderContacts: 0
50 | m_ShowColliderAABB: 0
51 | m_ContactArrowScale: 0.2
52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
57 |
--------------------------------------------------------------------------------
/Assets/StringKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Unity.Collections.LowLevel.Unsafe;
3 |
4 | namespace Experiment
5 | {
6 | ///
7 | /// Just a quick unmanaged string, its got some issues with displaying the string in
8 | /// Visual studio debugging but the values do come out correctly at runtime.
9 | ///
10 | public unsafe struct StringKey : IComparable, IEquatable
11 | {
12 | private fixed byte _bytes[CharCapacity * sizeof(char)];
13 | private readonly int _usedBytes;
14 | public readonly int _hash;
15 | public readonly int CharCount;
16 | public const int CharCapacity = 20;
17 |
18 | public StringKey(string input)
19 | {
20 | CharCount = input.Length > CharCapacity ? CharCapacity : input.Length;
21 | _usedBytes = CharCount * sizeof(char);
22 |
23 | fixed (char* src = input)
24 | fixed (byte* dst = _bytes)
25 | {
26 | UnsafeUtility.MemCpy(dst, src, _usedBytes);
27 |
28 | unchecked
29 | {
30 | _hash = _bytes[0];
31 | for (int i = 1; i < _usedBytes; i++)
32 | {
33 | _hash = (_hash * 397) ^ _bytes[i];
34 | }
35 | }
36 | }
37 | }
38 |
39 | public string Value
40 | {
41 | get
42 | {
43 | char[] chars = new char[CharCount];
44 | fixed (byte* src = _bytes)
45 | fixed (char* dst = chars)
46 | {
47 | UnsafeUtility.MemCpy(dst, src, _usedBytes);
48 | }
49 | return new string(chars);
50 | }
51 | }
52 |
53 | public int CompareTo(StringKey other)
54 | {
55 | fixed (byte* ptr = _bytes)
56 | {
57 | return UnsafeUtility.MemCmp(ptr, other._bytes, CharCount);
58 | }
59 | }
60 |
61 | public override bool Equals(object obj)
62 | {
63 | return !ReferenceEquals(null, obj) && (obj is StringKey other && Equals(other));
64 | }
65 |
66 | public bool Equals(StringKey other) => CompareTo(other) == 0;
67 |
68 | public override int GetHashCode() => _hash;
69 | }
70 | }
--------------------------------------------------------------------------------
/ProjectSettings/GraphicsSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!30 &1
4 | GraphicsSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 12
7 | m_Deferred:
8 | m_Mode: 1
9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
10 | m_DeferredReflections:
11 | m_Mode: 1
12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
13 | m_ScreenSpaceShadows:
14 | m_Mode: 1
15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
16 | m_LegacyDeferred:
17 | m_Mode: 1
18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
19 | m_DepthNormals:
20 | m_Mode: 1
21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
22 | m_MotionVectors:
23 | m_Mode: 1
24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
25 | m_LightHalo:
26 | m_Mode: 1
27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
28 | m_LensFlare:
29 | m_Mode: 1
30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
31 | m_AlwaysIncludedShaders:
32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
38 | m_PreloadedShaders: []
39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
40 | type: 0}
41 | m_CustomRenderPipeline: {fileID: 0}
42 | m_TransparencySortMode: 0
43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1}
44 | m_DefaultRenderingPath: 1
45 | m_DefaultMobileRenderingPath: 1
46 | m_TierSettings: []
47 | m_LightmapStripping: 0
48 | m_FogStripping: 0
49 | m_InstancingStripping: 0
50 | m_LightmapKeepPlain: 1
51 | m_LightmapKeepDirCombined: 1
52 | m_LightmapKeepDynamicPlain: 1
53 | m_LightmapKeepDynamicDirCombined: 1
54 | m_LightmapKeepShadowMask: 1
55 | m_LightmapKeepSubtractive: 1
56 | m_FogKeepLinear: 1
57 | m_FogKeepExp: 1
58 | m_FogKeepExp2: 1
59 | m_AlbedoSwatchInfos: []
60 | m_LightsUseLinearIntensity: 0
61 | m_LightsUseColorTemperature: 0
62 |
--------------------------------------------------------------------------------
/Assets/Svelto/HashHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Experiment
4 | {
5 | public static class HashHelpers
6 | {
7 | public const int HashCollisionThreshold = 100;
8 |
9 | const int HashPrime = 101;
10 |
11 | public static readonly int[] Primes =
12 | {
13 | 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
14 | 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
15 | 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
16 | 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
17 | 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369
18 | };
19 |
20 | public static bool IsPrime(int candidate)
21 | {
22 | if ((candidate & 1) != 0)
23 | {
24 | int limit = (int)Math.Sqrt(candidate);
25 | for (int divisor = 3; divisor <= limit; divisor += 2)
26 | {
27 | if ((candidate % divisor) == 0)
28 | return false;
29 | }
30 |
31 | return true;
32 | }
33 |
34 | return (candidate == 2);
35 | }
36 |
37 | public static int GetPrime(int min)
38 | {
39 | if (min < 0)
40 | throw new ArgumentException();
41 | for (int i = 0; i < Primes.Length; i++)
42 | {
43 | int prime = Primes[i];
44 | if (prime >= min)
45 | return prime;
46 | }
47 |
48 | for (int i = (min | 1); i < int.MaxValue; i += 2)
49 | {
50 | if (IsPrime(i) && ((i - 1) % HashPrime != 0))
51 | return i;
52 | }
53 |
54 | return min;
55 | }
56 |
57 | public static int ExpandPrime(int oldSize)
58 | {
59 | int newSize = 2 * oldSize;
60 | if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
61 | {
62 | return MaxPrimeArrayLength;
63 | }
64 |
65 | return GetPrime(newSize);
66 | }
67 |
68 | public const int MaxPrimeArrayLength = 0x7FEFFFFD;
69 | }
70 | }
--------------------------------------------------------------------------------
/Assets/SampleScene.unity:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!29 &1
4 | OcclusionCullingSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | m_OcclusionBakeSettings:
8 | smallestOccluder: 5
9 | smallestHole: 0.25
10 | backfaceThreshold: 100
11 | m_SceneGUID: 00000000000000000000000000000000
12 | m_OcclusionCullingData: {fileID: 0}
13 | --- !u!104 &2
14 | RenderSettings:
15 | m_ObjectHideFlags: 0
16 | serializedVersion: 9
17 | m_Fog: 0
18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
19 | m_FogMode: 3
20 | m_FogDensity: 0.01
21 | m_LinearFogStart: 0
22 | m_LinearFogEnd: 300
23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
26 | m_AmbientIntensity: 1
27 | m_AmbientMode: 0
28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
30 | m_HaloStrength: 0.5
31 | m_FlareStrength: 1
32 | m_FlareFadeSpeed: 3
33 | m_HaloTexture: {fileID: 0}
34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
35 | m_DefaultReflectionMode: 0
36 | m_DefaultReflectionResolution: 128
37 | m_ReflectionBounces: 1
38 | m_ReflectionIntensity: 1
39 | m_CustomReflection: {fileID: 0}
40 | m_Sun: {fileID: 0}
41 | m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1}
42 | m_UseRadianceAmbientProbe: 0
43 | --- !u!157 &3
44 | LightmapSettings:
45 | m_ObjectHideFlags: 0
46 | serializedVersion: 11
47 | m_GIWorkflowMode: 0
48 | m_GISettings:
49 | serializedVersion: 2
50 | m_BounceScale: 1
51 | m_IndirectOutputScale: 1
52 | m_AlbedoBoost: 1
53 | m_EnvironmentLightingMode: 0
54 | m_EnableBakedLightmaps: 1
55 | m_EnableRealtimeLightmaps: 1
56 | m_LightmapEditorSettings:
57 | serializedVersion: 12
58 | m_Resolution: 2
59 | m_BakeResolution: 40
60 | m_AtlasSize: 1024
61 | m_AO: 0
62 | m_AOMaxDistance: 1
63 | m_CompAOExponent: 1
64 | m_CompAOExponentDirect: 0
65 | m_ExtractAmbientOcclusion: 0
66 | m_Padding: 2
67 | m_LightmapParameters: {fileID: 0}
68 | m_LightmapsBakeMode: 1
69 | m_TextureCompression: 1
70 | m_FinalGather: 0
71 | m_FinalGatherFiltering: 1
72 | m_FinalGatherRayCount: 256
73 | m_ReflectionCompression: 2
74 | m_MixedBakeMode: 2
75 | m_BakeBackend: 1
76 | m_PVRSampling: 1
77 | m_PVRDirectSampleCount: 32
78 | m_PVRSampleCount: 500
79 | m_PVRBounces: 2
80 | m_PVREnvironmentSampleCount: 500
81 | m_PVREnvironmentReferencePointCount: 2048
82 | m_PVRFilteringMode: 2
83 | m_PVRDenoiserTypeDirect: 0
84 | m_PVRDenoiserTypeIndirect: 0
85 | m_PVRDenoiserTypeAO: 0
86 | m_PVRFilterTypeDirect: 0
87 | m_PVRFilterTypeIndirect: 0
88 | m_PVRFilterTypeAO: 0
89 | m_PVREnvironmentMIS: 0
90 | m_PVRCulling: 1
91 | m_PVRFilteringGaussRadiusDirect: 1
92 | m_PVRFilteringGaussRadiusIndirect: 5
93 | m_PVRFilteringGaussRadiusAO: 2
94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5
95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2
96 | m_PVRFilteringAtrousPositionSigmaAO: 1
97 | m_ShowResolutionOverlay: 1
98 | m_ExportTrainingData: 0
99 | m_LightingDataAsset: {fileID: 0}
100 | m_UseShadowmask: 1
101 | --- !u!196 &4
102 | NavMeshSettings:
103 | serializedVersion: 2
104 | m_ObjectHideFlags: 0
105 | m_BuildSettings:
106 | serializedVersion: 2
107 | agentTypeID: 0
108 | agentRadius: 0.5
109 | agentHeight: 2
110 | agentSlope: 45
111 | agentClimb: 0.4
112 | ledgeDropHeight: 0
113 | maxJumpAcrossDistance: 0
114 | minRegionArea: 2
115 | manualCellSize: 0
116 | cellSize: 0.16666667
117 | manualTileSize: 0
118 | tileSize: 256
119 | accuratePlacement: 0
120 | debug:
121 | m_Flags: 0
122 | m_NavMeshData: {fileID: 0}
123 | --- !u!1 &1900525701
124 | GameObject:
125 | m_ObjectHideFlags: 0
126 | m_CorrespondingSourceObject: {fileID: 0}
127 | m_PrefabInstance: {fileID: 0}
128 | m_PrefabAsset: {fileID: 0}
129 | serializedVersion: 6
130 | m_Component:
131 | - component: {fileID: 1900525703}
132 | - component: {fileID: 1900525702}
133 | m_Layer: 0
134 | m_Name: <<< HERE, click RUN Button
135 | m_TagString: Untagged
136 | m_Icon: {fileID: 0}
137 | m_NavMeshLayer: 0
138 | m_StaticEditorFlags: 0
139 | m_IsActive: 1
140 | --- !u!114 &1900525702
141 | MonoBehaviour:
142 | m_ObjectHideFlags: 0
143 | m_CorrespondingSourceObject: {fileID: 0}
144 | m_PrefabInstance: {fileID: 0}
145 | m_PrefabAsset: {fileID: 0}
146 | m_GameObject: {fileID: 1900525701}
147 | m_Enabled: 1
148 | m_EditorHideFlags: 0
149 | m_Script: {fileID: 11500000, guid: 991fbc0dd450b94478ea976b4d81e905, type: 3}
150 | m_Name:
151 | m_EditorClassIdentifier:
152 | --- !u!4 &1900525703
153 | Transform:
154 | m_ObjectHideFlags: 0
155 | m_CorrespondingSourceObject: {fileID: 0}
156 | m_PrefabInstance: {fileID: 0}
157 | m_PrefabAsset: {fileID: 0}
158 | m_GameObject: {fileID: 1900525701}
159 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
160 | m_LocalPosition: {x: 0, y: 0, z: 0}
161 | m_LocalScale: {x: 1, y: 1, z: 1}
162 | m_Children: []
163 | m_Father: {fileID: 0}
164 | m_RootOrder: 0
165 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
166 |
--------------------------------------------------------------------------------
/ProjectSettings/InputManager.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!13 &1
4 | InputManager:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | m_Axes:
8 | - serializedVersion: 3
9 | m_Name: Horizontal
10 | descriptiveName:
11 | descriptiveNegativeName:
12 | negativeButton: left
13 | positiveButton: right
14 | altNegativeButton: a
15 | altPositiveButton: d
16 | gravity: 3
17 | dead: 0.001
18 | sensitivity: 3
19 | snap: 1
20 | invert: 0
21 | type: 0
22 | axis: 0
23 | joyNum: 0
24 | - serializedVersion: 3
25 | m_Name: Vertical
26 | descriptiveName:
27 | descriptiveNegativeName:
28 | negativeButton: down
29 | positiveButton: up
30 | altNegativeButton: s
31 | altPositiveButton: w
32 | gravity: 3
33 | dead: 0.001
34 | sensitivity: 3
35 | snap: 1
36 | invert: 0
37 | type: 0
38 | axis: 0
39 | joyNum: 0
40 | - serializedVersion: 3
41 | m_Name: Fire1
42 | descriptiveName:
43 | descriptiveNegativeName:
44 | negativeButton:
45 | positiveButton: left ctrl
46 | altNegativeButton:
47 | altPositiveButton: mouse 0
48 | gravity: 1000
49 | dead: 0.001
50 | sensitivity: 1000
51 | snap: 0
52 | invert: 0
53 | type: 0
54 | axis: 0
55 | joyNum: 0
56 | - serializedVersion: 3
57 | m_Name: Fire2
58 | descriptiveName:
59 | descriptiveNegativeName:
60 | negativeButton:
61 | positiveButton: left alt
62 | altNegativeButton:
63 | altPositiveButton: mouse 1
64 | gravity: 1000
65 | dead: 0.001
66 | sensitivity: 1000
67 | snap: 0
68 | invert: 0
69 | type: 0
70 | axis: 0
71 | joyNum: 0
72 | - serializedVersion: 3
73 | m_Name: Fire3
74 | descriptiveName:
75 | descriptiveNegativeName:
76 | negativeButton:
77 | positiveButton: left shift
78 | altNegativeButton:
79 | altPositiveButton: mouse 2
80 | gravity: 1000
81 | dead: 0.001
82 | sensitivity: 1000
83 | snap: 0
84 | invert: 0
85 | type: 0
86 | axis: 0
87 | joyNum: 0
88 | - serializedVersion: 3
89 | m_Name: Jump
90 | descriptiveName:
91 | descriptiveNegativeName:
92 | negativeButton:
93 | positiveButton: space
94 | altNegativeButton:
95 | altPositiveButton:
96 | gravity: 1000
97 | dead: 0.001
98 | sensitivity: 1000
99 | snap: 0
100 | invert: 0
101 | type: 0
102 | axis: 0
103 | joyNum: 0
104 | - serializedVersion: 3
105 | m_Name: Mouse X
106 | descriptiveName:
107 | descriptiveNegativeName:
108 | negativeButton:
109 | positiveButton:
110 | altNegativeButton:
111 | altPositiveButton:
112 | gravity: 0
113 | dead: 0
114 | sensitivity: 0.1
115 | snap: 0
116 | invert: 0
117 | type: 1
118 | axis: 0
119 | joyNum: 0
120 | - serializedVersion: 3
121 | m_Name: Mouse Y
122 | descriptiveName:
123 | descriptiveNegativeName:
124 | negativeButton:
125 | positiveButton:
126 | altNegativeButton:
127 | altPositiveButton:
128 | gravity: 0
129 | dead: 0
130 | sensitivity: 0.1
131 | snap: 0
132 | invert: 0
133 | type: 1
134 | axis: 1
135 | joyNum: 0
136 | - serializedVersion: 3
137 | m_Name: Mouse ScrollWheel
138 | descriptiveName:
139 | descriptiveNegativeName:
140 | negativeButton:
141 | positiveButton:
142 | altNegativeButton:
143 | altPositiveButton:
144 | gravity: 0
145 | dead: 0
146 | sensitivity: 0.1
147 | snap: 0
148 | invert: 0
149 | type: 1
150 | axis: 2
151 | joyNum: 0
152 | - serializedVersion: 3
153 | m_Name: Horizontal
154 | descriptiveName:
155 | descriptiveNegativeName:
156 | negativeButton:
157 | positiveButton:
158 | altNegativeButton:
159 | altPositiveButton:
160 | gravity: 0
161 | dead: 0.19
162 | sensitivity: 1
163 | snap: 0
164 | invert: 0
165 | type: 2
166 | axis: 0
167 | joyNum: 0
168 | - serializedVersion: 3
169 | m_Name: Vertical
170 | descriptiveName:
171 | descriptiveNegativeName:
172 | negativeButton:
173 | positiveButton:
174 | altNegativeButton:
175 | altPositiveButton:
176 | gravity: 0
177 | dead: 0.19
178 | sensitivity: 1
179 | snap: 0
180 | invert: 1
181 | type: 2
182 | axis: 1
183 | joyNum: 0
184 | - serializedVersion: 3
185 | m_Name: Fire1
186 | descriptiveName:
187 | descriptiveNegativeName:
188 | negativeButton:
189 | positiveButton: joystick button 0
190 | altNegativeButton:
191 | altPositiveButton:
192 | gravity: 1000
193 | dead: 0.001
194 | sensitivity: 1000
195 | snap: 0
196 | invert: 0
197 | type: 0
198 | axis: 0
199 | joyNum: 0
200 | - serializedVersion: 3
201 | m_Name: Fire2
202 | descriptiveName:
203 | descriptiveNegativeName:
204 | negativeButton:
205 | positiveButton: joystick button 1
206 | altNegativeButton:
207 | altPositiveButton:
208 | gravity: 1000
209 | dead: 0.001
210 | sensitivity: 1000
211 | snap: 0
212 | invert: 0
213 | type: 0
214 | axis: 0
215 | joyNum: 0
216 | - serializedVersion: 3
217 | m_Name: Fire3
218 | descriptiveName:
219 | descriptiveNegativeName:
220 | negativeButton:
221 | positiveButton: joystick button 2
222 | altNegativeButton:
223 | altPositiveButton:
224 | gravity: 1000
225 | dead: 0.001
226 | sensitivity: 1000
227 | snap: 0
228 | invert: 0
229 | type: 0
230 | axis: 0
231 | joyNum: 0
232 | - serializedVersion: 3
233 | m_Name: Jump
234 | descriptiveName:
235 | descriptiveNegativeName:
236 | negativeButton:
237 | positiveButton: joystick button 3
238 | altNegativeButton:
239 | altPositiveButton:
240 | gravity: 1000
241 | dead: 0.001
242 | sensitivity: 1000
243 | snap: 0
244 | invert: 0
245 | type: 0
246 | axis: 0
247 | joyNum: 0
248 | - serializedVersion: 3
249 | m_Name: Submit
250 | descriptiveName:
251 | descriptiveNegativeName:
252 | negativeButton:
253 | positiveButton: return
254 | altNegativeButton:
255 | altPositiveButton: joystick button 0
256 | gravity: 1000
257 | dead: 0.001
258 | sensitivity: 1000
259 | snap: 0
260 | invert: 0
261 | type: 0
262 | axis: 0
263 | joyNum: 0
264 | - serializedVersion: 3
265 | m_Name: Submit
266 | descriptiveName:
267 | descriptiveNegativeName:
268 | negativeButton:
269 | positiveButton: enter
270 | altNegativeButton:
271 | altPositiveButton: space
272 | gravity: 1000
273 | dead: 0.001
274 | sensitivity: 1000
275 | snap: 0
276 | invert: 0
277 | type: 0
278 | axis: 0
279 | joyNum: 0
280 | - serializedVersion: 3
281 | m_Name: Cancel
282 | descriptiveName:
283 | descriptiveNegativeName:
284 | negativeButton:
285 | positiveButton: escape
286 | altNegativeButton:
287 | altPositiveButton: joystick button 1
288 | gravity: 1000
289 | dead: 0.001
290 | sensitivity: 1000
291 | snap: 0
292 | invert: 0
293 | type: 0
294 | axis: 0
295 | joyNum: 0
296 |
--------------------------------------------------------------------------------
/ProjectSettings/QualitySettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!47 &1
4 | QualitySettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 5
7 | m_CurrentQuality: 5
8 | m_QualitySettings:
9 | - serializedVersion: 2
10 | name: Very Low
11 | pixelLightCount: 0
12 | shadows: 0
13 | shadowResolution: 0
14 | shadowProjection: 1
15 | shadowCascades: 1
16 | shadowDistance: 15
17 | shadowNearPlaneOffset: 3
18 | shadowCascade2Split: 0.33333334
19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
20 | shadowmaskMode: 0
21 | blendWeights: 1
22 | textureQuality: 1
23 | anisotropicTextures: 0
24 | antiAliasing: 0
25 | softParticles: 0
26 | softVegetation: 0
27 | realtimeReflectionProbes: 0
28 | billboardsFaceCameraPosition: 0
29 | vSyncCount: 0
30 | lodBias: 0.3
31 | maximumLODLevel: 0
32 | streamingMipmapsActive: 0
33 | streamingMipmapsAddAllCameras: 1
34 | streamingMipmapsMemoryBudget: 512
35 | streamingMipmapsRenderersPerFrame: 512
36 | streamingMipmapsMaxLevelReduction: 2
37 | streamingMipmapsMaxFileIORequests: 1024
38 | particleRaycastBudget: 4
39 | asyncUploadTimeSlice: 2
40 | asyncUploadBufferSize: 16
41 | asyncUploadPersistentBuffer: 1
42 | resolutionScalingFixedDPIFactor: 1
43 | excludedTargetPlatforms: []
44 | - serializedVersion: 2
45 | name: Low
46 | pixelLightCount: 0
47 | shadows: 0
48 | shadowResolution: 0
49 | shadowProjection: 1
50 | shadowCascades: 1
51 | shadowDistance: 20
52 | shadowNearPlaneOffset: 3
53 | shadowCascade2Split: 0.33333334
54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
55 | shadowmaskMode: 0
56 | blendWeights: 2
57 | textureQuality: 0
58 | anisotropicTextures: 0
59 | antiAliasing: 0
60 | softParticles: 0
61 | softVegetation: 0
62 | realtimeReflectionProbes: 0
63 | billboardsFaceCameraPosition: 0
64 | vSyncCount: 0
65 | lodBias: 0.4
66 | maximumLODLevel: 0
67 | streamingMipmapsActive: 0
68 | streamingMipmapsAddAllCameras: 1
69 | streamingMipmapsMemoryBudget: 512
70 | streamingMipmapsRenderersPerFrame: 512
71 | streamingMipmapsMaxLevelReduction: 2
72 | streamingMipmapsMaxFileIORequests: 1024
73 | particleRaycastBudget: 16
74 | asyncUploadTimeSlice: 2
75 | asyncUploadBufferSize: 16
76 | asyncUploadPersistentBuffer: 1
77 | resolutionScalingFixedDPIFactor: 1
78 | excludedTargetPlatforms: []
79 | - serializedVersion: 2
80 | name: Medium
81 | pixelLightCount: 1
82 | shadows: 1
83 | shadowResolution: 0
84 | shadowProjection: 1
85 | shadowCascades: 1
86 | shadowDistance: 20
87 | shadowNearPlaneOffset: 3
88 | shadowCascade2Split: 0.33333334
89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
90 | shadowmaskMode: 0
91 | blendWeights: 2
92 | textureQuality: 0
93 | anisotropicTextures: 1
94 | antiAliasing: 0
95 | softParticles: 0
96 | softVegetation: 0
97 | realtimeReflectionProbes: 0
98 | billboardsFaceCameraPosition: 0
99 | vSyncCount: 1
100 | lodBias: 0.7
101 | maximumLODLevel: 0
102 | streamingMipmapsActive: 0
103 | streamingMipmapsAddAllCameras: 1
104 | streamingMipmapsMemoryBudget: 512
105 | streamingMipmapsRenderersPerFrame: 512
106 | streamingMipmapsMaxLevelReduction: 2
107 | streamingMipmapsMaxFileIORequests: 1024
108 | particleRaycastBudget: 64
109 | asyncUploadTimeSlice: 2
110 | asyncUploadBufferSize: 16
111 | asyncUploadPersistentBuffer: 1
112 | resolutionScalingFixedDPIFactor: 1
113 | excludedTargetPlatforms: []
114 | - serializedVersion: 2
115 | name: High
116 | pixelLightCount: 2
117 | shadows: 2
118 | shadowResolution: 1
119 | shadowProjection: 1
120 | shadowCascades: 2
121 | shadowDistance: 40
122 | shadowNearPlaneOffset: 3
123 | shadowCascade2Split: 0.33333334
124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
125 | shadowmaskMode: 1
126 | blendWeights: 2
127 | textureQuality: 0
128 | anisotropicTextures: 1
129 | antiAliasing: 0
130 | softParticles: 0
131 | softVegetation: 1
132 | realtimeReflectionProbes: 1
133 | billboardsFaceCameraPosition: 1
134 | vSyncCount: 1
135 | lodBias: 1
136 | maximumLODLevel: 0
137 | streamingMipmapsActive: 0
138 | streamingMipmapsAddAllCameras: 1
139 | streamingMipmapsMemoryBudget: 512
140 | streamingMipmapsRenderersPerFrame: 512
141 | streamingMipmapsMaxLevelReduction: 2
142 | streamingMipmapsMaxFileIORequests: 1024
143 | particleRaycastBudget: 256
144 | asyncUploadTimeSlice: 2
145 | asyncUploadBufferSize: 16
146 | asyncUploadPersistentBuffer: 1
147 | resolutionScalingFixedDPIFactor: 1
148 | excludedTargetPlatforms: []
149 | - serializedVersion: 2
150 | name: Very High
151 | pixelLightCount: 3
152 | shadows: 2
153 | shadowResolution: 2
154 | shadowProjection: 1
155 | shadowCascades: 2
156 | shadowDistance: 70
157 | shadowNearPlaneOffset: 3
158 | shadowCascade2Split: 0.33333334
159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
160 | shadowmaskMode: 1
161 | blendWeights: 4
162 | textureQuality: 0
163 | anisotropicTextures: 2
164 | antiAliasing: 2
165 | softParticles: 1
166 | softVegetation: 1
167 | realtimeReflectionProbes: 1
168 | billboardsFaceCameraPosition: 1
169 | vSyncCount: 1
170 | lodBias: 1.5
171 | maximumLODLevel: 0
172 | streamingMipmapsActive: 0
173 | streamingMipmapsAddAllCameras: 1
174 | streamingMipmapsMemoryBudget: 512
175 | streamingMipmapsRenderersPerFrame: 512
176 | streamingMipmapsMaxLevelReduction: 2
177 | streamingMipmapsMaxFileIORequests: 1024
178 | particleRaycastBudget: 1024
179 | asyncUploadTimeSlice: 2
180 | asyncUploadBufferSize: 16
181 | asyncUploadPersistentBuffer: 1
182 | resolutionScalingFixedDPIFactor: 1
183 | excludedTargetPlatforms: []
184 | - serializedVersion: 2
185 | name: Ultra
186 | pixelLightCount: 4
187 | shadows: 2
188 | shadowResolution: 2
189 | shadowProjection: 1
190 | shadowCascades: 4
191 | shadowDistance: 150
192 | shadowNearPlaneOffset: 3
193 | shadowCascade2Split: 0.33333334
194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
195 | shadowmaskMode: 1
196 | blendWeights: 4
197 | textureQuality: 0
198 | anisotropicTextures: 2
199 | antiAliasing: 2
200 | softParticles: 1
201 | softVegetation: 1
202 | realtimeReflectionProbes: 1
203 | billboardsFaceCameraPosition: 1
204 | vSyncCount: 1
205 | lodBias: 2
206 | maximumLODLevel: 0
207 | streamingMipmapsActive: 0
208 | streamingMipmapsAddAllCameras: 1
209 | streamingMipmapsMemoryBudget: 512
210 | streamingMipmapsRenderersPerFrame: 512
211 | streamingMipmapsMaxLevelReduction: 2
212 | streamingMipmapsMaxFileIORequests: 1024
213 | particleRaycastBudget: 4096
214 | asyncUploadTimeSlice: 2
215 | asyncUploadBufferSize: 16
216 | asyncUploadPersistentBuffer: 1
217 | resolutionScalingFixedDPIFactor: 1
218 | excludedTargetPlatforms: []
219 | m_PerPlatformDefaultQuality:
220 | Android: 2
221 | Lumin: 5
222 | Nintendo 3DS: 5
223 | Nintendo Switch: 5
224 | PS4: 5
225 | PSP2: 2
226 | Standalone: 5
227 | WebGL: 3
228 | Windows Store Apps: 5
229 | XboxOne: 5
230 | iPhone: 2
231 | tvOS: 2
232 |
--------------------------------------------------------------------------------
/Assets/Tester.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 | using System.Linq;
4 | using System;
5 | using System.Diagnostics;
6 | using Unity.Burst;
7 | using Unity.Collections;
8 | using Unity.Jobs;
9 | using UnityEditor;
10 | using Debug = UnityEngine.Debug;
11 |
12 | namespace Experiment
13 | {
14 | [BurstCompile]
15 | public struct TestJob : IJob
16 | {
17 | public NativeArray Keys;
18 | public NativeFasterDictionary Map;
19 |
20 | public void Execute()
21 | {
22 | for (int i = 0; i < Map.Length; i++)
23 | {
24 | if (Map.TryFindIndex(Keys[i], out int findIndex))
25 | {
26 | ref var v = ref Map.GetValue(findIndex);
27 | v.Id = i;
28 | v.Position = Vector3.up;
29 | }
30 | }
31 | }
32 |
33 | }
34 |
35 | [ExecuteInEditMode]
36 | public class Tester : MonoBehaviour
37 | {
38 | void Start()
39 | {
40 |
41 | }
42 |
43 | public void RunGo()
44 | {
45 | var words = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.".Split(' ');
46 | var map = new NativeFasterDictionary(100, Allocator.Persistent);
47 | var map2 = new NativeFasterDictionary(100, Allocator.Persistent);
48 | var dict = new Dictionary(100);
49 | var fdict = new FasterDictionary(100);
50 |
51 | // I would test this against unity's NativeHashMap except they currently have no ability to set values by key :S
52 |
53 | try
54 | {
55 | for (int i = 0; i < words.Length; i++)
56 | {
57 | var key = new StringKey(words[i]);
58 | map[key] = new SomeData();
59 | map2[key] = new SomeData();
60 | dict[key] = new SomeData();
61 | fdict[key] = new SomeData();
62 | }
63 |
64 | var randomKeys = new StringKey[map.Length];
65 | for (int i = 0; i < map.Length; i++)
66 | {
67 | var idx = UnityEngine.Random.Range(0, map.Length - 1);
68 | randomKeys[i] = new StringKey(words[idx]);
69 | }
70 |
71 | // Fair comparison assigning new value.
72 | NormalNativeDict(map, randomKeys);
73 |
74 | // Proper version using refs
75 | NormalNativeDictRef(map2, randomKeys);
76 |
77 | // Note the first time a job runs it's 10x slower.
78 | BurstJob(randomKeys, map);
79 |
80 | // Svelto's implementation.
81 | NormalFasterDict(fdict, randomKeys);
82 |
83 | // Stock standard C#
84 | NormalCSharpDict(dict, randomKeys);
85 |
86 | // Verify that the updates were correctly done
87 | for (int i = 0; i < words.Length; i++)
88 | {
89 | var key = new StringKey(words[i]);
90 |
91 | var id1 = map[key].Id;
92 | var id2 = map2[key].Id;
93 | var id3 = dict[key].Id;
94 | var id4 = fdict[key].Id;
95 | Debug.Assert(id1 == id2 && id1 == id3 && id1 == id4);
96 |
97 | var p1 = map[key].Position;
98 | var p2 = map2[key].Position;
99 | var p3 = dict[key].Position;
100 | var p4 = fdict[key].Position;
101 | Debug.Assert(p1 == p2 && p1 == p3 && p1 == p4);
102 | }
103 |
104 | Debug.Log("-----------------------------------------");
105 | }
106 | catch (Exception e)
107 | {
108 | Debug.Log(e);
109 | throw;
110 | }
111 | finally
112 | {
113 | map.Dispose();
114 | map2.Dispose();
115 | }
116 | }
117 |
118 | private static void NormalNativeDict(NativeFasterDictionary input, StringKey[] randomKeys)
119 | {
120 | var sw1 = new Stopwatch();
121 | sw1.Restart();
122 | var keys = randomKeys;
123 | var map = input;
124 |
125 | for (int i = 0; i < map.Length; i++)
126 | {
127 | var key = keys[i];
128 | if (map.TryGetValue(key, out var data))
129 | {
130 | map[key] = new SomeData
131 | {
132 | Id = i,
133 | Position = Vector3.up
134 | };
135 | }
136 | }
137 |
138 | sw1.Stop();
139 | Debug.Log($"NativeDict (Value) Took {sw1.Elapsed.TotalMilliseconds:N4} ms");
140 | }
141 |
142 |
143 | private static void NormalNativeDictRef(NativeFasterDictionary input, StringKey[] randomKeys)
144 | {
145 | var sw1 = new Stopwatch();
146 | sw1.Restart();
147 | var keys = randomKeys;
148 | var map = input;
149 |
150 | for (int i = 0; i < map.Length; i++)
151 | {
152 | if (map.TryFindIndex(keys[i], out var findIndex))
153 | {
154 | ref var v = ref map.GetValue(findIndex);
155 | v.Id = i;
156 | v.Position = Vector3.up;
157 | }
158 | }
159 |
160 | sw1.Stop();
161 | Debug.Log($"NativeDict (Ref) Took {sw1.Elapsed.TotalMilliseconds:N4} ms");
162 | }
163 |
164 |
165 | private static void NormalCSharpDict(Dictionary input, StringKey[] randomKeys)
166 | {
167 | var sw1 = new Stopwatch();
168 | sw1.Restart();
169 | var keys = randomKeys;
170 | var map = input;
171 |
172 | for (int i = 0; i < map.Count; i++)
173 | {
174 | var key = keys[i];
175 | if (map.TryGetValue(key, out var data))
176 | {
177 | map[key] = new SomeData
178 | {
179 | Id = i,
180 | Position = Vector3.up
181 | };
182 | }
183 | }
184 |
185 | sw1.Stop();
186 | Debug.Log($"C# Dict Took {sw1.Elapsed.TotalMilliseconds:N4} ms");
187 | }
188 |
189 |
190 | private static void NormalFasterDict(FasterDictionary input, StringKey[] randomKeys)
191 | {
192 | var sw1 = new Stopwatch();
193 | sw1.Restart();
194 | var keys = randomKeys;
195 | var map = input;
196 |
197 | for (int i = 0; i < map.Count; i++)
198 | {
199 | var key = keys[i];
200 | if (map.TryGetValue(key, out var data))
201 | {
202 | map[key] = new SomeData
203 | {
204 | Id = i,
205 | Position = Vector3.up
206 | };
207 | }
208 | }
209 |
210 | sw1.Stop();
211 | Debug.Log($"FasterDict Took {sw1.Elapsed.TotalMilliseconds:N4} ms");
212 | }
213 |
214 |
215 | private static void BurstJob(StringKey[] randomKeys, NativeFasterDictionary map)
216 | {
217 | var sw2 = new Stopwatch();
218 |
219 | using (var tmp = new NativeArray(randomKeys, Allocator.TempJob))
220 | {
221 | var job = new TestJob
222 | {
223 | Keys = tmp,
224 | Map = map
225 | };
226 |
227 | sw2.Restart();
228 | job.Run();
229 | sw2.Stop();
230 | }
231 |
232 | Debug.Log($"NativeDict (Burst Ref) Took {sw2.Elapsed.TotalMilliseconds:N4} ms");
233 | }
234 | }
235 |
236 | public struct SomeData
237 | {
238 | public int Id;
239 | public Vector3 Position;
240 | public Vector3 Velocity;
241 | public Quaternion Rotation;
242 | }
243 |
244 |
245 |
246 |
247 |
248 |
249 | #if UNITY_EDITOR
250 |
251 | [CustomEditor(typeof(Tester))]
252 | [CanEditMultipleObjects]
253 | public class TestEditor : Editor
254 | {
255 | public override void OnInspectorGUI()
256 | {
257 | DrawDefaultInspector();
258 |
259 | foreach (var targ in targets.Cast())
260 | {
261 | if (GUILayout.Button("Run"))
262 | {
263 | targ.RunGo();
264 | }
265 | SceneView.RepaintAll();
266 | }
267 | }
268 | }
269 |
270 | #endif
271 |
272 |
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/Assets/NativeSpan.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.InteropServices;
4 | using Unity.Burst;
5 | using Unity.Collections;
6 | using Unity.Collections.LowLevel.Unsafe;
7 |
8 | namespace Experiment
9 | {
10 | ///
11 | /// This is pretty much just a NativeArray with all the safety removed
12 | /// and with the ability to assign it on top of an existing data allocation.
13 | ///
14 | [NativeContainer]
15 | [DebuggerDisplay("Length = {Length}")]
16 | [NativeContainerSupportsMinMaxWriteRestriction]
17 | public unsafe struct NativeSpan
18 | {
19 | [NativeDisableUnsafePtrRestriction]
20 | internal unsafe void* m_Buffer;
21 | internal int m_Length;
22 | internal int m_MinIndex;
23 | internal int m_MaxIndex;
24 | internal int _itemSize;
25 |
26 | public int Length => m_Length;
27 |
28 | public static unsafe NativeSpan Assign(void* ptr, int itemSize, int length)
29 | {
30 | NativeSpan buffer;
31 | buffer.m_Buffer = ptr;
32 | buffer.m_Length = length;
33 | buffer._itemSize = itemSize;
34 | buffer.m_MinIndex = 0;
35 | buffer.m_MaxIndex = length - 1;
36 | return buffer;
37 | }
38 |
39 | public static unsafe NativeSpan Assign(void* ptr, int length) where T : struct
40 | {
41 | return Assign(ptr, UnsafeUtility.SizeOf(), length);
42 | }
43 |
44 | public static unsafe NativeSpan Assign(IntPtr ptr, int length) where T : struct
45 | {
46 | return Assign((void*)ptr, UnsafeUtility.SizeOf(), length);
47 | }
48 |
49 | public unsafe void Clear()
50 | {
51 | UnsafeUtility.MemClear(m_Buffer, (long)Length * _itemSize);
52 | }
53 |
54 | [BurstDiscard]
55 | internal static void IsBlittableAndThrow() where T : struct
56 | {
57 | if (!UnsafeUtility.IsBlittable())
58 | throw new InvalidOperationException(string.Format("{0} used in NativeArray2<{1}> must be blittable.", (object)typeof(T), (object)typeof(T)));
59 | }
60 |
61 | [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
62 | private unsafe void CheckElementReadAccess(int index)
63 | {
64 | if (index < m_MinIndex || index > m_MaxIndex)
65 | FailOutOfRangeError(index);
66 | }
67 |
68 | [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
69 | private unsafe void CheckElementWriteAccess(int index)
70 | {
71 | if (index < m_MinIndex || index > m_MaxIndex)
72 | FailOutOfRangeError(index);
73 | }
74 |
75 | [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
76 | private unsafe void CheckElementWriteAccess(int index, int offset)
77 | {
78 | if (index < m_MinIndex || index > m_MaxIndex)
79 | FailOutOfRangeError(index);
80 |
81 | if (offset >= _itemSize)
82 | throw new ArgumentOutOfRangeException("Offset within an item cannot be larger than the item size");
83 | }
84 |
85 | public unsafe int Count() where T : struct => m_Length * UnsafeUtility.SizeOf();
86 |
87 | public unsafe T GetItem(int index)
88 | {
89 | CheckElementReadAccess(index);
90 | return UnsafeUtility.ReadArrayElement(m_Buffer, index);
91 | }
92 |
93 | public unsafe ref T AsRef(int index) where T : struct
94 | {
95 | return ref UnsafeUtilityEx.AsRef((void*)((IntPtr)m_Buffer + (UnsafeUtility.SizeOf() * index)));
96 | }
97 |
98 | public unsafe Enumerator GetEnumerator() where T : struct
99 | => new Enumerator((int*)m_Buffer, Length);
100 |
101 | public unsafe struct Enumerator where T : struct
102 | {
103 | private readonly int* _ptr;
104 | private readonly int _length;
105 | private int _index;
106 |
107 | public Enumerator(int* offsetPtr, int length)
108 | {
109 | _ptr = offsetPtr;
110 | _length = length;
111 | _index = -1;
112 | }
113 |
114 | public T Current => UnsafeUtilityEx.ArrayElementAsRef((byte*)_ptr, _index);
115 |
116 | public bool MoveNext() => ++_index < _length;
117 | }
118 |
119 | public unsafe ref T AsRef(int index, int offset) where T : struct
120 | {
121 | return ref UnsafeUtilityEx.AsRef((void*)((IntPtr)m_Buffer + (UnsafeUtility.SizeOf() * index) + offset));
122 | }
123 |
124 | public unsafe T* AsPtr(int index) where T : unmanaged
125 | {
126 | return (T*)((IntPtr)m_Buffer + UnsafeUtility.SizeOf() * index);
127 | }
128 |
129 | public unsafe T* AsPtr(int index, int offset) where T : unmanaged
130 | {
131 | return (T*)((IntPtr)m_Buffer + (UnsafeUtility.SizeOf() * index) + offset);
132 | }
133 |
134 | public unsafe void* AsPtr(int index)
135 | {
136 | return (void*)((IntPtr)m_Buffer + _itemSize * index);
137 | }
138 |
139 | public unsafe void SetItem(int index, T value)
140 | {
141 | CheckElementWriteAccess(index);
142 | UnsafeUtility.WriteArrayElement(m_Buffer, index, value);
143 | }
144 |
145 | public unsafe void SetItem(int index, T value, int offset)
146 | {
147 | CheckElementWriteAccess(index, offset);
148 | UnsafeUtility.WriteArrayElement((void*)((IntPtr)m_Buffer + offset), index, value);
149 | }
150 |
151 | public void CopyTo(T[] array) where T : struct
152 | {
153 | Copy(this, array);
154 | }
155 |
156 | public void CopyTo(NativeArray array) where T : struct
157 | {
158 | Copy(this, array);
159 | }
160 |
161 | public void CopyTo(NativeSpan buffer) where T : struct
162 | {
163 | Copy(this, buffer);
164 | }
165 |
166 | public T[] ToArray() where T : struct
167 | {
168 | T[] dst = new T[Length];
169 | Copy(this, dst);
170 | return dst;
171 | }
172 |
173 | public T[] ToArray(int length) where T : struct
174 | {
175 | T[] dst = new T[length];
176 | Copy(this, dst, length);
177 | return dst;
178 | }
179 |
180 | private void FailOutOfRangeError(int index)
181 | {
182 | if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1))
183 | throw new IndexOutOfRangeException(string.Format("Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n", (object)index, (object)m_MinIndex, (object)m_MaxIndex) + "ReadWriteBuffers are restricted to only read & write the element at the job index. You can use double buffering strategies to avoid race conditions due to reading & writing in parallel to the same elements from a job.");
184 | throw new IndexOutOfRangeException(string.Format("Index {0} is out of range of '{1}' Length.", (object)index, (object)Length));
185 | }
186 |
187 | public static void Copy(NativeSpan src, NativeSpan dst) where T : struct
188 | {
189 | if (src.Length != dst.Length)
190 | throw new ArgumentException("source and destination length must be the same");
191 |
192 | Copy(src, 0, dst, 0, src.Length);
193 | }
194 |
195 | public static void Copy(NativeSpan src, NativeArray dst) where T : struct
196 | {
197 | #if ENABLE_UNITY_COLLECTIONS_CHECKS
198 | AtomicSafetyHandle.CheckWriteAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(dst));
199 | #endif
200 | if (src.Length != dst.Length)
201 | throw new ArgumentException("source and destination length must be the same");
202 |
203 | Copy(src, 0, dst, 0, src.Length);
204 | }
205 |
206 | public static void Copy(T[] src, NativeSpan dst) where T : struct
207 | {
208 | if (src.Length != dst.Length)
209 | throw new ArgumentException("source and destination length must be the same");
210 | Copy(src, 0, dst, 0, src.Length);
211 | }
212 |
213 | public static void Copy(NativeSpan src, T[] dst) where T : struct
214 | {
215 | if (src.Length != dst.Length)
216 | throw new ArgumentException("source and destination length must be the same");
217 |
218 | Copy(src, 0, dst, 0, src.Length);
219 | }
220 |
221 | public static void Copy(NativeSpan src, NativeSpan dst, int length) where T : struct
222 | {
223 | Copy(src, 0, dst, 0, length);
224 | }
225 |
226 | public static void Copy(T[] src, NativeSpan dst, int length) where T : struct
227 | {
228 | Copy(src, 0, dst, 0, length);
229 | }
230 |
231 | public static void Copy(NativeSpan src, T[] dst, int length) where T : struct
232 | {
233 | Copy(src, 0, dst, 0, length);
234 | }
235 |
236 | public static unsafe void Copy(NativeSpan src, int srcIndex, NativeSpan dst, int dstIndex, int length) where T : struct
237 | {
238 | if (length < 0)
239 | throw new ArgumentOutOfRangeException(nameof(length), "length must be equal or greater than zero.");
240 | if (srcIndex < 0 || srcIndex > src.Length || srcIndex == src.Length && src.Length > 0)
241 | throw new ArgumentOutOfRangeException(nameof(srcIndex), "srcIndex is outside the range of valid indexes for the source NativeArray2.");
242 | if (dstIndex < 0 || dstIndex > dst.Length || dstIndex == dst.Length && dst.Length > 0)
243 | throw new ArgumentOutOfRangeException(nameof(dstIndex), "dstIndex is outside the range of valid indexes for the destination NativeArray2.");
244 | if (srcIndex + length > src.Length)
245 | throw new ArgumentException("length is greater than the number of elements from srcIndex to the end of the source NativeArray2.", nameof(length));
246 | if (dstIndex + length > dst.Length)
247 | throw new ArgumentException("length is greater than the number of elements from dstIndex to the end of the destination NativeArray2.", nameof(length));
248 | UnsafeUtility.MemCpy((void*)((IntPtr)dst.m_Buffer + (dstIndex * UnsafeUtility.SizeOf())), (void*)((IntPtr)src.m_Buffer + (srcIndex * UnsafeUtility.SizeOf())), (long)(length * UnsafeUtility.SizeOf()));
249 | }
250 |
251 | public static unsafe void Copy(NativeSpan src, int srcIndex, NativeArray dst, int dstIndex, int length) where T : struct
252 | {
253 | #if ENABLE_UNITY_COLLECTIONS_CHECKS
254 | AtomicSafetyHandle.CheckWriteAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(dst));
255 | #endif
256 | if (length < 0)
257 | throw new ArgumentOutOfRangeException(nameof(length), "length must be equal or greater than zero.");
258 | if (srcIndex < 0 || srcIndex > src.Length || srcIndex == src.Length && src.Length > 0)
259 | throw new ArgumentOutOfRangeException(nameof(srcIndex), "srcIndex is outside the range of valid indexes for the source NativeArray2.");
260 | if (dstIndex < 0 || dstIndex > dst.Length || dstIndex == dst.Length && dst.Length > 0)
261 | throw new ArgumentOutOfRangeException(nameof(dstIndex), "dstIndex is outside the range of valid indexes for the destination NativeArray2.");
262 | if (srcIndex + length > src.Length)
263 | throw new ArgumentException("length is greater than the number of elements from srcIndex to the end of the source NativeArray2.", nameof(length));
264 | if (dstIndex + length > dst.Length)
265 | throw new ArgumentException("length is greater than the number of elements from dstIndex to the end of the destination NativeArray2.", nameof(length));
266 | UnsafeUtility.MemCpy((void*)((IntPtr)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(dst) + (dstIndex * UnsafeUtility.SizeOf())), (void*)((IntPtr)src.m_Buffer + (srcIndex * UnsafeUtility.SizeOf())), (long)(length * UnsafeUtility.SizeOf()));
267 | }
268 |
269 | public static unsafe void Copy(T[] src, int srcIndex, NativeSpan dst, int dstIndex, int length) where T : struct
270 | {
271 | if (src == null)
272 | throw new ArgumentNullException(nameof(src));
273 | if (length < 0)
274 | throw new ArgumentOutOfRangeException(nameof(length), "length must be equal or greater than zero.");
275 | if (srcIndex < 0 || srcIndex > src.Length || srcIndex == src.Length && src.Length > 0)
276 | throw new ArgumentOutOfRangeException(nameof(srcIndex), "srcIndex is outside the range of valid indexes for the source array.");
277 | if (dstIndex < 0 || dstIndex > dst.Length || dstIndex == dst.Length && dst.Length > 0)
278 | throw new ArgumentOutOfRangeException(nameof(dstIndex), "dstIndex is outside the range of valid indexes for the destination NativeArray2.");
279 | if (srcIndex + length > src.Length)
280 | throw new ArgumentException("length is greater than the number of elements from srcIndex to the end of the source array.", nameof(length));
281 | if (dstIndex + length > dst.Length)
282 | throw new ArgumentException("length is greater than the number of elements from dstIndex to the end of the destination NativeArray2.", nameof(length));
283 | GCHandle gcHandle = GCHandle.Alloc((object)src, GCHandleType.Pinned);
284 | IntPtr num = gcHandle.AddrOfPinnedObject();
285 | UnsafeUtility.MemCpy((void*)((IntPtr)dst.m_Buffer + (dstIndex * UnsafeUtility.SizeOf())), (void*)(num + (srcIndex * UnsafeUtility.SizeOf())), (long)(length * UnsafeUtility.SizeOf()));
286 | gcHandle.Free();
287 | }
288 |
289 | public static unsafe void Copy(NativeSpan src, int srcIndex, T[] dst, int dstIndex, int length) where T : struct
290 | {
291 | if (dst == null)
292 | throw new ArgumentNullException(nameof(dst));
293 | if (length < 0)
294 | throw new ArgumentOutOfRangeException(nameof(length), "length must be equal or greater than zero.");
295 | if (srcIndex < 0 || srcIndex > src.Length || srcIndex == src.Length && src.Length > 0)
296 | throw new ArgumentOutOfRangeException(nameof(srcIndex), "srcIndex is outside the range of valid indexes for the source NativeArray2.");
297 | if (dstIndex < 0 || dstIndex > dst.Length || dstIndex == dst.Length && dst.Length > 0)
298 | throw new ArgumentOutOfRangeException(nameof(dstIndex), "dstIndex is outside the range of valid indexes for the destination array.");
299 | if (srcIndex + length > src.Length)
300 | throw new ArgumentException("length is greater than the number of elements from srcIndex to the end of the source NativeArray2.", nameof(length));
301 | if (dstIndex + length > dst.Length)
302 | throw new ArgumentException("length is greater than the number of elements from dstIndex to the end of the destination array.", nameof(length));
303 | GCHandle gcHandle = GCHandle.Alloc((object)dst, GCHandleType.Pinned);
304 | UnsafeUtility.MemCpy((void*)((IntPtr)(void*)gcHandle.AddrOfPinnedObject() + (dstIndex * UnsafeUtility.SizeOf())), (void*)((IntPtr)src.m_Buffer + (srcIndex * UnsafeUtility.SizeOf())), (long)(length * UnsafeUtility.SizeOf()));
305 | gcHandle.Free();
306 | }
307 |
308 | ///
309 | /// Calculate an element index based on its memory address
310 | ///
311 | public unsafe int IndexOf(void* elementPtr)
312 | {
313 | if (elementPtr == null)
314 | throw new ArgumentNullException(nameof(elementPtr));
315 |
316 | int offset = (int)elementPtr - (int)(IntPtr)m_Buffer;
317 | int index = offset / _itemSize;
318 |
319 | if (index < m_MinIndex || index > m_MaxIndex)
320 | throw new ArgumentOutOfRangeException($"Index '{index}' is out of range ({m_MinIndex}-{m_MaxIndex})");
321 |
322 | return index;
323 | }
324 |
325 | public unsafe void* GetUnsafePtr()
326 | {
327 | return m_Buffer;
328 | }
329 |
330 | public bool IsValid() => (IntPtr)m_Buffer != IntPtr.Zero;
331 |
332 |
333 |
334 | }
335 | }
--------------------------------------------------------------------------------
/ProjectSettings/ProjectSettings.asset:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!129 &1
4 | PlayerSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 16
7 | productGUID: bf93134628d2d2f4382b5180128ea08e
8 | AndroidProfiler: 0
9 | AndroidFilterTouchesWhenObscured: 0
10 | AndroidEnableSustainedPerformanceMode: 0
11 | defaultScreenOrientation: 4
12 | targetDevice: 2
13 | useOnDemandResources: 0
14 | accelerometerFrequency: 60
15 | companyName: DefaultCompany
16 | productName: NativeFasterDictionaryTest
17 | defaultCursor: {fileID: 0}
18 | cursorHotspot: {x: 0, y: 0}
19 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
20 | m_ShowUnitySplashScreen: 1
21 | m_ShowUnitySplashLogo: 1
22 | m_SplashScreenOverlayOpacity: 1
23 | m_SplashScreenAnimation: 1
24 | m_SplashScreenLogoStyle: 1
25 | m_SplashScreenDrawMode: 0
26 | m_SplashScreenBackgroundAnimationZoom: 1
27 | m_SplashScreenLogoAnimationZoom: 1
28 | m_SplashScreenBackgroundLandscapeAspect: 1
29 | m_SplashScreenBackgroundPortraitAspect: 1
30 | m_SplashScreenBackgroundLandscapeUvs:
31 | serializedVersion: 2
32 | x: 0
33 | y: 0
34 | width: 1
35 | height: 1
36 | m_SplashScreenBackgroundPortraitUvs:
37 | serializedVersion: 2
38 | x: 0
39 | y: 0
40 | width: 1
41 | height: 1
42 | m_SplashScreenLogos: []
43 | m_VirtualRealitySplashScreen: {fileID: 0}
44 | m_HolographicTrackingLossScreen: {fileID: 0}
45 | defaultScreenWidth: 1024
46 | defaultScreenHeight: 768
47 | defaultScreenWidthWeb: 960
48 | defaultScreenHeightWeb: 600
49 | m_StereoRenderingPath: 0
50 | m_ActiveColorSpace: 0
51 | m_MTRendering: 1
52 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000
53 | iosShowActivityIndicatorOnLoading: -1
54 | androidShowActivityIndicatorOnLoading: -1
55 | iosAppInBackgroundBehavior: 0
56 | displayResolutionDialog: 0
57 | iosAllowHTTPDownload: 1
58 | allowedAutorotateToPortrait: 1
59 | allowedAutorotateToPortraitUpsideDown: 1
60 | allowedAutorotateToLandscapeRight: 1
61 | allowedAutorotateToLandscapeLeft: 1
62 | useOSAutorotation: 1
63 | use32BitDisplayBuffer: 1
64 | preserveFramebufferAlpha: 0
65 | disableDepthAndStencilBuffers: 0
66 | androidStartInFullscreen: 1
67 | androidRenderOutsideSafeArea: 1
68 | androidBlitType: 0
69 | defaultIsNativeResolution: 1
70 | macRetinaSupport: 1
71 | runInBackground: 1
72 | captureSingleScreen: 0
73 | muteOtherAudioSources: 0
74 | Prepare IOS For Recording: 0
75 | Force IOS Speakers When Recording: 0
76 | deferSystemGesturesMode: 0
77 | hideHomeButton: 0
78 | submitAnalytics: 1
79 | usePlayerLog: 1
80 | bakeCollisionMeshes: 0
81 | forceSingleInstance: 0
82 | resizableWindow: 0
83 | useMacAppStoreValidation: 0
84 | macAppStoreCategory: public.app-category.games
85 | gpuSkinning: 1
86 | graphicsJobs: 0
87 | xboxPIXTextureCapture: 0
88 | xboxEnableAvatar: 0
89 | xboxEnableKinect: 0
90 | xboxEnableKinectAutoTracking: 0
91 | xboxEnableFitness: 0
92 | visibleInBackground: 1
93 | allowFullscreenSwitch: 1
94 | graphicsJobMode: 0
95 | fullscreenMode: 1
96 | xboxSpeechDB: 0
97 | xboxEnableHeadOrientation: 0
98 | xboxEnableGuest: 0
99 | xboxEnablePIXSampling: 0
100 | metalFramebufferOnly: 0
101 | xboxOneResolution: 0
102 | xboxOneSResolution: 0
103 | xboxOneXResolution: 3
104 | xboxOneMonoLoggingLevel: 0
105 | xboxOneLoggingLevel: 1
106 | xboxOneDisableEsram: 0
107 | xboxOnePresentImmediateThreshold: 0
108 | switchQueueCommandMemory: 0
109 | switchQueueControlMemory: 16384
110 | switchQueueComputeMemory: 262144
111 | switchNVNShaderPoolsGranularity: 33554432
112 | switchNVNDefaultPoolsGranularity: 16777216
113 | switchNVNOtherPoolsGranularity: 16777216
114 | vulkanEnableSetSRGBWrite: 0
115 | m_SupportedAspectRatios:
116 | 4:3: 1
117 | 5:4: 1
118 | 16:10: 1
119 | 16:9: 1
120 | Others: 1
121 | bundleVersion: 0.1
122 | preloadedAssets: []
123 | metroInputSource: 0
124 | wsaTransparentSwapchain: 0
125 | m_HolographicPauseOnTrackingLoss: 1
126 | xboxOneDisableKinectGpuReservation: 1
127 | xboxOneEnable7thCore: 1
128 | vrSettings:
129 | cardboard:
130 | depthFormat: 0
131 | enableTransitionView: 0
132 | daydream:
133 | depthFormat: 0
134 | useSustainedPerformanceMode: 0
135 | enableVideoLayer: 0
136 | useProtectedVideoMemory: 0
137 | minimumSupportedHeadTracking: 0
138 | maximumSupportedHeadTracking: 1
139 | hololens:
140 | depthFormat: 1
141 | depthBufferSharingEnabled: 1
142 | lumin:
143 | depthFormat: 0
144 | frameTiming: 2
145 | enableGLCache: 0
146 | glCacheMaxBlobSize: 524288
147 | glCacheMaxFileSize: 8388608
148 | oculus:
149 | sharedDepthBuffer: 1
150 | dashSupport: 1
151 | enable360StereoCapture: 0
152 | isWsaHolographicRemotingEnabled: 0
153 | protectGraphicsMemory: 0
154 | enableFrameTimingStats: 0
155 | useHDRDisplay: 0
156 | m_ColorGamuts: 00000000
157 | targetPixelDensity: 30
158 | resolutionScalingMode: 0
159 | androidSupportedAspectRatio: 1
160 | androidMaxAspectRatio: 2.1
161 | applicationIdentifier: {}
162 | buildNumber: {}
163 | AndroidBundleVersionCode: 1
164 | AndroidMinSdkVersion: 16
165 | AndroidTargetSdkVersion: 0
166 | AndroidPreferredInstallLocation: 1
167 | aotOptions:
168 | stripEngineCode: 1
169 | iPhoneStrippingLevel: 0
170 | iPhoneScriptCallOptimization: 0
171 | ForceInternetPermission: 0
172 | ForceSDCardPermission: 0
173 | CreateWallpaper: 0
174 | APKExpansionFiles: 0
175 | keepLoadedShadersAlive: 0
176 | StripUnusedMeshComponents: 1
177 | VertexChannelCompressionMask: 4054
178 | iPhoneSdkVersion: 988
179 | iOSTargetOSVersionString: 9.0
180 | tvOSSdkVersion: 0
181 | tvOSRequireExtendedGameController: 0
182 | tvOSTargetOSVersionString: 9.0
183 | uIPrerenderedIcon: 0
184 | uIRequiresPersistentWiFi: 0
185 | uIRequiresFullScreen: 1
186 | uIStatusBarHidden: 1
187 | uIExitOnSuspend: 0
188 | uIStatusBarStyle: 0
189 | iPhoneSplashScreen: {fileID: 0}
190 | iPhoneHighResSplashScreen: {fileID: 0}
191 | iPhoneTallHighResSplashScreen: {fileID: 0}
192 | iPhone47inSplashScreen: {fileID: 0}
193 | iPhone55inPortraitSplashScreen: {fileID: 0}
194 | iPhone55inLandscapeSplashScreen: {fileID: 0}
195 | iPhone58inPortraitSplashScreen: {fileID: 0}
196 | iPhone58inLandscapeSplashScreen: {fileID: 0}
197 | iPadPortraitSplashScreen: {fileID: 0}
198 | iPadHighResPortraitSplashScreen: {fileID: 0}
199 | iPadLandscapeSplashScreen: {fileID: 0}
200 | iPadHighResLandscapeSplashScreen: {fileID: 0}
201 | iPhone65inPortraitSplashScreen: {fileID: 0}
202 | iPhone65inLandscapeSplashScreen: {fileID: 0}
203 | iPhone61inPortraitSplashScreen: {fileID: 0}
204 | iPhone61inLandscapeSplashScreen: {fileID: 0}
205 | appleTVSplashScreen: {fileID: 0}
206 | appleTVSplashScreen2x: {fileID: 0}
207 | tvOSSmallIconLayers: []
208 | tvOSSmallIconLayers2x: []
209 | tvOSLargeIconLayers: []
210 | tvOSLargeIconLayers2x: []
211 | tvOSTopShelfImageLayers: []
212 | tvOSTopShelfImageLayers2x: []
213 | tvOSTopShelfImageWideLayers: []
214 | tvOSTopShelfImageWideLayers2x: []
215 | iOSLaunchScreenType: 0
216 | iOSLaunchScreenPortrait: {fileID: 0}
217 | iOSLaunchScreenLandscape: {fileID: 0}
218 | iOSLaunchScreenBackgroundColor:
219 | serializedVersion: 2
220 | rgba: 0
221 | iOSLaunchScreenFillPct: 100
222 | iOSLaunchScreenSize: 100
223 | iOSLaunchScreenCustomXibPath:
224 | iOSLaunchScreeniPadType: 0
225 | iOSLaunchScreeniPadImage: {fileID: 0}
226 | iOSLaunchScreeniPadBackgroundColor:
227 | serializedVersion: 2
228 | rgba: 0
229 | iOSLaunchScreeniPadFillPct: 100
230 | iOSLaunchScreeniPadSize: 100
231 | iOSLaunchScreeniPadCustomXibPath:
232 | iOSUseLaunchScreenStoryboard: 0
233 | iOSLaunchScreenCustomStoryboardPath:
234 | iOSDeviceRequirements: []
235 | iOSURLSchemes: []
236 | iOSBackgroundModes: 0
237 | iOSMetalForceHardShadows: 0
238 | metalEditorSupport: 1
239 | metalAPIValidation: 1
240 | iOSRenderExtraFrameOnPause: 0
241 | appleDeveloperTeamID:
242 | iOSManualSigningProvisioningProfileID:
243 | tvOSManualSigningProvisioningProfileID:
244 | iOSManualSigningProvisioningProfileType: 0
245 | tvOSManualSigningProvisioningProfileType: 0
246 | appleEnableAutomaticSigning: 0
247 | iOSRequireARKit: 0
248 | iOSAutomaticallyDetectAndAddCapabilities: 1
249 | appleEnableProMotion: 0
250 | clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea
251 | templatePackageId: com.unity.template.3d@2.3.1
252 | templateDefaultScene: Assets/Scenes/SampleScene.unity
253 | AndroidTargetArchitectures: 1
254 | AndroidSplashScreenScale: 0
255 | androidSplashScreen: {fileID: 0}
256 | AndroidKeystoreName: '{inproject}: '
257 | AndroidKeyaliasName:
258 | AndroidBuildApkPerCpuArchitecture: 0
259 | AndroidTVCompatibility: 0
260 | AndroidIsGame: 1
261 | AndroidEnableTango: 0
262 | androidEnableBanner: 1
263 | androidUseLowAccuracyLocation: 0
264 | androidUseCustomKeystore: 0
265 | m_AndroidBanners:
266 | - width: 320
267 | height: 180
268 | banner: {fileID: 0}
269 | androidGamepadSupportLevel: 0
270 | resolutionDialogBanner: {fileID: 0}
271 | m_BuildTargetIcons: []
272 | m_BuildTargetPlatformIcons: []
273 | m_BuildTargetBatching:
274 | - m_BuildTarget: Standalone
275 | m_StaticBatching: 1
276 | m_DynamicBatching: 0
277 | - m_BuildTarget: tvOS
278 | m_StaticBatching: 1
279 | m_DynamicBatching: 0
280 | - m_BuildTarget: Android
281 | m_StaticBatching: 1
282 | m_DynamicBatching: 0
283 | - m_BuildTarget: iPhone
284 | m_StaticBatching: 1
285 | m_DynamicBatching: 0
286 | - m_BuildTarget: WebGL
287 | m_StaticBatching: 0
288 | m_DynamicBatching: 0
289 | m_BuildTargetGraphicsAPIs:
290 | - m_BuildTarget: AndroidPlayer
291 | m_APIs: 150000000b000000
292 | m_Automatic: 0
293 | - m_BuildTarget: iOSSupport
294 | m_APIs: 10000000
295 | m_Automatic: 1
296 | - m_BuildTarget: AppleTVSupport
297 | m_APIs: 10000000
298 | m_Automatic: 0
299 | - m_BuildTarget: WebGLSupport
300 | m_APIs: 0b000000
301 | m_Automatic: 1
302 | m_BuildTargetVRSettings:
303 | - m_BuildTarget: Standalone
304 | m_Enabled: 0
305 | m_Devices:
306 | - Oculus
307 | - OpenVR
308 | m_BuildTargetEnableVuforiaSettings: []
309 | openGLRequireES31: 0
310 | openGLRequireES31AEP: 0
311 | openGLRequireES32: 0
312 | m_TemplateCustomTags: {}
313 | mobileMTRendering:
314 | Android: 1
315 | iPhone: 1
316 | tvOS: 1
317 | m_BuildTargetGroupLightmapEncodingQuality: []
318 | m_BuildTargetGroupLightmapSettings: []
319 | playModeTestRunnerEnabled: 0
320 | runPlayModeTestAsEditModeTest: 0
321 | actionOnDotNetUnhandledException: 1
322 | enableInternalProfiler: 0
323 | logObjCUncaughtExceptions: 1
324 | enableCrashReportAPI: 0
325 | cameraUsageDescription:
326 | locationUsageDescription:
327 | microphoneUsageDescription:
328 | switchNetLibKey:
329 | switchSocketMemoryPoolSize: 6144
330 | switchSocketAllocatorPoolSize: 128
331 | switchSocketConcurrencyLimit: 14
332 | switchScreenResolutionBehavior: 2
333 | switchUseCPUProfiler: 0
334 | switchApplicationID: 0x01004b9000490000
335 | switchNSODependencies:
336 | switchTitleNames_0:
337 | switchTitleNames_1:
338 | switchTitleNames_2:
339 | switchTitleNames_3:
340 | switchTitleNames_4:
341 | switchTitleNames_5:
342 | switchTitleNames_6:
343 | switchTitleNames_7:
344 | switchTitleNames_8:
345 | switchTitleNames_9:
346 | switchTitleNames_10:
347 | switchTitleNames_11:
348 | switchTitleNames_12:
349 | switchTitleNames_13:
350 | switchTitleNames_14:
351 | switchPublisherNames_0:
352 | switchPublisherNames_1:
353 | switchPublisherNames_2:
354 | switchPublisherNames_3:
355 | switchPublisherNames_4:
356 | switchPublisherNames_5:
357 | switchPublisherNames_6:
358 | switchPublisherNames_7:
359 | switchPublisherNames_8:
360 | switchPublisherNames_9:
361 | switchPublisherNames_10:
362 | switchPublisherNames_11:
363 | switchPublisherNames_12:
364 | switchPublisherNames_13:
365 | switchPublisherNames_14:
366 | switchIcons_0: {fileID: 0}
367 | switchIcons_1: {fileID: 0}
368 | switchIcons_2: {fileID: 0}
369 | switchIcons_3: {fileID: 0}
370 | switchIcons_4: {fileID: 0}
371 | switchIcons_5: {fileID: 0}
372 | switchIcons_6: {fileID: 0}
373 | switchIcons_7: {fileID: 0}
374 | switchIcons_8: {fileID: 0}
375 | switchIcons_9: {fileID: 0}
376 | switchIcons_10: {fileID: 0}
377 | switchIcons_11: {fileID: 0}
378 | switchIcons_12: {fileID: 0}
379 | switchIcons_13: {fileID: 0}
380 | switchIcons_14: {fileID: 0}
381 | switchSmallIcons_0: {fileID: 0}
382 | switchSmallIcons_1: {fileID: 0}
383 | switchSmallIcons_2: {fileID: 0}
384 | switchSmallIcons_3: {fileID: 0}
385 | switchSmallIcons_4: {fileID: 0}
386 | switchSmallIcons_5: {fileID: 0}
387 | switchSmallIcons_6: {fileID: 0}
388 | switchSmallIcons_7: {fileID: 0}
389 | switchSmallIcons_8: {fileID: 0}
390 | switchSmallIcons_9: {fileID: 0}
391 | switchSmallIcons_10: {fileID: 0}
392 | switchSmallIcons_11: {fileID: 0}
393 | switchSmallIcons_12: {fileID: 0}
394 | switchSmallIcons_13: {fileID: 0}
395 | switchSmallIcons_14: {fileID: 0}
396 | switchManualHTML:
397 | switchAccessibleURLs:
398 | switchLegalInformation:
399 | switchMainThreadStackSize: 1048576
400 | switchPresenceGroupId:
401 | switchLogoHandling: 0
402 | switchReleaseVersion: 0
403 | switchDisplayVersion: 1.0.0
404 | switchStartupUserAccount: 0
405 | switchTouchScreenUsage: 0
406 | switchSupportedLanguagesMask: 0
407 | switchLogoType: 0
408 | switchApplicationErrorCodeCategory:
409 | switchUserAccountSaveDataSize: 0
410 | switchUserAccountSaveDataJournalSize: 0
411 | switchApplicationAttribute: 0
412 | switchCardSpecSize: -1
413 | switchCardSpecClock: -1
414 | switchRatingsMask: 0
415 | switchRatingsInt_0: 0
416 | switchRatingsInt_1: 0
417 | switchRatingsInt_2: 0
418 | switchRatingsInt_3: 0
419 | switchRatingsInt_4: 0
420 | switchRatingsInt_5: 0
421 | switchRatingsInt_6: 0
422 | switchRatingsInt_7: 0
423 | switchRatingsInt_8: 0
424 | switchRatingsInt_9: 0
425 | switchRatingsInt_10: 0
426 | switchRatingsInt_11: 0
427 | switchLocalCommunicationIds_0:
428 | switchLocalCommunicationIds_1:
429 | switchLocalCommunicationIds_2:
430 | switchLocalCommunicationIds_3:
431 | switchLocalCommunicationIds_4:
432 | switchLocalCommunicationIds_5:
433 | switchLocalCommunicationIds_6:
434 | switchLocalCommunicationIds_7:
435 | switchParentalControl: 0
436 | switchAllowsScreenshot: 1
437 | switchAllowsVideoCapturing: 1
438 | switchAllowsRuntimeAddOnContentInstall: 0
439 | switchDataLossConfirmation: 0
440 | switchUserAccountLockEnabled: 0
441 | switchSystemResourceMemory: 16777216
442 | switchSupportedNpadStyles: 3
443 | switchNativeFsCacheSize: 32
444 | switchIsHoldTypeHorizontal: 0
445 | switchSupportedNpadCount: 8
446 | switchSocketConfigEnabled: 0
447 | switchTcpInitialSendBufferSize: 32
448 | switchTcpInitialReceiveBufferSize: 64
449 | switchTcpAutoSendBufferSizeMax: 256
450 | switchTcpAutoReceiveBufferSizeMax: 256
451 | switchUdpSendBufferSize: 9
452 | switchUdpReceiveBufferSize: 42
453 | switchSocketBufferEfficiency: 4
454 | switchSocketInitializeEnabled: 1
455 | switchNetworkInterfaceManagerInitializeEnabled: 1
456 | switchPlayerConnectionEnabled: 1
457 | ps4NPAgeRating: 12
458 | ps4NPTitleSecret:
459 | ps4NPTrophyPackPath:
460 | ps4ParentalLevel: 11
461 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000
462 | ps4Category: 0
463 | ps4MasterVersion: 01.00
464 | ps4AppVersion: 01.00
465 | ps4AppType: 0
466 | ps4ParamSfxPath:
467 | ps4VideoOutPixelFormat: 0
468 | ps4VideoOutInitialWidth: 1920
469 | ps4VideoOutBaseModeInitialWidth: 1920
470 | ps4VideoOutReprojectionRate: 60
471 | ps4PronunciationXMLPath:
472 | ps4PronunciationSIGPath:
473 | ps4BackgroundImagePath:
474 | ps4StartupImagePath:
475 | ps4StartupImagesFolder:
476 | ps4IconImagesFolder:
477 | ps4SaveDataImagePath:
478 | ps4SdkOverride:
479 | ps4BGMPath:
480 | ps4ShareFilePath:
481 | ps4ShareOverlayImagePath:
482 | ps4PrivacyGuardImagePath:
483 | ps4NPtitleDatPath:
484 | ps4RemotePlayKeyAssignment: -1
485 | ps4RemotePlayKeyMappingDir:
486 | ps4PlayTogetherPlayerCount: 0
487 | ps4EnterButtonAssignment: 1
488 | ps4ApplicationParam1: 0
489 | ps4ApplicationParam2: 0
490 | ps4ApplicationParam3: 0
491 | ps4ApplicationParam4: 0
492 | ps4DownloadDataSize: 0
493 | ps4GarlicHeapSize: 2048
494 | ps4ProGarlicHeapSize: 2560
495 | playerPrefsMaxSize: 32768
496 | ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
497 | ps4pnSessions: 1
498 | ps4pnPresence: 1
499 | ps4pnFriends: 1
500 | ps4pnGameCustomData: 1
501 | playerPrefsSupport: 0
502 | enableApplicationExit: 0
503 | resetTempFolder: 1
504 | restrictedAudioUsageRights: 0
505 | ps4UseResolutionFallback: 0
506 | ps4ReprojectionSupport: 0
507 | ps4UseAudio3dBackend: 0
508 | ps4SocialScreenEnabled: 0
509 | ps4ScriptOptimizationLevel: 0
510 | ps4Audio3dVirtualSpeakerCount: 14
511 | ps4attribCpuUsage: 0
512 | ps4PatchPkgPath:
513 | ps4PatchLatestPkgPath:
514 | ps4PatchChangeinfoPath:
515 | ps4PatchDayOne: 0
516 | ps4attribUserManagement: 0
517 | ps4attribMoveSupport: 0
518 | ps4attrib3DSupport: 0
519 | ps4attribShareSupport: 0
520 | ps4attribExclusiveVR: 0
521 | ps4disableAutoHideSplash: 0
522 | ps4videoRecordingFeaturesUsed: 0
523 | ps4contentSearchFeaturesUsed: 0
524 | ps4attribEyeToEyeDistanceSettingVR: 0
525 | ps4IncludedModules: []
526 | monoEnv:
527 | splashScreenBackgroundSourceLandscape: {fileID: 0}
528 | splashScreenBackgroundSourcePortrait: {fileID: 0}
529 | spritePackerPolicy:
530 | webGLMemorySize: 16
531 | webGLExceptionSupport: 1
532 | webGLNameFilesAsHashes: 0
533 | webGLDataCaching: 1
534 | webGLDebugSymbols: 0
535 | webGLEmscriptenArgs:
536 | webGLModulesDirectory:
537 | webGLTemplate: APPLICATION:Default
538 | webGLAnalyzeBuildSize: 0
539 | webGLUseEmbeddedResources: 0
540 | webGLCompressionFormat: 1
541 | webGLLinkerTarget: 1
542 | webGLThreadsSupport: 0
543 | webGLWasmStreaming: 0
544 | scriptingDefineSymbols: {}
545 | platformArchitecture: {}
546 | scriptingBackend: {}
547 | il2cppCompilerConfiguration: {}
548 | managedStrippingLevel: {}
549 | incrementalIl2cppBuild: {}
550 | allowUnsafeCode: 1
551 | additionalIl2CppArgs:
552 | scriptingRuntimeVersion: 1
553 | gcIncremental: 0
554 | gcWBarrierValidation: 0
555 | apiCompatibilityLevelPerPlatform: {}
556 | m_RenderingPath: 1
557 | m_MobileRenderingPath: 1
558 | metroPackageName: Template_3D
559 | metroPackageVersion:
560 | metroCertificatePath:
561 | metroCertificatePassword:
562 | metroCertificateSubject:
563 | metroCertificateIssuer:
564 | metroCertificateNotAfter: 0000000000000000
565 | metroApplicationDescription: Template_3D
566 | wsaImages: {}
567 | metroTileShortName:
568 | metroTileShowName: 0
569 | metroMediumTileShowName: 0
570 | metroLargeTileShowName: 0
571 | metroWideTileShowName: 0
572 | metroSupportStreamingInstall: 0
573 | metroLastRequiredScene: 0
574 | metroDefaultTileSize: 1
575 | metroTileForegroundText: 2
576 | metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
577 | metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
578 | a: 1}
579 | metroSplashScreenUseBackgroundColor: 0
580 | platformCapabilities: {}
581 | metroTargetDeviceFamilies: {}
582 | metroFTAName:
583 | metroFTAFileTypes: []
584 | metroProtocolName:
585 | XboxOneProductId:
586 | XboxOneUpdateKey:
587 | XboxOneSandboxId:
588 | XboxOneContentId:
589 | XboxOneTitleId:
590 | XboxOneSCId:
591 | XboxOneGameOsOverridePath:
592 | XboxOnePackagingOverridePath:
593 | XboxOneAppManifestOverridePath:
594 | XboxOneVersion: 1.0.0.0
595 | XboxOnePackageEncryption: 0
596 | XboxOnePackageUpdateGranularity: 2
597 | XboxOneDescription:
598 | XboxOneLanguage:
599 | - enus
600 | XboxOneCapability: []
601 | XboxOneGameRating: {}
602 | XboxOneIsContentPackage: 0
603 | XboxOneEnableGPUVariability: 1
604 | XboxOneSockets: {}
605 | XboxOneSplashScreen: {fileID: 0}
606 | XboxOneAllowedProductIds: []
607 | XboxOnePersistentLocalStorageSize: 0
608 | XboxOneXTitleMemory: 8
609 | xboxOneScriptCompiler: 1
610 | XboxOneOverrideIdentityName:
611 | vrEditorSettings:
612 | daydream:
613 | daydreamIconForeground: {fileID: 0}
614 | daydreamIconBackground: {fileID: 0}
615 | cloudServicesEnabled:
616 | UNet: 1
617 | luminIcon:
618 | m_Name:
619 | m_ModelFolderPath:
620 | m_PortalFolderPath:
621 | luminCert:
622 | m_CertPath:
623 | m_SignPackage: 1
624 | luminIsChannelApp: 0
625 | luminVersion:
626 | m_VersionCode: 1
627 | m_VersionName:
628 | facebookSdkVersion: 7.9.4
629 | facebookAppId:
630 | facebookCookies: 1
631 | facebookLogging: 1
632 | facebookStatus: 1
633 | facebookXfbml: 0
634 | facebookFrictionlessRequests: 1
635 | apiCompatibilityLevel: 6
636 | cloudProjectId:
637 | framebufferDepthMemorylessMode: 0
638 | projectName:
639 | organizationId:
640 | cloudEnabled: 0
641 | enableNativePlatformBackendsForNewInputSystem: 0
642 | disableOldInputManagerSupport: 0
643 | legacyClampBlendShapeWeights: 1
644 |
--------------------------------------------------------------------------------
/Assets/NativeFasterDictionary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using Unity.Collections;
5 | using Unity.Collections.LowLevel.Unsafe;
6 |
7 | namespace Experiment
8 | {
9 | public struct NativeFasterDictionaryData
10 | {
11 | public int FreeValueCellIndex;
12 | public int Collisions;
13 | public int Capacity;
14 | public NativeFasterDictionaryLayout Layout;
15 | public NativeSpan Values;
16 | public NativeSpan Nodes;
17 | public NativeSpan Buckets;
18 | }
19 |
20 | public struct NativeFasterDictionaryLayout
21 | {
22 | public int HeaderOffset;
23 | public int HeaderBytes;
24 | public int NodesOffset;
25 | public int NodesBytes;
26 | public int NodeItemSize;
27 | public int NodesCount;
28 | public int BucketsOffset;
29 | public int BucketsBytes;
30 | public int BucketItemSize;
31 | public int BucketsCount;
32 | public int ValuesOffset;
33 | public int ValuesBytes;
34 | public int ValueItemSize;
35 | public int ValuesCount;
36 | public int AllocationBytes;
37 | }
38 |
39 | // The original design of this dictionary is from https://github.com/sebas77/Svelto.ECS by Sebas77
40 | // It was modified to native code so that it can run in burst compiled jobs.
41 |
42 | // The intention with this design is that the values data is stored sequentially together in a continuous area so
43 | // that it can be quickly directly accessed by index and extracted to a NativeArray.
44 |
45 | [DebuggerTypeProxy(typeof(NativeFasterDictionary<,>.NativeFasterDictionaryDebugView <,>))]
46 | public unsafe struct NativeFasterDictionary : IDisposable where TKey : struct, IComparable where TValue : struct
47 | {
48 | [NativeDisableUnsafePtrRestriction]
49 | public NativeFasterDictionaryData* Data;
50 | private readonly Allocator _allocator;
51 | private static TValue _defaultValue;
52 | private readonly int _isCreated;
53 |
54 | [DebuggerDisplay("Key={Key} Hash={Hashcode} [{Previous}|{Next}]")]
55 | public struct Node
56 | {
57 | public readonly TKey Key;
58 | public readonly int Hashcode;
59 | public int Previous;
60 | public int Next;
61 |
62 | public Node(ref TKey key, int hash, int previousNode)
63 | {
64 | Key = key;
65 | Hashcode = hash;
66 | Previous = previousNode;
67 | Next = -1;
68 | }
69 |
70 | public Node(ref TKey key, int hash)
71 | {
72 | Key = key;
73 | Hashcode = hash;
74 | Previous = -1;
75 | Next = -1;
76 | }
77 | }
78 |
79 | public NativeFasterDictionary(int size, Allocator allocator) : this()
80 | {
81 | Data = Allocate(size, allocator);
82 | _allocator = allocator;
83 | _isCreated = 1;
84 | }
85 |
86 | private void Copy(NativeFasterDictionaryData* src, NativeFasterDictionaryData* dst)
87 | {
88 | if (src->Layout.AllocationBytes > dst->Layout.AllocationBytes)
89 | throw new Exception("Shrinking allocation is not supported");
90 |
91 | dst->FreeValueCellIndex = src->FreeValueCellIndex;
92 | dst->Collisions = src->Collisions;
93 |
94 | UnsafeUtility.MemCpy(dst->Nodes.GetUnsafePtr(), src->Nodes.GetUnsafePtr(), src->Layout.NodesBytes);
95 | UnsafeUtility.MemCpy(dst->Values.GetUnsafePtr(), src->Values.GetUnsafePtr(), src->Layout.ValuesBytes);
96 | UnsafeUtility.MemCpy(dst->Buckets.GetUnsafePtr(), src->Buckets.GetUnsafePtr(), src->Layout.BucketsBytes);
97 | }
98 |
99 | private NativeFasterDictionaryData* Allocate(int size, Allocator allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
100 | {
101 | var layout = CalculateLayout(size);
102 |
103 | var ptr = UnsafeUtility.Malloc(layout.AllocationBytes, UnsafeUtility.AlignOf(), allocator);
104 |
105 | if (options == NativeArrayOptions.ClearMemory)
106 | {
107 | UnsafeUtility.MemClear(ptr, layout.AllocationBytes);
108 | }
109 |
110 | var header = new NativeFasterDictionaryData
111 | {
112 | //BaseAddress = ptr,
113 | FreeValueCellIndex = 0,
114 | Collisions = 0,
115 | Capacity = size,
116 | Layout = layout,
117 | Nodes = NativeSpan.Assign((IntPtr)ptr + layout.NodesOffset, layout.NodesCount),
118 | Values = NativeSpan.Assign((IntPtr)ptr + layout.ValuesOffset, layout.ValuesCount),
119 | Buckets = NativeSpan.Assign((IntPtr)ptr + layout.BucketsOffset, layout.BucketsCount),
120 | };
121 |
122 | UnsafeUtility.CopyStructureToPtr(ref header, ptr);
123 | return CastPtr(ptr, 0);
124 | }
125 |
126 | public NativeFasterDictionaryLayout CalculateLayout(int size)
127 | {
128 | // - Header
129 | // - NodesData
130 | // - ValuesData
131 | // - BucketsData
132 |
133 | NativeFasterDictionaryLayout layout;
134 |
135 | layout.NodeItemSize = UnsafeUtility.SizeOf();
136 | layout.ValueItemSize = UnsafeUtility.SizeOf();
137 | layout.BucketItemSize = UnsafeUtility.SizeOf();
138 |
139 | layout.ValuesCount = size;
140 | layout.NodesCount = size;
141 | layout.BucketsCount = HashHelpers.GetPrime(size);
142 |
143 | layout.HeaderBytes = UnsafeUtility.SizeOf();
144 | layout.NodesBytes = layout.NodeItemSize * layout.NodesCount;
145 | layout.ValuesBytes = layout.ValueItemSize * layout.ValuesCount;
146 | layout.BucketsBytes = layout.BucketItemSize * layout.BucketsCount;
147 |
148 | layout.HeaderOffset = 0;
149 | layout.ValuesOffset = layout.HeaderBytes;
150 | layout.NodesOffset = layout.ValuesOffset + layout.ValuesBytes;
151 | layout.BucketsOffset = layout.NodesOffset + layout.NodesBytes;
152 |
153 | layout.AllocationBytes = layout.HeaderBytes + layout.ValuesBytes + layout.NodesBytes + layout.BucketsBytes;
154 |
155 | return layout;
156 | }
157 |
158 | public T* CastPtr(void* ptr, int offset) where T : unmanaged
159 | {
160 | return (T*)((IntPtr)ptr + offset);
161 | }
162 |
163 | public TValue[] GetValuesArray(out int count)
164 | {
165 | count = Data->FreeValueCellIndex;
166 | return Data->Values.ToArray();
167 | }
168 |
169 | public int Length => Data->FreeValueCellIndex;
170 |
171 | public void Add(TKey key, TValue value)
172 | {
173 | Add(key, ref value);
174 | }
175 |
176 | public void Add(TKey key, ref TValue value)
177 | {
178 | if (AddValue(key, ref value) == false)
179 | {
180 | throw new ArgumentException("Key already present");
181 | }
182 | }
183 |
184 | public void Expand(int newSize)
185 | {
186 | if (newSize <= Data->Capacity)
187 | return;
188 |
189 | var newData = Allocate(newSize, _allocator);
190 | var oldData = Data;
191 |
192 | Copy(oldData, newData);
193 |
194 | Data = newData;
195 |
196 | UnsafeUtility.Free(oldData, _allocator);
197 | }
198 |
199 | public void Clear()
200 | {
201 | if (Data->FreeValueCellIndex == 0)
202 | return;
203 |
204 | Data->FreeValueCellIndex = 0;
205 | Data->Buckets.Clear();
206 | Data->Values.Clear();
207 | Data->Nodes.Clear();
208 | }
209 |
210 | public bool ContainsKey(TKey key)
211 | {
212 | return TryFindIndex(key, out int findIndex);
213 | }
214 |
215 | public bool TryGetValue(TKey key, out TValue result)
216 | {
217 | if (TryFindIndex(key, out var findIndex))
218 | {
219 | result = Data->Values.GetItem(findIndex);
220 | return true;
221 | }
222 | result = default;
223 | return false;
224 | }
225 |
226 | public TryResult TryGetValue(TKey key)
227 | {
228 | if (TryFindIndex(key, out var findIndex))
229 | {
230 | return new TryResult
231 | {
232 | HasValue = true,
233 | Ptr = Data->Values.AsPtr(findIndex)
234 | };
235 | }
236 | return default;
237 | }
238 |
239 | public ref struct TryResult where T : struct
240 | {
241 | public bool HasValue;
242 | internal void* Ptr;
243 |
244 | public ref T Value => ref UnsafeUtilityEx.AsRef(Ptr);
245 | }
246 |
247 | public TValue this[TKey key]
248 | {
249 | get => GetValue(key);
250 | set => AddValue(key, ref value);
251 | }
252 |
253 | public ref TValue GetValue(TKey key)
254 | {
255 | if (TryFindIndex(key, out var findIndex))
256 | {
257 | return ref Data->Values.AsRef(findIndex);
258 | }
259 | throw new KeyNotFoundException();
260 | }
261 |
262 | public ref TValue GetValue(int index)
263 | {
264 | return ref Data->Values.AsRef(index);
265 | }
266 |
267 | static int Hash(TKey key)
268 | {
269 | return key.GetHashCode() & 0x7FFFFFFF;
270 | }
271 |
272 | static uint Reduce(uint x, uint n)
273 | {
274 | if (x >= n)
275 | {
276 | var hash = (11400714819323198485 * x);
277 | hash >>= 32;
278 |
279 | return (uint)((hash * n) >> 32);
280 | }
281 |
282 | return x;
283 | }
284 |
285 | private bool AddValue(TKey key, ref TValue value)
286 | {
287 | int hash = Hash(key);
288 | int bucketIndex = (int)Reduce((uint)hash, (uint)Data->Buckets.Length);
289 | int valueIndex = Data->Buckets.GetItem(bucketIndex) - 1;
290 |
291 | if (valueIndex == -1)
292 | {
293 | GetFreeNodeRef() = new Node(ref key, hash);
294 | }
295 | else //collision or already exists
296 | {
297 | int currentValueIndex = valueIndex;
298 |
299 | for (int i = 0; i < Data->Nodes.Length; i++)
300 | {
301 | if (currentValueIndex == -1)
302 | break;
303 |
304 | ref var node = ref Data->Nodes.AsRef(currentValueIndex);
305 | if (node.Hashcode == hash && node.Key.CompareTo(key) == 0)
306 | {
307 | Data->Values.AsRef(currentValueIndex) = value;
308 | return false;
309 | }
310 | currentValueIndex = node.Previous;
311 | }
312 |
313 | Data->Collisions++;
314 |
315 | GetFreeNodeRef() = new Node(ref key, hash, valueIndex);
316 |
317 | Data->Nodes.AsRef(valueIndex).Next = Data->FreeValueCellIndex;
318 | }
319 |
320 | Data->Buckets.AsRef(bucketIndex) = Data->FreeValueCellIndex + 1;
321 | GetFreeValueRef() = value;
322 | Data->FreeValueCellIndex++;
323 |
324 | if (Data->FreeValueCellIndex == Data->Values.Length)
325 | {
326 | RemapCollisions();
327 | }
328 | if (Data->Collisions > Data->Buckets.Length)
329 | {
330 | RemapCollisions();
331 | }
332 | return true;
333 | }
334 |
335 | private void RemapCollisions()
336 | {
337 | Expand(HashHelpers.ExpandPrime(Data->Capacity));
338 |
339 | Data->Collisions = 0;
340 |
341 | for (int i = 0; i < Data->FreeValueCellIndex; i++)
342 | {
343 | ref var node = ref Data->Nodes.AsRef(i);
344 |
345 | var bucketIndex = (int)Reduce((uint)node.Hashcode, (uint)Data->Buckets.Length - 1);
346 | ref var bucketValue = ref Data->Buckets.AsRef(bucketIndex);
347 | int existingValueIndex = bucketValue - 1;
348 |
349 | bucketValue = i + 1;
350 |
351 | if (existingValueIndex != -1)
352 | {
353 | Data->Collisions++;
354 | node.Previous = existingValueIndex;
355 | node.Next = -1;
356 | Data->Nodes.AsRef(existingValueIndex).Next = i;
357 | }
358 | else
359 | {
360 | node.Next = -1;
361 | node.Previous = -1;
362 | }
363 | }
364 | }
365 |
366 | public bool Remove(TKey key)
367 | {
368 | int hash = Hash(key);
369 | int bucketIndex = (int)Reduce((uint)hash, (uint)Data->Buckets.Length);
370 | ref var bucketIndexRef = ref Data->Buckets.AsRef(bucketIndex);
371 |
372 | int indexToValueToRemove = bucketIndexRef - 1;
373 | while (indexToValueToRemove != -1)
374 | {
375 | ref var nodeToRemove = ref Data->Nodes.AsRef(indexToValueToRemove);
376 |
377 | if (nodeToRemove.Hashcode == hash && nodeToRemove.Key.CompareTo(key) == 0)
378 | {
379 | if (bucketIndexRef - 1 == indexToValueToRemove)
380 | {
381 | int value = nodeToRemove.Previous;
382 | bucketIndexRef = value + 1;
383 | }
384 |
385 | int next = nodeToRemove.Next;
386 | int previous = nodeToRemove.Previous;
387 |
388 | if (next != -1)
389 | {
390 | Data->Nodes.AsRef(next).Previous = previous;
391 | }
392 | if (previous != -1)
393 | {
394 | Data->Nodes.AsRef(previous).Next = next;
395 | }
396 | break;
397 | }
398 | indexToValueToRemove = nodeToRemove.Previous;
399 | }
400 |
401 | if (indexToValueToRemove == -1)
402 | return false; //not found!
403 |
404 | Data->FreeValueCellIndex--;
405 |
406 | if (indexToValueToRemove != Data->FreeValueCellIndex)
407 | {
408 | ref var freeNode = ref GetFreeNodeRef();
409 | int movingBucketIndex = (int)Reduce((uint)freeNode.Hashcode, (uint)Data->Buckets.Length);
410 |
411 | ref var tmpBucketIndex = ref Data->Buckets.AsRef(movingBucketIndex);
412 | if (tmpBucketIndex - 1 == Data->FreeValueCellIndex)
413 | tmpBucketIndex = indexToValueToRemove + 1;
414 |
415 | if (freeNode.Next != -1)
416 | {
417 | Data->Nodes.AsRef(freeNode.Next).Previous = indexToValueToRemove;
418 | }
419 | if (freeNode.Previous != -1)
420 | {
421 | Data->Nodes.AsRef(freeNode.Previous).Next = indexToValueToRemove;
422 | }
423 | Data->Nodes.AsRef(indexToValueToRemove) = freeNode;
424 | Data->Values.AsRef(indexToValueToRemove) = GetFreeValueRef();
425 | }
426 | return true;
427 | }
428 |
429 | public ref Node GetFreeNodeRef() => ref Data->Nodes.AsRef(Data->FreeValueCellIndex);
430 |
431 | public ref TValue GetFreeValueRef() => ref Data->Values.AsRef(Data->FreeValueCellIndex);
432 |
433 | private int GetValueIndexFromHash(int hash)
434 | {
435 | // All the index are stored with an offset + 1, so that in the bucket list 0 means actually not existing.
436 | // When read the offset must be offset by -1 again to be the real one. In this way I avoid to initialize the array to -1
437 | int bucketIndex = (int)Reduce((uint)hash, (uint)Data->Buckets.Length);
438 | return Data->Buckets.GetItem(bucketIndex) - 1;
439 | }
440 |
441 | public bool TryFindIndex(TKey key, out int findIndex)
442 | {
443 | int hash = Hash(key);
444 | int valueIndex = GetValueIndexFromHash(hash);
445 | if (valueIndex > Data->Nodes.m_MaxIndex)
446 | {
447 | throw new IndexOutOfRangeException($"Index: {valueIndex} is outside the valid range [0-{Data->Nodes.m_MaxIndex}]");
448 | }
449 |
450 | for (int i = 0; i < Data->Nodes.Length; i++)
451 | {
452 | if (valueIndex < 0)
453 | break;
454 |
455 | ref var node = ref Data->Nodes.AsRef(valueIndex);
456 | if (node.Hashcode == hash && node.Key.CompareTo(key) == 0)
457 | {
458 | findIndex = valueIndex;
459 | return true;
460 | }
461 | valueIndex = node.Previous;
462 | }
463 | findIndex = 0;
464 | return false;
465 | }
466 |
467 | public void Dispose()
468 | {
469 | if (_isCreated == 1)
470 | {
471 | UnsafeUtility.Free(Data, _allocator);
472 | }
473 | Data = null;
474 | }
475 |
476 | internal sealed class NativeFasterDictionaryDebugView where TKey : struct, IComparable where TValue : struct
477 | {
478 | private NativeFasterDictionary _source;
479 |
480 | public NativeFasterDictionaryDebugView(NativeFasterDictionary source)
481 | {
482 | _source = source;
483 | }
484 |
485 | public NativeFasterDictionaryData Header => *_source.Data;
486 |
487 | public TValue[] Values => _source.Data->Values.ToArray();
488 |
489 | public NativeFasterDictionary.Node[] Nodes
490 | {
491 | get => _source.Data->Nodes.ToArray.Node>();
492 | }
493 |
494 | public int[] Buckets => _source.Data->Buckets.ToArray();
495 |
496 | public int Length => _source.Length;
497 | }
498 |
499 | public static class HashHelpers
500 | {
501 | public const int MaxPrimeArrayLength = 0x7FEFFFFD;
502 | public const int HashCollisionThreshold = 100;
503 | public const int HashPrime = 101;
504 |
505 | public static readonly int[] Primes =
506 | {
507 | 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
508 | 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
509 | 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
510 | 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
511 | 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369
512 | };
513 |
514 | public static bool IsPrime(int candidate)
515 | {
516 | if ((candidate & 1) != 0)
517 | {
518 | int limit = (int)Math.Sqrt(candidate);
519 | for (int divisor = 3; divisor <= limit; divisor += 2)
520 | {
521 | if ((candidate % divisor) == 0)
522 | return false;
523 | }
524 | return true;
525 | }
526 | return (candidate == 2);
527 | }
528 |
529 | public static int GetPrime(int min)
530 | {
531 | if (min < 0)
532 | {
533 | throw new ArgumentException();
534 | }
535 | for (int i = 0; i < Primes.Length; i++)
536 | {
537 | int prime = Primes[i];
538 | if (prime >= min)
539 | return prime;
540 | }
541 | for (int i = (min | 1); i < int.MaxValue; i += 2)
542 | {
543 | if (IsPrime(i) && ((i - 1) % HashPrime != 0))
544 | return i;
545 | }
546 | return min;
547 | }
548 |
549 | public static int ExpandPrime(int oldSize)
550 | {
551 | int newSize = 2 * oldSize;
552 | if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
553 | {
554 | return MaxPrimeArrayLength;
555 | }
556 | return GetPrime(newSize);
557 | }
558 | }
559 |
560 | }
561 |
562 | }
--------------------------------------------------------------------------------
/Assets/Svelto/FasterDictionary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.CompilerServices;
5 |
6 | namespace Experiment
7 | {
8 |
9 | ///
10 | /// by sebas77
11 | /// https://github.com/sebas77/Svelto.Tasks.Examples/blob/205506feef7557a8aed74d65f2a86353d90afcb7/Assets/Svelto.Tasks/Svelto.Common/DataStructures/FasterDictionary.cs
12 | ///
13 | ///
14 | ///
15 | public class FasterDictionary : IDictionary where TKey : IComparable
16 | {
17 | public FasterDictionary(int size)
18 | {
19 | _valuesInfo = new Node[size];
20 | _values = new TValue[size];
21 | _buckets = new int[HashHelpers.GetPrime(size)];
22 | }
23 |
24 | public FasterDictionary() : this(1) { }
25 |
26 | ICollection IDictionary.Keys
27 | {
28 | get { throw new NotImplementedException(); }
29 | }
30 |
31 | public FasterDictionaryKeys Keys
32 | {
33 | get { throw new NotImplementedException(); }
34 | }
35 |
36 | ICollection IDictionary.Values
37 | {
38 | get { throw new NotImplementedException(); }
39 | }
40 |
41 | //public ReadOnlyCollectionStruct Values
42 | //{
43 | // get { return new ReadOnlyCollectionStruct(_values, _freeValueCellIndex); }
44 | //}
45 |
46 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
47 | public TValue[] GetValuesArray(out int count)
48 | {
49 | count = _freeValueCellIndex;
50 |
51 | return _values;
52 | }
53 |
54 | public int Collisions => _collisions;
55 |
56 | public int Count
57 | {
58 | get { return _freeValueCellIndex; }
59 | }
60 |
61 | public bool IsReadOnly
62 | {
63 | get { return false; }
64 | }
65 |
66 | public void Add(TKey key, TValue value)
67 | {
68 | Add(key, ref value);
69 | }
70 |
71 | public void Add(TKey key, ref TValue value)
72 | {
73 | if (AddValue(key, ref value) == false)
74 | {
75 | throw new FasterDictionaryException("Key already present");
76 | }
77 | }
78 |
79 | public void Add(KeyValuePair item)
80 | {
81 | throw new NotImplementedException();
82 | }
83 |
84 | public void Clear()
85 | {
86 | if (_freeValueCellIndex == 0) return;
87 |
88 | _freeValueCellIndex = 0;
89 |
90 | Array.Clear(_buckets, 0, _buckets.Length);
91 | Array.Clear(_values, 0, _values.Length);
92 | Array.Clear(_valuesInfo, 0, _valuesInfo.Length);
93 | }
94 |
95 | public bool Contains(KeyValuePair item)
96 | {
97 | throw new NotImplementedException();
98 | }
99 |
100 | public bool ContainsKey(TKey key)
101 | {
102 | uint findIndex;
103 | if (FindIndex(key, _buckets, _valuesInfo, out findIndex))
104 | {
105 | return true;
106 | }
107 |
108 | return false;
109 | }
110 |
111 | public void CopyTo(KeyValuePair[] array, int arrayIndex)
112 | {
113 | throw new NotImplementedException();
114 | }
115 |
116 | IEnumerator> IEnumerable>.GetEnumerator()
117 | {
118 | return new FasterDictionaryKeyValueEnumerator(this);
119 | }
120 |
121 | public FasterDictionaryKeyValueEnumerator GetEnumerator()
122 | {
123 | return new FasterDictionaryKeyValueEnumerator(this);
124 | }
125 |
126 | public bool Remove(KeyValuePair item)
127 | {
128 | throw new NotImplementedException();
129 | }
130 |
131 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
132 | protected uint GetValueIndex(TKey index)
133 | {
134 | return GetIndex(index, _buckets, _valuesInfo);
135 | }
136 |
137 | public bool TryGetValue(TKey key, out TValue result)
138 | {
139 | uint findIndex;
140 | if (FindIndex(key, _buckets, _valuesInfo, out findIndex))
141 | {
142 | result = _values[findIndex];
143 | return true;
144 | }
145 |
146 | result = default(TValue);
147 | return false;
148 | }
149 |
150 | IEnumerator IEnumerable.GetEnumerator()
151 | {
152 | throw new NotImplementedException();
153 | }
154 |
155 | public void AddCapacity(int size)
156 | {
157 | throw new NotImplementedException();
158 | }
159 |
160 | public TValue this[TKey key]
161 | {
162 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
163 | get => _values[GetIndex(key, _buckets, _valuesInfo)];
164 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
165 | set => AddValue(key, ref value);
166 | }
167 |
168 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
169 | static int Hash(TKey key)
170 | {
171 | return key.GetHashCode() & 0x7FFFFFFF;
172 | }
173 |
174 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
175 | static uint Reduce(uint x, uint N)
176 | {
177 | {
178 | if (x >= N)
179 | {
180 | var hash = (11400714819323198485 * x);
181 | hash >>= 32;
182 |
183 | return (uint)((hash * N) >> 32);
184 | }
185 |
186 | return x;
187 | }
188 | }
189 |
190 | bool AddValue(TKey key, ref TValue value)
191 | {
192 | int hash = Hash(key);
193 | uint bucketIndex = Reduce((uint)hash, (uint)_buckets.Length);
194 |
195 | //buckets value -1 means it's empty
196 | var valueIndex = _buckets[bucketIndex] - 1;
197 |
198 | if (valueIndex == -1)
199 | //create the info node at the last position and fill it with the relevant information
200 | _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash);
201 | else //collision or already exists
202 | {
203 | {
204 | int currentValueIndex = valueIndex;
205 | do
206 | {
207 | //must check if the key already exists in the dictionary
208 | //for some reason this is faster than using Comparer.default, should investigate
209 | if (_valuesInfo[currentValueIndex].hashcode == hash
210 | && _valuesInfo[currentValueIndex].key.CompareTo(key) == 0)
211 | {//the key already exists, simply replace the value!
212 | _values[currentValueIndex] = value;
213 | return false;
214 | }
215 |
216 | currentValueIndex = _valuesInfo[currentValueIndex].previous;
217 | }
218 | while (currentValueIndex != -1); //-1 means no more values with key with the same hash
219 | }
220 |
221 | //oops collision!
222 | _collisions++;
223 | //create a new node which previous index points to node currently pointed in the bucket
224 | _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash, valueIndex);
225 | //update the next of the existing cell to point to the new one
226 | //old one -> new one | old one <- next one
227 | _valuesInfo[valueIndex].next = _freeValueCellIndex;
228 | //Important: the new node is always the one that will be pointed by the bucket cell
229 | //so I can assume that the one pointed by the bucket is always the last value added
230 | //(next = -1)
231 | }
232 |
233 | //item with this bucketIndex will point to the last value created
234 | //ToDo: if instead I assume that the original one is the one in the bucket
235 | //I wouldn't need to update the bucket here. Small optimization but important
236 | _buckets[bucketIndex] = _freeValueCellIndex + 1;
237 |
238 | _values[_freeValueCellIndex] = value;
239 |
240 | _freeValueCellIndex++;
241 |
242 | if (_freeValueCellIndex == _values.Length)
243 | {
244 | Array.Resize(ref _values,
245 | HashHelpers.ExpandPrime(_freeValueCellIndex));
246 | Array.Resize(ref _valuesInfo,
247 | HashHelpers.ExpandPrime(_freeValueCellIndex));
248 | }
249 |
250 | //too many collisions?
251 | if (_collisions > _buckets.Length)
252 | {
253 | //we need more space and less collisions
254 | //ToDo: need to change from prime to Fibonacci sequence (could be quite faster)
255 | _buckets = new int[HashHelpers.ExpandPrime(_collisions)];
256 |
257 | _collisions = 0;
258 |
259 | //we need to get all the hash code of all the values stored so far and spread them over the new bucket
260 | //length
261 | for (int newValueIndex = 0; newValueIndex < _freeValueCellIndex; newValueIndex++)
262 | {
263 | //get the original hash code and find the new bucketIndex due to the new length
264 | bucketIndex = Reduce((uint)_valuesInfo[newValueIndex].hashcode, (uint)_buckets.Length);
265 | //bucketsIndex can be -1 or a next value. If it's -1 means no collisions. If there is collision,
266 | //we create a new node which prev points to the old one. Old one next points to the new one.
267 | //the bucket will now points to the new one
268 | //In this way we can rebuild the linkedlist.
269 | //get the current valueIndex, it's -1 if no collision happens
270 | int existingValueIndex = _buckets[bucketIndex] - 1;
271 | //update the bucket index to the index of the current item that share the bucketIndex
272 | //(last found is always the one in the bucket)
273 | _buckets[bucketIndex] = newValueIndex + 1;
274 | if (existingValueIndex != -1)
275 | { //oops a value was already being pointed by this cell in the new bucket list,
276 | //it means there is a collision, problem
277 | _collisions++;
278 | //the bucket will point to this value, so
279 | //the previous index will be used as previous for the new value.
280 | _valuesInfo[newValueIndex].previous = existingValueIndex;
281 | _valuesInfo[newValueIndex].next = -1;
282 | //and update the previous next index to the new one
283 | _valuesInfo[existingValueIndex].next = newValueIndex;
284 | }
285 | else
286 | { //ok nothing was indexed, the bucket was empty. We need to update the previous
287 | //values of next and previous
288 | _valuesInfo[newValueIndex].next = -1;
289 | _valuesInfo[newValueIndex].previous = -1;
290 | }
291 | }
292 | }
293 |
294 | return true;
295 | }
296 |
297 | public bool Remove(TKey key)
298 | {
299 | int hash = Hash(key);
300 | uint bucketIndex = Reduce((uint)hash, (uint)_buckets.Length);
301 |
302 | //find the bucket
303 | int indexToValueToRemove = _buckets[bucketIndex] - 1;
304 |
305 | //Part one: look for the actual key in the bucket list if found
306 | //we update the bucket list so that it doesn't point anymore
307 | //to the cell to remove
308 | while (indexToValueToRemove != -1)
309 | {
310 | if (_valuesInfo[indexToValueToRemove].hashcode == hash
311 | && _valuesInfo[indexToValueToRemove].key.CompareTo(key) == 0)
312 | {
313 | //if the key is found and the bucket points directly to the node to remove
314 | if (_buckets[bucketIndex] - 1 == indexToValueToRemove)
315 | {
316 | //DBC.Common.Check.Require(_valuesInfo[indexToValueToRemove].next == -1,
317 | // "if the bucket points to the cell, next MUST NOT exists");
318 | //the bucket will point to the previous cell. if a previous cell exists
319 | //its next pointer must be updated!
320 | //<--- iteration order
321 | // B(ucket points always to the last one)
322 | // ------- ------- -------
323 | // | 1 | | 2 | | 3 | //bucket cannot have next, only previous
324 | // ------- ------- -------
325 | //--> insert order
326 | int value = _valuesInfo[indexToValueToRemove].previous;
327 | _buckets[bucketIndex] = value + 1;
328 | }
329 | else
330 | //DBC.Common.Check.Require(_valuesInfo[indexToValueToRemove].next != -1,
331 | // "if the bucket points to another cell, next MUST exists");
332 |
333 | UpdateLinkedList(indexToValueToRemove, _valuesInfo);
334 |
335 | break;
336 | }
337 |
338 | indexToValueToRemove = _valuesInfo[indexToValueToRemove].previous;
339 | }
340 |
341 | if (indexToValueToRemove == -1)
342 | return false; //not found!
343 |
344 | _freeValueCellIndex--; //one less value to iterate
345 |
346 | //Part two:
347 | //At this point nodes pointers and buckets are updated, but the _values array
348 | //still has got the value to delete. Remember the goal of this dictionary is to be able
349 | //to iterate over the values like an array, so the values array must always be up to date
350 |
351 | //if the cell to remove is the last one in the list, we can perform less operations (no swapping needed)
352 | //otherwise we want to move the last value cell over the value to remove
353 |
354 | if (indexToValueToRemove != _freeValueCellIndex)
355 | { //we can move the last value of both arrays in place of the one to delete.
356 | //in order to do so, we need to be sure that the bucket pointer is updated
357 | //first we find the index in the bucket list of the pointer that points to the cell
358 | //to move
359 | var movingBucketIndex = Reduce((uint)_valuesInfo[_freeValueCellIndex].hashcode, (uint)_buckets.Length);
360 |
361 | //if the key is found and the bucket points directly to the node to remove
362 | //it must now point to the cell where it's going to be moved
363 | if (_buckets[movingBucketIndex] - 1 == _freeValueCellIndex)
364 | _buckets[movingBucketIndex] = indexToValueToRemove + 1;
365 |
366 | //otherwise it means that there was more than one key with the same hash (collision), so
367 | //we need to update the linked list and its pointers
368 | int next = _valuesInfo[_freeValueCellIndex].next;
369 | int previous = _valuesInfo[_freeValueCellIndex].previous;
370 |
371 | //they now point to the cell where the last value is moved into
372 | if (next != -1)
373 | _valuesInfo[next].previous = indexToValueToRemove;
374 | if (previous != -1)
375 | _valuesInfo[previous].next = indexToValueToRemove;
376 |
377 | //finally, actually move the values
378 | _valuesInfo[indexToValueToRemove] = _valuesInfo[_freeValueCellIndex];
379 | _values[indexToValueToRemove] = _values[_freeValueCellIndex];
380 | }
381 |
382 | return true;
383 | }
384 |
385 | public void Trim()
386 | {
387 | if (HashHelpers.ExpandPrime(_freeValueCellIndex) < _valuesInfo.Length)
388 | {
389 | Array.Resize(ref _values,
390 | HashHelpers.ExpandPrime(_freeValueCellIndex));
391 | Array.Resize(ref _valuesInfo,
392 | HashHelpers.ExpandPrime(_freeValueCellIndex));
393 | }
394 | }
395 |
396 | //I store all the index with an offset + 1, so that in the bucket
397 | //list 0 means actually not existing.
398 |
399 | //When read the offset must
400 | //be offset by -1 again to be the real one. In this way
401 | //I avoid to initialize the array to -1
402 |
403 | protected bool FindIndex(TKey key, out uint findIndex)
404 | {
405 | int hash = Hash(key);
406 | uint bucketIndex = Reduce((uint)hash, (uint)_buckets.Length);
407 |
408 | int valueIndex = _buckets[bucketIndex] - 1;
409 |
410 | //even if we found an existing value we need to be sure it's the one we requested
411 | while (valueIndex != -1)
412 | {
413 | //for some reason this is way faster than using Comparer.default, should investigate
414 | if (_valuesInfo[valueIndex].hashcode == hash &&
415 | _valuesInfo[valueIndex].key.CompareTo(key) == 0)
416 | {
417 | //this is the one
418 | findIndex = (uint)valueIndex;
419 | return true;
420 | }
421 |
422 | valueIndex = _valuesInfo[valueIndex].previous;
423 | }
424 |
425 | findIndex = 0;
426 | return false;
427 | }
428 |
429 | static uint GetIndex(TKey key, int[] buckets, Node[] valuesInfo)
430 | {
431 | uint findIndex;
432 | if (FindIndex(key, buckets, valuesInfo, out findIndex)) return findIndex;
433 |
434 | throw new FasterDictionaryException("Key not found");
435 | }
436 |
437 | static bool FindIndex(TKey key, int[] buckets, Node[] valuesInfo, out uint findIndex)
438 | {
439 | int hash = Hash(key);
440 | var bucketIndex = Reduce((uint)hash, (uint)buckets.Length);
441 |
442 | int valueIndex = buckets[bucketIndex] - 1;
443 |
444 | while (valueIndex != -1)
445 | { //for some reason this is way faster they use Comparer.default, should investigate
446 | if (valuesInfo[valueIndex].hashcode == hash && valuesInfo[valueIndex].key.CompareTo(key) == 0)
447 | {
448 | findIndex = (uint)valueIndex;
449 | return true;
450 | }
451 |
452 | valueIndex = valuesInfo[valueIndex].previous;
453 | }
454 | findIndex = 0;
455 | return false;
456 | }
457 |
458 | static void UpdateLinkedList(int index, Node[] valuesInfo)
459 | {
460 | int next = valuesInfo[index].next;
461 | int previous = valuesInfo[index].previous;
462 |
463 | if (next != -1)
464 | valuesInfo[next].previous = previous;
465 | if (previous != -1)
466 | valuesInfo[previous].next = next;
467 | }
468 |
469 | public struct FasterDictionaryKeyValueEnumerator : IEnumerator>
470 | {
471 | public FasterDictionaryKeyValueEnumerator(FasterDictionary dic) : this()
472 | {
473 | _dic = dic;
474 | _index = -1;
475 | _count = dic.Count;
476 | }
477 |
478 | public void Dispose()
479 | { }
480 |
481 | public bool MoveNext()
482 | {
483 | if (_count != _dic.Count)
484 | throw new FasterDictionaryException("can't modify a dictionary during its iteration");
485 |
486 | if (_index < _count - 1)
487 | {
488 | _index++;
489 | return true;
490 | }
491 |
492 | return false;
493 | }
494 |
495 | public void Reset()
496 | {
497 | throw new NotImplementedException();
498 | }
499 |
500 | public KeyValuePair Current { get { return new KeyValuePair(_dic._valuesInfo[_index].key, _dic._values[_index]); } }
501 |
502 | object IEnumerator.Current
503 | {
504 | get { throw new NotImplementedException(); }
505 | }
506 |
507 | readonly FasterDictionary _dic;
508 | readonly int _count;
509 |
510 | int _index;
511 | }
512 |
513 | struct Node
514 | {
515 | public readonly TKey key;
516 | public readonly int hashcode;
517 | public int previous;
518 | public int next;
519 |
520 | public Node(ref TKey key, int hash, int previousNode)
521 | {
522 | this.key = key;
523 | hashcode = hash;
524 | previous = previousNode;
525 | next = -1;
526 | }
527 |
528 | public Node(ref TKey key, int hash)
529 | {
530 | this.key = key;
531 | hashcode = hash;
532 | previous = -1;
533 | next = -1;
534 | }
535 | }
536 |
537 | public struct FasterDictionaryKeys : ICollection
538 | {
539 | internal FasterDictionaryKeys(FasterDictionary dic) : this()
540 | {
541 | }
542 |
543 | IEnumerator IEnumerable.GetEnumerator()
544 | {
545 | throw new NotImplementedException();
546 | }
547 |
548 | IEnumerator IEnumerable.GetEnumerator()
549 | {
550 | throw new NotImplementedException();
551 | }
552 |
553 | public FasterDictionaryKeyEnumerator GetEnumerator()
554 | {
555 | throw new NotImplementedException();
556 | }
557 |
558 | public void Add(TKey item)
559 | {
560 | throw new NotImplementedException();
561 | }
562 |
563 | public void Clear()
564 | {
565 | throw new NotImplementedException();
566 | }
567 |
568 | public bool Contains(TKey item)
569 | {
570 | throw new NotImplementedException();
571 | }
572 |
573 | public void CopyTo(TKey[] array, int arrayIndex)
574 | {
575 | throw new NotImplementedException();
576 | }
577 |
578 | public bool Remove(TKey item)
579 | {
580 | throw new NotImplementedException();
581 | }
582 |
583 | public int Count { get; }
584 | public bool IsReadOnly { get; }
585 | }
586 |
587 | public struct FasterDictionaryKeyEnumerator : IEnumerator
588 | {
589 | public bool MoveNext()
590 | {
591 | throw new NotImplementedException();
592 | }
593 |
594 | public void Reset()
595 | {
596 | throw new NotImplementedException();
597 | }
598 |
599 | public TKey Current { get; }
600 |
601 | object IEnumerator.Current
602 | {
603 | get { return Current; }
604 | }
605 |
606 | public void Dispose()
607 | {
608 | throw new NotImplementedException();
609 | }
610 | }
611 |
612 |
613 | protected TValue[] _values;
614 |
615 | Node[] _valuesInfo;
616 | int[] _buckets;
617 | int _freeValueCellIndex;
618 | public int _collisions;
619 | }
620 |
621 | public class FasterDictionaryException : Exception
622 | {
623 | public FasterDictionaryException(string keyAlreadyExisting) : base(keyAlreadyExisting)
624 | {
625 |
626 | }
627 | }
628 | }
--------------------------------------------------------------------------------