Merge pull request #16527 from peppy/remove-parameterless-beatmapinfo-ctor-usage

Avoid constructor allocation/GC overhead in realm implicit constructors
This commit is contained in:
Dan Balasescu
2022-01-20 18:11:35 +09:00
committed by GitHub
9 changed files with 98 additions and 61 deletions

View File

@ -63,23 +63,9 @@ namespace osu.Game.Tests.Database
using (var realm = realmContextFactory.CreateContext()) using (var realm = realmContextFactory.CreateContext())
using (var transaction = realm.BeginWrite()) using (var transaction = realm.BeginWrite())
{ {
realm.Add(new RealmKeyBinding realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.A)));
{ realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.S)));
Action = GlobalAction.Back, realm.Add(new RealmKeyBinding(GlobalAction.Back, new KeyCombination(InputKey.D)));
KeyCombination = new KeyCombination(InputKey.A)
});
realm.Add(new RealmKeyBinding
{
Action = GlobalAction.Back,
KeyCombination = new KeyCombination(InputKey.S)
});
realm.Add(new RealmKeyBinding
{
Action = GlobalAction.Back,
KeyCombination = new KeyCombination(InputKey.D)
});
transaction.Commit(); transaction.Commit();
} }

View File

@ -26,37 +26,36 @@ namespace osu.Game.Beatmaps
public class BeatmapInfo : RealmObject, IHasGuidPrimaryKey, IBeatmapInfo, IEquatable<BeatmapInfo> public class BeatmapInfo : RealmObject, IHasGuidPrimaryKey, IBeatmapInfo, IEquatable<BeatmapInfo>
{ {
[PrimaryKey] [PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid(); public Guid ID { get; set; }
public string DifficultyName { get; set; } = string.Empty; public string DifficultyName { get; set; } = string.Empty;
public RulesetInfo Ruleset { get; set; } public RulesetInfo Ruleset { get; set; } = null!;
public BeatmapDifficulty Difficulty { get; set; } public BeatmapDifficulty Difficulty { get; set; } = null!;
public BeatmapMetadata Metadata { get; set; } public BeatmapMetadata Metadata { get; set; } = null!;
[JsonIgnore]
[Backlink(nameof(ScoreInfo.BeatmapInfo))] [Backlink(nameof(ScoreInfo.BeatmapInfo))]
public IQueryable<ScoreInfo> Scores { get; } = null!; public IQueryable<ScoreInfo> Scores { get; } = null!;
public BeatmapInfo(RulesetInfo ruleset, BeatmapDifficulty difficulty, BeatmapMetadata metadata) public BeatmapInfo(RulesetInfo? ruleset = null, BeatmapDifficulty? difficulty = null, BeatmapMetadata? metadata = null)
{ {
Ruleset = ruleset; ID = Guid.NewGuid();
Difficulty = difficulty; Ruleset = ruleset ?? new RulesetInfo
Metadata = metadata;
}
[UsedImplicitly]
public BeatmapInfo() // TODO: consider removing this and migrating all usages to ctor with parameters.
{
Ruleset = new RulesetInfo
{ {
OnlineID = 0, OnlineID = 0,
ShortName = @"osu", ShortName = @"osu",
Name = @"null placeholder ruleset" Name = @"null placeholder ruleset"
}; };
Difficulty = new BeatmapDifficulty(); Difficulty = difficulty ?? new BeatmapDifficulty();
Metadata = new BeatmapMetadata(); Metadata = metadata ?? new BeatmapMetadata();
}
[UsedImplicitly]
private BeatmapInfo()
{
} }
public BeatmapSetInfo? BeatmapSet { get; set; } public BeatmapSetInfo? BeatmapSet { get; set; }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Models; using osu.Game.Models;
@ -27,7 +28,7 @@ namespace osu.Game.Beatmaps
[JsonProperty("artist_unicode")] [JsonProperty("artist_unicode")]
public string ArtistUnicode { get; set; } = string.Empty; public string ArtistUnicode { get; set; } = string.Empty;
public RealmUser Author { get; set; } = new RealmUser(); // TODO: not sure we want to initialise this only to have it overwritten by retrieval. public RealmUser Author { get; set; } = null!;
public string Source { get; set; } = string.Empty; public string Source { get; set; } = string.Empty;
@ -43,6 +44,16 @@ namespace osu.Game.Beatmaps
public string AudioFile { get; set; } = string.Empty; public string AudioFile { get; set; } = string.Empty;
public string BackgroundFile { get; set; } = string.Empty; public string BackgroundFile { get; set; } = string.Empty;
public BeatmapMetadata(RealmUser? user = null)
{
Author = new RealmUser();
}
[UsedImplicitly] // Realm
private BeatmapMetadata()
{
}
IUser IBeatmapMetadataInfo.Author => Author; IUser IBeatmapMetadataInfo.Author => Author;
public override string ToString() => this.GetDisplayTitle(); public override string ToString() => this.GetDisplayTitle();

View File

@ -4,6 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Extensions; using osu.Game.Extensions;
@ -19,13 +21,14 @@ namespace osu.Game.Beatmaps
public class BeatmapSetInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable<BeatmapSetInfo>, IBeatmapSetInfo public class BeatmapSetInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable<BeatmapSetInfo>, IBeatmapSetInfo
{ {
[PrimaryKey] [PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid(); public Guid ID { get; set; }
[Indexed] [Indexed]
public int OnlineID { get; set; } = -1; public int OnlineID { get; set; } = -1;
public DateTimeOffset DateAdded { get; set; } public DateTimeOffset DateAdded { get; set; }
[JsonIgnore]
public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata(); public IBeatmapMetadataInfo Metadata => Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
public IList<BeatmapInfo> Beatmaps { get; } = null!; public IList<BeatmapInfo> Beatmaps { get; } = null!;
@ -57,6 +60,19 @@ namespace osu.Game.Beatmaps
public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM); public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM);
public BeatmapSetInfo(IEnumerable<BeatmapInfo>? beatmaps = null)
: this()
{
ID = Guid.NewGuid();
if (beatmaps != null)
Beatmaps.AddRange(beatmaps);
}
[UsedImplicitly] // Realm
private BeatmapSetInfo()
{
}
/// <summary> /// <summary>
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
/// The path returned is relative to the user file storage. /// The path returned is relative to the user file storage.

View File

@ -48,6 +48,7 @@ namespace osu.Game.Database
copyChangesToRealm(s.Metadata, d.Metadata); copyChangesToRealm(s.Metadata, d.Metadata);
}); });
c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>() c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>()
.ConstructUsing(_ => new BeatmapSetInfo(null))
.ForMember(s => s.Beatmaps, cc => cc.Ignore()) .ForMember(s => s.Beatmaps, cc => cc.Ignore())
.AfterMap((s, d) => .AfterMap((s, d) =>
{ {
@ -77,6 +78,7 @@ namespace osu.Game.Database
applyCommonConfiguration(c); applyCommonConfiguration(c);
c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>() c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>()
.ConstructUsing(_ => new BeatmapSetInfo(null))
.MaxDepth(2) .MaxDepth(2)
.AfterMap((s, d) => .AfterMap((s, d) =>
{ {
@ -109,6 +111,7 @@ namespace osu.Game.Database
applyCommonConfiguration(c); applyCommonConfiguration(c);
c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>() c.CreateMap<BeatmapSetInfo, BeatmapSetInfo>()
.ConstructUsing(_ => new BeatmapSetInfo(null))
.MaxDepth(2) .MaxDepth(2)
.ForMember(b => b.Files, cc => cc.Ignore()) .ForMember(b => b.Files, cc => cc.Ignore())
.AfterMap((s, d) => .AfterMap((s, d) =>

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using JetBrains.Annotations;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Database; using osu.Game.Database;
using Realms; using Realms;
@ -14,7 +15,7 @@ namespace osu.Game.Input.Bindings
public class RealmKeyBinding : RealmObject, IHasGuidPrimaryKey, IKeyBinding public class RealmKeyBinding : RealmObject, IHasGuidPrimaryKey, IKeyBinding
{ {
[PrimaryKey] [PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid(); public Guid ID { get; set; }
public string? RulesetName { get; set; } public string? RulesetName { get; set; }
@ -38,6 +39,21 @@ namespace osu.Game.Input.Bindings
public int ActionInt { get; set; } public int ActionInt { get; set; }
[MapTo(nameof(KeyCombination))] [MapTo(nameof(KeyCombination))]
public string KeyCombinationString { get; set; } = string.Empty; public string KeyCombinationString { get; set; } = null!;
public RealmKeyBinding(object action, KeyCombination keyCombination, string? rulesetName = null, int? variant = null)
{
Action = action;
KeyCombination = keyCombination;
RulesetName = rulesetName;
Variant = variant;
ID = Guid.NewGuid();
}
[UsedImplicitly] // Realm
private RealmKeyBinding()
{
}
} }
} }

View File

@ -92,13 +92,7 @@ namespace osu.Game.Input
if (defaultsCount > existingCount) if (defaultsCount > existingCount)
{ {
// insert any defaults which are missing. // insert any defaults which are missing.
realm.Add(defaultsForAction.Skip(existingCount).Select(k => new RealmKeyBinding realm.Add(defaultsForAction.Skip(existingCount).Select(k => new RealmKeyBinding(k.Action, k.KeyCombination, rulesetName, variant)));
{
KeyCombinationString = k.KeyCombination.ToString(),
ActionInt = (int)k.Action,
RulesetName = rulesetName,
Variant = variant
}));
} }
else if (defaultsCount < existingCount) else if (defaultsCount < existingCount)
{ {

View File

@ -29,11 +29,11 @@ namespace osu.Game.Scoring
public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable<ScoreInfo>, IScoreInfo public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable<ScoreInfo>, IScoreInfo
{ {
[PrimaryKey] [PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid(); public Guid ID { get; set; }
public BeatmapInfo BeatmapInfo { get; set; } public BeatmapInfo BeatmapInfo { get; set; } = null!;
public RulesetInfo Ruleset { get; set; } public RulesetInfo Ruleset { get; set; } = null!;
public IList<RealmNamedFileUsage> Files { get; } = null!; public IList<RealmNamedFileUsage> Files { get; } = null!;
@ -57,7 +57,7 @@ namespace osu.Game.Scoring
public long OnlineID { get; set; } = -1; public long OnlineID { get; set; } = -1;
[MapTo("User")] [MapTo("User")]
public RealmUser RealmUser { get; set; } public RealmUser RealmUser { get; set; } = null!;
[MapTo("Mods")] [MapTo("Mods")]
public string ModsJson { get; set; } = string.Empty; public string ModsJson { get; set; } = string.Empty;
@ -65,19 +65,17 @@ namespace osu.Game.Scoring
[MapTo("Statistics")] [MapTo("Statistics")]
public string StatisticsJson { get; set; } = string.Empty; public string StatisticsJson { get; set; } = string.Empty;
public ScoreInfo(BeatmapInfo beatmap, RulesetInfo ruleset, RealmUser realmUser) public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{ {
Ruleset = ruleset; Ruleset = ruleset ?? new RulesetInfo();
BeatmapInfo = beatmap; BeatmapInfo = beatmap ?? new BeatmapInfo();
RealmUser = realmUser; RealmUser = realmUser ?? new RealmUser();
ID = Guid.NewGuid();
} }
[UsedImplicitly] [UsedImplicitly] // Realm
public ScoreInfo() // TODO: consider removing this and migrating all usages to ctor with parameters. private ScoreInfo()
{ {
Ruleset = new RulesetInfo();
RealmUser = new RealmUser();
BeatmapInfo = new BeatmapInfo();
} }
// TODO: this is a bit temporary to account for the fact that this class is used to ferry API user data to certain UI components. // TODO: this is a bit temporary to account for the fact that this class is used to ferry API user data to certain UI components.

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Testing; using osu.Framework.Testing;
@ -26,16 +27,16 @@ namespace osu.Game.Skinning
[PrimaryKey] [PrimaryKey]
[JsonProperty] [JsonProperty]
public Guid ID { get; set; } = Guid.NewGuid(); public Guid ID { get; set; }
[JsonProperty] [JsonProperty]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = null!;
[JsonProperty] [JsonProperty]
public string Creator { get; set; } = string.Empty; public string Creator { get; set; } = null!;
[JsonProperty] [JsonProperty]
public string InstantiationInfo { get; set; } = string.Empty; public string InstantiationInfo { get; set; } = null!;
public string Hash { get; set; } = string.Empty; public string Hash { get; set; } = string.Empty;
@ -55,6 +56,19 @@ namespace osu.Game.Skinning
public bool DeletePending { get; set; } public bool DeletePending { get; set; }
public SkinInfo(string? name = null, string? creator = null, string? instantiationInfo = null)
{
Name = name ?? string.Empty;
Creator = creator ?? string.Empty;
InstantiationInfo = instantiationInfo ?? string.Empty;
ID = Guid.NewGuid();
}
[UsedImplicitly] // Realm
private SkinInfo()
{
}
public bool Equals(SkinInfo? other) public bool Equals(SkinInfo? other)
{ {
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;